(column_number_displayed): New variable.
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
b8009dd1 2 Copyright (C) 1989, 1993, 1994 Free Software Foundation, Inc.
dc6f92b8
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
4746118a 8the Free Software Foundation; either version 2, or (at your option)
dc6f92b8
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
3afe33e7
RS
20/* Xt features made by Fred Pierresteguy. */
21
039440c4
RS
22/* On 4.3 these lose if they come after xterm.h. */
23/* On HP-UX 8.0 signal.h loses if it comes after config.h. */
24/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
25#include <signal.h>
26
18160b98 27#include <config.h>
dc6f92b8 28
4846819e
RS
29#include <stdio.h>
30
3afe33e7 31/* Need syssignal.h for various externs and definitions that may be required
bc20ebbf 32 by some configurations for calls to signal later in this source file. */
3afe33e7
RS
33#include "syssignal.h"
34
dc6f92b8
JB
35#ifdef HAVE_X_WINDOWS
36
37#include "lisp.h"
9ac0d9e0 38#include "blockinput.h"
dc6f92b8 39
dc6f92b8
JB
40/* This may include sys/types.h, and that somehow loses
41 if this is not done before the other system files. */
42#include "xterm.h"
f451eb13 43#include <X11/cursorfont.h>
dc6f92b8 44
16bd92ea 45#ifndef USG
dc6f92b8
JB
46/* Load sys/types.h if not already loaded.
47 In some systems loading it twice is suicidal. */
48#ifndef makedev
49#include <sys/types.h>
c118dd06
JB
50#endif /* makedev */
51#endif /* USG */
dc6f92b8
JB
52
53#ifdef BSD
54#include <sys/ioctl.h>
c118dd06 55#endif /* ! defined (BSD) */
dc6f92b8 56
2d368234 57#include "systty.h"
3a2712f9 58#include "systime.h"
dc6f92b8 59
b8009dd1 60#ifndef INCLUDED_FCNTL
dc6f92b8 61#include <fcntl.h>
b8009dd1 62#endif
dc6f92b8
JB
63#include <ctype.h>
64#include <errno.h>
65#include <setjmp.h>
66#include <sys/stat.h>
67#include <sys/param.h>
68
7a13e894 69#include "frame.h"
dc6f92b8
JB
70#include "dispextern.h"
71#include "termhooks.h"
72#include "termopts.h"
73#include "termchar.h"
74#if 0
75#include "sink.h"
76#include "sinkmask.h"
c118dd06 77#endif /* ! 0 */
dc6f92b8 78#include "gnu.h"
dc6f92b8 79#include "disptab.h"
dc6f92b8 80#include "buffer.h"
f451eb13 81#include "window.h"
3b2fa4e6 82#include "keyboard.h"
bde7c500 83#include "intervals.h"
dc6f92b8 84
3afe33e7 85#ifdef USE_X_TOOLKIT
9d7e2e3e 86extern void free_frame_menubar ();
c2df547c 87extern void _XEditResCheckMessages ();
3afe33e7
RS
88#endif /* USE_X_TOOLKIT */
89
b849c413
RS
90#ifndef USE_X_TOOLKIT
91#define x_any_window_to_frame x_window_to_frame
5627c40e 92#define x_top_window_to_frame x_window_to_frame
b849c413
RS
93#endif
94
546e6d5b
RS
95#ifdef USE_X_TOOLKIT
96#ifndef XtNinitialState
97#define XtNinitialState "initialState"
98#endif
99#endif
100
dc6f92b8
JB
101#define min(a,b) ((a)<(b) ? (a) : (b))
102#define max(a,b) ((a)>(b) ? (a) : (b))
69388238 103\f
334208b7
RS
104/* This is a chain of structures for all the X displays currently in use. */
105struct x_display_info *x_display_list;
dc6f92b8 106
7a13e894
RS
107/* This is a list of cons cells, each of the form (NAME . FONT-LIST-CACHE),
108 one for each element of x_display_list and in the same order.
109 NAME is the name of the frame.
110 FONT-LIST-CACHE records previous values returned by x-list-fonts. */
111Lisp_Object x_display_name_list;
f451eb13 112
987d2ad1 113/* Frame being updated by update_frame. This is declared in term.c.
d0386f2a 114 This is set by update_begin and looked at by all the
dc6f92b8 115 XT functions. It is zero while not inside an update.
f676886a
JB
116 In that case, the XT functions assume that `selected_frame'
117 is the frame to apply to. */
d0386f2a 118extern struct frame *updating_frame;
dc6f92b8 119
f676886a 120/* The frame (if any) which has the X window that has keyboard focus.
f451eb13
JB
121 Zero if none. This is examined by Ffocus_frame in frame.c. Note
122 that a mere EnterNotify event can set this; if you need to know the
123 last frame specified in a FocusIn or FocusOut event, use
124 x_focus_event_frame. */
f676886a 125struct frame *x_focus_frame;
dc6f92b8 126
0134a210
RS
127/* This is a frame waiting to be autoraised, within XTread_socket. */
128struct frame *pending_autoraise_frame;
129
f451eb13
JB
130/* The last frame mentioned in a FocusIn or FocusOut event. This is
131 separate from x_focus_frame, because whether or not LeaveNotify
132 events cause us to lose focus depends on whether or not we have
133 received a FocusIn event for it. */
134struct frame *x_focus_event_frame;
135
f676886a
JB
136/* The frame which currently has the visual highlight, and should get
137 keyboard input (other sorts of input have the frame encoded in the
138 event). It points to the X focus frame's selected window's
139 frame. It differs from x_focus_frame when we're using a global
6d4238f3 140 minibuffer. */
f676886a 141static struct frame *x_highlight_frame;
6d4238f3 142
7f9c7f94
RS
143#ifdef USE_X_TOOLKIT
144/* The application context for Xt use. */
145XtAppContext Xt_app_con;
146#endif
147
dc6f92b8
JB
148/* During an update, maximum vpos for ins/del line operations to affect. */
149
150static int flexlines;
151
152/* During an update, nonzero if chars output now should be highlighted. */
153
154static int highlight;
155
156/* Nominal cursor position -- where to draw output.
157 During an update, these are different from the cursor-box position. */
158
159static int curs_x;
160static int curs_y;
161
69388238
RS
162/* Mouse movement.
163
164 In order to avoid asking for motion events and then throwing most
165 of them away or busy-polling the server for mouse positions, we ask
166 the server for pointer motion hints. This means that we get only
167 one event per group of mouse movements. "Groups" are delimited by
168 other kinds of events (focus changes and button clicks, for
169 example), or by XQueryPointer calls; when one of these happens, we
170 get another MotionNotify event the next time the mouse moves. This
171 is at least as efficient as getting motion events when mouse
172 tracking is on, and I suspect only negligibly worse when tracking
173 is off.
174
175 The silly O'Reilly & Associates Nutshell guides barely document
176 pointer motion hints at all (I think you have to infer how they
177 work from an example), and the description of XQueryPointer doesn't
178 mention that calling it causes you to get another motion hint from
179 the server, which is very important. */
180
181/* Where the mouse was last time we reported a mouse event. */
182static FRAME_PTR last_mouse_frame;
183static XRectangle last_mouse_glyph;
184
185/* The scroll bar in which the last X motion event occurred.
186
187 If the last X motion event occurred in a scroll bar, we set this
188 so XTmouse_position can know whether to report a scroll bar motion or
189 an ordinary motion.
190
191 If the last X motion event didn't occur in a scroll bar, we set this
192 to Qnil, to tell XTmouse_position to return an ordinary motion event. */
193static Lisp_Object last_mouse_scroll_bar;
194
69388238
RS
195/* This is a hack. We would really prefer that XTmouse_position would
196 return the time associated with the position it returns, but there
197 doesn't seem to be any way to wrest the timestamp from the server
198 along with the position query. So, we just keep track of the time
199 of the last movement we received, and return that in hopes that
200 it's somewhat accurate. */
201static Time last_mouse_movement_time;
202
c0a04927
RS
203/* Incremented by XTread_socket whenever it really tries to read events. */
204#ifdef __STDC__
205static int volatile input_signal_count;
206#else
207static int input_signal_count;
208#endif
209
7a13e894
RS
210/* Used locally within XTread_socket. */
211static int x_noop_count;
dc6f92b8 212
7a13e894
RS
213/* Initial values of argv and argc. */
214extern char **initial_argv;
215extern int initial_argc;
dc6f92b8 216
7a13e894 217extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 218
7a13e894
RS
219/* Tells if a window manager is present or not. */
220
221extern Lisp_Object Vx_no_window_manager;
dc6f92b8
JB
222
223/* Nonzero enables some debugging for the X interface code. */
224extern int _Xdebug;
225
c2df547c 226extern Lisp_Object Qface, Qmouse_face;
b8009dd1 227
dc6f92b8
JB
228extern int errno;
229
dfeccd2d 230/* A mask of extra modifier bits to put into every keyboard char. */
64bb1782
RS
231extern int extra_keyboard_modifiers;
232
334208b7 233extern XrmDatabase x_load_resources ();
dc6f92b8 234
7a13e894
RS
235void x_delete_display ();
236
dc6f92b8 237static void flashback ();
c83febd7 238static void redraw_previous_char ();
0cdd0c9f 239static void redraw_following_char ();
3afe33e7 240static unsigned int x_x_to_emacs_modifiers ();
dc6f92b8 241
55836b73 242static int fast_find_position ();
b8009dd1
RS
243static void note_mouse_highlight ();
244static void clear_mouse_face ();
245static void show_mouse_face ();
58769bee 246static void do_line_dance ();
b8009dd1 247
4746118a
JB
248static int XTcursor_to ();
249static int XTclear_end_of_line ();
7a13e894 250static int x_io_error_quitter ();
334208b7
RS
251\f
252/* Return the struct x_display_info corresponding to DPY. */
253
254struct x_display_info *
255x_display_info_for_display (dpy)
256 Display *dpy;
257{
258 struct x_display_info *dpyinfo;
259
260 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
261 if (dpyinfo->display == dpy)
262 return dpyinfo;
16bd92ea 263
334208b7
RS
264 return 0;
265}
16bd92ea 266\f
58769bee 267/* Starting and ending updates.
f451eb13
JB
268
269 These hooks are called by update_frame at the beginning and end
f676886a
JB
270 of a frame update. We record in `updating_frame' the identity
271 of the frame being updated, so that the XT... functions do not
272 need to take a frame as argument. Most of the XT... functions
dc6f92b8 273 should never be called except during an update, the only exceptions
c83febd7 274 being XTcursor_to, XTwrite_glyphs and XTreassert_line_highlight. */
dc6f92b8 275
dc6f92b8 276static
f676886a
JB
277XTupdate_begin (f)
278 struct frame *f;
58769bee 279{
dc6f92b8
JB
280 int mask;
281
f676886a 282 if (f == 0)
dc6f92b8
JB
283 abort ();
284
f676886a 285 flexlines = f->height;
dc6f92b8
JB
286 highlight = 0;
287
dc6f92b8 288 BLOCK_INPUT;
b8009dd1 289
7a13e894 290 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
b8009dd1 291 {
514e4681 292 /* Don't do highlighting for mouse motion during the update. */
7a13e894
RS
293 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 1;
294 if (!NILP (FRAME_X_DISPLAY_INFO (f)->mouse_face_window))
514e4681
RS
295 {
296 int firstline, lastline, i;
7a13e894 297 struct window *w = XWINDOW (FRAME_X_DISPLAY_INFO (f)->mouse_face_window);
514e4681
RS
298
299 /* Find the first, and the last+1, lines affected by redisplay. */
300 for (firstline = 0; firstline < f->height; firstline++)
301 if (FRAME_DESIRED_GLYPHS (f)->enable[firstline])
302 break;
303
304 lastline = f->height;
305 for (i = f->height - 1; i >= 0; i--)
306 {
307 if (FRAME_DESIRED_GLYPHS (f)->enable[i])
308 break;
309 else
310 lastline = i;
311 }
312
313 /* Can we tell that this update does not affect the window
314 where the mouse highlight is? If so, no need to turn off. */
315 if (! (firstline > (XFASTINT (w->top) + window_internal_height (w))
316 || lastline < XFASTINT (w->top)))
317 /* Otherwise turn off the mouse highlight now. */
7a13e894 318 clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
514e4681 319 }
b8009dd1 320 }
6ccf47d1 321
dc6f92b8
JB
322 UNBLOCK_INPUT;
323}
324
dc6f92b8 325static
f676886a
JB
326XTupdate_end (f)
327 struct frame *f;
58769bee 328{
dc6f92b8
JB
329 int mask;
330
dc6f92b8 331 BLOCK_INPUT;
dc6f92b8 332
58769bee 333 do_line_dance ();
f676886a 334 x_display_cursor (f, 1);
dc6f92b8 335
7a13e894
RS
336 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
337 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1
RS
338#if 0
339 /* This fails in the case of having updated only the echo area
340 if we have switched buffers. In that case, FRAME_CURRENT_GLYPHS
341 has no relation to the current contents, and its charstarts
342 have no relation to the contents of the window-buffer.
343 I don't know a clean way to check
344 for that case. window_end_valid isn't set up yet. */
7a13e894
RS
345 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
346 note_mouse_highlight (f, FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_x,
347 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_y);
b8009dd1
RS
348#endif
349
334208b7 350 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
351 UNBLOCK_INPUT;
352}
b8009dd1 353
514e4681 354/* This is called after a redisplay on frame F. */
b8009dd1
RS
355
356static
357XTframe_up_to_date (f)
358 FRAME_PTR f;
359{
7a13e894
RS
360 if (FRAME_X_DISPLAY_INFO (f)->mouse_face_deferred_gc
361 || f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
514e4681 362 {
7a13e894
RS
363 note_mouse_highlight (FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame,
364 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_x,
365 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_y);
366 FRAME_X_DISPLAY_INFO (f)->mouse_face_deferred_gc = 0;
514e4681 367 }
b8009dd1 368}
dc6f92b8
JB
369\f
370/* External interface to control of standout mode.
371 Call this when about to modify line at position VPOS
372 and not change whether it is highlighted. */
373
374XTreassert_line_highlight (new, vpos)
375 int new, vpos;
376{
377 highlight = new;
378}
379
380/* Call this when about to modify line at position VPOS
381 and change whether it is highlighted. */
382
383static
384XTchange_line_highlight (new_highlight, vpos, first_unused_hpos)
385 int new_highlight, vpos, first_unused_hpos;
386{
387 highlight = new_highlight;
388 XTcursor_to (vpos, 0);
f676886a 389 XTclear_end_of_line (updating_frame->width);
dc6f92b8
JB
390}
391
392/* This is used when starting Emacs and when restarting after suspend.
393 When starting Emacs, no X window is mapped. And nothing must be done
394 to Emacs's own window if it is suspended (though that rarely happens). */
395
396static
397XTset_terminal_modes ()
398{
399}
400
401/* This is called when exiting or suspending Emacs.
402 Exiting will make the X-windows go away, and suspending
403 requires no action. */
404
405static
406XTreset_terminal_modes ()
407{
f676886a 408/* XTclear_frame (); */
dc6f92b8
JB
409}
410\f
f451eb13
JB
411/* Set the nominal cursor position of the frame.
412 This is where display update commands will take effect.
dc6f92b8
JB
413 This does not affect the place where the cursor-box is displayed. */
414
4746118a 415static int
dc6f92b8
JB
416XTcursor_to (row, col)
417 register int row, col;
418{
419 int mask;
420 int orow = row;
421
422 curs_x = col;
423 curs_y = row;
424
f676886a 425 if (updating_frame == 0)
dc6f92b8
JB
426 {
427 BLOCK_INPUT;
f676886a 428 x_display_cursor (selected_frame, 1);
334208b7 429 XFlush (FRAME_X_DISPLAY (selected_frame));
dc6f92b8
JB
430 UNBLOCK_INPUT;
431 }
432}
433\f
434/* Display a sequence of N glyphs found at GP.
435 WINDOW is the x-window to output to. LEFT and TOP are starting coords.
b8009dd1
RS
436 HL is 1 if this text is highlighted, 2 if the cursor is on it,
437 3 if should appear in its mouse-face.
0cdd0c9f
RS
438 JUST_FOREGROUND if 1 means draw only the foreground;
439 don't alter the background.
dc6f92b8 440
07e34cb0 441 FONT is the default font to use (for glyphs whose font-code is 0).
dc6f92b8 442
07e34cb0
JB
443 Since the display generation code is responsible for calling
444 compute_char_face and compute_glyph_face on everything it puts in
445 the display structure, we can assume that the face code on each
28f72798 446 glyph is a valid index into FRAME_COMPUTED_FACES (f), and the one
f94397b5
KH
447 to which we can actually apply intern_face.
448 Call this function with input blocked. */
dc6f92b8 449
07e34cb0
JB
450#if 1
451/* This is the multi-face code. */
dc6f92b8 452
dc6f92b8 453static void
0cdd0c9f 454dumpglyphs (f, left, top, gp, n, hl, just_foreground)
f676886a 455 struct frame *f;
dc6f92b8
JB
456 int left, top;
457 register GLYPH *gp; /* Points to first GLYPH. */
458 register int n; /* Number of glyphs to display. */
459 int hl;
0cdd0c9f 460 int just_foreground;
dc6f92b8 461{
07e34cb0
JB
462 /* Holds characters to be displayed. */
463 char *buf = (char *) alloca (f->width * sizeof (*buf));
dc6f92b8
JB
464 register char *cp; /* Steps through buf[]. */
465 register int tlen = GLYPH_TABLE_LENGTH;
466 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
c118dd06 467 Window window = FRAME_X_WINDOW (f);
0cdd0c9f 468 int orig_left = left;
dc6f92b8 469
07e34cb0 470 while (n > 0)
dc6f92b8
JB
471 {
472 /* Get the face-code of the next GLYPH. */
473 int cf, len;
474 int g = *gp;
475
07e34cb0 476 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
6f63ba79 477 cf = FAST_GLYPH_FACE (g);
dc6f92b8
JB
478
479 /* Find the run of consecutive glyphs with the same face-code.
480 Extract their character codes into BUF. */
481 cp = buf;
482 while (n > 0)
483 {
484 g = *gp;
07e34cb0 485 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
6f63ba79 486 if (FAST_GLYPH_FACE (g) != cf)
dc6f92b8
JB
487 break;
488
6f63ba79 489 *cp++ = FAST_GLYPH_CHAR (g);
dc6f92b8
JB
490 --n;
491 ++gp;
492 }
493
494 /* LEN gets the length of the run. */
495 len = cp - buf;
496
497 /* Now output this run of chars, with the font and pixel values
498 determined by the face code CF. */
07e34cb0
JB
499 {
500 struct face *face = FRAME_DEFAULT_FACE (f);
334208b7 501 XFontStruct *font = FACE_FONT (face);
07e34cb0 502 GC gc = FACE_GC (face);
990ba854 503 int stippled = 0;
07e34cb0 504
b8009dd1
RS
505 /* HL = 3 means use a mouse face previously chosen. */
506 if (hl == 3)
7a13e894 507 cf = FRAME_X_DISPLAY_INFO (f)->mouse_face_face_id;
b8009dd1 508
b73b6aaf
RS
509 /* First look at the face of the text itself. */
510 if (cf != 0)
07e34cb0 511 {
a07d4bc5
RS
512 /* It's possible for the display table to specify
513 a face code that is out of range. Use 0 in that case. */
28f72798
JB
514 if (cf < 0 || cf >= FRAME_N_COMPUTED_FACES (f)
515 || FRAME_COMPUTED_FACES (f) [cf] == 0)
a07d4bc5 516 cf = 0;
07e34cb0
JB
517
518 if (cf == 1)
519 face = FRAME_MODE_LINE_FACE (f);
520 else
28f72798 521 face = intern_face (f, FRAME_COMPUTED_FACES (f) [cf]);
07e34cb0
JB
522 font = FACE_FONT (face);
523 gc = FACE_GC (face);
990ba854
RS
524 if (FACE_STIPPLE (face))
525 stippled = 1;
07e34cb0 526 }
4a4dc352
JB
527
528 /* Then comes the distinction between modeline and normal text. */
07e34cb0
JB
529 else if (hl == 0)
530 ;
531 else if (hl == 1)
532 {
533 face = FRAME_MODE_LINE_FACE (f);
534 font = FACE_FONT (face);
535 gc = FACE_GC (face);
990ba854
RS
536 if (FACE_STIPPLE (face))
537 stippled = 1;
b73b6aaf
RS
538 }
539
540#define FACE_DEFAULT (~0)
541
542 /* Now override that if the cursor's on this character. */
b5cf7a0e 543 if (hl == 2)
b73b6aaf 544 {
990ba854
RS
545 /* The cursor overrides stippling. */
546 stippled = 0;
547
11dd3d61
RS
548 if ((!face->font
549 || (int) face->font == FACE_DEFAULT
550 || face->font == f->display.x->font)
551 && face->background == f->display.x->background_pixel
552 && face->foreground == f->display.x->foreground_pixel)
b5cf7a0e
JB
553 {
554 gc = f->display.x->cursor_gc;
555 }
556 /* Cursor on non-default face: must merge. */
557 else
558 {
559 XGCValues xgcv;
560 unsigned long mask;
561
562 xgcv.background = f->display.x->cursor_pixel;
11dd3d61 563 xgcv.foreground = face->background;
df5a440b
RS
564 /* If the glyph would be invisible,
565 try a different foreground. */
566 if (xgcv.foreground == xgcv.background)
da893f1f 567 xgcv.foreground = face->foreground;
df5a440b
RS
568 if (xgcv.foreground == xgcv.background)
569 xgcv.foreground = f->display.x->cursor_foreground_pixel;
570 if (xgcv.foreground == xgcv.background)
571 xgcv.foreground = face->foreground;
572 /* Make sure the cursor is distinct from text in this face. */
573 if (xgcv.background == face->background
574 && xgcv.foreground == face->foreground)
575 {
576 xgcv.background = face->foreground;
577 xgcv.foreground = face->background;
578 }
b5cf7a0e
JB
579 xgcv.font = face->font->fid;
580 xgcv.graphics_exposures = 0;
581 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
7a13e894
RS
582 if (FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc)
583 XChangeGC (FRAME_X_DISPLAY (f),
584 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc,
585 mask, &xgcv);
11dd3d61 586 else
7a13e894 587 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc
334208b7 588 = XCreateGC (FRAME_X_DISPLAY (f), window, mask, &xgcv);
7a13e894 589 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
b73b6aaf 590#if 0
11dd3d61
RS
591/* If this code is restored, it must also reset to the default stipple
592 if necessary. */
b5cf7a0e 593 if (face->stipple && face->stipple != FACE_DEFAULT)
334208b7 594 XSetStipple (FRAME_X_DISPLAY (f), gc, face->stipple);
b73b6aaf 595#endif
b5cf7a0e 596 }
07e34cb0 597 }
07e34cb0 598
b5cf7a0e
JB
599 if ((int) font == FACE_DEFAULT)
600 font = f->display.x->font;
601
0cdd0c9f 602 if (just_foreground)
334208b7 603 XDrawString (FRAME_X_DISPLAY (f), window, gc,
0cdd0c9f
RS
604 left, top + FONT_BASE (font), buf, len);
605 else
606 {
990ba854
RS
607 if (stippled)
608 {
609 /* Turn stipple on. */
610 XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillOpaqueStippled);
611
612 /* Draw stipple on background. */
334208b7 613 XFillRectangle (FRAME_X_DISPLAY (f), window, gc,
990ba854
RS
614 left, top,
615 FONT_WIDTH (font) * len,
616 FONT_HEIGHT (font));
617
618 /* Turn stipple off. */
619 XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillSolid);
620
621 /* Draw the text, solidly, onto the stipple pattern. */
334208b7 622 XDrawString (FRAME_X_DISPLAY (f), window, gc,
990ba854
RS
623 left, top + FONT_BASE (font), buf, len);
624 }
625 else
334208b7 626 XDrawImageString (FRAME_X_DISPLAY (f), window, gc,
990ba854
RS
627 left, top + FONT_BASE (font), buf, len);
628
0cdd0c9f
RS
629 /* Clear the rest of the line's height. */
630 if (f->display.x->line_height != FONT_HEIGHT (font))
334208b7 631 XClearArea (FRAME_X_DISPLAY (f), window, left,
0cdd0c9f
RS
632 top + FONT_HEIGHT (font),
633 FONT_WIDTH (font) * len,
634 /* This is how many pixels of height
635 we have to clear. */
636 f->display.x->line_height - FONT_HEIGHT (font),
637 False);
638 }
639
640#if 0 /* Doesn't work, because it uses FRAME_CURRENT_GLYPHS,
641 which often is not up to date yet. */
642 if (!just_foreground)
643 {
644 if (left == orig_left)
645 redraw_previous_char (f, PIXEL_TO_CHAR_COL (f, left),
646 PIXEL_TO_CHAR_ROW (f, top), hl == 1);
647 if (n == 0)
648 redraw_following_char (f, PIXEL_TO_CHAR_COL (f, left + len * FONT_WIDTH (font)),
649 PIXEL_TO_CHAR_ROW (f, top), hl == 1);
650 }
651#endif
07e34cb0
JB
652
653 /* We should probably check for XA_UNDERLINE_POSITION and
654 XA_UNDERLINE_THICKNESS properties on the font, but let's
655 just get the thing working, and come back to that. */
dc6f92b8 656 {
4a4dc352 657 int underline_position = 1;
07e34cb0 658
4a4dc352
JB
659 if (font->descent <= underline_position)
660 underline_position = font->descent - 1;
07e34cb0
JB
661
662 if (face->underline)
334208b7 663 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
07e34cb0
JB
664 FACE_GC (face),
665 left, (top
666 + FONT_BASE (font)
667 + underline_position),
668 len * FONT_WIDTH (font), 1);
dc6f92b8 669 }
07e34cb0
JB
670
671 left += len * FONT_WIDTH (font);
672 }
dc6f92b8
JB
673 }
674}
07e34cb0
JB
675#endif /* 1 */
676
677#if 0
678/* This is the old single-face code. */
679
680static void
681dumpglyphs (f, left, top, gp, n, hl, font)
682 struct frame *f;
683 int left, top;
684 register GLYPH *gp; /* Points to first GLYPH. */
685 register int n; /* Number of glyphs to display. */
686 int hl;
334208b7 687 XFontStruct *font;
07e34cb0
JB
688{
689 register int len;
690 Window window = FRAME_X_WINDOW (f);
691 GC drawing_gc = (hl == 2 ? f->display.x->cursor_gc
692 : (hl ? f->display.x->reverse_gc
693 : f->display.x->normal_gc));
694
695 if (sizeof (GLYPH) == sizeof (XChar2b))
334208b7 696 XDrawImageString16 (FRAME_X_DISPLAY (f), window, drawing_gc,
07e34cb0
JB
697 left, top + FONT_BASE (font), (XChar2b *) gp, n);
698 else if (sizeof (GLYPH) == sizeof (unsigned char))
334208b7 699 XDrawImageString (FRAME_X_DISPLAY (f), window, drawing_gc,
07e34cb0
JB
700 left, top + FONT_BASE (font), (char *) gp, n);
701 else
702 /* What size of glyph ARE you using? And does X have a function to
703 draw them? */
704 abort ();
705}
706#endif
dc6f92b8 707\f
f451eb13
JB
708/* Output some text at the nominal frame cursor position.
709 Advance the cursor over the text.
dc6f92b8
JB
710 Output LEN glyphs at START.
711
712 `highlight', set up by XTreassert_line_highlight or XTchange_line_highlight,
713 controls the pixel values used for foreground and background. */
714
715static
716XTwrite_glyphs (start, len)
717 register GLYPH *start;
718 int len;
719{
720 register int temp_length;
721 int mask;
f676886a 722 struct frame *f;
dc6f92b8
JB
723
724 BLOCK_INPUT;
725
58769bee 726 do_line_dance ();
f676886a
JB
727 f = updating_frame;
728 if (f == 0)
dc6f92b8 729 {
f676886a 730 f = selected_frame;
dc6f92b8 731 /* If not within an update,
f676886a
JB
732 output at the frame's visible cursor. */
733 curs_x = f->cursor_x;
734 curs_y = f->cursor_y;
dc6f92b8
JB
735 }
736
f676886a 737 dumpglyphs (f,
12ba150f
JB
738 CHAR_TO_PIXEL_COL (f, curs_x),
739 CHAR_TO_PIXEL_ROW (f, curs_y),
0cdd0c9f 740 start, len, highlight, 0);
90e65f07
JB
741
742 /* If we drew on top of the cursor, note that it is turned off. */
f676886a
JB
743 if (curs_y == f->phys_cursor_y
744 && curs_x <= f->phys_cursor_x
745 && curs_x + len > f->phys_cursor_x)
746 f->phys_cursor_x = -1;
58769bee 747
f676886a 748 if (updating_frame == 0)
dc6f92b8 749 {
f676886a
JB
750 f->cursor_x += len;
751 x_display_cursor (f, 1);
752 f->cursor_x -= len;
dc6f92b8
JB
753 }
754 else
755 curs_x += len;
756
757 UNBLOCK_INPUT;
758}
759\f
f451eb13
JB
760/* Clear to the end of the line.
761 Erase the current text line from the nominal cursor position (inclusive)
dc6f92b8
JB
762 to column FIRST_UNUSED (exclusive). The idea is that everything
763 from FIRST_UNUSED onward is already erased. */
58769bee 764
4746118a 765static int
dc6f92b8
JB
766XTclear_end_of_line (first_unused)
767 register int first_unused;
768{
f676886a 769 struct frame *f = updating_frame;
dc6f92b8
JB
770 int mask;
771
f676886a 772 if (f == 0)
dc6f92b8
JB
773 abort ();
774
f676886a 775 if (curs_y < 0 || curs_y >= f->height)
dc6f92b8
JB
776 return;
777 if (first_unused <= 0)
778 return;
779
f676886a
JB
780 if (first_unused >= f->width)
781 first_unused = f->width;
dc6f92b8
JB
782
783 BLOCK_INPUT;
784
90e65f07 785 /* Notice if the cursor will be cleared by this operation. */
f676886a
JB
786 if (curs_y == f->phys_cursor_y
787 && curs_x <= f->phys_cursor_x
788 && f->phys_cursor_x < first_unused)
789 f->phys_cursor_x = -1;
dc6f92b8 790
334208b7 791 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12ba150f
JB
792 CHAR_TO_PIXEL_COL (f, curs_x),
793 CHAR_TO_PIXEL_ROW (f, curs_y),
f676886a 794 FONT_WIDTH (f->display.x->font) * (first_unused - curs_x),
a27f9f86 795 f->display.x->line_height, False);
c83febd7 796#if 0
0cdd0c9f 797 redraw_previous_char (f, curs_x, curs_y, highlight);
c83febd7 798#endif
dc6f92b8
JB
799
800 UNBLOCK_INPUT;
801}
802
0cdd0c9f
RS
803static
804XTclear_frame ()
805{
806 int mask;
807 struct frame *f = updating_frame;
808
809 if (f == 0)
810 f = selected_frame;
811
812 f->phys_cursor_x = -1; /* Cursor not visible. */
813 curs_x = 0; /* Nominal cursor position is top left. */
814 curs_y = 0;
58769bee 815
0cdd0c9f
RS
816 BLOCK_INPUT;
817
334208b7 818 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0cdd0c9f
RS
819
820 /* We have to clear the scroll bars, too. If we have changed
821 colors or something like that, then they should be notified. */
822 x_scroll_bar_clear (f);
823
334208b7 824 XFlush (FRAME_X_DISPLAY (f));
0cdd0c9f
RS
825 UNBLOCK_INPUT;
826}
827\f
828#if 0
829/* This currently does not work because FRAME_CURRENT_GLYPHS doesn't
830 always contain the right glyphs to use.
831
832 It also needs to be changed to look at the details of the font and
833 see whether there is really overlap, and do nothing when there is
834 not. This can use font_char_overlap_left and font_char_overlap_right,
835 but just how to use them is not clear. */
836
c83febd7
RS
837/* Erase the character (if any) at the position just before X, Y in frame F,
838 then redraw it and the character before it.
839 This is necessary when we erase starting at X,
f94397b5
KH
840 in case the character after X overlaps into the one before X.
841 Call this function with input blocked. */
c83febd7
RS
842
843static void
0cdd0c9f 844redraw_previous_char (f, x, y, highlight_flag)
c83febd7
RS
845 FRAME_PTR f;
846 int x, y;
0cdd0c9f 847 int highlight_flag;
c83febd7
RS
848{
849 /* Erase the character before the new ones, in case
850 what was here before overlaps it.
851 Reoutput that character, and the previous character
852 (in case the previous character overlaps it). */
853 if (x > 0)
854 {
855 int start_x = x - 2;
856 if (start_x < 0)
857 start_x = 0;
334208b7 858 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
c83febd7
RS
859 CHAR_TO_PIXEL_COL (f, x - 1),
860 CHAR_TO_PIXEL_ROW (f, y),
861 FONT_WIDTH (f->display.x->font),
a27f9f86 862 f->display.x->line_height, False);
c83febd7
RS
863
864 dumpglyphs (f, CHAR_TO_PIXEL_COL (f, start_x),
865 CHAR_TO_PIXEL_ROW (f, y),
866 &FRAME_CURRENT_GLYPHS (f)->glyphs[y][start_x],
0cdd0c9f 867 x - start_x, highlight_flag, 1);
c83febd7
RS
868 }
869}
870
0cdd0c9f
RS
871/* Erase the character (if any) at the position X, Y in frame F,
872 then redraw it and the character after it.
873 This is necessary when we erase endng at X,
874 in case the character after X overlaps into the one before X.
875 Call this function with input blocked. */
876
877static void
878redraw_following_char (f, x, y, highlight_flag)
879 FRAME_PTR f;
880 int x, y;
881 int highlight_flag;
dc6f92b8 882{
0cdd0c9f
RS
883 int limit = FRAME_CURRENT_GLYPHS (f)->used[y];
884 /* Erase the character after the new ones, in case
885 what was here before overlaps it.
886 Reoutput that character, and the following character
887 (in case the following character overlaps it). */
888 if (x < limit
889 && FRAME_CURRENT_GLYPHS (f)->glyphs[y][x] != SPACEGLYPH)
890 {
891 int end_x = x + 2;
892 if (end_x > limit)
893 end_x = limit;
334208b7 894 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
0cdd0c9f
RS
895 CHAR_TO_PIXEL_COL (f, x),
896 CHAR_TO_PIXEL_ROW (f, y),
897 FONT_WIDTH (f->display.x->font),
898 f->display.x->line_height, False);
dc6f92b8 899
0cdd0c9f
RS
900 dumpglyphs (f, CHAR_TO_PIXEL_COL (f, x),
901 CHAR_TO_PIXEL_ROW (f, y),
902 &FRAME_CURRENT_GLYPHS (f)->glyphs[y][x],
903 end_x - x, highlight_flag, 1);
904 }
905}
906#endif /* 0 */
907\f
908#if 0 /* Not in use yet */
dc6f92b8 909
0cdd0c9f 910/* Return 1 if character C in font F extends past its left edge. */
dbc4e1c1 911
0cdd0c9f
RS
912static int
913font_char_overlap_left (font, c)
914 XFontStruct *font;
915 int c;
916{
917 XCharStruct *s;
dbc4e1c1 918
0cdd0c9f
RS
919 /* Find the bounding-box info for C. */
920 if (font->per_char == 0)
921 s = &font->max_bounds;
922 else
923 {
924 int rowlen = font->max_char_or_byte2 - font->min_char_or_byte2 + 1;
925 int row, within;
58769bee 926
0cdd0c9f
RS
927 /* Decode char into row number (byte 1) and code within row (byte 2). */
928 row = c >> 8;
929 within = c & 0177;
930 if (!(within >= font->min_char_or_byte2
931 && within <= font->max_char_or_byte2
932 && row >= font->min_byte1
933 && row <= font->max_byte1))
934 {
935 /* If char is out of range, try the font's default char instead. */
936 c = font->default_char;
937 row = c >> (INTBITS - 8);
938 within = c & 0177;
939 }
940 if (!(within >= font->min_char_or_byte2
941 && within <= font->max_char_or_byte2
942 && row >= font->min_byte1
943 && row <= font->max_byte1))
944 /* Still out of range means this char does not overlap. */
945 return 0;
946 else
947 /* We found the info for this char. */
948 s = (font->per_char + (within - font->min_char_or_byte2)
949 + row * rowlen);
950 }
dbc4e1c1 951
0cdd0c9f
RS
952 return (s && s->lbearing < 0);
953}
dbc4e1c1 954
0cdd0c9f
RS
955/* Return 1 if character C in font F extends past its right edge. */
956
957static int
958font_char_overlap_right (font, c)
959 XFontStruct *font;
960 int c;
961{
962 XCharStruct *s;
963
964 /* Find the bounding-box info for C. */
965 if (font->per_char == 0)
966 s = &font->max_bounds;
967 else
968 {
969 int rowlen = font->max_char_or_byte2 - font->min_char_or_byte2 + 1;
970 int row, within;
58769bee 971
0cdd0c9f
RS
972 /* Decode char into row number (byte 1) and code within row (byte 2). */
973 row = c >> 8;
974 within = c & 0177;
975 if (!(within >= font->min_char_or_byte2
976 && within <= font->max_char_or_byte2
977 && row >= font->min_byte1
978 && row <= font->max_byte1))
979 {
980 /* If char is out of range, try the font's default char instead. */
981 c = font->default_char;
982 row = c >> (INTBITS - 8);
983 within = c & 0177;
984 }
985 if (!(within >= font->min_char_or_byte2
986 && within <= font->max_char_or_byte2
987 && row >= font->min_byte1
988 && row <= font->max_byte1))
989 /* Still out of range means this char does not overlap. */
990 return 0;
991 else
992 /* We found the info for this char. */
993 s = (font->per_char + (within - font->min_char_or_byte2)
994 + row * rowlen);
995 }
996
997 return (s && s->rbearing >= s->width);
dc6f92b8 998}
0cdd0c9f 999#endif /* 0 */
dc6f92b8 1000\f
dbc4e1c1
JB
1001/* Invert the middle quarter of the frame for .15 sec. */
1002
1003/* We use the select system call to do the waiting, so we have to make sure
eb8c3be9 1004 it's available. If it isn't, we just won't do visual bells. */
dbc4e1c1
JB
1005#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
1006
1007/* Subtract the `struct timeval' values X and Y,
1008 storing the result in RESULT.
1009 Return 1 if the difference is negative, otherwise 0. */
1010
1011static int
1012timeval_subtract (result, x, y)
1013 struct timeval *result, x, y;
1014{
1015 /* Perform the carry for the later subtraction by updating y.
1016 This is safer because on some systems
1017 the tv_sec member is unsigned. */
1018 if (x.tv_usec < y.tv_usec)
1019 {
1020 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
1021 y.tv_usec -= 1000000 * nsec;
1022 y.tv_sec += nsec;
1023 }
1024 if (x.tv_usec - y.tv_usec > 1000000)
1025 {
1026 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
1027 y.tv_usec += 1000000 * nsec;
1028 y.tv_sec -= nsec;
1029 }
1030
1031 /* Compute the time remaining to wait. tv_usec is certainly positive. */
1032 result->tv_sec = x.tv_sec - y.tv_sec;
1033 result->tv_usec = x.tv_usec - y.tv_usec;
1034
1035 /* Return indication of whether the result should be considered negative. */
1036 return x.tv_sec < y.tv_sec;
1037}
dc6f92b8 1038
f676886a
JB
1039XTflash (f)
1040 struct frame *f;
dc6f92b8 1041{
dbc4e1c1 1042 BLOCK_INPUT;
dc6f92b8 1043
dbc4e1c1
JB
1044 {
1045 GC gc;
dc6f92b8 1046
dbc4e1c1
JB
1047 /* Create a GC that will use the GXxor function to flip foreground pixels
1048 into background pixels. */
1049 {
1050 XGCValues values;
dc6f92b8 1051
dbc4e1c1
JB
1052 values.function = GXxor;
1053 values.foreground = (f->display.x->foreground_pixel
1054 ^ f->display.x->background_pixel);
58769bee 1055
334208b7 1056 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
1057 GCFunction | GCForeground, &values);
1058 }
dc6f92b8 1059
dbc4e1c1
JB
1060 {
1061 int width = PIXEL_WIDTH (f);
1062 int height = PIXEL_HEIGHT (f);
dc6f92b8 1063
334208b7 1064 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
dbc4e1c1 1065 width/4, height/4, width/2, height/2);
334208b7 1066 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 1067
dbc4e1c1
JB
1068 {
1069 struct timeval wakeup, now;
dc6f92b8 1070
66c30ea1 1071 EMACS_GET_TIME (wakeup);
dc6f92b8 1072
dbc4e1c1
JB
1073 /* Compute time to wait until, propagating carry from usecs. */
1074 wakeup.tv_usec += 150000;
1075 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
1076 wakeup.tv_usec %= 1000000;
1077
1078 /* Keep waiting until past the time wakeup. */
1079 while (1)
1080 {
1081 struct timeval timeout;
1082
66c30ea1 1083 EMACS_GET_TIME (timeout);
dbc4e1c1
JB
1084
1085 /* In effect, timeout = wakeup - timeout.
1086 Break if result would be negative. */
1087 if (timeval_subtract (&timeout, wakeup, timeout))
1088 break;
1089
1090 /* Try to wait that long--but we might wake up sooner. */
1091 select (0, 0, 0, 0, &timeout);
1092 }
1093 }
58769bee 1094
334208b7 1095 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
dbc4e1c1 1096 width/4, height/4, width/2, height/2);
334208b7
RS
1097 XFreeGC (FRAME_X_DISPLAY (f), gc);
1098 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 1099 }
dbc4e1c1
JB
1100 }
1101
1102 UNBLOCK_INPUT;
dc6f92b8
JB
1103}
1104
dbc4e1c1
JB
1105#endif
1106
1107
dc6f92b8
JB
1108/* Make audible bell. */
1109
334208b7 1110#define XRINGBELL XBell (FRAME_X_DISPLAY (selected_frame), 0)
dc6f92b8
JB
1111
1112XTring_bell ()
1113{
334208b7 1114 if (FRAME_X_DISPLAY (selected_frame) == 0)
5a6ef893
RS
1115 return;
1116
dbc4e1c1 1117#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
dc6f92b8 1118 if (visible_bell)
f676886a 1119 XTflash (selected_frame);
dc6f92b8 1120 else
dbc4e1c1 1121#endif
dc6f92b8
JB
1122 {
1123 BLOCK_INPUT;
1124 XRINGBELL;
334208b7 1125 XFlush (FRAME_X_DISPLAY (selected_frame));
dc6f92b8
JB
1126 UNBLOCK_INPUT;
1127 }
1128}
1129\f
f451eb13
JB
1130/* Insert and delete character.
1131 These are not supposed to be used because we are supposed to turn
1132 off the feature of using them. */
dc6f92b8 1133
58769bee 1134static
dc6f92b8
JB
1135XTinsert_glyphs (start, len)
1136 register char *start;
1137 register int len;
1138{
1139 abort ();
1140}
1141
58769bee 1142static
dc6f92b8
JB
1143XTdelete_glyphs (n)
1144 register int n;
1145{
1146 abort ();
1147}
1148\f
1149/* Specify how many text lines, from the top of the window,
1150 should be affected by insert-lines and delete-lines operations.
1151 This, and those operations, are used only within an update
1152 that is bounded by calls to XTupdate_begin and XTupdate_end. */
1153
1154static
1155XTset_terminal_window (n)
1156 register int n;
1157{
f676886a 1158 if (updating_frame == 0)
dc6f92b8
JB
1159 abort ();
1160
f676886a
JB
1161 if ((n <= 0) || (n > updating_frame->height))
1162 flexlines = updating_frame->height;
dc6f92b8
JB
1163 else
1164 flexlines = n;
1165}
1166\f
7a13e894
RS
1167/* These variables need not be per frame
1168 because redisplay is done on a frame-by-frame basis
1169 and the line dance for one frame is finished before
1170 anything is done for anoter frame. */
1171
58769bee
KH
1172/* Array of line numbers from cached insert/delete operations.
1173 line_dance[i] is the old position of the line that we want
1174 to move to line i, or -1 if we want a blank line there. */
1175static int *line_dance;
dc6f92b8 1176
58769bee
KH
1177/* Allocated length of that array. */
1178static int line_dance_len;
dc6f92b8 1179
58769bee
KH
1180/* Flag indicating whether we've done any work. */
1181static int line_dance_in_progress;
dc6f92b8 1182
58769bee
KH
1183/* Perform an insert-lines or delete-lines operation,
1184 inserting N lines or deleting -N lines at vertical position VPOS. */
1185XTins_del_lines (vpos, n)
1186 int vpos, n;
dc6f92b8 1187{
58769bee 1188 register int fence, i;
dc6f92b8 1189
58769bee 1190 if (vpos >= flexlines)
dc6f92b8
JB
1191 return;
1192
58769bee 1193 if (!line_dance_in_progress)
dc6f92b8 1194 {
58769bee
KH
1195 int ht = updating_frame->height;
1196 if (ht > line_dance_len)
1197 {
1198 line_dance = (int *)xrealloc (line_dance, ht * sizeof (int));
1199 line_dance_len = ht;
1200 }
1201 for (i = 0; i < ht; ++i) line_dance[i] = i;
1202 line_dance_in_progress = 1;
1203 }
1204 if (n >= 0)
1205 {
1206 if (n > flexlines - vpos)
1207 n = flexlines - vpos;
1208 fence = vpos + n;
1209 for (i = flexlines; --i >= fence;)
1210 line_dance[i] = line_dance[i-n];
1211 for (i = fence; --i >= vpos;)
1212 line_dance[i] = -1;
dc6f92b8
JB
1213 }
1214 else
1215 {
58769bee
KH
1216 n = -n;
1217 if (n > flexlines - vpos)
1218 n = flexlines - vpos;
1219 fence = flexlines - n;
1220 for (i = vpos; i < fence; ++i)
1221 line_dance[i] = line_dance[i + n];
1222 for (i = fence; i < flexlines; ++i)
1223 line_dance[i] = -1;
dc6f92b8
JB
1224 }
1225}
1226
58769bee
KH
1227/* Here's where we actually move the pixels around.
1228 Must be called with input blocked. */
1229static void
1230do_line_dance ()
dc6f92b8 1231{
58769bee
KH
1232 register int i, j, distance;
1233 register struct frame *f;
1234 int ht;
1235 int intborder;
1236
1237 /* Must check this flag first. If it's not set, then not only is the
1238 array uninitialized, but we might not even have a frame. */
1239 if (!line_dance_in_progress)
1240 return;
1241
1242 f = updating_frame;
1243 if (f == 0)
dc6f92b8
JB
1244 abort ();
1245
58769bee
KH
1246 ht = f->height;
1247 intborder = f->display.x->internal_border_width;
1248
f676886a 1249 x_display_cursor (updating_frame, 0);
dc6f92b8 1250
58769bee
KH
1251 for (i = 0; i < ht; ++i)
1252 if (line_dance[i] != -1 && (distance = line_dance[i]-i) > 0)
1253 {
1254 for (j = i; (j < ht && line_dance[j] != -1
1255 && line_dance[j]-j == distance); ++j);
1256 /* Copy [i,j) upward from [i+distance,j+distance) */
334208b7 1257 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
58769bee
KH
1258 FRAME_X_WINDOW (f), f->display.x->normal_gc,
1259 intborder, CHAR_TO_PIXEL_ROW (f, i+distance),
1260 f->width * FONT_WIDTH (f->display.x->font),
1261 (j-i) * f->display.x->line_height,
1262 intborder, CHAR_TO_PIXEL_ROW (f, i));
1263 i = j-1;
1264 }
dc6f92b8 1265
58769bee
KH
1266 for (i = ht; --i >=0; )
1267 if (line_dance[i] != -1 && (distance = line_dance[i]-i) < 0)
1268 {
1269 for (j = i; (--j >= 0 && line_dance[j] != -1
0ccf5d73 1270 && line_dance[j]-j == distance););
58769bee 1271 /* Copy (j,i] downward from (j+distance, i+distance] */
334208b7 1272 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
58769bee
KH
1273 FRAME_X_WINDOW (f), f->display.x->normal_gc,
1274 intborder, CHAR_TO_PIXEL_ROW (f, j+1+distance),
1275 f->width * FONT_WIDTH (f->display.x->font),
1276 (i-j) * f->display.x->line_height,
1277 intborder, CHAR_TO_PIXEL_ROW (f, j+1));
1278 i = j+1;
1279 }
1280
1281 for (i = 0; i < ht; ++i)
1282 if (line_dance[i] == -1)
1283 {
1284 for (j = i; j < ht && line_dance[j] == -1; ++j);
1285 /* Clear [i,j) */
334208b7 1286 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
58769bee
KH
1287 intborder, CHAR_TO_PIXEL_ROW (f, i),
1288 f->width * FONT_WIDTH (f->display.x->font),
1289 (j-i) * f->display.x->line_height, False);
1290 i = j-1;
1291 }
1292 line_dance_in_progress = 0;
dc6f92b8
JB
1293}
1294\f
f451eb13 1295/* Support routines for exposure events. */
dc6f92b8
JB
1296static void clear_cursor ();
1297
f676886a
JB
1298/* Output into a rectangle of an X-window (for frame F)
1299 the characters in f->phys_lines that overlap that rectangle.
dc6f92b8 1300 TOP and LEFT are the position of the upper left corner of the rectangle.
f94397b5
KH
1301 ROWS and COLS are the size of the rectangle.
1302 Call this function with input blocked. */
dc6f92b8
JB
1303
1304static void
f676886a
JB
1305dumprectangle (f, left, top, cols, rows)
1306 struct frame *f;
dc6f92b8
JB
1307 register int left, top, cols, rows;
1308{
f676886a 1309 register struct frame_glyphs *active_frame = FRAME_CURRENT_GLYPHS (f);
dc6f92b8
JB
1310 int cursor_cleared = 0;
1311 int bottom, right;
1312 register int y;
1313
f676886a 1314 if (FRAME_GARBAGED_P (f))
dc6f92b8
JB
1315 return;
1316
dc6f92b8
JB
1317 /* Express rectangle as four edges, instead of position-and-size. */
1318 bottom = top + rows;
1319 right = left + cols;
58769bee 1320
dc6f92b8
JB
1321 /* Convert rectangle edges in pixels to edges in chars.
1322 Round down for left and top, up for right and bottom. */
12ba150f
JB
1323 top = PIXEL_TO_CHAR_ROW (f, top);
1324 left = PIXEL_TO_CHAR_COL (f, left);
a27f9f86 1325 bottom += (f->display.x->line_height - 1);
f676886a 1326 right += (FONT_WIDTH (f->display.x->font) - 1);
12ba150f
JB
1327 bottom = PIXEL_TO_CHAR_ROW (f, bottom);
1328 right = PIXEL_TO_CHAR_COL (f, right);
dc6f92b8
JB
1329
1330 /* Clip the rectangle to what can be visible. */
1331 if (left < 0)
1332 left = 0;
1333 if (top < 0)
1334 top = 0;
f676886a
JB
1335 if (right > f->width)
1336 right = f->width;
1337 if (bottom > f->height)
1338 bottom = f->height;
dc6f92b8
JB
1339
1340 /* Get size in chars of the rectangle. */
1341 cols = right - left;
1342 rows = bottom - top;
1343
1344 /* If rectangle has zero area, return. */
1345 if (rows <= 0) return;
1346 if (cols <= 0) return;
1347
1348 /* Turn off the cursor if it is in the rectangle.
1349 We will turn it back on afterward. */
f676886a
JB
1350 if ((f->phys_cursor_x >= left) && (f->phys_cursor_x < right)
1351 && (f->phys_cursor_y >= top) && (f->phys_cursor_y < bottom))
dc6f92b8 1352 {
f676886a 1353 clear_cursor (f);
dc6f92b8
JB
1354 cursor_cleared = 1;
1355 }
1356
1357 /* Display the text in the rectangle, one text line at a time. */
1358
1359 for (y = top; y < bottom; y++)
1360 {
f676886a 1361 GLYPH *line = &active_frame->glyphs[y][left];
dc6f92b8 1362
f676886a 1363 if (! active_frame->enable[y] || left > active_frame->used[y])
dc6f92b8
JB
1364 continue;
1365
f676886a 1366 dumpglyphs (f,
12ba150f
JB
1367 CHAR_TO_PIXEL_COL (f, left),
1368 CHAR_TO_PIXEL_ROW (f, y),
1369 line, min (cols, active_frame->used[y] - left),
0cdd0c9f 1370 active_frame->highlight[y], 0);
dc6f92b8
JB
1371 }
1372
1373 /* Turn the cursor on if we turned it off. */
1374
1375 if (cursor_cleared)
f676886a 1376 x_display_cursor (f, 1);
dc6f92b8 1377}
dc6f92b8 1378\f
dc6f92b8 1379static void
334208b7
RS
1380frame_highlight (f)
1381 struct frame *f;
dc6f92b8 1382{
b3e1e05c
JB
1383 /* We used to only do this if Vx_no_window_manager was non-nil, but
1384 the ICCCM (section 4.1.6) says that the window's border pixmap
1385 and border pixel are window attributes which are "private to the
1386 client", so we can always change it to whatever we want. */
1387 BLOCK_INPUT;
334208b7
RS
1388 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1389 f->display.x->border_pixel);
b3e1e05c 1390 UNBLOCK_INPUT;
334208b7 1391 x_display_cursor (f, 1);
dc6f92b8
JB
1392}
1393
1394static void
334208b7
RS
1395frame_unhighlight (f)
1396 struct frame *f;
dc6f92b8 1397{
b3e1e05c
JB
1398 /* We used to only do this if Vx_no_window_manager was non-nil, but
1399 the ICCCM (section 4.1.6) says that the window's border pixmap
1400 and border pixel are window attributes which are "private to the
1401 client", so we can always change it to whatever we want. */
1402 BLOCK_INPUT;
334208b7
RS
1403 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1404 f->display.x->border_tile);
b3e1e05c 1405 UNBLOCK_INPUT;
334208b7 1406 x_display_cursor (f, 1);
dc6f92b8 1407}
dc6f92b8 1408
f676886a 1409static void XTframe_rehighlight ();
6d4238f3 1410
f676886a
JB
1411/* The focus has changed. Update the frames as necessary to reflect
1412 the new situation. Note that we can't change the selected frame
dc6f92b8 1413 here, because the lisp code we are interrupting might become confused.
eb8c3be9 1414 Each event gets marked with the frame in which it occurred, so the
6d4238f3 1415 lisp code can tell when the switch took place by examining the events. */
dc6f92b8 1416
6d4238f3 1417static void
f676886a
JB
1418x_new_focus_frame (frame)
1419 struct frame *frame;
dc6f92b8 1420{
f676886a 1421 struct frame *old_focus = x_focus_frame;
dc6f92b8
JB
1422 int events_enqueued = 0;
1423
f676886a 1424 if (frame != x_focus_frame)
dc6f92b8 1425 {
58769bee 1426 /* Set this before calling other routines, so that they see
f676886a
JB
1427 the correct value of x_focus_frame. */
1428 x_focus_frame = frame;
6d4238f3
JB
1429
1430 if (old_focus && old_focus->auto_lower)
f676886a 1431 x_lower_frame (old_focus);
dc6f92b8
JB
1432
1433#if 0
f676886a 1434 selected_frame = frame;
e0c1aef2
KH
1435 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
1436 selected_frame);
f676886a
JB
1437 Fselect_window (selected_frame->selected_window);
1438 choose_minibuf_frame ();
c118dd06 1439#endif /* ! 0 */
dc6f92b8 1440
f676886a 1441 if (x_focus_frame && x_focus_frame->auto_raise)
0134a210
RS
1442 pending_autoraise_frame = x_focus_frame;
1443 else
1444 pending_autoraise_frame = 0;
6d4238f3 1445 }
dc6f92b8 1446
f676886a 1447 XTframe_rehighlight ();
6d4238f3
JB
1448}
1449
1450
f451eb13
JB
1451/* The focus has changed, or we have redirected a frame's focus to
1452 another frame (this happens when a frame uses a surrogate
1453 minibuffer frame). Shift the highlight as appropriate. */
6d4238f3 1454static void
f676886a 1455XTframe_rehighlight ()
6d4238f3 1456{
f676886a 1457 struct frame *old_highlight = x_highlight_frame;
6d4238f3 1458
f676886a 1459 if (x_focus_frame)
6d4238f3 1460 {
f451eb13 1461 x_highlight_frame =
ab648270 1462 ((XGCTYPE (FRAME_FOCUS_FRAME (x_focus_frame)) == Lisp_Frame)
f451eb13
JB
1463 ? XFRAME (FRAME_FOCUS_FRAME (x_focus_frame))
1464 : x_focus_frame);
1465 if (! FRAME_LIVE_P (x_highlight_frame))
1466 {
1467 FRAME_FOCUS_FRAME (x_focus_frame) = Qnil;
1468 x_highlight_frame = x_focus_frame;
1469 }
dc6f92b8 1470 }
6d4238f3 1471 else
f676886a 1472 x_highlight_frame = 0;
dc6f92b8 1473
f676886a 1474 if (x_highlight_frame != old_highlight)
6d4238f3
JB
1475 {
1476 if (old_highlight)
f676886a
JB
1477 frame_unhighlight (old_highlight);
1478 if (x_highlight_frame)
1479 frame_highlight (x_highlight_frame);
6d4238f3 1480 }
dc6f92b8
JB
1481}
1482\f
e4571a43 1483/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 1484
28430d3c
JB
1485/* Initialize mode_switch_bit and modifier_meaning. */
1486static void
334208b7
RS
1487x_find_modifier_meanings (dpyinfo)
1488 struct x_display_info *dpyinfo;
28430d3c 1489{
f689eb05 1490 int min_code, max_code;
28430d3c
JB
1491 KeySym *syms;
1492 int syms_per_code;
1493 XModifierKeymap *mods;
1494
334208b7
RS
1495 dpyinfo->meta_mod_mask = 0;
1496 dpyinfo->shift_lock_mask = 0;
1497 dpyinfo->alt_mod_mask = 0;
1498 dpyinfo->super_mod_mask = 0;
1499 dpyinfo->hyper_mod_mask = 0;
58769bee 1500
9658a521 1501#ifdef HAVE_X11R4
334208b7 1502 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 1503#else
334208b7
RS
1504 min_code = display->min_keycode;
1505 max_code = display->max_keycode;
9658a521
JB
1506#endif
1507
334208b7 1508 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
1509 min_code, max_code - min_code + 1,
1510 &syms_per_code);
334208b7 1511 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 1512
58769bee 1513 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 1514 Alt keysyms are on. */
28430d3c
JB
1515 {
1516 int row, col; /* The row and column in the modifier table. */
1517
1518 for (row = 3; row < 8; row++)
1519 for (col = 0; col < mods->max_keypermod; col++)
1520 {
1521 KeyCode code =
1522 mods->modifiermap[(row * mods->max_keypermod) + col];
1523
af92970c
KH
1524 /* Zeroes are used for filler. Skip them. */
1525 if (code == 0)
1526 continue;
1527
28430d3c
JB
1528 /* Are any of this keycode's keysyms a meta key? */
1529 {
1530 int code_col;
1531
1532 for (code_col = 0; code_col < syms_per_code; code_col++)
1533 {
f689eb05 1534 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 1535
f689eb05 1536 switch (sym)
28430d3c 1537 {
f689eb05
JB
1538 case XK_Meta_L:
1539 case XK_Meta_R:
334208b7 1540 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 1541 break;
f689eb05
JB
1542
1543 case XK_Alt_L:
1544 case XK_Alt_R:
334208b7 1545 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
1546 break;
1547
1548 case XK_Hyper_L:
1549 case XK_Hyper_R:
334208b7 1550 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
1551 break;
1552
1553 case XK_Super_L:
1554 case XK_Super_R:
334208b7 1555 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 1556 break;
11edeb03
JB
1557
1558 case XK_Shift_Lock:
1559 /* Ignore this if it's not on the lock modifier. */
1560 if ((1 << row) == LockMask)
334208b7 1561 dpyinfo->shift_lock_mask = LockMask;
11edeb03 1562 break;
28430d3c
JB
1563 }
1564 }
1565 }
1566 }
1567 }
1568
f689eb05 1569 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 1570 if (! dpyinfo->meta_mod_mask)
a3c44b14 1571 {
334208b7
RS
1572 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
1573 dpyinfo->alt_mod_mask = 0;
a3c44b14 1574 }
f689eb05 1575
148c4b70
RS
1576 /* If some keys are both alt and meta,
1577 make them just meta, not alt. */
334208b7 1578 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 1579 {
334208b7 1580 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 1581 }
58769bee 1582
28430d3c 1583 XFree ((char *) syms);
f689eb05 1584 XFreeModifiermap (mods);
28430d3c
JB
1585}
1586
dfeccd2d
JB
1587/* Convert between the modifier bits X uses and the modifier bits
1588 Emacs uses. */
7c5283e4 1589static unsigned int
334208b7
RS
1590x_x_to_emacs_modifiers (dpyinfo, state)
1591 struct x_display_info *dpyinfo;
dc6f92b8
JB
1592 unsigned int state;
1593{
334208b7
RS
1594 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
1595 | ((state & ControlMask) ? ctrl_modifier : 0)
1596 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
1597 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
1598 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
1599 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
1600}
1601
dfeccd2d 1602static unsigned int
334208b7
RS
1603x_emacs_to_x_modifiers (dpyinfo, state)
1604 struct x_display_info *dpyinfo;
dfeccd2d
JB
1605 unsigned int state;
1606{
334208b7
RS
1607 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
1608 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
1609 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
1610 | ((state & shift_modifier) ? ShiftMask : 0)
1611 | ((state & ctrl_modifier) ? ControlMask : 0)
1612 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 1613}
e4571a43
JB
1614\f
1615/* Mouse clicks and mouse movement. Rah. */
e4571a43
JB
1616
1617/* Given a pixel position (PIX_X, PIX_Y) on the frame F, return
1618 glyph co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle
69388238
RS
1619 that the glyph at X, Y occupies, if BOUNDS != 0.
1620 If NOCLIP is nonzero, do not force the value into range. */
1621
c8dba240 1622void
69388238 1623pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 1624 FRAME_PTR f;
69388238 1625 register int pix_x, pix_y;
e4571a43
JB
1626 register int *x, *y;
1627 XRectangle *bounds;
69388238 1628 int noclip;
e4571a43 1629{
69388238
RS
1630 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
1631 even for negative values. */
1632 if (pix_x < 0)
1633 pix_x -= FONT_WIDTH ((f)->display.x->font) - 1;
1634 if (pix_y < 0)
a27f9f86 1635 pix_y -= (f)->display.x->line_height - 1;
69388238 1636
e4571a43
JB
1637 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
1638 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
1639
1640 if (bounds)
1641 {
1642 bounds->width = FONT_WIDTH (f->display.x->font);
a27f9f86 1643 bounds->height = f->display.x->line_height;
e4571a43
JB
1644 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
1645 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
1646 }
1647
69388238
RS
1648 if (!noclip)
1649 {
1650 if (pix_x < 0)
1651 pix_x = 0;
1652 else if (pix_x > f->width)
1653 pix_x = f->width;
1654
1655 if (pix_y < 0)
1656 pix_y = 0;
1657 else if (pix_y > f->height)
1658 pix_y = f->height;
1659 }
e4571a43
JB
1660
1661 *x = pix_x;
1662 *y = pix_y;
1663}
1664
2b5c9e71
RS
1665void
1666glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1667 FRAME_PTR f;
1668 register int x, y;
1669 register int *pix_x, *pix_y;
1670{
1671 *pix_x = CHAR_TO_PIXEL_COL (f, x);
1672 *pix_y = CHAR_TO_PIXEL_ROW (f, y);
1673}
1674
dc6f92b8
JB
1675/* Prepare a mouse-event in *RESULT for placement in the input queue.
1676
1677 If the event is a button press, then note that we have grabbed
f451eb13 1678 the mouse. */
dc6f92b8
JB
1679
1680static Lisp_Object
f451eb13 1681construct_mouse_click (result, event, f)
dc6f92b8
JB
1682 struct input_event *result;
1683 XButtonEvent *event;
f676886a 1684 struct frame *f;
dc6f92b8 1685{
f451eb13 1686 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 1687 otherwise. */
f451eb13 1688 result->kind = mouse_click;
69388238 1689 result->code = event->button - Button1;
1113d9db 1690 result->timestamp = event->time;
334208b7
RS
1691 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
1692 event->state)
f689eb05 1693 | (event->type == ButtonRelease
58769bee 1694 ? up_modifier
f689eb05 1695 : down_modifier));
dc6f92b8 1696
f451eb13
JB
1697 {
1698 int row, column;
dc6f92b8 1699
2b5c9e71 1700#if 0
69388238 1701 pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL, 0);
90e1eb6f
KH
1702 XSETFASTINT (result->x, column);
1703 XSETFASTINT (result->y, row);
2b5c9e71 1704#endif
e0c1aef2
KH
1705 XSETINT (result->x, event->x);
1706 XSETINT (result->y, event->y);
1707 XSETFRAME (result->frame_or_window, f);
f451eb13 1708 }
dc6f92b8 1709}
b849c413
RS
1710
1711/* Prepare a menu-event in *RESULT for placement in the input queue. */
1712
1713static Lisp_Object
1714construct_menu_click (result, event, f)
1715 struct input_event *result;
1716 XButtonEvent *event;
1717 struct frame *f;
1718{
1719 /* Make the event type no_event; we'll change that when we decide
1720 otherwise. */
1721 result->kind = mouse_click;
e0c1aef2 1722 XSETINT (result->code, event->button - Button1);
b849c413 1723 result->timestamp = event->time;
334208b7
RS
1724 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
1725 event->state)
b849c413 1726 | (event->type == ButtonRelease
58769bee 1727 ? up_modifier
b849c413
RS
1728 : down_modifier));
1729
e0c1aef2
KH
1730 XSETINT (result->x, event->x);
1731 XSETINT (result->y, -1);
1732 XSETFRAME (result->frame_or_window, f);
b849c413 1733}
69388238 1734\f
90e65f07
JB
1735/* Function to report a mouse movement to the mainstream Emacs code.
1736 The input handler calls this.
1737
1738 We have received a mouse movement event, which is given in *event.
1739 If the mouse is over a different glyph than it was last time, tell
1740 the mainstream emacs code by setting mouse_moved. If not, ask for
1741 another motion event, so we can check again the next time it moves. */
b8009dd1 1742
90e65f07 1743static void
12ba150f 1744note_mouse_movement (frame, event)
f676886a 1745 FRAME_PTR frame;
90e65f07
JB
1746 XMotionEvent *event;
1747
1748{
e5d77022
JB
1749 last_mouse_movement_time = event->time;
1750
27f338af
RS
1751 if (event->window != FRAME_X_WINDOW (frame))
1752 {
1753 mouse_moved = 1;
1754 last_mouse_scroll_bar = Qnil;
1755
1756 note_mouse_highlight (frame, -1, -1);
1757
1758 /* Ask for another mouse motion event. */
1759 {
1760 int dummy;
847e150a 1761 Window dummy_window;
27f338af
RS
1762
1763 XQueryPointer (event->display, FRAME_X_WINDOW (frame),
847e150a 1764 &dummy_window, &dummy_window,
27f338af
RS
1765 &dummy, &dummy, &dummy, &dummy,
1766 (unsigned int *) &dummy);
1767 }
1768 }
1769
90e65f07 1770 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
1771 else if (event->x < last_mouse_glyph.x
1772 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
1773 || event->y < last_mouse_glyph.y
1774 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f
JB
1775 {
1776 mouse_moved = 1;
ab648270 1777 last_mouse_scroll_bar = Qnil;
b8009dd1
RS
1778
1779 note_mouse_highlight (frame, event->x, event->y);
1780
1781 /* Ask for another mouse motion event. */
1782 {
1783 int dummy;
847e150a 1784 Window dummy_window;
b8009dd1 1785
27f338af 1786 XQueryPointer (event->display, FRAME_X_WINDOW (frame),
847e150a 1787 &dummy_window, &dummy_window,
b8009dd1
RS
1788 &dummy, &dummy, &dummy, &dummy,
1789 (unsigned int *) &dummy);
1790 }
12ba150f 1791 }
90e65f07
JB
1792 else
1793 {
1794 /* It's on the same glyph. Call XQueryPointer so we'll get an
1795 event the next time the mouse moves and we can see if it's
1796 *still* on the same glyph. */
1797 int dummy;
847e150a 1798 Window dummy_window;
58769bee 1799
27f338af 1800 XQueryPointer (event->display, FRAME_X_WINDOW (frame),
847e150a 1801 &dummy_window, &dummy_window,
90e65f07
JB
1802 &dummy, &dummy, &dummy, &dummy,
1803 (unsigned int *) &dummy);
1804 }
1805}
1806
bf1c0ba1
RS
1807/* This is used for debugging, to turn off note_mouse_highlight. */
1808static int disable_mouse_highlight;
1809
b8009dd1
RS
1810/* Take proper action when the mouse has moved to position X, Y on frame F
1811 as regards highlighting characters that have mouse-face properties.
27f338af
RS
1812 Also dehighlighting chars where the mouse was before.
1813 X and Y can be negative or out of range. */
b8009dd1
RS
1814
1815static void
1816note_mouse_highlight (f, x, y)
1817 FRAME_PTR f;
1818{
1819 int row, column, portion;
1820 XRectangle new_glyph;
1821 Lisp_Object window;
1822 struct window *w;
1823
bf1c0ba1
RS
1824 if (disable_mouse_highlight)
1825 return;
1826
7a13e894
RS
1827 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_x = x;
1828 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_y = y;
1829 FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame = f;
b8009dd1 1830
7a13e894 1831 if (FRAME_X_DISPLAY_INFO (f)->mouse_face_defer)
b8009dd1
RS
1832 return;
1833
514e4681
RS
1834 if (gc_in_progress)
1835 {
7a13e894 1836 FRAME_X_DISPLAY_INFO (f)->mouse_face_deferred_gc = 1;
514e4681
RS
1837 return;
1838 }
1839
b8009dd1
RS
1840 /* Find out which glyph the mouse is on. */
1841 pixel_to_glyph_coords (f, x, y, &column, &row,
334208b7 1842 &new_glyph, FRAME_X_DISPLAY_INFO (f)->grabbed);
b8009dd1
RS
1843
1844 /* Which window is that in? */
1845 window = window_from_coordinates (f, column, row, &portion);
1846 w = XWINDOW (window);
1847
1848 /* If we were displaying active text in another window, clear that. */
7a13e894
RS
1849 if (! EQ (window, FRAME_X_DISPLAY_INFO (f)->mouse_face_window))
1850 clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
b8009dd1 1851
0cdd0c9f
RS
1852 /* Are we in a window whose display is up to date?
1853 And verify the buffer's text has not changed. */
27f338af
RS
1854 if (WINDOWP (window) && portion == 0 && row >= 0 && column >= 0
1855 && row < FRAME_HEIGHT (f) && column < FRAME_WIDTH (f)
0cdd0c9f
RS
1856 && EQ (w->window_end_valid, w->buffer)
1857 && w->last_modified == BUF_MODIFF (XBUFFER (w->buffer)))
b8009dd1
RS
1858 {
1859 int *ptr = FRAME_CURRENT_GLYPHS (f)->charstarts[row];
1860 int i, pos;
1861
1862 /* Find which buffer position the mouse corresponds to. */
1863 for (i = column; i >= 0; i--)
1864 if (ptr[i] > 0)
1865 break;
1866 pos = ptr[i];
1867 /* Is it outside the displayed active region (if any)? */
55836b73 1868 if (pos <= 0)
7a13e894
RS
1869 clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
1870 else if (! (EQ (window, FRAME_X_DISPLAY_INFO (f)->mouse_face_window)
1871 && row >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
1872 && row <= FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
1873 && (row > FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
1874 || column >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col)
1875 && (row < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
1876 || column < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col
1877 || FRAME_X_DISPLAY_INFO (f)->mouse_face_past_end)))
b8009dd1
RS
1878 {
1879 Lisp_Object mouse_face, overlay, position;
1880 Lisp_Object *overlay_vec;
1881 int len, noverlays, ignor1;
f8bdb8e6 1882 struct buffer *obuf;
e444162e 1883 int obegv, ozv;
f8bdb8e6 1884
e444162e
RS
1885 /* If we get an out-of-range value, return now; avoid an error. */
1886 if (pos > BUF_Z (XBUFFER (w->buffer)))
f8bdb8e6 1887 return;
b8009dd1 1888
09fe4c31
RS
1889 /* Make the window's buffer temporarily current for
1890 overlays_at and compute_char_face. */
f8bdb8e6 1891 obuf = current_buffer;
09fe4c31 1892 current_buffer = XBUFFER (w->buffer);
e444162e
RS
1893 obegv = BEGV;
1894 ozv = ZV;
1895 BEGV = BEG;
1896 ZV = Z;
09fe4c31 1897
b8009dd1 1898 /* Yes. Clear the display of the old active region, if any. */
7a13e894 1899 clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
b8009dd1
RS
1900
1901 /* Is this char mouse-active? */
e0c1aef2 1902 XSETINT (position, pos);
b8009dd1
RS
1903
1904 len = 10;
1905 overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
1906
1907 /* Put all the overlays we want in a vector in overlay_vec.
1908 Store the length in len. */
7965883b
RS
1909 noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len,
1910 NULL, NULL);
09fe4c31 1911 noverlays = sort_overlays (overlay_vec, noverlays, w);
b8009dd1
RS
1912
1913 /* Find the highest priority overlay that has a mouse-face prop. */
1914 overlay = Qnil;
1915 for (i = 0; i < noverlays; i++)
1916 {
1917 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
1918 if (!NILP (mouse_face))
1919 {
1920 overlay = overlay_vec[i];
1921 break;
1922 }
1923 }
1924 free (overlay_vec);
1925 /* If no overlay applies, get a text property. */
1926 if (NILP (overlay))
1927 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
1928
1929 /* Handle the overlay case. */
1930 if (! NILP (overlay))
1931 {
1932 /* Find the range of text around this char that
1933 should be active. */
1934 Lisp_Object before, after;
1935 int ignore;
1936
1937 before = Foverlay_start (overlay);
1938 after = Foverlay_end (overlay);
1939 /* Record this as the current active region. */
7a13e894
RS
1940 fast_find_position (window, before,
1941 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col,
1942 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row);
1943 FRAME_X_DISPLAY_INFO (f)->mouse_face_past_end
1944 = !fast_find_position (window, after,
1945 &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col,
1946 &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row);
1947 FRAME_X_DISPLAY_INFO (f)->mouse_face_window = window;
1948 FRAME_X_DISPLAY_INFO (f)->mouse_face_face_id
1949 = compute_char_face (f, w, pos, 0, 0,
1950 &ignore, pos + 1, 1);
b8009dd1
RS
1951
1952 /* Display it as active. */
7a13e894 1953 show_mouse_face (FRAME_X_DISPLAY_INFO (f), 1);
b8009dd1
RS
1954 }
1955 /* Handle the text property case. */
1956 else if (! NILP (mouse_face))
1957 {
1958 /* Find the range of text around this char that
1959 should be active. */
1960 Lisp_Object before, after, beginning, end;
1961 int ignore;
1962
1963 beginning = Fmarker_position (w->start);
e0c1aef2
KH
1964 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
1965 - XFASTINT (w->window_end_pos)));
b8009dd1
RS
1966 before
1967 = Fprevious_single_property_change (make_number (pos + 1),
1968 Qmouse_face,
1969 w->buffer, beginning);
1970 after
1971 = Fnext_single_property_change (position, Qmouse_face,
1972 w->buffer, end);
1973 /* Record this as the current active region. */
7a13e894
RS
1974 fast_find_position (window, before,
1975 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col,
1976 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row);
1977 FRAME_X_DISPLAY_INFO (f)->mouse_face_past_end
1978 = !fast_find_position (window, after,
1979 &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col,
1980 &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row);
1981 FRAME_X_DISPLAY_INFO (f)->mouse_face_window = window;
1982 FRAME_X_DISPLAY_INFO (f)->mouse_face_face_id
b8009dd1
RS
1983 = compute_char_face (f, w, pos, 0, 0,
1984 &ignore, pos + 1, 1);
1985
1986 /* Display it as active. */
7a13e894 1987 show_mouse_face (FRAME_X_DISPLAY_INFO (f), 1);
b8009dd1 1988 }
e444162e
RS
1989 BEGV = obegv;
1990 ZV = ozv;
09fe4c31 1991 current_buffer = obuf;
b8009dd1 1992 }
b8009dd1
RS
1993 }
1994}
1995\f
1996/* Find the row and column of position POS in window WINDOW.
1997 Store them in *COLUMNP and *ROWP.
bf1c0ba1
RS
1998 This assumes display in WINDOW is up to date.
1999 If POS is above start of WINDOW, return coords
2000 of start of first screen line.
4d73d038
RS
2001 If POS is after end of WINDOW, return coords of end of last screen line.
2002
2003 Value is 1 if POS is in range, 0 if it was off screen. */
b8009dd1
RS
2004
2005static int
2006fast_find_position (window, pos, columnp, rowp)
2007 Lisp_Object window;
2008 int pos;
2009 int *columnp, *rowp;
2010{
2011 struct window *w = XWINDOW (window);
2012 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2013 int i;
4d73d038 2014 int row = 0;
b8009dd1
RS
2015 int left = w->left;
2016 int top = w->top;
2017 int height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
2018 int width = window_internal_width (w);
2019 int *charstarts;
bf1c0ba1 2020 int lastcol;
b8009dd1 2021
4d73d038 2022 /* Find the right row. */
b8009dd1
RS
2023 for (i = 0;
2024 i < height;
2025 i++)
2026 {
2027 int linestart = FRAME_CURRENT_GLYPHS (f)->charstarts[top + i][left];
2028 if (linestart > pos)
2029 break;
2030 if (linestart > 0)
2031 row = i;
2032 }
2033
4d73d038 2034 /* Find the right column with in it. */
b8009dd1 2035 charstarts = FRAME_CURRENT_GLYPHS (f)->charstarts[top + row];
bf1c0ba1 2036 lastcol = left;
b8009dd1 2037 for (i = 0; i < width; i++)
bf1c0ba1
RS
2038 {
2039 if (charstarts[left + i] == pos)
2040 {
2041 *rowp = row + top;
2042 *columnp = i + left;
2043 return 1;
2044 }
2045 else if (charstarts[left + i] > pos)
4d73d038
RS
2046 break;
2047 else if (charstarts[left + i] > 0)
bf1c0ba1
RS
2048 lastcol = left + i;
2049 }
b8009dd1 2050
bf1c0ba1
RS
2051 *rowp = row + top;
2052 *columnp = lastcol;
b8009dd1
RS
2053 return 0;
2054}
2055
2056/* Display the active region described by mouse_face_*
2057 in its mouse-face if HL > 0, in its normal face if HL = 0. */
2058
2059static void
7a13e894
RS
2060show_mouse_face (dpyinfo, hl)
2061 struct x_display_info *dpyinfo;
b8009dd1
RS
2062 int hl;
2063{
7a13e894 2064 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
b8009dd1
RS
2065 int width = window_internal_width (w);
2066 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2067 int i;
514e4681 2068 int cursor_off = 0;
fb3b7de5
RS
2069 int old_curs_x = curs_x;
2070 int old_curs_y = curs_y;
2071
2072 /* Set these variables temporarily
2073 so that if we have to turn the cursor off and on again
2074 we will put it back at the same place. */
2075 curs_x = f->phys_cursor_x;
2076 curs_y = f->phys_cursor_y;
b8009dd1 2077
7a13e894
RS
2078 for (i = FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row;
2079 i <= FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row; i++)
b8009dd1 2080 {
7a13e894
RS
2081 int column = (i == FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
2082 ? FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col
2083 : w->left);
2084 int endcolumn = (i == FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
2085 ? FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col
2086 : w->left + width);
6f4c2453 2087 endcolumn = min (endcolumn, FRAME_CURRENT_GLYPHS (f)->used[i]);
514e4681
RS
2088
2089 /* If the cursor's in the text we are about to rewrite,
2090 turn the cursor off. */
2091 if (i == curs_y
7a13e894
RS
2092 && curs_x >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col - 1
2093 && curs_x <= FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col)
514e4681
RS
2094 {
2095 x_display_cursor (f, 0);
2096 cursor_off = 1;
2097 }
b8009dd1
RS
2098
2099 dumpglyphs (f,
2100 CHAR_TO_PIXEL_COL (f, column),
2101 CHAR_TO_PIXEL_ROW (f, i),
2102 FRAME_CURRENT_GLYPHS (f)->glyphs[i] + column,
2103 endcolumn - column,
2104 /* Highlight with mouse face if hl > 0. */
0cdd0c9f 2105 hl > 0 ? 3 : 0, 0);
b8009dd1
RS
2106 }
2107
514e4681
RS
2108 /* If we turned the cursor off, turn it back on. */
2109 if (cursor_off)
2110 x_display_cursor (f, 1);
27ead1d5 2111
fb3b7de5
RS
2112 curs_x = old_curs_x;
2113 curs_y = old_curs_y;
2114
27ead1d5
FP
2115 /* Change the mouse cursor according to the value of HL. */
2116 if (hl > 0)
334208b7
RS
2117 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2118 f->display.x->cross_cursor);
27ead1d5 2119 else
334208b7
RS
2120 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2121 f->display.x->text_cursor);
b8009dd1
RS
2122}
2123
2124/* Clear out the mouse-highlighted active region.
2125 Redraw it unhighlighted first. */
2126
2127static void
7a13e894
RS
2128clear_mouse_face (dpyinfo)
2129 struct x_display_info *dpyinfo;
b8009dd1 2130{
7a13e894
RS
2131 if (! NILP (dpyinfo->mouse_face_window))
2132 show_mouse_face (dpyinfo, 0);
b8009dd1 2133
7a13e894
RS
2134 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
2135 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
2136 dpyinfo->mouse_face_window = Qnil;
b8009dd1
RS
2137}
2138\f
ab648270
JB
2139static struct scroll_bar *x_window_to_scroll_bar ();
2140static void x_scroll_bar_report_motion ();
12ba150f 2141
90e65f07
JB
2142/* Return the current position of the mouse.
2143
ab648270
JB
2144 If the mouse movement started in a scroll bar, set *f, *bar_window,
2145 and *part to the frame, window, and scroll bar part that the mouse
12ba150f 2146 is over. Set *x and *y to the portion and whole of the mouse's
ab648270 2147 position on the scroll bar.
12ba150f
JB
2148
2149 If the mouse movement started elsewhere, set *f to the frame the
2150 mouse is on, *bar_window to nil, and *x and *y to the character cell
2151 the mouse is over.
2152
2153 Set *time to the server timestamp for the time at which the mouse
2154 was at this position.
2155
a135645a
RS
2156 Don't store anything if we don't have a valid set of values to report.
2157
90e65f07 2158 This clears the mouse_moved flag, so we can wait for the next mouse
12ba150f
JB
2159 movement. This also calls XQueryPointer, which will cause the
2160 server to give us another MotionNotify when the mouse moves
2161 again. */
90e65f07
JB
2162
2163static void
334208b7
RS
2164XTmouse_position (fp, bar_window, part, x, y, time)
2165 FRAME_PTR *fp;
12ba150f 2166 Lisp_Object *bar_window;
ab648270 2167 enum scroll_bar_part *part;
90e65f07 2168 Lisp_Object *x, *y;
e5d77022 2169 unsigned long *time;
90e65f07 2170{
a135645a
RS
2171 FRAME_PTR f1;
2172
90e65f07
JB
2173 BLOCK_INPUT;
2174
ab648270 2175 if (! NILP (last_mouse_scroll_bar))
334208b7 2176 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
2177 else
2178 {
12ba150f
JB
2179 Window root;
2180 int root_x, root_y;
90e65f07 2181
12ba150f
JB
2182 Window dummy_window;
2183 int dummy;
2184
2185 mouse_moved = 0;
ab648270 2186 last_mouse_scroll_bar = Qnil;
12ba150f
JB
2187
2188 /* Figure out which root window we're on. */
334208b7
RS
2189 XQueryPointer (FRAME_X_DISPLAY (*fp),
2190 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
2191
2192 /* The root window which contains the pointer. */
2193 &root,
2194
2195 /* Trash which we can't trust if the pointer is on
2196 a different screen. */
2197 &dummy_window,
2198
2199 /* The position on that root window. */
58769bee 2200 &root_x, &root_y,
12ba150f
JB
2201
2202 /* More trash we can't trust. */
2203 &dummy, &dummy,
2204
2205 /* Modifier keys and pointer buttons, about which
2206 we don't care. */
2207 (unsigned int *) &dummy);
2208
2209 /* Now we have a position on the root; find the innermost window
2210 containing the pointer. */
2211 {
2212 Window win, child;
2213 int win_x, win_y;
2214 int parent_x, parent_y;
2215
2216 win = root;
69388238 2217
334208b7 2218 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 2219 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 2220 {
69388238
RS
2221 /* If mouse was grabbed on a frame, give coords for that frame
2222 even if the mouse is now outside it. */
334208b7 2223 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 2224
12ba150f 2225 /* From-window, to-window. */
69388238 2226 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
2227
2228 /* From-position, to-position. */
2229 root_x, root_y, &win_x, &win_y,
2230
2231 /* Child of win. */
2232 &child);
69388238
RS
2233 f1 = last_mouse_frame;
2234 }
2235 else
2236 {
2237 while (1)
2238 {
334208b7 2239 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 2240
69388238
RS
2241 /* From-window, to-window. */
2242 root, win,
12ba150f 2243
69388238
RS
2244 /* From-position, to-position. */
2245 root_x, root_y, &win_x, &win_y,
2246
2247 /* Child of win. */
2248 &child);
2249
2250 if (child == None)
2251 break;
2252
2253 win = child;
2254 parent_x = win_x;
2255 parent_y = win_y;
2256 }
12ba150f 2257
69388238
RS
2258 /* Now we know that:
2259 win is the innermost window containing the pointer
2260 (XTC says it has no child containing the pointer),
2261 win_x and win_y are the pointer's position in it
2262 (XTC did this the last time through), and
2263 parent_x and parent_y are the pointer's position in win's parent.
2264 (They are what win_x and win_y were when win was child.
2265 If win is the root window, it has no parent, and
2266 parent_{x,y} are invalid, but that's okay, because we'll
2267 never use them in that case.) */
2268
2269 /* Is win one of our frames? */
2b5c9e71 2270 f1 = x_any_window_to_frame (win);
69388238 2271 }
58769bee 2272
ab648270 2273 /* If not, is it one of our scroll bars? */
a135645a 2274 if (! f1)
12ba150f 2275 {
ab648270 2276 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
2277
2278 if (bar)
2279 {
a135645a 2280 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
2281 win_x = parent_x;
2282 win_y = parent_y;
2283 }
2284 }
90e65f07 2285
a135645a 2286 if (f1)
12ba150f 2287 {
2b5c9e71
RS
2288 int ignore1, ignore2;
2289
2290 /* Ok, we found a frame. Store all the values. */
a135645a 2291
2b5c9e71 2292 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
334208b7
RS
2293 &last_mouse_glyph,
2294 FRAME_X_DISPLAY_INFO (f1)->grabbed);
12ba150f
JB
2295
2296 *bar_window = Qnil;
2297 *part = 0;
334208b7 2298 *fp = f1;
e0c1aef2
KH
2299 XSETINT (*x, win_x);
2300 XSETINT (*y, win_y);
12ba150f
JB
2301 *time = last_mouse_movement_time;
2302 }
2303 }
2304 }
90e65f07
JB
2305
2306 UNBLOCK_INPUT;
2307}
c118dd06 2308\f
ab648270 2309/* Scroll bar support. */
f451eb13 2310
ab648270
JB
2311/* Given an X window ID, find the struct scroll_bar which manages it.
2312 This can be called in GC, so we have to make sure to strip off mark
2313 bits. */
2314static struct scroll_bar *
2315x_window_to_scroll_bar (window_id)
f451eb13
JB
2316 Window window_id;
2317{
2318 Lisp_Object tail, frame;
f451eb13 2319
ab648270
JB
2320 for (tail = Vframe_list;
2321 XGCTYPE (tail) == Lisp_Cons;
2322 tail = XCONS (tail)->cdr)
f451eb13 2323 {
abdda982 2324 Lisp_Object frame, bar, condemned;
f451eb13 2325
abdda982 2326 frame = XCONS (tail)->car;
f451eb13 2327 /* All elements of Vframe_list should be frames. */
ab648270 2328 if (XGCTYPE (frame) != Lisp_Frame)
f451eb13
JB
2329 abort ();
2330
ab648270 2331 /* Scan this frame's scroll bar list for a scroll bar with the
f451eb13 2332 right window ID. */
ab648270
JB
2333 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
2334 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
cf7cb199 2335 /* This trick allows us to search both the ordinary and
ab648270
JB
2336 condemned scroll bar lists with one loop. */
2337 ! GC_NILP (bar) || (bar = condemned,
2338 condemned = Qnil,
2339 ! GC_NILP (bar));
bc20ebbf 2340 bar = XSCROLL_BAR (bar)->next)
ab648270
JB
2341 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
2342 return XSCROLL_BAR (bar);
f451eb13
JB
2343 }
2344
2345 return 0;
2346}
2347
ab648270
JB
2348/* Open a new X window to serve as a scroll bar, and return the
2349 scroll bar vector for it. */
2350static struct scroll_bar *
2351x_scroll_bar_create (window, top, left, width, height)
12ba150f 2352 struct window *window;
f451eb13
JB
2353 int top, left, width, height;
2354{
334208b7
RS
2355 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2356 struct scroll_bar *bar
2357 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
2358
2359 BLOCK_INPUT;
2360
2361 {
2362 XSetWindowAttributes a;
2363 unsigned long mask;
334208b7 2364 a.background_pixel = f->display.x->background_pixel;
12ba150f 2365 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 2366 | ButtonMotionMask | PointerMotionHintMask
12ba150f 2367 | ExposureMask);
7a13e894 2368 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 2369
dbc4e1c1 2370 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 2371
3afe33e7
RS
2372#if 0
2373
2374 ac = 0;
2375 XtSetArg (al[ac], XtNx, left); ac++;
2376 XtSetArg (al[ac], XtNy, top); ac++;
2377 XtSetArg (al[ac], XtNwidth, width); ac++;
2378 XtSetArg (al[ac], XtNheight, height); ac++;
2379 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
2380 sb_widget = XtCreateManagedWidget ("box",
7246d1d3 2381 boxWidgetClass,
334208b7 2382 f->display.x->edit_widget, al, ac);
7246d1d3 2383 SET_SCROLL_BAR_X_WINDOW
3afe33e7 2384 (bar, sb_widget->core.window);
58769bee 2385#endif
7246d1d3 2386 SET_SCROLL_BAR_X_WINDOW
58769bee 2387 (bar,
334208b7 2388 XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f451eb13 2389
ab648270 2390 /* Position and size of scroll bar. */
12ba150f 2391 left, top, width, height,
f451eb13 2392
12ba150f
JB
2393 /* Border width, depth, class, and visual. */
2394 0, CopyFromParent, CopyFromParent, CopyFromParent,
f451eb13 2395
12ba150f
JB
2396 /* Attributes. */
2397 mask, &a));
f451eb13
JB
2398 }
2399
e0c1aef2
KH
2400 XSETWINDOW (bar->window, window);
2401 XSETINT (bar->top, top);
2402 XSETINT (bar->left, left);
2403 XSETINT (bar->width, width);
2404 XSETINT (bar->height, height);
2405 XSETINT (bar->start, 0);
2406 XSETINT (bar->end, 0);
12ba150f 2407 bar->dragging = Qnil;
f451eb13
JB
2408
2409 /* Add bar to its frame's list of scroll bars. */
334208b7 2410 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 2411 bar->prev = Qnil;
334208b7 2412 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
12ba150f 2413 if (! NILP (bar->next))
e0c1aef2 2414 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 2415
7f9c7f94 2416 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
f451eb13
JB
2417
2418 UNBLOCK_INPUT;
12ba150f
JB
2419
2420 return bar;
f451eb13
JB
2421}
2422
12ba150f
JB
2423/* Draw BAR's handle in the proper position.
2424 If the handle is already drawn from START to END, don't bother
2425 redrawing it, unless REBUILD is non-zero; in that case, always
2426 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 2427 events.)
12ba150f
JB
2428
2429 Normally, we want to constrain the start and end of the handle to
ab648270 2430 fit inside its rectangle, but if the user is dragging the scroll bar
12ba150f
JB
2431 handle, we want to let them drag it down all the way, so that the
2432 bar's top is as far down as it goes; otherwise, there's no way to
2433 move to the very end of the buffer. */
f451eb13 2434static void
ab648270
JB
2435x_scroll_bar_set_handle (bar, start, end, rebuild)
2436 struct scroll_bar *bar;
f451eb13 2437 int start, end;
12ba150f 2438 int rebuild;
f451eb13 2439{
12ba150f 2440 int dragging = ! NILP (bar->dragging);
ab648270 2441 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7
RS
2442 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2443 GC gc = f->display.x->normal_gc;
12ba150f
JB
2444
2445 /* If the display is already accurate, do nothing. */
2446 if (! rebuild
2447 && start == XINT (bar->start)
2448 && end == XINT (bar->end))
2449 return;
2450
f451eb13
JB
2451 BLOCK_INPUT;
2452
2453 {
ab648270
JB
2454 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (XINT (bar->width));
2455 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2456 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
f451eb13
JB
2457
2458 /* Make sure the values are reasonable, and try to preserve
2459 the distance between start and end. */
12ba150f
JB
2460 {
2461 int length = end - start;
2462
2463 if (start < 0)
2464 start = 0;
2465 else if (start > top_range)
2466 start = top_range;
2467 end = start + length;
2468
2469 if (end < start)
2470 end = start;
2471 else if (end > top_range && ! dragging)
2472 end = top_range;
2473 }
f451eb13 2474
ab648270 2475 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
2476 XSETINT (bar->start, start);
2477 XSETINT (bar->end, end);
f451eb13 2478
12ba150f
JB
2479 /* Clip the end position, just for display. */
2480 if (end > top_range)
2481 end = top_range;
f451eb13 2482
ab648270 2483 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
2484 below top positions, to make sure the handle is always at least
2485 that many pixels tall. */
ab648270 2486 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 2487
12ba150f
JB
2488 /* Draw the empty space above the handle. Note that we can't clear
2489 zero-height areas; that means "clear to end of window." */
2490 if (0 < start)
334208b7 2491 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 2492
12ba150f 2493 /* x, y, width, height, and exposures. */
ab648270
JB
2494 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2495 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
2496 inside_width, start,
2497 False);
f451eb13 2498
12ba150f 2499 /* Draw the handle itself. */
334208b7 2500 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13 2501
12ba150f 2502 /* x, y, width, height */
ab648270
JB
2503 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2504 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 2505 inside_width, end - start);
f451eb13 2506
f451eb13 2507
12ba150f
JB
2508 /* Draw the empty space below the handle. Note that we can't
2509 clear zero-height areas; that means "clear to end of window." */
2510 if (end < inside_height)
334208b7 2511 XClearArea (FRAME_X_DISPLAY (f), w,
f451eb13 2512
12ba150f 2513 /* x, y, width, height, and exposures. */
ab648270
JB
2514 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2515 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
2516 inside_width, inside_height - end,
2517 False);
f451eb13 2518
f451eb13
JB
2519 }
2520
f451eb13
JB
2521 UNBLOCK_INPUT;
2522}
2523
eb8c3be9 2524/* Move a scroll bar around on the screen, to accommodate changing
12ba150f 2525 window configurations. */
f451eb13 2526static void
ab648270
JB
2527x_scroll_bar_move (bar, top, left, width, height)
2528 struct scroll_bar *bar;
f451eb13
JB
2529 int top, left, width, height;
2530{
334208b7
RS
2531 Window w = SCROLL_BAR_X_WINDOW (bar);
2532 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2533
f451eb13
JB
2534 BLOCK_INPUT;
2535
2536 {
2537 XWindowChanges wc;
2538 unsigned int mask = 0;
2539
2540 wc.x = left;
2541 wc.y = top;
2542 wc.width = width;
2543 wc.height = height;
2544
12ba150f
JB
2545 if (left != XINT (bar->left)) mask |= CWX;
2546 if (top != XINT (bar->top)) mask |= CWY;
2547 if (width != XINT (bar->width)) mask |= CWWidth;
2548 if (height != XINT (bar->height)) mask |= CWHeight;
58769bee 2549
12ba150f 2550 if (mask)
334208b7 2551 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
12ba150f 2552 mask, &wc);
f451eb13
JB
2553 }
2554
e0c1aef2
KH
2555 XSETINT (bar->left, left);
2556 XSETINT (bar->top, top);
2557 XSETINT (bar->width, width);
2558 XSETINT (bar->height, height);
12ba150f 2559
f451eb13
JB
2560 UNBLOCK_INPUT;
2561}
2562
ab648270 2563/* Destroy the X window for BAR, and set its Emacs window's scroll bar
12ba150f
JB
2564 to nil. */
2565static void
ab648270
JB
2566x_scroll_bar_remove (bar)
2567 struct scroll_bar *bar;
12ba150f
JB
2568{
2569 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2570
2571 BLOCK_INPUT;
2572
2573 /* Destroy the window. */
334208b7 2574 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
12ba150f 2575
ab648270
JB
2576 /* Disassociate this scroll bar from its window. */
2577 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
2578
2579 UNBLOCK_INPUT;
2580}
2581
2582/* Set the handle of the vertical scroll bar for WINDOW to indicate
2583 that we are displaying PORTION characters out of a total of WHOLE
ab648270 2584 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f
JB
2585 create one. */
2586static void
ab648270 2587XTset_vertical_scroll_bar (window, portion, whole, position)
f451eb13
JB
2588 struct window *window;
2589 int portion, whole, position;
2590{
2591 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
f451eb13 2592 int top = XINT (window->top);
ab648270
JB
2593 int left = WINDOW_VERTICAL_SCROLL_BAR_COLUMN (window);
2594 int height = WINDOW_VERTICAL_SCROLL_BAR_HEIGHT (window);
f451eb13 2595
ab648270 2596 /* Where should this scroll bar be, pixelwise? */
12ba150f
JB
2597 int pixel_top = CHAR_TO_PIXEL_ROW (f, top);
2598 int pixel_left = CHAR_TO_PIXEL_COL (f, left);
b2cad826
KH
2599 int pixel_width
2600 = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
2601 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2602 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->display.x->font)));
ab648270 2603 int pixel_height = VERTICAL_SCROLL_BAR_PIXEL_HEIGHT (f, height);
f451eb13 2604
ab648270 2605 struct scroll_bar *bar;
12ba150f 2606
ab648270
JB
2607 /* Does the scroll bar exist yet? */
2608 if (NILP (window->vertical_scroll_bar))
2609 bar = x_scroll_bar_create (window,
f451eb13
JB
2610 pixel_top, pixel_left,
2611 pixel_width, pixel_height);
2612 else
12ba150f
JB
2613 {
2614 /* It may just need to be moved and resized. */
ab648270
JB
2615 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2616 x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
12ba150f 2617 }
f451eb13 2618
ab648270 2619 /* Set the scroll bar's current state, unless we're currently being
f451eb13 2620 dragged. */
12ba150f 2621 if (NILP (bar->dragging))
f451eb13 2622 {
12ba150f 2623 int top_range =
ab648270 2624 VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
f451eb13 2625
12ba150f 2626 if (whole == 0)
ab648270 2627 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
2628 else
2629 {
43f868f5
JB
2630 int start = ((double) position * top_range) / whole;
2631 int end = ((double) (position + portion) * top_range) / whole;
12ba150f 2632
ab648270 2633 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 2634 }
f451eb13
JB
2635 }
2636
e0c1aef2 2637 XSETVECTOR (window->vertical_scroll_bar, bar);
f451eb13
JB
2638}
2639
12ba150f 2640
f451eb13 2641/* The following three hooks are used when we're doing a thorough
ab648270 2642 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 2643 are going to be deleted, because keeping track of when windows go
12ba150f
JB
2644 away is a real pain - "Can you say set-window-configuration, boys
2645 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 2646 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 2647 from the fiery pit when we actually redisplay its window. */
f451eb13 2648
ab648270
JB
2649/* Arrange for all scroll bars on FRAME to be removed at the next call
2650 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
2651 `*redeem_scroll_bar_hook' is applied to its window before the judgement. */
58769bee 2652static void
ab648270 2653XTcondemn_scroll_bars (frame)
f451eb13
JB
2654 FRAME_PTR frame;
2655{
12ba150f
JB
2656 /* The condemned list should be empty at this point; if it's not,
2657 then the rest of Emacs isn't using the condemn/redeem/judge
2658 protocol correctly. */
ab648270 2659 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
12ba150f
JB
2660 abort ();
2661
2662 /* Move them all to the "condemned" list. */
ab648270
JB
2663 FRAME_CONDEMNED_SCROLL_BARS (frame) = FRAME_SCROLL_BARS (frame);
2664 FRAME_SCROLL_BARS (frame) = Qnil;
f451eb13
JB
2665}
2666
ab648270 2667/* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
12ba150f 2668 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 2669static void
ab648270 2670XTredeem_scroll_bar (window)
12ba150f 2671 struct window *window;
f451eb13 2672{
ab648270 2673 struct scroll_bar *bar;
12ba150f 2674
ab648270
JB
2675 /* We can't redeem this window's scroll bar if it doesn't have one. */
2676 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
2677 abort ();
2678
ab648270 2679 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
2680
2681 /* Unlink it from the condemned list. */
2682 {
2683 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2684
2685 if (NILP (bar->prev))
2686 {
2687 /* If the prev pointer is nil, it must be the first in one of
2688 the lists. */
ab648270 2689 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
12ba150f
JB
2690 /* It's not condemned. Everything's fine. */
2691 return;
ab648270
JB
2692 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
2693 window->vertical_scroll_bar))
2694 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
12ba150f
JB
2695 else
2696 /* If its prev pointer is nil, it must be at the front of
2697 one or the other! */
2698 abort ();
2699 }
2700 else
ab648270 2701 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f
JB
2702
2703 if (! NILP (bar->next))
ab648270 2704 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 2705
ab648270 2706 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 2707 bar->prev = Qnil;
e0c1aef2 2708 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
12ba150f 2709 if (! NILP (bar->next))
e0c1aef2 2710 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
12ba150f 2711 }
f451eb13
JB
2712}
2713
ab648270
JB
2714/* Remove all scroll bars on FRAME that haven't been saved since the
2715 last call to `*condemn_scroll_bars_hook'. */
f451eb13 2716static void
ab648270 2717XTjudge_scroll_bars (f)
12ba150f 2718 FRAME_PTR f;
f451eb13 2719{
12ba150f 2720 Lisp_Object bar, next;
f451eb13 2721
ab648270 2722 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
2723
2724 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
2725 more events on the hapless scroll bars. */
2726 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
2727
2728 for (; ! NILP (bar); bar = next)
f451eb13 2729 {
ab648270 2730 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 2731
ab648270 2732 x_scroll_bar_remove (b);
12ba150f
JB
2733
2734 next = b->next;
2735 b->next = b->prev = Qnil;
f451eb13 2736 }
12ba150f 2737
ab648270 2738 /* Now there should be no references to the condemned scroll bars,
12ba150f 2739 and they should get garbage-collected. */
f451eb13
JB
2740}
2741
2742
ab648270
JB
2743/* Handle an Expose or GraphicsExpose event on a scroll bar.
2744
2745 This may be called from a signal handler, so we have to ignore GC
2746 mark bits. */
f451eb13 2747static void
ab648270
JB
2748x_scroll_bar_expose (bar, event)
2749 struct scroll_bar *bar;
f451eb13
JB
2750 XEvent *event;
2751{
ab648270 2752 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7
RS
2753 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2754 GC gc = f->display.x->normal_gc;
12ba150f 2755
f451eb13
JB
2756 BLOCK_INPUT;
2757
ab648270 2758 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 2759
ab648270 2760 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 2761 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
2762
2763 /* x, y, width, height */
12ba150f 2764 0, 0, XINT (bar->width) - 1, XINT (bar->height) - 1);
f451eb13 2765
f451eb13
JB
2766 UNBLOCK_INPUT;
2767}
2768
ab648270
JB
2769/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2770 is set to something other than no_event, it is enqueued.
2771
2772 This may be called from a signal handler, so we have to ignore GC
2773 mark bits. */
f451eb13 2774static void
ab648270
JB
2775x_scroll_bar_handle_click (bar, event, emacs_event)
2776 struct scroll_bar *bar;
f451eb13
JB
2777 XEvent *event;
2778 struct input_event *emacs_event;
2779{
ab648270 2780 if (XGCTYPE (bar->window) != Lisp_Window)
12ba150f
JB
2781 abort ();
2782
ab648270 2783 emacs_event->kind = scroll_bar_click;
69388238 2784 emacs_event->code = event->xbutton.button - Button1;
f451eb13 2785 emacs_event->modifiers =
334208b7
RS
2786 (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
2787 event->xbutton.state)
f451eb13
JB
2788 | (event->type == ButtonRelease
2789 ? up_modifier
2790 : down_modifier));
12ba150f 2791 emacs_event->frame_or_window = bar->window;
f451eb13 2792 emacs_event->timestamp = event->xbutton.time;
12ba150f
JB
2793 {
2794 int internal_height =
ab648270 2795 VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
12ba150f 2796 int top_range =
ab648270
JB
2797 VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2798 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
2799
2800 if (y < 0) y = 0;
2801 if (y > top_range) y = top_range;
2802
2803 if (y < XINT (bar->start))
ab648270
JB
2804 emacs_event->part = scroll_bar_above_handle;
2805 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2806 emacs_event->part = scroll_bar_handle;
12ba150f 2807 else
ab648270 2808 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
2809
2810 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
2811 they want to drag it. Lisp code needs to be able to decide
2812 whether or not we're dragging. */
929787e1 2813#if 0
12ba150f
JB
2814 /* If the user has just clicked on the handle, record where they're
2815 holding it. */
2816 if (event->type == ButtonPress
ab648270 2817 && emacs_event->part == scroll_bar_handle)
e0c1aef2 2818 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 2819#endif
12ba150f
JB
2820
2821 /* If the user has released the handle, set it to its final position. */
2822 if (event->type == ButtonRelease
2823 && ! NILP (bar->dragging))
2824 {
2825 int new_start = y - XINT (bar->dragging);
2826 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 2827
ab648270 2828 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
2829 bar->dragging = Qnil;
2830 }
f451eb13 2831
5116f055
JB
2832 /* Same deal here as the other #if 0. */
2833#if 0
58769bee 2834 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 2835 the handle. */
ab648270 2836 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
2837 emacs_event->x = bar->start;
2838 else
e0c1aef2 2839 XSETINT (emacs_event->x, y);
5116f055 2840#else
e0c1aef2 2841 XSETINT (emacs_event->x, y);
5116f055 2842#endif
f451eb13 2843
e0c1aef2 2844 XSETINT (emacs_event->y, top_range);
12ba150f
JB
2845 }
2846}
f451eb13 2847
ab648270
JB
2848/* Handle some mouse motion while someone is dragging the scroll bar.
2849
2850 This may be called from a signal handler, so we have to ignore GC
2851 mark bits. */
f451eb13 2852static void
ab648270
JB
2853x_scroll_bar_note_movement (bar, event)
2854 struct scroll_bar *bar;
f451eb13
JB
2855 XEvent *event;
2856{
2857 last_mouse_movement_time = event->xmotion.time;
2858
2859 mouse_moved = 1;
e0c1aef2 2860 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
2861
2862 /* If we're dragging the bar, display it. */
ab648270 2863 if (! GC_NILP (bar->dragging))
f451eb13
JB
2864 {
2865 /* Where should the handle be now? */
12ba150f 2866 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 2867
12ba150f 2868 if (new_start != XINT (bar->start))
f451eb13 2869 {
12ba150f 2870 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 2871
ab648270 2872 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
2873 }
2874 }
2875
2876 /* Call XQueryPointer so we'll get an event the next time the mouse
2877 moves and we can see *still* on the same position. */
2878 {
2879 int dummy;
847e150a 2880 Window dummy_window;
58769bee 2881
f451eb13 2882 XQueryPointer (event->xmotion.display, event->xmotion.window,
847e150a 2883 &dummy_window, &dummy_window,
f451eb13
JB
2884 &dummy, &dummy, &dummy, &dummy,
2885 (unsigned int *) &dummy);
2886 }
2887}
2888
12ba150f 2889/* Return information to the user about the current position of the mouse
ab648270 2890 on the scroll bar. */
12ba150f 2891static void
334208b7
RS
2892x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
2893 FRAME_PTR *fp;
12ba150f 2894 Lisp_Object *bar_window;
ab648270 2895 enum scroll_bar_part *part;
12ba150f
JB
2896 Lisp_Object *x, *y;
2897 unsigned long *time;
2898{
ab648270 2899 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
2900 Window w = SCROLL_BAR_X_WINDOW (bar);
2901 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 2902 int win_x, win_y;
559cb2fb
JB
2903 Window dummy_window;
2904 int dummy_coord;
2905 unsigned int dummy_mask;
12ba150f 2906
cf7cb199
JB
2907 BLOCK_INPUT;
2908
ab648270 2909 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 2910 report that. */
334208b7 2911 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 2912
559cb2fb
JB
2913 /* Root, child, root x and root y. */
2914 &dummy_window, &dummy_window,
2915 &dummy_coord, &dummy_coord,
12ba150f 2916
559cb2fb
JB
2917 /* Position relative to scroll bar. */
2918 &win_x, &win_y,
12ba150f 2919
559cb2fb
JB
2920 /* Mouse buttons and modifier keys. */
2921 &dummy_mask))
7a13e894 2922 ;
559cb2fb
JB
2923 else
2924 {
2925 int inside_height
2926 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2927 int top_range
2928 = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2929
2930 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2931
2932 if (! NILP (bar->dragging))
2933 win_y -= XINT (bar->dragging);
2934
2935 if (win_y < 0)
2936 win_y = 0;
2937 if (win_y > top_range)
2938 win_y = top_range;
2939
334208b7 2940 *fp = f;
7a13e894 2941 *bar_window = bar->window;
559cb2fb
JB
2942
2943 if (! NILP (bar->dragging))
2944 *part = scroll_bar_handle;
2945 else if (win_y < XINT (bar->start))
2946 *part = scroll_bar_above_handle;
2947 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2948 *part = scroll_bar_handle;
2949 else
2950 *part = scroll_bar_below_handle;
12ba150f 2951
e0c1aef2
KH
2952 XSETINT (*x, win_y);
2953 XSETINT (*y, top_range);
12ba150f 2954
559cb2fb
JB
2955 mouse_moved = 0;
2956 last_mouse_scroll_bar = Qnil;
2957 }
12ba150f 2958
559cb2fb 2959 *time = last_mouse_movement_time;
cf7cb199 2960
cf7cb199 2961 UNBLOCK_INPUT;
12ba150f
JB
2962}
2963
f451eb13 2964
dbc4e1c1 2965/* The screen has been cleared so we may have changed foreground or
ab648270
JB
2966 background colors, and the scroll bars may need to be redrawn.
2967 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
2968 redraw them. */
2969
ab648270 2970x_scroll_bar_clear (f)
dbc4e1c1
JB
2971 FRAME_PTR f;
2972{
2973 Lisp_Object bar;
2974
9bc4522e 2975 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
ab648270 2976 bar = XSCROLL_BAR (bar)->next)
334208b7 2977 XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
dbc4e1c1
JB
2978 0, 0, 0, 0, True);
2979}
2980
3afe33e7
RS
2981/* This processes Expose events from the menubar specific X event
2982 loop in menubar.c. This allows to redisplay the frame if necessary
2983 when handling menubar or popup items. */
2984
2985void
2986process_expose_from_menu (event)
2987 XEvent event;
2988{
2989 FRAME_PTR f;
2990
f94397b5
KH
2991 BLOCK_INPUT;
2992
3afe33e7
RS
2993 f = x_window_to_frame (event.xexpose.window);
2994 if (f)
2995 {
2996 if (f->async_visible == 0)
2997 {
2998 f->async_visible = 1;
2999 f->async_iconified = 0;
3000 SET_FRAME_GARBAGED (f);
3001 }
3002 else
3003 {
3004 dumprectangle (x_window_to_frame (event.xexpose.window),
3005 event.xexpose.x, event.xexpose.y,
3006 event.xexpose.width, event.xexpose.height);
3007 }
3008 }
3009 else
3010 {
3011 struct scroll_bar *bar
3012 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 3013
3afe33e7
RS
3014 if (bar)
3015 x_scroll_bar_expose (bar, &event);
3016 }
f94397b5
KH
3017
3018 UNBLOCK_INPUT;
3afe33e7 3019}
09756a85
RS
3020\f
3021/* Define a queue to save up SelectionRequest events for later handling. */
3022
3023struct selection_event_queue
3024 {
3025 XEvent event;
3026 struct selection_event_queue *next;
3027 };
3028
3029static struct selection_event_queue *queue;
3030
3031/* Nonzero means queue up certain events--don't process them yet. */
3032static int x_queue_selection_requests;
3033
3034/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 3035
09756a85 3036static void
334208b7
RS
3037x_queue_event (f, event)
3038 FRAME_PTR f;
09756a85
RS
3039 XEvent *event;
3040{
3041 struct selection_event_queue *queue_tmp
3042 = (struct selection_event_queue *) malloc (sizeof (struct selection_event_queue));
3043
58769bee 3044 if (queue_tmp != NULL)
09756a85
RS
3045 {
3046 queue_tmp->event = *event;
3047 queue_tmp->next = queue;
3048 queue = queue_tmp;
3049 }
3050}
3051
3052/* Take all the queued events and put them back
3053 so that they get processed afresh. */
3054
3055static void
334208b7
RS
3056x_unqueue_events (f)
3057 FRAME_PTR f;
09756a85 3058{
58769bee 3059 while (queue != NULL)
09756a85
RS
3060 {
3061 struct selection_event_queue *queue_tmp = queue;
334208b7 3062 XPutBackEvent (FRAME_X_DISPLAY (f), &queue_tmp->event);
09756a85
RS
3063 queue = queue_tmp->next;
3064 free ((char *)queue_tmp);
3065 }
3066}
3067
3068/* Start queuing SelectionRequest events. */
3069
3070void
334208b7
RS
3071x_start_queuing_selection_requests (f)
3072 FRAME_PTR f;
09756a85
RS
3073{
3074 x_queue_selection_requests++;
3075}
3076
3077/* Stop queuing SelectionRequest events. */
3078
3079void
334208b7
RS
3080x_stop_queuing_selection_requests (f)
3081 FRAME_PTR f;
09756a85
RS
3082{
3083 x_queue_selection_requests--;
334208b7 3084 x_unqueue_events (f);
09756a85 3085}
f451eb13
JB
3086\f
3087/* The main X event-reading loop - XTread_socket. */
dc6f92b8 3088
dc6f92b8
JB
3089/* Timestamp of enter window event. This is only used by XTread_socket,
3090 but we have to put it out here, since static variables within functions
3091 sometimes don't work. */
3092static Time enter_timestamp;
3093
11edeb03 3094/* This holds the state XLookupString needs to implement dead keys
58769bee 3095 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
3096 says that a portable program can't use this, but Stephen Gildea assures
3097 me that letting the compiler initialize it to zeros will work okay.
3098
3099 This must be defined outside of XTread_socket, for the same reasons
3100 given for enter_timestamp, above. */
3101static XComposeStatus compose_status;
3102
10e6549c
RS
3103/* Record the last 100 characters stored
3104 to help debug the loss-of-chars-during-GC problem. */
3105int temp_index;
3106short temp_buffer[100];
3107
7a13e894
RS
3108/* Set this to nonzero to fake an "X I/O error"
3109 on a particular display. */
3110struct x_display_info *XTread_socket_fake_io_error;
3111
dc6f92b8
JB
3112/* Read events coming from the X server.
3113 This routine is called by the SIGIO handler.
3114 We return as soon as there are no more events to be read.
3115
3116 Events representing keys are stored in buffer BUFP,
3117 which can hold up to NUMCHARS characters.
3118 We return the number of characters stored into the buffer,
3119 thus pretending to be `read'.
3120
3121 WAITP is nonzero if we should block until input arrives.
3122 EXPECTED is nonzero if the caller knows input is available. */
3123
7c5283e4 3124int
dc6f92b8
JB
3125XTread_socket (sd, bufp, numchars, waitp, expected)
3126 register int sd;
3127 register struct input_event *bufp;
3128 register int numchars;
3129 int waitp;
3130 int expected;
3131{
3132 int count = 0;
3133 int nbytes = 0;
3134 int mask;
3135 int items_pending; /* How many items are in the X queue. */
3136 XEvent event;
f676886a 3137 struct frame *f;
66f55a9d 3138 int event_found = 0;
dc6f92b8
JB
3139 int prefix;
3140 Lisp_Object part;
334208b7 3141 struct x_display_info *dpyinfo;
dc6f92b8 3142
9ac0d9e0 3143 if (interrupt_input_blocked)
dc6f92b8 3144 {
9ac0d9e0 3145 interrupt_input_pending = 1;
dc6f92b8
JB
3146 return -1;
3147 }
3148
9ac0d9e0 3149 interrupt_input_pending = 0;
dc6f92b8 3150 BLOCK_INPUT;
c0a04927
RS
3151
3152 /* So people can tell when we have read the available input. */
3153 input_signal_count++;
3154
dc6f92b8
JB
3155 if (numchars <= 0)
3156 abort (); /* Don't think this happens. */
3157
7a13e894
RS
3158 /* Find the display we are supposed to read input for.
3159 It's the one communicating on descriptor SD. */
3160 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
3161 {
3162#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 3163#ifdef FIOSNBIO
7a13e894
RS
3164 /* If available, Xlib uses FIOSNBIO to make the socket
3165 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
3166 FIOSNBIO is ignored, and instead of signalling EWOULDBLOCK,
3167 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
3168 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 3169#endif /* ! defined (FIOSNBIO) */
7a13e894 3170#endif
dc6f92b8 3171
7a13e894
RS
3172#if 0 /* This code can't be made to work, with multiple displays,
3173 and appears not to be used on any system any more.
3174 Also keyboard.c doesn't turn O_NDELAY on and off
3175 for X connections. */
dc6f92b8
JB
3176#ifndef SIGIO
3177#ifndef HAVE_SELECT
7a13e894
RS
3178 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
3179 {
3180 extern int read_alarm_should_throw;
3181 read_alarm_should_throw = 1;
3182 XPeekEvent (dpyinfo->display, &event);
3183 read_alarm_should_throw = 0;
3184 }
c118dd06
JB
3185#endif /* HAVE_SELECT */
3186#endif /* SIGIO */
7a13e894 3187#endif
dc6f92b8 3188
7a13e894
RS
3189 /* For debugging, this gives a way to fake an I/O error. */
3190 if (dpyinfo == XTread_socket_fake_io_error)
3191 {
3192 XTread_socket_fake_io_error = 0;
3193 x_io_error_quitter (dpyinfo->display);
3194 }
dc6f92b8 3195
7a13e894 3196 while (XPending (dpyinfo->display) != 0)
dc6f92b8 3197 {
7a13e894
RS
3198 XNextEvent (dpyinfo->display, &event);
3199 event_found = 1;
3200
3201 switch (event.type)
3202 {
3203 case ClientMessage:
c047688c 3204 {
7a13e894
RS
3205 if (event.xclient.message_type
3206 == dpyinfo->Xatom_wm_protocols
3207 && event.xclient.format == 32)
c047688c 3208 {
7a13e894
RS
3209 if (event.xclient.data.l[0]
3210 == dpyinfo->Xatom_wm_take_focus)
c047688c 3211 {
7a13e894
RS
3212 f = x_window_to_frame (event.xclient.window);
3213 /* Since we set WM_TAKE_FOCUS, we must call
3214 XSetInputFocus explicitly. But not if f is null,
3215 since that might be an event for a deleted frame. */
3216 if (f)
3217 XSetInputFocus (event.xclient.display,
3218 event.xclient.window,
3219 RevertToPointerRoot,
3220 event.xclient.data.l[1]);
3221 /* Not certain about handling scroll bars here */
c047688c 3222 }
7a13e894
RS
3223 else if (event.xclient.data.l[0]
3224 == dpyinfo->Xatom_wm_save_yourself)
3225 {
3226 /* Save state modify the WM_COMMAND property to
3227 something which can reinstate us. This notifies
3228 the session manager, who's looking for such a
3229 PropertyNotify. Can restart processing when
3230 a keyboard or mouse event arrives. */
3231 if (numchars > 0)
3232 {
3233 f = x_top_window_to_frame (event.xclient.window);
3234
3235 /* This is just so we only give real data once
3236 for a single Emacs process. */
3237 if (f == selected_frame)
3238 XSetCommand (FRAME_X_DISPLAY (f),
3239 event.xclient.window,
3240 initial_argv, initial_argc);
3241 else
3242 XSetCommand (FRAME_X_DISPLAY (f),
3243 event.xclient.window,
3244 0, 0);
3245 }
3246 }
3247 else if (event.xclient.data.l[0]
3248 == dpyinfo->Xatom_wm_delete_window)
1fb20991 3249 {
7a13e894 3250 struct frame *f = x_any_window_to_frame (event.xclient.window);
1fb20991 3251
7a13e894
RS
3252 if (f)
3253 {
3254 if (numchars == 0)
3255 abort ();
1fb20991 3256
7a13e894
RS
3257 bufp->kind = delete_window_event;
3258 XSETFRAME (bufp->frame_or_window, f);
3259 bufp++;
3260
3261 count += 1;
3262 numchars -= 1;
3263 }
1fb20991 3264 }
c047688c 3265 }
7a13e894
RS
3266 else if (event.xclient.message_type
3267 == dpyinfo->Xatom_wm_configure_denied)
3268 {
3269 }
3270 else if (event.xclient.message_type
3271 == dpyinfo->Xatom_wm_window_moved)
3272 {
3273 int new_x, new_y;
3274 struct frame *f = x_window_to_frame (event.xclient.window);
58769bee 3275
7a13e894
RS
3276 new_x = event.xclient.data.s[0];
3277 new_y = event.xclient.data.s[1];
1fb20991 3278
7a13e894
RS
3279 if (f)
3280 {
3281 f->display.x->left_pos = new_x;
3282 f->display.x->top_pos = new_y;
3283 }
1fb20991 3284 }
5627c40e 3285#if defined (USE_X_TOOLKIT) && defined (HAVE_X11R5)
7a13e894
RS
3286 else if (event.xclient.message_type
3287 == dpyinfo->Xatom_editres)
3288 {
3289 struct frame *f = x_any_window_to_frame (event.xclient.window);
3290 _XEditResCheckMessages (f->display.x->widget, NULL, &event, NULL);
3291 }
5627c40e 3292#endif /* USE_X_TOOLKIT and HAVE_X11R5 */
7a13e894
RS
3293 }
3294 break;
dc6f92b8 3295
7a13e894 3296 case SelectionNotify:
3afe33e7 3297#ifdef USE_X_TOOLKIT
7a13e894
RS
3298 if (! x_window_to_frame (event.xselection.requestor))
3299 goto OTHER;
3afe33e7 3300#endif /* not USE_X_TOOLKIT */
7a13e894
RS
3301 x_handle_selection_notify (&event);
3302 break;
d56a553a 3303
7a13e894 3304 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 3305#ifdef USE_X_TOOLKIT
7a13e894
RS
3306 if (! x_window_to_frame (event.xselectionclear.window))
3307 goto OTHER;
3afe33e7 3308#endif /* USE_X_TOOLKIT */
7a13e894
RS
3309 {
3310 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 3311
7a13e894
RS
3312 if (numchars == 0)
3313 abort ();
d56a553a 3314
7a13e894
RS
3315 bufp->kind = selection_clear_event;
3316 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3317 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3318 SELECTION_EVENT_TIME (bufp) = eventp->time;
3319 bufp++;
d56a553a 3320
7a13e894
RS
3321 count += 1;
3322 numchars -= 1;
3323 }
3324 break;
dc6f92b8 3325
7a13e894 3326 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 3327#ifdef USE_X_TOOLKIT
7a13e894
RS
3328 if (!x_window_to_frame (event.xselectionrequest.owner))
3329 goto OTHER;
3afe33e7 3330#endif /* USE_X_TOOLKIT */
7a13e894
RS
3331 if (x_queue_selection_requests)
3332 x_queue_event (x_window_to_frame (event.xselectionrequest.owner),
3333 &event);
3334 else
3335 {
3336 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
dc6f92b8 3337
7a13e894
RS
3338 if (numchars == 0)
3339 abort ();
3340
3341 bufp->kind = selection_request_event;
3342 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3343 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
3344 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3345 SELECTION_EVENT_TARGET (bufp) = eventp->target;
3346 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
3347 SELECTION_EVENT_TIME (bufp) = eventp->time;
3348 bufp++;
3349
3350 count += 1;
3351 numchars -= 1;
3352 }
3353 break;
3354
3355 case PropertyNotify:
3afe33e7 3356#ifdef USE_X_TOOLKIT
7a13e894
RS
3357 if (!x_any_window_to_frame (event.xproperty.window))
3358 goto OTHER;
3afe33e7 3359#endif /* not USE_X_TOOLKIT */
7a13e894
RS
3360 x_handle_property_notify (&event);
3361 break;
dc6f92b8 3362
7a13e894
RS
3363 case ReparentNotify:
3364 f = x_top_window_to_frame (event.xreparent.window);
3365 if (f)
3366 {
3367 int x, y;
3368 f->display.x->parent_desc = event.xreparent.parent;
3369 x_real_positions (f, &x, &y);
3370 f->display.x->left_pos = x;
3371 f->display.x->top_pos = y;
3372 }
3373 break;
3bd330d4 3374
7a13e894
RS
3375 case Expose:
3376 f = x_window_to_frame (event.xexpose.window);
3377 if (f)
dc6f92b8 3378 {
7a13e894
RS
3379 if (f->async_visible == 0)
3380 {
3381 f->async_visible = 1;
3382 f->async_iconified = 0;
3383 SET_FRAME_GARBAGED (f);
3384 }
3385 else
3386 dumprectangle (x_window_to_frame (event.xexpose.window),
3387 event.xexpose.x, event.xexpose.y,
3388 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
3389 }
3390 else
7a13e894
RS
3391 {
3392 struct scroll_bar *bar
3393 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 3394
7a13e894
RS
3395 if (bar)
3396 x_scroll_bar_expose (bar, &event);
3afe33e7 3397#ifdef USE_X_TOOLKIT
7a13e894
RS
3398 else
3399 goto OTHER;
3afe33e7 3400#endif /* USE_X_TOOLKIT */
7a13e894
RS
3401 }
3402 break;
dc6f92b8 3403
7a13e894
RS
3404 case GraphicsExpose: /* This occurs when an XCopyArea's
3405 source area was obscured or not
3406 available.*/
3407 f = x_window_to_frame (event.xgraphicsexpose.drawable);
3408 if (f)
3409 {
3410 dumprectangle (f,
3411 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
3412 event.xgraphicsexpose.width,
3413 event.xgraphicsexpose.height);
3414 }
3afe33e7 3415#ifdef USE_X_TOOLKIT
7a13e894
RS
3416 else
3417 goto OTHER;
3afe33e7 3418#endif /* USE_X_TOOLKIT */
7a13e894 3419 break;
dc6f92b8 3420
7a13e894
RS
3421 case NoExpose: /* This occurs when an XCopyArea's
3422 source area was completely
3423 available */
3424 break;
dc6f92b8 3425
7a13e894
RS
3426 case UnmapNotify:
3427 f = x_any_window_to_frame (event.xunmap.window);
3428 if (f) /* F may no longer exist if
3429 the frame was deleted. */
3430 {
3431 /* While a frame is unmapped, display generation is
3432 disabled; you don't want to spend time updating a
3433 display that won't ever be seen. */
3434 f->async_visible = 0;
3435 /* We can't distinguish, from the event, whether the window
3436 has become iconified or invisible. So assume, if it
3437 was previously visible, than now it is iconified.
3438 We depend on x_make_frame_invisible to mark it iconified. */
3439 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
3440 f->async_iconified = 1;
3441 }
3afe33e7 3442#ifdef USE_X_TOOLKIT
7a13e894 3443 goto OTHER;
3afe33e7 3444#endif /* USE_X_TOOLKIT */
7a13e894 3445 break;
dc6f92b8 3446
7a13e894
RS
3447 case MapNotify:
3448 /* We use x_top_window_to_frame because map events can come
3449 for subwindows and they don't mean that the frame is visible. */
3450 f = x_top_window_to_frame (event.xmap.window);
3451 if (f)
3452 {
3453 f->async_visible = 1;
3454 f->async_iconified = 0;
dc6f92b8 3455
7a13e894
RS
3456 /* wait_reading_process_input will notice this and update
3457 the frame's display structures. */
3458 SET_FRAME_GARBAGED (f);
3459 }
3afe33e7 3460#ifdef USE_X_TOOLKIT
7a13e894 3461 goto OTHER;
3afe33e7 3462#endif /* USE_X_TOOLKIT */
7a13e894 3463 break;
dc6f92b8 3464
7a13e894
RS
3465 /* Turn off processing if we become fully obscured. */
3466 case VisibilityNotify:
3467 break;
dc6f92b8 3468
7a13e894
RS
3469 case KeyPress:
3470 f = x_any_window_to_frame (event.xkey.window);
f451eb13 3471
7a13e894
RS
3472 if (f != 0)
3473 {
3474 KeySym keysym, orig_keysym;
3475 /* al%imercury@uunet.uu.net says that making this 81 instead of
3476 80 fixed a bug whereby meta chars made his Emacs hang. */
3477 unsigned char copy_buffer[81];
3478 int modifiers;
64bb1782 3479
7a13e894
RS
3480 event.xkey.state
3481 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
3482 extra_keyboard_modifiers);
3483 modifiers = event.xkey.state;
3a2712f9 3484
7a13e894 3485 /* This will have to go some day... */
752a043f 3486
7a13e894
RS
3487 /* make_lispy_event turns chars into control chars.
3488 Don't do it here because XLookupString is too eager. */
3489 event.xkey.state &= ~ControlMask;
3490 nbytes =
3491 XLookupString (&event.xkey, copy_buffer, 80, &keysym,
3492 &compose_status);
dc6f92b8 3493
7a13e894 3494 orig_keysym = keysym;
55123275 3495
7a13e894
RS
3496 if (numchars > 1)
3497 {
3498 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
3499 || keysym == XK_Delete
3500 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
3501 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 3502#ifdef HPUX
7a13e894
RS
3503 /* This recognizes the "extended function keys".
3504 It seems there's no cleaner way.
3505 Test IsModifierKey to avoid handling mode_switch
3506 incorrectly. */
3507 || ((unsigned) (keysym) >= XK_Select
3508 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
3509#endif
3510#ifdef XK_dead_circumflex
7a13e894 3511 || orig_keysym == XK_dead_circumflex
69388238
RS
3512#endif
3513#ifdef XK_dead_grave
7a13e894 3514 || orig_keysym == XK_dead_grave
69388238
RS
3515#endif
3516#ifdef XK_dead_tilde
7a13e894 3517 || orig_keysym == XK_dead_tilde
69388238
RS
3518#endif
3519#ifdef XK_dead_diaeresis
7a13e894 3520 || orig_keysym == XK_dead_diaeresis
69388238
RS
3521#endif
3522#ifdef XK_dead_macron
7a13e894 3523 || orig_keysym == XK_dead_macron
69388238
RS
3524#endif
3525#ifdef XK_dead_degree
7a13e894 3526 || orig_keysym == XK_dead_degree
69388238
RS
3527#endif
3528#ifdef XK_dead_acute
7a13e894 3529 || orig_keysym == XK_dead_acute
69388238
RS
3530#endif
3531#ifdef XK_dead_cedilla
7a13e894 3532 || orig_keysym == XK_dead_cedilla
69388238
RS
3533#endif
3534#ifdef XK_dead_breve
7a13e894 3535 || orig_keysym == XK_dead_breve
69388238
RS
3536#endif
3537#ifdef XK_dead_ogonek
7a13e894 3538 || orig_keysym == XK_dead_ogonek
69388238
RS
3539#endif
3540#ifdef XK_dead_caron
7a13e894 3541 || orig_keysym == XK_dead_caron
69388238
RS
3542#endif
3543#ifdef XK_dead_doubleacute
7a13e894 3544 || orig_keysym == XK_dead_doubleacute
69388238
RS
3545#endif
3546#ifdef XK_dead_abovedot
7a13e894 3547 || orig_keysym == XK_dead_abovedot
c34790e0 3548#endif
7a13e894
RS
3549 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
3550 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
3551 /* Any "vendor-specific" key is ok. */
3552 || (orig_keysym & (1 << 28)))
3553 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
3554#ifndef HAVE_X11R5
3555#ifdef XK_Mode_switch
7a13e894 3556 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
3557#endif
3558#ifdef XK_Num_Lock
7a13e894 3559 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
3560#endif
3561#endif /* not HAVE_X11R5 */
7a13e894 3562 ))
dc6f92b8 3563 {
10e6549c
RS
3564 if (temp_index == sizeof temp_buffer / sizeof (short))
3565 temp_index = 0;
7a13e894
RS
3566 temp_buffer[temp_index++] = keysym;
3567 bufp->kind = non_ascii_keystroke;
3568 bufp->code = keysym;
e0c1aef2 3569 XSETFRAME (bufp->frame_or_window, f);
334208b7
RS
3570 bufp->modifiers
3571 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
3572 modifiers);
1113d9db 3573 bufp->timestamp = event.xkey.time;
dc6f92b8 3574 bufp++;
7a13e894
RS
3575 count++;
3576 numchars--;
dc6f92b8 3577 }
7a13e894
RS
3578 else if (numchars > nbytes)
3579 {
3580 register int i;
3581
3582 for (i = 0; i < nbytes; i++)
3583 {
3584 if (temp_index == sizeof temp_buffer / sizeof (short))
3585 temp_index = 0;
3586 temp_buffer[temp_index++] = copy_buffer[i];
3587 bufp->kind = ascii_keystroke;
3588 bufp->code = copy_buffer[i];
3589 XSETFRAME (bufp->frame_or_window, f);
3590 bufp->modifiers
3591 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
3592 modifiers);
3593 bufp->timestamp = event.xkey.time;
3594 bufp++;
3595 }
3596
3597 count += nbytes;
3598 numchars -= nbytes;
3599 }
3600 else
3601 abort ();
dc6f92b8 3602 }
10e6549c
RS
3603 else
3604 abort ();
dc6f92b8 3605 }
7a13e894 3606 break;
f451eb13 3607
7a13e894
RS
3608 /* Here's a possible interpretation of the whole
3609 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If you get a
3610 FocusIn event, you have to get a FocusOut event before you
3611 relinquish the focus. If you haven't received a FocusIn event,
3612 then a mere LeaveNotify is enough to free you. */
f451eb13 3613
7a13e894
RS
3614 case EnterNotify:
3615 f = x_any_window_to_frame (event.xcrossing.window);
6d4238f3 3616
7a13e894 3617 if (event.xcrossing.focus) /* Entered Window */
dc6f92b8 3618 {
7a13e894
RS
3619 /* Avoid nasty pop/raise loops. */
3620 if (f && (!(f->auto_raise)
3621 || !(f->auto_lower)
3622 || (event.xcrossing.time - enter_timestamp) > 500))
3623 {
3624 x_new_focus_frame (f);
3625 enter_timestamp = event.xcrossing.time;
3626 }
dc6f92b8 3627 }
7a13e894
RS
3628 else if (f == x_focus_frame)
3629 x_new_focus_frame (0);
3630 /* EnterNotify counts as mouse movement,
3631 so update things that depend on mouse position. */
3632 if (f)
3633 note_mouse_movement (f, &event.xmotion);
3afe33e7 3634#ifdef USE_X_TOOLKIT
7a13e894 3635 goto OTHER;
3afe33e7 3636#endif /* USE_X_TOOLKIT */
7a13e894 3637 break;
dc6f92b8 3638
7a13e894
RS
3639 case FocusIn:
3640 f = x_any_window_to_frame (event.xfocus.window);
3641 if (event.xfocus.detail != NotifyPointer)
3642 x_focus_event_frame = f;
3643 if (f)
3644 x_new_focus_frame (f);
3afe33e7 3645#ifdef USE_X_TOOLKIT
7a13e894 3646 goto OTHER;
3afe33e7 3647#endif /* USE_X_TOOLKIT */
7a13e894 3648 break;
f451eb13 3649
10c5e63d 3650
7a13e894
RS
3651 case LeaveNotify:
3652 f = x_top_window_to_frame (event.xcrossing.window);
3653 if (f)
10c5e63d 3654 {
7a13e894
RS
3655 if (f == dpyinfo->mouse_face_mouse_frame)
3656 /* If we move outside the frame,
3657 then we're certainly no longer on any text in the frame. */
3658 clear_mouse_face (dpyinfo);
3659
3660 if (event.xcrossing.focus)
3661 {
3662 if (! x_focus_event_frame)
3663 x_new_focus_frame (0);
3664 else
3665 x_new_focus_frame (f);
3666 }
10c5e63d 3667 else
7a13e894
RS
3668 {
3669 if (f == x_focus_event_frame)
3670 x_focus_event_frame = 0;
3671 if (f == x_focus_frame)
3672 x_new_focus_frame (0);
3673 }
10c5e63d 3674 }
3afe33e7 3675#ifdef USE_X_TOOLKIT
7a13e894 3676 goto OTHER;
3afe33e7 3677#endif /* USE_X_TOOLKIT */
7a13e894 3678 break;
dc6f92b8 3679
7a13e894
RS
3680 case FocusOut:
3681 f = x_any_window_to_frame (event.xfocus.window);
3682 if (event.xfocus.detail != NotifyPointer
3683 && f == x_focus_event_frame)
3684 x_focus_event_frame = 0;
3685 if (f && f == x_focus_frame)
3686 x_new_focus_frame (0);
3afe33e7 3687#ifdef USE_X_TOOLKIT
7a13e894 3688 goto OTHER;
3afe33e7 3689#endif /* USE_X_TOOLKIT */
7a13e894 3690 break;
dc6f92b8 3691
7a13e894 3692 case MotionNotify:
dc6f92b8 3693 {
7a13e894
RS
3694 if (dpyinfo->grabbed && last_mouse_frame
3695 && FRAME_LIVE_P (last_mouse_frame))
3696 f = last_mouse_frame;
3697 else
3698 f = x_window_to_frame (event.xmotion.window);
3699 if (f)
3700 note_mouse_movement (f, &event.xmotion);
3701 else
3702 {
3703 struct scroll_bar *bar
3704 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 3705
7a13e894
RS
3706 if (bar)
3707 x_scroll_bar_note_movement (bar, &event);
b8009dd1 3708
7a13e894
RS
3709 /* If we move outside the frame,
3710 then we're certainly no longer on any text in the frame. */
3711 clear_mouse_face (dpyinfo);
3712 }
dc6f92b8 3713 }
0a178815 3714#if 0 /* This should be unnecessary, since the toolkit has no use
7a13e894
RS
3715 for motion events that happen outside of the menu event loop,
3716 and it seems to cause the bug that mouse events stop coming
3717 after a while. */
3afe33e7 3718#ifdef USE_X_TOOLKIT
7a13e894 3719 goto OTHER;
3afe33e7 3720#endif /* USE_X_TOOLKIT */
0a178815 3721#endif
7a13e894 3722 break;
dc6f92b8 3723
7a13e894
RS
3724 case ConfigureNotify:
3725 f = x_any_window_to_frame (event.xconfigure.window);
3afe33e7 3726#ifdef USE_X_TOOLKIT
7a13e894 3727 if (f
3a35ab44 3728#if 0
7a13e894 3729 && ! event.xconfigure.send_event
3a35ab44 3730#endif
7a13e894 3731 && (event.xconfigure.window == XtWindow (f->display.x->widget)))
af395ec1
RS
3732 {
3733 Window win, child;
3734 int win_x, win_y;
3735
6cc35d86
JB
3736 /* Find the position of the outside upper-left corner of
3737 the window, in the root coordinate system. Don't
3738 refer to the parent window here; we may be processing
3739 this event after the window manager has changed our
3740 parent, but before we have reached the ReparentNotify. */
334208b7 3741 XTranslateCoordinates (FRAME_X_DISPLAY (f),
58769bee 3742
af395ec1 3743 /* From-window, to-window. */
7a13e894 3744 XtWindow (f->display.x->widget),
334208b7 3745 FRAME_X_DISPLAY_INFO (f)->root_window,
af395ec1
RS
3746
3747 /* From-position, to-position. */
6cc35d86
JB
3748 -event.xconfigure.border_width,
3749 -event.xconfigure.border_width,
af395ec1
RS
3750 &win_x, &win_y,
3751
3752 /* Child of win. */
3753 &child);
3754 event.xconfigure.x = win_x;
3755 event.xconfigure.y = win_y;
7a13e894
RS
3756
3757 f->display.x->pixel_width = event.xconfigure.width;
3758 f->display.x->pixel_height = event.xconfigure.height;
3759 f->display.x->left_pos = event.xconfigure.x;
3760 f->display.x->top_pos = event.xconfigure.y;
3761
3762 /* What we have now is the position of Emacs's own window.
3763 Convert that to the position of the window manager window. */
3764 {
3765 int x, y;
3766 x_real_positions (f, &x, &y);
3767 f->display.x->left_pos = x;
3768 f->display.x->top_pos = y;
3769 }
af395ec1 3770 }
7a13e894
RS
3771 goto OTHER;
3772#else /* not USE_X_TOOLKIT */
3773 if (f)
3774 {
3775 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
3776 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
3777
3778 /* Even if the number of character rows and columns has
3779 not changed, the font size may have changed, so we need
3780 to check the pixel dimensions as well. */
3781 if (columns != f->width
3782 || rows != f->height
3783 || event.xconfigure.width != f->display.x->pixel_width
3784 || event.xconfigure.height != f->display.x->pixel_height)
3785 {
3786 change_frame_size (f, rows, columns, 0, 1);
3787 SET_FRAME_GARBAGED (f);
3788 }
af395ec1 3789
7a13e894
RS
3790 if (! event.xconfigure.send_event)
3791 {
3792 Window win, child;
3793 int win_x, win_y;
3794
3795 /* Find the position of the outside upper-left corner of
3796 the window, in the root coordinate system. Don't
3797 refer to the parent window here; we may be processing
3798 this event after the window manager has changed our
3799 parent, but before we have reached the ReparentNotify. */
3800 XTranslateCoordinates (FRAME_X_DISPLAY (f),
3801
3802 /* From-window, to-window. */
3803 f->display.x->window_desc,
3804 FRAME_X_DISPLAY_INFO (f)->root_window,
3805
3806 /* From-position, to-position. */
3807 -event.xconfigure.border_width,
3808 -event.xconfigure.border_width,
3809 &win_x, &win_y,
3810
3811 /* Child of win. */
3812 &child);
3813 event.xconfigure.x = win_x;
3814 event.xconfigure.y = win_y;
3815 }
3a35ab44 3816
7a13e894
RS
3817 f->display.x->pixel_width = event.xconfigure.width;
3818 f->display.x->pixel_height = event.xconfigure.height;
3819 f->display.x->left_pos = event.xconfigure.x;
3820 f->display.x->top_pos = event.xconfigure.y;
3821
3822 /* What we have now is the position of Emacs's own window.
3823 Convert that to the position of the window manager window. */
fd13dbb2 3824 {
7a13e894
RS
3825 int x, y;
3826 x_real_positions (f, &x, &y);
3827 f->display.x->left_pos = x;
3828 f->display.x->top_pos = y;
3829 if (y != event.xconfigure.y)
3830 {
3831 /* Since the WM decorations come below top_pos now,
3832 we must put them below top_pos in the future. */
3833 f->display.x->win_gravity = NorthWestGravity;
3834 x_wm_set_size_hint (f, 0, 0);
3835 }
fd13dbb2 3836 }
7a13e894 3837 }
3afe33e7 3838#endif /* not USE_X_TOOLKIT */
7a13e894 3839 break;
dc6f92b8 3840
7a13e894
RS
3841 case ButtonPress:
3842 case ButtonRelease:
3843 {
3844 /* If we decide we want to generate an event to be seen
3845 by the rest of Emacs, we put it here. */
3846 struct input_event emacs_event;
3847 emacs_event.kind = no_event;
dc6f92b8 3848
7a13e894 3849 bzero (&compose_status, sizeof (compose_status));
9b07615b 3850
7a13e894
RS
3851 f = x_window_to_frame (event.xbutton.window);
3852 if (f)
3853 {
3854 if (!x_focus_frame || (f == x_focus_frame))
3855 construct_mouse_click (&emacs_event, &event, f);
3856 }
3857 else
3858 {
3859 struct scroll_bar *bar
3860 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 3861
7a13e894
RS
3862 if (bar)
3863 x_scroll_bar_handle_click (bar, &event, &emacs_event);
3afe33e7 3864#ifdef USE_X_TOOLKIT
7a13e894
RS
3865 else
3866 {
3867 /* Assume we have a menubar button press. A bad
3868 assumption should behave benignly. */
3869 popup_get_selection (&event);
3870 break;
3871 }
3872#endif /* USE_X_TOOLKIT */
3873 }
3874
3875 if (event.type == ButtonPress)
3876 {
3877 dpyinfo->grabbed |= (1 << event.xbutton.button);
3878 last_mouse_frame = f;
3879 }
3afe33e7
RS
3880 else
3881 {
7a13e894 3882 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 3883 }
23faf38f 3884
7a13e894
RS
3885 if (numchars >= 1 && emacs_event.kind != no_event)
3886 {
3887 bcopy (&emacs_event, bufp, sizeof (struct input_event));
3888 bufp++;
3889 count++;
3890 numchars--;
3891 }
3afe33e7
RS
3892
3893#ifdef USE_X_TOOLKIT
7a13e894 3894 goto OTHER;
3afe33e7 3895#endif /* USE_X_TOOLKIT */
7a13e894
RS
3896 }
3897 break;
dc6f92b8 3898
7a13e894
RS
3899 case CirculateNotify:
3900 break;
3901 case CirculateRequest:
3902 break;
dc6f92b8 3903
7a13e894
RS
3904 case MappingNotify:
3905 /* Someone has changed the keyboard mapping - update the
3906 local cache. */
3907 switch (event.xmapping.request)
3908 {
3909 case MappingModifier:
3910 x_find_modifier_meanings (dpyinfo);
3911 /* This is meant to fall through. */
3912 case MappingKeyboard:
3913 XRefreshKeyboardMapping (&event.xmapping);
3914 }
3afe33e7 3915#ifdef USE_X_TOOLKIT
7a13e894 3916 goto OTHER;
3afe33e7 3917#endif /* USE_X_TOOLKIT */
7a13e894 3918 break;
dc6f92b8 3919
7a13e894 3920 default:
3afe33e7 3921#ifdef USE_X_TOOLKIT
7a13e894
RS
3922 OTHER:
3923 BLOCK_INPUT;
3924 XtDispatchEvent (&event);
3925 UNBLOCK_INPUT;
3afe33e7 3926#endif /* USE_X_TOOLKIT */
7a13e894
RS
3927 break;
3928 }
dc6f92b8
JB
3929 }
3930 }
3931
9a5196d0
RS
3932 /* On some systems, an X bug causes Emacs to get no more events
3933 when the window is destroyed. Detect that. (1994.) */
58769bee 3934 if (! event_found)
ef2a22d0 3935 {
ef2a22d0
RS
3936 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
3937 One XNOOP in 100 loops will make Emacs terminate.
3938 B. Bretthauer, 1994 */
3939 x_noop_count++;
58769bee 3940 if (x_noop_count >= 100)
ef2a22d0
RS
3941 {
3942 x_noop_count=0;
7a13e894
RS
3943 /* Use the first display in the list. Why not? */
3944 XNoOp (x_display_list->display);
ef2a22d0
RS
3945 }
3946 }
502add23 3947
0134a210
RS
3948 /* If the focus was just given to an autoraising frame,
3949 raise it now. */
7a13e894 3950 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
3951 if (pending_autoraise_frame)
3952 {
3953 x_raise_frame (pending_autoraise_frame);
3954 pending_autoraise_frame = 0;
3955 }
0134a210 3956
dc6f92b8
JB
3957 UNBLOCK_INPUT;
3958 return count;
3959}
dc6f92b8 3960\f
f451eb13
JB
3961/* Drawing the cursor. */
3962
3963
dc6f92b8
JB
3964/* Draw a hollow box cursor. Don't change the inside of the box. */
3965
3966static void
f676886a
JB
3967x_draw_box (f)
3968 struct frame *f;
dc6f92b8 3969{
2a6cf806
RS
3970 int left = CHAR_TO_PIXEL_COL (f, curs_x);
3971 int top = CHAR_TO_PIXEL_ROW (f, curs_y);
f676886a 3972 int width = FONT_WIDTH (f->display.x->font);
a27f9f86 3973 int height = f->display.x->line_height;
dc6f92b8 3974
334208b7 3975 XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f676886a 3976 f->display.x->cursor_gc,
dc6f92b8 3977 left, top, width - 1, height - 1);
dc6f92b8
JB
3978}
3979
f676886a 3980/* Clear the cursor of frame F to background color,
dc6f92b8
JB
3981 and mark the cursor as not shown.
3982 This is used when the text where the cursor is
3983 is about to be rewritten. */
3984
3985static void
f676886a
JB
3986clear_cursor (f)
3987 struct frame *f;
dc6f92b8
JB
3988{
3989 int mask;
3990
f451eb13 3991 if (! FRAME_VISIBLE_P (f)
f676886a 3992 || f->phys_cursor_x < 0)
dc6f92b8
JB
3993 return;
3994
f676886a 3995 x_display_cursor (f, 0);
f676886a 3996 f->phys_cursor_x = -1;
dc6f92b8
JB
3997}
3998
f676886a 3999/* Redraw the glyph at ROW, COLUMN on frame F, in the style
90e65f07
JB
4000 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
4001 glyph drawn. */
dc6f92b8
JB
4002
4003static void
f676886a
JB
4004x_draw_single_glyph (f, row, column, glyph, highlight)
4005 struct frame *f;
dc6f92b8 4006 int row, column;
90e65f07 4007 GLYPH glyph;
dc6f92b8
JB
4008 int highlight;
4009{
f676886a 4010 dumpglyphs (f,
12ba150f
JB
4011 CHAR_TO_PIXEL_COL (f, column),
4012 CHAR_TO_PIXEL_ROW (f, row),
0cdd0c9f 4013 &glyph, 1, highlight, 0);
dc6f92b8
JB
4014}
4015
dc6f92b8 4016static void
dbc4e1c1 4017x_display_bar_cursor (f, on)
f676886a 4018 struct frame *f;
dc6f92b8
JB
4019 int on;
4020{
f676886a 4021 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
90e65f07 4022
49d838ea
JB
4023 /* This is pointless on invisible frames, and dangerous on garbaged
4024 frames; in the latter case, the frame may be in the midst of
4025 changing its size, and curs_x and curs_y may be off the frame. */
4026 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dbc4e1c1
JB
4027 return;
4028
4029 if (! on && f->phys_cursor_x < 0)
4030 return;
4031
f676886a 4032 /* If we're not updating, then we want to use the current frame's
1113d9db 4033 cursor position, not our local idea of where the cursor ought to be. */
f676886a 4034 if (f != updating_frame)
1113d9db 4035 {
f676886a
JB
4036 curs_x = FRAME_CURSOR_X (f);
4037 curs_y = FRAME_CURSOR_Y (f);
1113d9db
JB
4038 }
4039
dbc4e1c1
JB
4040 /* If there is anything wrong with the current cursor state, remove it. */
4041 if (f->phys_cursor_x >= 0
4042 && (!on
4043 || f->phys_cursor_x != curs_x
4044 || f->phys_cursor_y != curs_y
4045 || f->display.x->current_cursor != bar_cursor))
4046 {
4047 /* Erase the cursor by redrawing the character underneath it. */
4048 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4049 f->phys_cursor_glyph,
4050 current_glyphs->highlight[f->phys_cursor_y]);
4051 f->phys_cursor_x = -1;
4052 }
4053
4054 /* If we now need a cursor in the new place or in the new form, do it so. */
4055 if (on
4056 && (f->phys_cursor_x < 0
4057 || (f->display.x->current_cursor != bar_cursor)))
4058 {
4059 f->phys_cursor_glyph
4060 = ((current_glyphs->enable[curs_y]
4061 && curs_x < current_glyphs->used[curs_y])
4062 ? current_glyphs->glyphs[curs_y][curs_x]
4063 : SPACEGLYPH);
334208b7 4064 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
4065 f->display.x->cursor_gc,
4066 CHAR_TO_PIXEL_COL (f, curs_x),
4067 CHAR_TO_PIXEL_ROW (f, curs_y),
a27f9f86 4068 1, f->display.x->line_height);
dbc4e1c1
JB
4069
4070 f->phys_cursor_x = curs_x;
4071 f->phys_cursor_y = curs_y;
4072
4073 f->display.x->current_cursor = bar_cursor;
4074 }
4075
4076 if (updating_frame != f)
334208b7 4077 XFlush (FRAME_X_DISPLAY (f));
dbc4e1c1
JB
4078}
4079
4080
4081/* Turn the displayed cursor of frame F on or off according to ON.
4082 If ON is nonzero, where to put the cursor is specified
4083 by F->cursor_x and F->cursor_y. */
4084
4085static void
4086x_display_box_cursor (f, on)
4087 struct frame *f;
4088 int on;
4089{
4090 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4091
49d838ea
JB
4092 /* This is pointless on invisible frames, and dangerous on garbaged
4093 frames; in the latter case, the frame may be in the midst of
4094 changing its size, and curs_x and curs_y may be off the frame. */
4095 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dc6f92b8
JB
4096 return;
4097
4098 /* If cursor is off and we want it off, return quickly. */
f676886a 4099 if (!on && f->phys_cursor_x < 0)
dc6f92b8
JB
4100 return;
4101
dbc4e1c1
JB
4102 /* If we're not updating, then we want to use the current frame's
4103 cursor position, not our local idea of where the cursor ought to be. */
4104 if (f != updating_frame)
4105 {
4106 curs_x = FRAME_CURSOR_X (f);
4107 curs_y = FRAME_CURSOR_Y (f);
4108 }
4109
dc6f92b8
JB
4110 /* If cursor is currently being shown and we don't want it to be
4111 or it is in the wrong place,
4112 or we want a hollow box and it's not so, (pout!)
4113 erase it. */
f676886a 4114 if (f->phys_cursor_x >= 0
dc6f92b8 4115 && (!on
f676886a
JB
4116 || f->phys_cursor_x != curs_x
4117 || f->phys_cursor_y != curs_y
dbc4e1c1 4118 || (f->display.x->current_cursor != hollow_box_cursor
f676886a 4119 && (f != x_highlight_frame))))
dc6f92b8 4120 {
79cf7456
RS
4121 int mouse_face_here = 0;
4122
4123 /* If the cursor is in the mouse face area, redisplay that when
4124 we clear the cursor. */
7a13e894 4125 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame
79cf7456 4126 &&
7a13e894
RS
4127 (f->phys_cursor_y > FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
4128 || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
4129 && f->phys_cursor_x >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col))
79cf7456 4130 &&
7a13e894
RS
4131 (f->phys_cursor_y < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
4132 || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
4133 && f->phys_cursor_x < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col)))
79cf7456
RS
4134 mouse_face_here = 1;
4135
0cdd0c9f
RS
4136 /* If the font is not as tall as a whole line,
4137 we must explicitly clear the line's whole height. */
4138 if (FONT_HEIGHT (f->display.x->font) != f->display.x->line_height)
334208b7 4139 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
0cdd0c9f
RS
4140 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
4141 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
4142 FONT_WIDTH (f->display.x->font),
4143 f->display.x->line_height, False);
dc6f92b8 4144 /* Erase the cursor by redrawing the character underneath it. */
f676886a
JB
4145 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4146 f->phys_cursor_glyph,
79cf7456
RS
4147 (mouse_face_here
4148 ? 3
4149 : current_glyphs->highlight[f->phys_cursor_y]));
f676886a 4150 f->phys_cursor_x = -1;
dc6f92b8
JB
4151 }
4152
4153 /* If we want to show a cursor,
4154 or we want a box cursor and it's not so,
4155 write it in the right place. */
4156 if (on
f676886a 4157 && (f->phys_cursor_x < 0
dbc4e1c1 4158 || (f->display.x->current_cursor != filled_box_cursor
f676886a 4159 && f == x_highlight_frame)))
dc6f92b8 4160 {
f676886a 4161 f->phys_cursor_glyph
1113d9db
JB
4162 = ((current_glyphs->enable[curs_y]
4163 && curs_x < current_glyphs->used[curs_y])
4164 ? current_glyphs->glyphs[curs_y][curs_x]
90e65f07 4165 : SPACEGLYPH);
f676886a 4166 if (f != x_highlight_frame)
dc6f92b8 4167 {
f676886a 4168 x_draw_box (f);
dbc4e1c1 4169 f->display.x->current_cursor = hollow_box_cursor;
dc6f92b8
JB
4170 }
4171 else
4172 {
f676886a
JB
4173 x_draw_single_glyph (f, curs_y, curs_x,
4174 f->phys_cursor_glyph, 2);
dbc4e1c1 4175 f->display.x->current_cursor = filled_box_cursor;
dc6f92b8
JB
4176 }
4177
f676886a
JB
4178 f->phys_cursor_x = curs_x;
4179 f->phys_cursor_y = curs_y;
dc6f92b8
JB
4180 }
4181
f676886a 4182 if (updating_frame != f)
334208b7 4183 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
4184}
4185
f676886a
JB
4186x_display_cursor (f, on)
4187 struct frame *f;
dc6f92b8
JB
4188 int on;
4189{
f94397b5
KH
4190 BLOCK_INPUT;
4191
dbc4e1c1 4192 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
f676886a 4193 x_display_box_cursor (f, on);
dbc4e1c1 4194 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
f676886a 4195 x_display_bar_cursor (f, on);
dbc4e1c1
JB
4196 else
4197 /* Those are the only two we have implemented! */
4198 abort ();
f94397b5
KH
4199
4200 UNBLOCK_INPUT;
dc6f92b8
JB
4201}
4202\f
4203/* Icons. */
4204
f676886a 4205/* Refresh bitmap kitchen sink icon for frame F
dc6f92b8
JB
4206 when we get an expose event for it. */
4207
f676886a
JB
4208refreshicon (f)
4209 struct frame *f;
dc6f92b8 4210{
dc6f92b8 4211 /* Normally, the window manager handles this function. */
dc6f92b8
JB
4212}
4213
dbc4e1c1 4214/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
4215
4216int
990ba854 4217x_bitmap_icon (f, file)
f676886a 4218 struct frame *f;
990ba854 4219 Lisp_Object file;
dc6f92b8 4220{
7f2ae036 4221 int mask, bitmap_id;
dc6f92b8
JB
4222 Window icon_window;
4223
c118dd06 4224 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
4225 return 1;
4226
990ba854
RS
4227 /* Free up our existing icon bitmap if any. */
4228 if (f->display.x->icon_bitmap > 0)
4229 x_destroy_bitmap (f, f->display.x->icon_bitmap);
4230 f->display.x->icon_bitmap = 0;
4231
4232 if (STRINGP (file))
7f2ae036
RS
4233 bitmap_id = x_create_bitmap_from_file (f, file);
4234 else
4235 {
990ba854 4236 /* Create the GNU bitmap if necessary. */
334208b7
RS
4237 if (!FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
4238 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
4239 = x_create_bitmap_from_data (f, gnu_bits,
4240 gnu_width, gnu_height);
990ba854
RS
4241
4242 /* The first time we create the GNU bitmap,
4243 this increments the refcount one extra time.
4244 As a result, the GNU bitmap is never freed.
4245 That way, we don't have to worry about allocating it again. */
334208b7 4246 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 4247
334208b7 4248 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
4249 }
4250
4251 x_wm_set_icon_pixmap (f, bitmap_id);
4252 f->display.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
4253
4254 return 0;
4255}
4256
4257
f676886a 4258/* Make the x-window of frame F use a rectangle with text. */
dc6f92b8
JB
4259
4260int
f676886a
JB
4261x_text_icon (f, icon_name)
4262 struct frame *f;
dc6f92b8
JB
4263 char *icon_name;
4264{
c118dd06 4265 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
4266 return 1;
4267
dc6f92b8 4268 if (icon_name)
f676886a 4269 f->display.x->icon_label = icon_name;
dc6f92b8 4270 else
f676886a
JB
4271 if (! f->display.x->icon_label)
4272 f->display.x->icon_label = " *emacs* ";
58769bee 4273
dfeccd2d 4274#if 0
334208b7 4275 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f676886a 4276 (char *) f->display.x->icon_label);
dfeccd2d 4277#endif
58769bee 4278
990ba854
RS
4279 if (f->display.x->icon_bitmap > 0)
4280 x_destroy_bitmap (f, f->display.x->icon_bitmap);
7f2ae036 4281 f->display.x->icon_bitmap = 0;
b1c884c3 4282 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
4283
4284 return 0;
4285}
4286\f
4746118a
JB
4287/* Handling X errors. */
4288
7a13e894 4289/* Handle the loss of connection to display DISPLAY. */
16bd92ea 4290
4746118a 4291static SIGTYPE
7a13e894
RS
4292x_connection_closed (display, error_message)
4293 Display *display;
4294 char *error_message;
4746118a 4295{
7a13e894
RS
4296 struct x_display_info *dpyinfo = x_display_info_for_display (display);
4297 Lisp_Object frame, tail;
4298
4746118a
JB
4299 if (_Xdebug)
4300 abort ();
12ba150f 4301
7a13e894
RS
4302 /* First delete frames whose minibuffers are on frames
4303 that are on the dead display. */
4304 FOR_EACH_FRAME (tail, frame)
4305 {
4306 Lisp_Object minibuf_frame;
4307 minibuf_frame
4308 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
4309 if (! EQ (frame, minibuf_frame)
4310 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
4311 Fdelete_frame (frame, Qt);
4312 }
4313
4314 /* Now delete all remaining frames on the dead display.
4315 We are now sure none of these is used as the minibuffer
4316 for another frame that we need to delete. */
4317 FOR_EACH_FRAME (tail, frame)
4318 if (FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
4319 Fdelete_frame (frame, Qt);
4320
4321 x_delete_display (dpyinfo);
4322
4323 if (x_display_list == 0)
4324 {
4325 fprintf (stderr, "%s", error_message);
4326 shut_down_emacs (0, 0, Qnil);
4327 exit (70);
4328 }
12ba150f 4329
7a13e894
RS
4330 /* Ordinary stack unwind doesn't deal with these. */
4331#ifdef SIGIO
4332 sigunblock (sigmask (SIGIO));
4333#endif
4334 sigunblock (sigmask (SIGALRM));
4335 TOTALLY_UNBLOCK_INPUT;
4336
4337 error ("%s", error_message);
4746118a
JB
4338}
4339
7a13e894
RS
4340/* This is the usual handler for X protocol errors.
4341 It kills all frames on the display that we got the error for.
4342 If that was the only one, it prints an error message and kills Emacs. */
4343
c118dd06
JB
4344static int
4345x_error_quitter (display, error)
4346 Display *display;
4347 XErrorEvent *error;
4348{
7a13e894 4349 char buf[256], buf1[356];
dc6f92b8 4350
58769bee 4351 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 4352 original error handler. */
dc6f92b8 4353
c118dd06 4354 XGetErrorText (display, error->error_code, buf, sizeof (buf));
7a13e894 4355 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 4356 buf, error->request_code);
7a13e894 4357 x_connection_closed (display, buf1);
dc6f92b8
JB
4358}
4359
7a13e894
RS
4360/* This is the handler for X IO errors, always.
4361 It kills all frames on the display that we lost touch with.
4362 If that was the only one, it prints an error message and kills Emacs. */
4363
8922af5f
JB
4364static int
4365x_io_error_quitter (display)
4366 Display *display;
4367{
7a13e894 4368 char buf[256];
8922af5f 4369
7a13e894
RS
4370 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
4371 x_connection_closed (display, buf);
8922af5f 4372}
7a13e894 4373\f
c118dd06 4374/* A buffer for storing X error messages. */
cef13e55
RS
4375static char *x_caught_error_message;
4376#define X_CAUGHT_ERROR_MESSAGE_SIZE 200
c118dd06
JB
4377
4378/* An X error handler which stores the error message in
4379 x_caught_error_message. This is what's installed when
4380 x_catch_errors is in effect. */
7a13e894 4381
c118dd06
JB
4382static int
4383x_error_catcher (display, error)
4384 Display *display;
4385 XErrorEvent *error;
4386{
4387 XGetErrorText (display, error->error_code,
cef13e55 4388 x_caught_error_message, X_CAUGHT_ERROR_MESSAGE_SIZE);
c118dd06
JB
4389}
4390
4391
7a13e894
RS
4392/* Begin trapping X errors for display DPY. Actually we trap X errors
4393 for all displays, but DPY should be the display you are actually
4394 operating on.
dc6f92b8 4395
c118dd06
JB
4396 After calling this function, X protocol errors no longer cause
4397 Emacs to exit; instead, they are recorded in x_cfc_error_message.
dc6f92b8 4398
c118dd06
JB
4399 Calling x_check_errors signals an Emacs error if an X error has
4400 occurred since the last call to x_catch_errors or x_check_errors.
4401
4402 Calling x_uncatch_errors resumes the normal error handling. */
4403
bc20ebbf 4404void x_catch_errors (), x_check_errors (), x_uncatch_errors ();
c118dd06
JB
4405
4406void
7a13e894
RS
4407x_catch_errors (dpy)
4408 Display *dpy;
dc6f92b8 4409{
c118dd06 4410 /* Make sure any errors from previous requests have been dealt with. */
7a13e894 4411 XSync (dpy, False);
dc6f92b8 4412
c118dd06 4413 /* Set up the error buffer. */
60f9aad3 4414 x_caught_error_message
cef13e55
RS
4415 = (char*) xmalloc (X_CAUGHT_ERROR_MESSAGE_SIZE);
4416 x_caught_error_message[0] = '\0';
16bd92ea 4417
c118dd06 4418 /* Install our little error handler. */
334208b7 4419 XSetErrorHandler (x_error_catcher);
c118dd06 4420}
16bd92ea 4421
c118dd06
JB
4422/* If any X protocol errors have arrived since the last call to
4423 x_catch_errors or x_check_errors, signal an Emacs error using
4424 sprintf (a buffer, FORMAT, the x error message text) as the text. */
812361a1 4425
c118dd06 4426void
7a13e894
RS
4427x_check_errors (dpy, format)
4428 Display *dpy;
c118dd06
JB
4429 char *format;
4430{
4431 /* Make sure to catch any errors incurred so far. */
7a13e894 4432 XSync (dpy, False);
16bd92ea 4433
cef13e55 4434 if (x_caught_error_message[0])
c118dd06 4435 {
cef13e55 4436 char buf[X_CAUGHT_ERROR_MESSAGE_SIZE + 56];
dc6f92b8 4437
cef13e55 4438 sprintf (buf, format, x_caught_error_message);
7a13e894 4439 x_uncatch_errors (dpy);
c118dd06
JB
4440 error (buf);
4441 }
4442}
4443
b849c413
RS
4444/* Nonzero if we had any X protocol errors since we did x_catch_errors. */
4445
4446int
7a13e894
RS
4447x_had_errors_p (dpy)
4448 Display *dpy;
b849c413
RS
4449{
4450 /* Make sure to catch any errors incurred so far. */
7a13e894 4451 XSync (dpy, False);
b849c413
RS
4452
4453 return x_caught_error_message[0] != 0;
4454}
4455
812361a1
RS
4456/* Stop catching X protocol errors and let them make Emacs die. */
4457
c118dd06 4458void
7a13e894
RS
4459x_uncatch_errors (dpy)
4460 Display *dpy;
c118dd06 4461{
9ac0d9e0 4462 xfree (x_caught_error_message);
cef13e55 4463 x_caught_error_message = 0;
334208b7 4464 XSetErrorHandler (x_error_quitter);
dc6f92b8
JB
4465}
4466
dc6f92b8
JB
4467#if 0
4468static unsigned int x_wire_count;
4469x_trace_wire ()
4470{
4471 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
4472}
c118dd06 4473#endif /* ! 0 */
dc6f92b8
JB
4474
4475\f
f451eb13
JB
4476/* Changing the font of the frame. */
4477
76bcdf39
RS
4478/* Give frame F the font named FONTNAME as its default font, and
4479 return the full name of that font. FONTNAME may be a wildcard
4480 pattern; in that case, we choose some font that fits the pattern.
4481 The return value shows which font we chose. */
4482
b5cf7a0e 4483Lisp_Object
f676886a
JB
4484x_new_font (f, fontname)
4485 struct frame *f;
dc6f92b8
JB
4486 register char *fontname;
4487{
dc6f92b8
JB
4488 int already_loaded;
4489 int n_matching_fonts;
4490 XFontStruct *font_info;
4491 char **font_names;
4492
4493 /* Get a list of all the fonts that match this name. Once we
4494 have a list of matching fonts, we compare them against the fonts
4495 we already have by comparing font ids. */
334208b7 4496 font_names = (char **) XListFonts (FRAME_X_DISPLAY (f), fontname,
2224a5fc 4497 1024, &n_matching_fonts);
0c94f6ee
JB
4498 /* Apparently it doesn't set n_matching_fonts to zero when it can't
4499 find any matches; font_names == 0 is the only clue. */
4500 if (! font_names)
4501 n_matching_fonts = 0;
4502
5835f860
RS
4503 /* Don't just give up if n_matching_fonts is 0.
4504 Apparently there's a bug on Suns: XListFontsWithInfo can
4505 fail to find a font, but XLoadQueryFont may still find it. */
dc6f92b8 4506
90e65f07 4507 /* See if we've already loaded a matching font. */
5835f860
RS
4508 already_loaded = -1;
4509 if (n_matching_fonts != 0)
4510 {
4511 int i, j;
dc6f92b8 4512
7a13e894 4513 for (i = 0; i < FRAME_X_DISPLAY_INFO (f)->n_fonts; i++)
5835f860 4514 for (j = 0; j < n_matching_fonts; j++)
7a13e894
RS
4515 if (!strcmp (FRAME_X_DISPLAY_INFO (f)->font_table[i].name, font_names[j])
4516 || !strcmp (FRAME_X_DISPLAY_INFO (f)->font_table[i].full_name, font_names[j]))
5835f860
RS
4517 {
4518 already_loaded = i;
7a13e894 4519 fontname = FRAME_X_DISPLAY_INFO (f)->font_table[i].full_name;
5835f860
RS
4520 goto found_font;
4521 }
4522 }
dc6f92b8 4523 found_font:
58769bee 4524
dc6f92b8 4525 /* If we have, just return it from the table. */
2224a5fc 4526 if (already_loaded >= 0)
7a13e894 4527 f->display.x->font = FRAME_X_DISPLAY_INFO (f)->font_table[already_loaded].font;
dc6f92b8
JB
4528 /* Otherwise, load the font and add it to the table. */
4529 else
4530 {
9696f58b 4531 int i;
76bcdf39 4532 char *full_name;
dc6f92b8 4533 XFontStruct *font;
7a13e894 4534 int n_fonts;
dc6f92b8 4535
9696f58b 4536 /* Try to find a character-cell font in the list. */
58769bee 4537#if 0
f126bd67 4538 /* A laudable goal, but this isn't how to do it. */
9696f58b
JB
4539 for (i = 0; i < n_matching_fonts; i++)
4540 if (! font_info[i].per_char)
4541 break;
f126bd67
JB
4542#else
4543 i = 0;
4544#endif
9696f58b 4545
5835f860
RS
4546 /* See comment above. */
4547 if (n_matching_fonts != 0)
9696f58b
JB
4548 fontname = font_names[i];
4549
334208b7 4550 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
dc6f92b8 4551 if (! font)
5835f860 4552 {
2224a5fc 4553 /* Free the information from XListFonts. */
5835f860 4554 if (n_matching_fonts)
2224a5fc 4555 XFreeFontNames (font_names);
5835f860
RS
4556 return Qnil;
4557 }
dc6f92b8
JB
4558
4559 /* Do we need to create the table? */
7a13e894 4560 if (FRAME_X_DISPLAY_INFO (f)->font_table_size == 0)
dc6f92b8 4561 {
7a13e894
RS
4562 FRAME_X_DISPLAY_INFO (f)->font_table_size = 16;
4563 FRAME_X_DISPLAY_INFO (f)->font_table
4564 = (struct font_info *) xmalloc (FRAME_X_DISPLAY_INFO (f)->font_table_size
4565 * sizeof (struct font_info));
dc6f92b8
JB
4566 }
4567 /* Do we need to grow the table? */
7a13e894
RS
4568 else if (FRAME_X_DISPLAY_INFO (f)->n_fonts
4569 >= FRAME_X_DISPLAY_INFO (f)->font_table_size)
dc6f92b8 4570 {
7a13e894
RS
4571 FRAME_X_DISPLAY_INFO (f)->font_table_size *= 2;
4572 FRAME_X_DISPLAY_INFO (f)->font_table
4573 = (struct font_info *) xrealloc (FRAME_X_DISPLAY_INFO (f)->font_table,
4574 (FRAME_X_DISPLAY_INFO (f)->font_table_size
4575 * sizeof (struct font_info)));
dc6f92b8
JB
4576 }
4577
76bcdf39
RS
4578 /* Try to get the full name of FONT. Put it in full_name. */
4579 full_name = 0;
4580 for (i = 0; i < font->n_properties; i++)
4581 {
4582 char *atom
334208b7 4583 = XGetAtomName (FRAME_X_DISPLAY (f), font->properties[i].name);
76bcdf39 4584 if (!strcmp (atom, "FONT"))
7965883b 4585 {
334208b7 4586 char *name = XGetAtomName (FRAME_X_DISPLAY (f),
7965883b
RS
4587 (Atom) (font->properties[i].card32));
4588 char *p = name;
4589 int dashes = 0;
4590
4591 /* Count the number of dashes in the "full name".
4592 If it is too few, this isn't really the font's full name,
4593 so don't use it.
4594 In X11R4, the fonts did not come with their canonical names
4595 stored in them. */
4596 while (*p)
4597 {
4598 if (*p == '-')
4599 dashes++;
4600 p++;
4601 }
4602
4603 if (dashes >= 13)
4604 full_name = name;
8ed24d5a
RS
4605
4606 break;
7965883b
RS
4607 }
4608
76bcdf39
RS
4609 XFree (atom);
4610 }
4611
7a13e894
RS
4612 n_fonts = FRAME_X_DISPLAY_INFO (f)->n_fonts;
4613 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name = (char *) xmalloc (strlen (fontname) + 1);
4614 bcopy (fontname, FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name, strlen (fontname) + 1);
76bcdf39 4615 if (full_name != 0)
7a13e894 4616 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].full_name = full_name;
76bcdf39 4617 else
7a13e894
RS
4618 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].full_name = FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name;
4619 f->display.x->font = FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].font = font;
4620 FRAME_X_DISPLAY_INFO (f)->n_fonts++;
76bcdf39 4621
d53067dc
RS
4622 if (full_name)
4623 fontname = full_name;
dc6f92b8 4624 }
2224a5fc 4625
b2cad826
KH
4626 /* Compute the scroll bar width in character columns. */
4627 if (f->scroll_bar_pixel_width > 0)
4628 {
4629 int wid = FONT_WIDTH (f->display.x->font);
4630 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
4631 }
4632 else
4633 f->scroll_bar_cols = 2;
4634
f676886a 4635 /* Now make the frame display the given font. */
c118dd06 4636 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 4637 {
334208b7 4638 XSetFont (FRAME_X_DISPLAY (f), f->display.x->normal_gc,
f676886a 4639 f->display.x->font->fid);
334208b7 4640 XSetFont (FRAME_X_DISPLAY (f), f->display.x->reverse_gc,
f676886a 4641 f->display.x->font->fid);
334208b7 4642 XSetFont (FRAME_X_DISPLAY (f), f->display.x->cursor_gc,
f676886a
JB
4643 f->display.x->font->fid);
4644
a27f9f86 4645 frame_update_line_height (f);
0134a210 4646 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 4647 }
a27f9f86
RS
4648 else
4649 /* If we are setting a new frame's font for the first time,
4650 there are no faces yet, so this font's height is the line height. */
0cdd0c9f 4651 f->display.x->line_height = FONT_HEIGHT (f->display.x->font);
dc6f92b8 4652
b5cf7a0e 4653 {
abdda982 4654 Lisp_Object lispy_name;
b5cf7a0e 4655
abdda982 4656 lispy_name = build_string (fontname);
b5cf7a0e 4657
2224a5fc 4658 /* Free the information from XListFonts. The data
b5cf7a0e 4659 we actually retain comes from XLoadQueryFont. */
2224a5fc 4660 XFreeFontNames (font_names);
b5cf7a0e
JB
4661
4662 return lispy_name;
4663 }
dc6f92b8 4664}
dc6f92b8 4665\f
43bca5d5 4666x_calc_absolute_position (f)
f676886a 4667 struct frame *f;
dc6f92b8 4668{
6dba1858
RS
4669 Window win, child;
4670 int win_x = 0, win_y = 0;
43bca5d5 4671 int flags = f->display.x->size_hint_flags;
6dba1858
RS
4672
4673 /* Find the position of the outside upper-left corner of
4674 the inner window, with respect to the outer window. */
334208b7 4675 if (f->display.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858
RS
4676 {
4677 BLOCK_INPUT;
334208b7 4678 XTranslateCoordinates (FRAME_X_DISPLAY (f),
58769bee 4679
6dba1858
RS
4680 /* From-window, to-window. */
4681 f->display.x->window_desc,
4682 f->display.x->parent_desc,
4683
4684 /* From-position, to-position. */
4685 0, 0, &win_x, &win_y,
4686
4687 /* Child of win. */
4688 &child);
4689 UNBLOCK_INPUT;
4690 }
4691
4692 /* Treat negative positions as relative to the leftmost bottommost
4693 position that fits on the screen. */
20f55f9a 4694 if (flags & XNegative)
334208b7 4695 f->display.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
69388238 4696 - 2 * f->display.x->border_width - win_x
31ea78fd
JB
4697 - PIXEL_WIDTH (f)
4698 + f->display.x->left_pos);
dc6f92b8 4699
20f55f9a 4700 if (flags & YNegative)
334208b7 4701 f->display.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
69388238 4702 - 2 * f->display.x->border_width - win_y
31ea78fd
JB
4703 - PIXEL_HEIGHT (f)
4704 + f->display.x->top_pos);
3a35ab44
RS
4705 /* The left_pos and top_pos
4706 are now relative to the top and left screen edges,
4707 so the flags should correspond. */
4708 f->display.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
4709}
4710
3a35ab44
RS
4711/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
4712 to really change the position, and 0 when calling from
4713 x_make_frame_visible (in that case, XOFF and YOFF are the current
4714 position values). */
4715
dc05a16b 4716x_set_offset (f, xoff, yoff, change_gravity)
f676886a 4717 struct frame *f;
dc6f92b8 4718 register int xoff, yoff;
dc05a16b 4719 int change_gravity;
dc6f92b8 4720{
3a35ab44
RS
4721 if (change_gravity)
4722 {
4723 f->display.x->top_pos = yoff;
4724 f->display.x->left_pos = xoff;
4725 f->display.x->size_hint_flags &= ~ (XNegative | YNegative);
4726 if (xoff < 0)
4727 f->display.x->size_hint_flags |= XNegative;
4728 if (yoff < 0)
4729 f->display.x->size_hint_flags |= YNegative;
4730 f->display.x->win_gravity = NorthWestGravity;
4731 }
43bca5d5 4732 x_calc_absolute_position (f);
dc6f92b8
JB
4733
4734 BLOCK_INPUT;
3a35ab44
RS
4735 x_wm_set_size_hint (f, 0, 0);
4736
3afe33e7 4737#ifdef USE_X_TOOLKIT
334208b7 4738 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget),
3afe33e7
RS
4739 f->display.x->left_pos, f->display.x->top_pos);
4740#else /* not USE_X_TOOLKIT */
334208b7 4741 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f676886a 4742 f->display.x->left_pos, f->display.x->top_pos);
3afe33e7 4743#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
4744 UNBLOCK_INPUT;
4745}
4746
bc20ebbf
FP
4747/* Call this to change the size of frame F's x-window.
4748 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
4749 for this size change and subsequent size changes.
4750 Otherwise we leave the window gravity unchanged. */
dc6f92b8 4751
bc20ebbf 4752x_set_window_size (f, change_gravity, cols, rows)
f676886a 4753 struct frame *f;
bc20ebbf 4754 int change_gravity;
b1c884c3 4755 int cols, rows;
dc6f92b8
JB
4756{
4757 int pixelwidth, pixelheight;
4758 int mask;
dc6f92b8 4759
80fd1fe2
FP
4760#ifdef USE_X_TOOLKIT
4761 BLOCK_INPUT;
3a20653d
RS
4762 {
4763 /* The x and y position of the widget is clobbered by the
4764 call to XtSetValues within EmacsFrameSetCharSize.
4765 This is a real kludge, but I don't understand Xt so I can't
4766 figure out a correct fix. Can anyone else tell me? -- rms. */
4767 int xpos = f->display.x->widget->core.x;
4768 int ypos = f->display.x->widget->core.y;
4769 EmacsFrameSetCharSize (f->display.x->edit_widget, cols, rows);
4770 f->display.x->widget->core.x = xpos;
4771 f->display.x->widget->core.y = ypos;
4772 }
80fd1fe2
FP
4773 UNBLOCK_INPUT;
4774
4775#else /* not USE_X_TOOLKIT */
4776
dc6f92b8
JB
4777 BLOCK_INPUT;
4778
b1c884c3 4779 check_frame_size (f, &rows, &cols);
6dba1858 4780 f->display.x->vertical_scroll_bar_extra
b2cad826
KH
4781 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4782 ? 0
4783 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 4784 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
b2cad826 4785 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->display.x->font)));
f451eb13
JB
4786 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
4787 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 4788
af31d76f
RS
4789 f->display.x->win_gravity = NorthWestGravity;
4790 x_wm_set_size_hint (f, 0, 0);
6ccf47d1 4791
334208b7
RS
4792 XSync (FRAME_X_DISPLAY (f), False);
4793 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4794 pixelwidth, pixelheight);
b1c884c3
JB
4795
4796 /* Now, strictly speaking, we can't be sure that this is accurate,
4797 but the window manager will get around to dealing with the size
4798 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
4799 ConfigureNotify event gets here.
4800
4801 We could just not bother storing any of this information here,
4802 and let the ConfigureNotify event set everything up, but that
4803 might be kind of confusing to the lisp code, since size changes
4804 wouldn't be reported in the frame parameters until some random
4805 point in the future when the ConfigureNotify event arrives. */
8922af5f 4806 change_frame_size (f, rows, cols, 0, 0);
b1c884c3
JB
4807 PIXEL_WIDTH (f) = pixelwidth;
4808 PIXEL_HEIGHT (f) = pixelheight;
4809
4d73d038
RS
4810 /* If cursor was outside the new size, mark it as off. */
4811 if (f->phys_cursor_y >= rows
4812 || f->phys_cursor_x >= cols)
4813 {
4814 f->phys_cursor_x = -1;
4815 f->phys_cursor_y = -1;
4816 }
4817
dbc4e1c1
JB
4818 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
4819 receive in the ConfigureNotify event; if we get what we asked
4820 for, then the event won't cause the screen to become garbaged, so
4821 we have to make sure to do it here. */
4822 SET_FRAME_GARBAGED (f);
4823
334208b7 4824 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 4825 UNBLOCK_INPUT;
80fd1fe2 4826#endif /* not USE_X_TOOLKIT */
dc6f92b8 4827}
dc6f92b8 4828\f
f451eb13 4829/* Mouse warping, focus shifting, raising and lowering. */
dc6f92b8 4830
9b378208 4831void
f676886a
JB
4832x_set_mouse_position (f, x, y)
4833 struct frame *f;
dc6f92b8
JB
4834 int x, y;
4835{
4836 int pix_x, pix_y;
4837
12ba150f 4838 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2;
a27f9f86 4839 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->display.x->line_height / 2;
f451eb13
JB
4840
4841 if (pix_x < 0) pix_x = 0;
4842 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
4843
4844 if (pix_y < 0) pix_y = 0;
4845 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
4846
4847 BLOCK_INPUT;
dc6f92b8 4848
334208b7
RS
4849 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
4850 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
4851 UNBLOCK_INPUT;
4852}
4853
9b378208
RS
4854/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
4855
4856void
4857x_set_mouse_pixel_position (f, pix_x, pix_y)
4858 struct frame *f;
4859 int pix_x, pix_y;
4860{
4861 BLOCK_INPUT;
4862
334208b7
RS
4863 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
4864 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
4865 UNBLOCK_INPUT;
4866}
4867
f676886a
JB
4868x_focus_on_frame (f)
4869 struct frame *f;
dc6f92b8 4870{
1fb20991 4871#if 0 /* This proves to be unpleasant. */
f676886a 4872 x_raise_frame (f);
1fb20991 4873#endif
6d4238f3
JB
4874#if 0
4875 /* I don't think that the ICCCM allows programs to do things like this
4876 without the interaction of the window manager. Whatever you end up
f676886a 4877 doing with this code, do it to x_unfocus_frame too. */
334208b7 4878 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 4879 RevertToPointerRoot, CurrentTime);
c118dd06 4880#endif /* ! 0 */
dc6f92b8
JB
4881}
4882
f676886a
JB
4883x_unfocus_frame (f)
4884 struct frame *f;
dc6f92b8 4885{
6d4238f3 4886#if 0
f676886a
JB
4887 /* Look at the remarks in x_focus_on_frame. */
4888 if (x_focus_frame == f)
334208b7 4889 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 4890 RevertToPointerRoot, CurrentTime);
c118dd06 4891#endif /* ! 0 */
dc6f92b8
JB
4892}
4893
f676886a 4894/* Raise frame F. */
dc6f92b8 4895
f676886a
JB
4896x_raise_frame (f)
4897 struct frame *f;
dc6f92b8 4898{
3a88c238 4899 if (f->async_visible)
dc6f92b8
JB
4900 {
4901 BLOCK_INPUT;
3afe33e7 4902#ifdef USE_X_TOOLKIT
334208b7 4903 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget));
3afe33e7 4904#else /* not USE_X_TOOLKIT */
334208b7 4905 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 4906#endif /* not USE_X_TOOLKIT */
334208b7 4907 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
4908 UNBLOCK_INPUT;
4909 }
4910}
4911
f676886a 4912/* Lower frame F. */
dc6f92b8 4913
f676886a
JB
4914x_lower_frame (f)
4915 struct frame *f;
dc6f92b8 4916{
3a88c238 4917 if (f->async_visible)
dc6f92b8
JB
4918 {
4919 BLOCK_INPUT;
3afe33e7 4920#ifdef USE_X_TOOLKIT
334208b7 4921 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget));
3afe33e7 4922#else /* not USE_X_TOOLKIT */
334208b7 4923 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 4924#endif /* not USE_X_TOOLKIT */
334208b7 4925 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
4926 UNBLOCK_INPUT;
4927 }
4928}
4929
dbc4e1c1
JB
4930static void
4931XTframe_raise_lower (f, raise)
4932 FRAME_PTR f;
4933 int raise;
4934{
4935 if (raise)
4936 x_raise_frame (f);
4937 else
4938 x_lower_frame (f);
4939}
4940
fd13dbb2
RS
4941/* Change from withdrawn state to mapped state,
4942 or deiconify. */
dc6f92b8 4943
f676886a
JB
4944x_make_frame_visible (f)
4945 struct frame *f;
dc6f92b8
JB
4946{
4947 int mask;
990ba854 4948 Lisp_Object type;
dc6f92b8 4949
dc6f92b8 4950 BLOCK_INPUT;
dc6f92b8 4951
990ba854
RS
4952 type = x_icon_type (f);
4953 if (!NILP (type))
4954 x_bitmap_icon (f, type);
bdcd49ba 4955
f676886a 4956 if (! FRAME_VISIBLE_P (f))
90e65f07 4957 {
af31d76f 4958#ifndef USE_X_TOOLKIT
fd13dbb2
RS
4959 if (! FRAME_ICONIFIED_P (f))
4960 x_set_offset (f, f->display.x->left_pos, f->display.x->top_pos, 0);
af31d76f 4961#endif
dc05a16b 4962
90e65f07 4963 if (! EQ (Vx_no_window_manager, Qt))
f676886a 4964 x_wm_set_window_state (f, NormalState);
3afe33e7 4965#ifdef USE_X_TOOLKIT
d7a38a2e
RS
4966 /* This was XtPopup, but that did nothing for an iconified frame. */
4967 XtMapWidget (f->display.x->widget);
3afe33e7 4968#else /* not USE_X_TOOLKIT */
7f9c7f94 4969 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 4970#endif /* not USE_X_TOOLKIT */
0134a210
RS
4971#if 0 /* This seems to bring back scroll bars in the wrong places
4972 if the window configuration has changed. They seem
4973 to come back ok without this. */
ab648270 4974 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 4975 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 4976#endif
90e65f07 4977 }
dc6f92b8 4978
334208b7 4979 XFlush (FRAME_X_DISPLAY (f));
90e65f07 4980
0dacf791
RS
4981 /* Synchronize to ensure Emacs knows the frame is visible
4982 before we do anything else. We do this loop with input not blocked
4983 so that incoming events are handled. */
4984 {
4985 Lisp_Object frame;
c0a04927
RS
4986 int count = input_signal_count;
4987
4988 /* This must come after we set COUNT. */
4989 UNBLOCK_INPUT;
4990
e0c1aef2 4991 XSETFRAME (frame, f);
c0a04927
RS
4992
4993 while (1)
2a6cf806 4994 {
334208b7 4995 x_sync (f);
c0a04927
RS
4996 /* Once we have handled input events,
4997 we should have received the MapNotify if one is coming.
4998 So if we have not got it yet, stop looping.
4999 Some window managers make their own decisions
5000 about visibility. */
5001 if (input_signal_count != count)
5002 break;
c12a7cbd 5003 /* Machines that do polling rather than SIGIO have been observed
23cf7c60
KH
5004 to go into a busy-wait here. So we'll fake an alarm signal
5005 to let the handler know that there's something to be read.
5006 We used to raise a real alarm, but it seems that the handler
5007 isn't always enabled here. This is probably a bug. */
8b2f8d4e 5008 if (input_polling_used ())
3b2fa4e6
RS
5009 {
5010 /* It could be confusing if a real alarm arrives while processing
5011 the fake one. Turn it off and let the handler reset it. */
5012 alarm (0);
5013 input_poll_signal ();
5014 }
c0a04927
RS
5015 /* Once we have handled input events,
5016 we should have received the MapNotify if one is coming.
5017 So if we have not got it yet, stop looping.
5018 Some window managers make their own decisions
5019 about visibility. */
5020 if (input_signal_count != count)
5021 break;
2a6cf806 5022 }
0dacf791
RS
5023 FRAME_SAMPLE_VISIBILITY (f);
5024 }
dc6f92b8
JB
5025}
5026
5027/* Change from mapped state to withdrawn state. */
5028
f676886a
JB
5029x_make_frame_invisible (f)
5030 struct frame *f;
dc6f92b8
JB
5031{
5032 int mask;
546e6d5b
RS
5033 Window window;
5034
5035#ifdef USE_X_TOOLKIT
5036 /* Use the frame's outermost window, not the one we normally draw on. */
5037 window = XtWindow (f->display.x->widget);
5038#else /* not USE_X_TOOLKIT */
5039 window = FRAME_X_WINDOW (f);
5040#endif /* not USE_X_TOOLKIT */
dc6f92b8 5041
9319ae23
RS
5042 /* Don't keep the highlight on an invisible frame. */
5043 if (x_highlight_frame == f)
5044 x_highlight_frame = 0;
5045
5627c40e 5046#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 5047 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 5048 return;
5627c40e 5049#endif
dc6f92b8
JB
5050
5051 BLOCK_INPUT;
c118dd06 5052
af31d76f
RS
5053 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
5054 that the current position of the window is user-specified, rather than
5055 program-specified, so that when the window is mapped again, it will be
5056 placed at the same location, without forcing the user to position it
5057 by hand again (they have already done that once for this window.) */
5058 x_wm_set_size_hint (f, 0, 1);
5059
c118dd06
JB
5060#ifdef HAVE_X11R4
5061
334208b7
RS
5062 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
5063 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
5064 {
5065 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 5066 error ("Can't notify window manager of window withdrawal");
c118dd06 5067 }
c118dd06 5068#else /* ! defined (HAVE_X11R4) */
16bd92ea 5069
c118dd06 5070 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
5071 if (! EQ (Vx_no_window_manager, Qt))
5072 {
16bd92ea 5073 XEvent unmap;
dc6f92b8 5074
16bd92ea 5075 unmap.xunmap.type = UnmapNotify;
546e6d5b 5076 unmap.xunmap.window = window;
334208b7 5077 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 5078 unmap.xunmap.from_configure = False;
334208b7
RS
5079 if (! XSendEvent (FRAME_X_DISPLAY (f),
5080 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
5081 False,
5082 SubstructureRedirectMask|SubstructureNotifyMask,
5083 &unmap))
5084 {
5085 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 5086 error ("Can't notify window manager of withdrawal");
16bd92ea 5087 }
dc6f92b8
JB
5088 }
5089
16bd92ea 5090 /* Unmap the window ourselves. Cheeky! */
334208b7 5091 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 5092#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 5093
5627c40e
RS
5094 /* We can't distinguish this from iconification
5095 just by the event that we get from the server.
5096 So we can't win using the usual strategy of letting
5097 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
5098 and synchronize with the server to make sure we agree. */
5099 f->visible = 0;
5100 FRAME_ICONIFIED_P (f) = 0;
5101 f->async_visible = 0;
5102 f->async_iconified = 0;
5103
334208b7 5104 x_sync (f);
5627c40e 5105
dc6f92b8
JB
5106 UNBLOCK_INPUT;
5107}
5108
dc6f92b8
JB
5109/* Change window state from mapped to iconified. */
5110
f676886a
JB
5111x_iconify_frame (f)
5112 struct frame *f;
dc6f92b8
JB
5113{
5114 int mask;
3afe33e7 5115 int result;
990ba854 5116 Lisp_Object type;
dc6f92b8 5117
9319ae23
RS
5118 /* Don't keep the highlight on an invisible frame. */
5119 if (x_highlight_frame == f)
5120 x_highlight_frame = 0;
5121
3a88c238 5122 if (f->async_iconified)
dc6f92b8
JB
5123 return;
5124
3afe33e7 5125 BLOCK_INPUT;
546e6d5b 5126
990ba854
RS
5127 type = x_icon_type (f);
5128 if (!NILP (type))
5129 x_bitmap_icon (f, type);
bdcd49ba
RS
5130
5131#ifdef USE_X_TOOLKIT
5132
546e6d5b
RS
5133 if (! FRAME_VISIBLE_P (f))
5134 {
5135 if (! EQ (Vx_no_window_manager, Qt))
5136 x_wm_set_window_state (f, IconicState);
5137 /* This was XtPopup, but that did nothing for an iconified frame. */
5138 XtMapWidget (f->display.x->widget);
5139 UNBLOCK_INPUT;
5140 return;
5141 }
5142
334208b7 5143 result = XIconifyWindow (FRAME_X_DISPLAY (f),
bc20ebbf 5144 XtWindow (f->display.x->widget),
334208b7 5145 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
5146 UNBLOCK_INPUT;
5147
5148 if (!result)
546e6d5b 5149 error ("Can't notify window manager of iconification");
3afe33e7
RS
5150
5151 f->async_iconified = 1;
8c002a25
KH
5152
5153 BLOCK_INPUT;
334208b7 5154 XFlush (FRAME_X_DISPLAY (f));
8c002a25 5155 UNBLOCK_INPUT;
3afe33e7
RS
5156#else /* not USE_X_TOOLKIT */
5157
fd13dbb2
RS
5158 /* Make sure the X server knows where the window should be positioned,
5159 in case the user deiconifies with the window manager. */
5160 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
5161 x_set_offset (f, f->display.x->left_pos, f->display.x->top_pos, 0);
5162
16bd92ea
JB
5163 /* Since we don't know which revision of X we're running, we'll use both
5164 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
5165
5166 /* X11R4: send a ClientMessage to the window manager using the
5167 WM_CHANGE_STATE type. */
5168 {
5169 XEvent message;
58769bee 5170
c118dd06 5171 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 5172 message.xclient.type = ClientMessage;
334208b7 5173 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
5174 message.xclient.format = 32;
5175 message.xclient.data.l[0] = IconicState;
5176
334208b7
RS
5177 if (! XSendEvent (FRAME_X_DISPLAY (f),
5178 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
5179 False,
5180 SubstructureRedirectMask | SubstructureNotifyMask,
5181 &message))
dc6f92b8
JB
5182 {
5183 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 5184 error ("Can't notify window manager of iconification");
dc6f92b8 5185 }
16bd92ea 5186 }
dc6f92b8 5187
58769bee 5188 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
5189 IconicState. */
5190 x_wm_set_window_state (f, IconicState);
dc6f92b8 5191
a9c00105
RS
5192 if (!FRAME_VISIBLE_P (f))
5193 {
5194 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 5195 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
5196 }
5197
3a88c238 5198 f->async_iconified = 1;
dc6f92b8 5199
334208b7 5200 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 5201 UNBLOCK_INPUT;
8c002a25 5202#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5203}
5204
c0ff3fab 5205/* Destroy the X window of frame F. */
dc6f92b8 5206
c0ff3fab 5207x_destroy_window (f)
f676886a 5208 struct frame *f;
dc6f92b8 5209{
7f9c7f94
RS
5210 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5211
dc6f92b8 5212 BLOCK_INPUT;
c0ff3fab
JB
5213
5214 if (f->display.x->icon_desc != 0)
334208b7
RS
5215 XDestroyWindow (FRAME_X_DISPLAY (f), f->display.x->icon_desc);
5216 XDestroyWindow (FRAME_X_DISPLAY (f), f->display.x->window_desc);
3afe33e7
RS
5217#ifdef USE_X_TOOLKIT
5218 XtDestroyWidget (f->display.x->widget);
9d7e2e3e 5219 free_frame_menubar (f);
3afe33e7
RS
5220#endif /* USE_X_TOOLKIT */
5221
07e34cb0 5222 free_frame_faces (f);
334208b7 5223 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 5224
9ac0d9e0 5225 xfree (f->display.x);
c0ff3fab 5226 f->display.x = 0;
f676886a
JB
5227 if (f == x_focus_frame)
5228 x_focus_frame = 0;
5229 if (f == x_highlight_frame)
5230 x_highlight_frame = 0;
c0ff3fab 5231
7f9c7f94
RS
5232 dpyinfo->reference_count--;
5233
5234 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 5235 {
7f9c7f94
RS
5236 dpyinfo->mouse_face_beg_row
5237 = dpyinfo->mouse_face_beg_col = -1;
5238 dpyinfo->mouse_face_end_row
5239 = dpyinfo->mouse_face_end_col = -1;
5240 dpyinfo->mouse_face_window = Qnil;
dc05a16b 5241 }
0134a210 5242
c0ff3fab 5243 UNBLOCK_INPUT;
dc6f92b8
JB
5244}
5245\f
f451eb13
JB
5246/* Setting window manager hints. */
5247
af31d76f
RS
5248/* Set the normal size hints for the window manager, for frame F.
5249 FLAGS is the flags word to use--or 0 meaning preserve the flags
5250 that the window now has.
5251 If USER_POSITION is nonzero, we set the USPosition
5252 flag (this is useful when FLAGS is 0). */
6dba1858 5253
af31d76f 5254x_wm_set_size_hint (f, flags, user_position)
f676886a 5255 struct frame *f;
af31d76f
RS
5256 long flags;
5257 int user_position;
dc6f92b8
JB
5258{
5259 XSizeHints size_hints;
3afe33e7
RS
5260
5261#ifdef USE_X_TOOLKIT
7e4f2521
FP
5262 Arg al[2];
5263 int ac = 0;
5264 Dimension widget_width, widget_height;
bc20ebbf 5265 Window window = XtWindow (f->display.x->widget);
3afe33e7 5266#else /* not USE_X_TOOLKIT */
c118dd06 5267 Window window = FRAME_X_WINDOW (f);
3afe33e7 5268#endif /* not USE_X_TOOLKIT */
dc6f92b8 5269
b72a58fd
RS
5270 /* Setting PMaxSize caused various problems. */
5271 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 5272
f676886a
JB
5273 flexlines = f->height;
5274
5275 size_hints.x = f->display.x->left_pos;
5276 size_hints.y = f->display.x->top_pos;
7553a6b7 5277
7e4f2521
FP
5278#ifdef USE_X_TOOLKIT
5279 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
5280 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
5281 XtGetValues (f->display.x->column_widget, al, ac);
5282 size_hints.height = widget_height;
5283 size_hints.width = widget_width;
5284#else /* not USE_X_TOOLKIT */
f676886a
JB
5285 size_hints.height = PIXEL_HEIGHT (f);
5286 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 5287#endif /* not USE_X_TOOLKIT */
7553a6b7 5288
f676886a 5289 size_hints.width_inc = FONT_WIDTH (f->display.x->font);
a27f9f86 5290 size_hints.height_inc = f->display.x->line_height;
334208b7
RS
5291 size_hints.max_width
5292 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
5293 size_hints.max_height
5294 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 5295
b1c884c3 5296 {
b0342f17 5297 int base_width, base_height;
0134a210 5298 int min_rows = 0, min_cols = 0;
b0342f17 5299
f451eb13
JB
5300 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
5301 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 5302
0134a210 5303 check_frame_size (f, &min_rows, &min_cols);
b0342f17 5304
0134a210
RS
5305 /* The window manager uses the base width hints to calculate the
5306 current number of rows and columns in the frame while
5307 resizing; min_width and min_height aren't useful for this
5308 purpose, since they might not give the dimensions for a
5309 zero-row, zero-column frame.
58769bee 5310
0134a210
RS
5311 We use the base_width and base_height members if we have
5312 them; otherwise, we set the min_width and min_height members
5313 to the size for a zero x zero frame. */
b0342f17
JB
5314
5315#ifdef HAVE_X11R4
0134a210
RS
5316 size_hints.flags |= PBaseSize;
5317 size_hints.base_width = base_width;
5318 size_hints.base_height = base_height;
5319 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
5320 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 5321#else
0134a210
RS
5322 size_hints.min_width = base_width;
5323 size_hints.min_height = base_height;
b0342f17 5324#endif
b1c884c3 5325 }
dc6f92b8 5326
af31d76f
RS
5327 if (flags)
5328 size_hints.flags |= flags;
dc6f92b8
JB
5329 else
5330 {
5331 XSizeHints hints; /* Sometimes I hate X Windows... */
af31d76f
RS
5332 long supplied_return;
5333 int value;
5334
5335#ifdef HAVE_X11R4
334208b7 5336 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
af31d76f
RS
5337 &supplied_return);
5338#else
334208b7 5339 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 5340#endif
58769bee 5341
af31d76f 5342 if (value == 0)
82ee0df4 5343 hints.flags = 0;
dc6f92b8
JB
5344 if (hints.flags & PSize)
5345 size_hints.flags |= PSize;
5346 if (hints.flags & PPosition)
5347 size_hints.flags |= PPosition;
5348 if (hints.flags & USPosition)
5349 size_hints.flags |= USPosition;
5350 if (hints.flags & USSize)
5351 size_hints.flags |= USSize;
5352 }
0134a210 5353
af31d76f 5354#ifdef PWinGravity
dc05a16b 5355 size_hints.win_gravity = f->display.x->win_gravity;
af31d76f 5356 size_hints.flags |= PWinGravity;
dc05a16b 5357
af31d76f 5358 if (user_position)
6dba1858 5359 {
af31d76f
RS
5360 size_hints.flags &= ~ PPosition;
5361 size_hints.flags |= USPosition;
6dba1858 5362 }
2554751d 5363#endif /* PWinGravity */
6dba1858 5364
b0342f17 5365#ifdef HAVE_X11R4
334208b7 5366 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 5367#else
334208b7 5368 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 5369#endif
dc6f92b8
JB
5370}
5371
5372/* Used for IconicState or NormalState */
f676886a
JB
5373x_wm_set_window_state (f, state)
5374 struct frame *f;
dc6f92b8
JB
5375 int state;
5376{
3afe33e7 5377#ifdef USE_X_TOOLKIT
546e6d5b
RS
5378 Arg al[1];
5379
5380 XtSetArg (al[0], XtNinitialState, state);
5381 XtSetValues (f->display.x->widget, al, 1);
3afe33e7 5382#else /* not USE_X_TOOLKIT */
c118dd06 5383 Window window = FRAME_X_WINDOW (f);
dc6f92b8 5384
16bd92ea
JB
5385 f->display.x->wm_hints.flags |= StateHint;
5386 f->display.x->wm_hints.initial_state = state;
b1c884c3 5387
334208b7 5388 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
546e6d5b 5389#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5390}
5391
7f2ae036 5392x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 5393 struct frame *f;
7f2ae036 5394 int pixmap_id;
dc6f92b8 5395{
75231bad
RS
5396#ifdef USE_X_TOOLKIT
5397 Window window = XtWindow (f->display.x->widget);
5398#else
c118dd06 5399 Window window = FRAME_X_WINDOW (f);
75231bad 5400#endif
dc6f92b8 5401
7f2ae036 5402 if (pixmap_id > 0)
dbc4e1c1 5403 {
7a13e894 5404 Pixmap icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
dbc4e1c1
JB
5405 f->display.x->wm_hints.icon_pixmap = icon_pixmap;
5406 f->display.x->wm_hints.flags |= IconPixmapHint;
5407 }
5408 else
7f2ae036
RS
5409 {
5410 f->display.x->wm_hints.icon_pixmap = None;
5411 f->display.x->wm_hints.flags &= ~IconPixmapHint;
5412 }
b1c884c3 5413
334208b7 5414 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
dc6f92b8
JB
5415}
5416
f676886a
JB
5417x_wm_set_icon_position (f, icon_x, icon_y)
5418 struct frame *f;
dc6f92b8
JB
5419 int icon_x, icon_y;
5420{
75231bad
RS
5421#ifdef USE_X_TOOLKIT
5422 Window window = XtWindow (f->display.x->widget);
5423#else
c118dd06 5424 Window window = FRAME_X_WINDOW (f);
75231bad 5425#endif
dc6f92b8 5426
16bd92ea
JB
5427 f->display.x->wm_hints.flags |= IconPositionHint;
5428 f->display.x->wm_hints.icon_x = icon_x;
5429 f->display.x->wm_hints.icon_y = icon_y;
b1c884c3 5430
334208b7 5431 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
dc6f92b8
JB
5432}
5433
5434\f
f451eb13
JB
5435/* Initialization. */
5436
3afe33e7
RS
5437#ifdef USE_X_TOOLKIT
5438static XrmOptionDescRec emacs_options[] = {
5439 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
5440 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
5441
5442 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
5443 XrmoptionSepArg, NULL},
5444 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
5445
5446 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5447 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5448 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5449 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5450 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5451 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
5452 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
5453};
5454#endif /* USE_X_TOOLKIT */
5455
7a13e894
RS
5456static int x_initialized;
5457
334208b7 5458struct x_display_info *
1f8255f2 5459x_term_init (display_name, xrm_option, resource_name)
334208b7 5460 Lisp_Object display_name;
1f8255f2
RS
5461 char *xrm_option;
5462 char *resource_name;
dc6f92b8 5463{
f676886a 5464 Lisp_Object frame;
dc6f92b8 5465 char *defaultvalue;
334208b7 5466 int connection;
7a13e894 5467 Display *dpy;
334208b7
RS
5468 struct x_display_info *dpyinfo;
5469 XrmDatabase xrdb;
5470
7a13e894
RS
5471 if (!x_initialized)
5472 {
5473 x_initialize ();
5474 x_initialized = 1;
5475 }
dc6f92b8 5476
3afe33e7 5477#ifdef USE_X_TOOLKIT
bdcd49ba
RS
5478#ifdef HAVE_X11R5
5479 XtSetLanguageProc (NULL, NULL, NULL);
5480#endif
5481
7f9c7f94
RS
5482 {
5483 int argc = 0;
5484 char *argv[3];
5485
5486 argv[0] = "";
5487 argc = 1;
5488 if (xrm_option)
5489 {
5490 argv[argc++] = "-xrm";
5491 argv[argc++] = xrm_option;
5492 }
5493 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
5494 resource_name, EMACS_CLASS,
5495 emacs_options, XtNumber (emacs_options),
5496 &argc, argv);
5497 }
3afe33e7
RS
5498
5499#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
5500#ifdef HAVE_X11R5
5501 XSetLocaleModifiers ("");
5502#endif
7a13e894 5503 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 5504#endif /* not USE_X_TOOLKIT */
334208b7 5505
7a13e894
RS
5506 /* Detect failure. */
5507 if (dpy == 0)
5508 return 0;
5509
5510 /* We have definitely succeeded. Record the new connection. */
5511
5512 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
5513
5514 /* Put this display on the chain. */
5515 dpyinfo->next = x_display_list;
5516 x_display_list = dpyinfo;
5517
5518 /* Put it on x_display_name_list as well, to keep them parallel. */
5519 x_display_name_list = Fcons (Fcons (display_name, Qnil),
5520 x_display_name_list);
5521 dpyinfo->name_list_element = XCONS (x_display_name_list)->car;
5522
5523 dpyinfo->display = dpy;
dc6f92b8 5524
dc6f92b8 5525#if 0
7a13e894 5526 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 5527#endif /* ! 0 */
7a13e894
RS
5528
5529 dpyinfo->x_id_name
5530 = (char *) xmalloc (XSTRING (Vinvocation_name)->size
5531 + XSTRING (Vsystem_name)->size
5532 + 2);
5533 sprintf (dpyinfo->x_id_name, "%s@%s",
5534 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
5535
5536 /* Figure out which modifier bits mean what. */
334208b7 5537 x_find_modifier_meanings (dpyinfo);
f451eb13 5538
ab648270 5539 /* Get the scroll bar cursor. */
7a13e894 5540 dpyinfo->vertical_scroll_bar_cursor
334208b7 5541 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 5542
334208b7
RS
5543 xrdb = x_load_resources (dpyinfo->display, xrm_option,
5544 resource_name, EMACS_CLASS);
5545#ifdef HAVE_XRMSETDATABASE
5546 XrmSetDatabase (dpyinfo->display, xrdb);
5547#else
5548 dpyinfo->display->db = xrdb;
5549#endif
7a13e894
RS
5550 /* Put thr rdb where we can find it in a way that works on
5551 all versions. */
5552 dpyinfo->xrdb = xrdb;
334208b7
RS
5553
5554 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
5555 DefaultScreen (dpyinfo->display));
5556 dpyinfo->visual = select_visual (dpyinfo->display, dpyinfo->screen,
5557 &dpyinfo->n_planes);
5558 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
5559 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
5560 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
5561 dpyinfo->grabbed = 0;
5562 dpyinfo->reference_count = 0;
5563 dpyinfo->icon_bitmap_id = -1;
7a13e894
RS
5564 dpyinfo->n_fonts = 0;
5565 dpyinfo->font_table_size = 0;
5566 dpyinfo->bitmaps = 0;
5567 dpyinfo->bitmaps_size = 0;
5568 dpyinfo->bitmaps_last = 0;
5569 dpyinfo->scratch_cursor_gc = 0;
5570 dpyinfo->mouse_face_mouse_frame = 0;
5571 dpyinfo->mouse_face_deferred_gc = 0;
5572 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
5573 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
5574 dpyinfo->mouse_face_face_id = 0;
5575 dpyinfo->mouse_face_window = Qnil;
5576 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
5577 dpyinfo->mouse_face_defer = 0;
334208b7
RS
5578
5579 dpyinfo->Xatom_wm_protocols
5580 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
5581 dpyinfo->Xatom_wm_take_focus
5582 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
5583 dpyinfo->Xatom_wm_save_yourself
5584 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
5585 dpyinfo->Xatom_wm_delete_window
5586 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
5587 dpyinfo->Xatom_wm_change_state
5588 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
5589 dpyinfo->Xatom_wm_configure_denied
5590 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
5591 dpyinfo->Xatom_wm_window_moved
5592 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
5593 dpyinfo->Xatom_editres
5594 = XInternAtom (dpyinfo->display, "Editres", False);
5595 dpyinfo->Xatom_CLIPBOARD
5596 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
5597 dpyinfo->Xatom_TIMESTAMP
5598 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
5599 dpyinfo->Xatom_TEXT
5600 = XInternAtom (dpyinfo->display, "TEXT", False);
5601 dpyinfo->Xatom_DELETE
5602 = XInternAtom (dpyinfo->display, "DELETE", False);
5603 dpyinfo->Xatom_MULTIPLE
5604 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
5605 dpyinfo->Xatom_INCR
5606 = XInternAtom (dpyinfo->display, "INCR", False);
5607 dpyinfo->Xatom_EMACS_TMP
5608 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
5609 dpyinfo->Xatom_TARGETS
5610 = XInternAtom (dpyinfo->display, "TARGETS", False);
5611 dpyinfo->Xatom_NULL
5612 = XInternAtom (dpyinfo->display, "NULL", False);
5613 dpyinfo->Xatom_ATOM_PAIR
5614 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
5615
5616 connection = ConnectionNumber (dpyinfo->display);
5617 dpyinfo->connection = connection;
5618
87485d6f
MW
5619#ifdef subprocesses
5620 /* This is only needed for distinguishing keyboard and process input. */
334208b7 5621 if (connection != 0)
7a13e894 5622 add_keyboard_wait_descriptor (connection);
87485d6f 5623#endif
6d4238f3 5624
041b69ac 5625#ifndef F_SETOWN_BUG
dc6f92b8 5626#ifdef F_SETOWN
dc6f92b8 5627#ifdef F_SETOWN_SOCK_NEG
61c3ce62 5628 /* stdin is a socket here */
334208b7 5629 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 5630#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 5631 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
5632#endif /* ! defined (F_SETOWN_SOCK_NEG) */
5633#endif /* ! defined (F_SETOWN) */
041b69ac 5634#endif /* F_SETOWN_BUG */
dc6f92b8
JB
5635
5636#ifdef SIGIO
7a13e894 5637 init_sigio (connection);
c118dd06 5638#endif /* ! defined (SIGIO) */
dc6f92b8 5639
7a13e894
RS
5640 return dpyinfo;
5641}
5642\f
5643/* Get rid of display DPYINFO, assuming all frames are already gone,
5644 and without sending any more commands to the X server. */
dc6f92b8 5645
7a13e894
RS
5646void
5647x_delete_display (dpyinfo)
5648 struct x_display_info *dpyinfo;
5649{
5650 delete_keyboard_wait_descriptor (dpyinfo->connection);
5651
5652 /* Discard this display from x_display_name_list and x_display_list.
5653 We can't use Fdelq because that can quit. */
5654 if (! NILP (x_display_name_list)
5655 && EQ (XCONS (x_display_name_list)->car, dpyinfo->name_list_element))
5656 x_display_name_list = XCONS (x_display_name_list)->cdr;
5657 else
5658 {
5659 Lisp_Object tail;
5660
5661 tail = x_display_name_list;
5662 while (CONSP (tail) && CONSP (XCONS (tail)->cdr))
5663 {
5664 if (EQ (XCONS (XCONS (tail)->cdr)->car,
5665 dpyinfo->name_list_element))
5666 {
5667 XCONS (tail)->cdr = XCONS (XCONS (tail)->cdr)->cdr;
5668 break;
5669 }
5670 tail = XCONS (tail)->cdr;
5671 }
5672 }
5673
5674 if (x_display_list == dpyinfo)
5675 x_display_list = dpyinfo->next;
7f9c7f94
RS
5676 else
5677 {
5678 struct x_display_info *tail;
7a13e894 5679
7f9c7f94
RS
5680 for (tail = x_display_list; tail; tail = tail->next)
5681 if (tail->next == dpyinfo)
5682 tail->next = tail->next->next;
5683 }
7a13e894 5684
7f9c7f94
RS
5685#ifndef USE_X_TOOLKIT
5686 /* I'm told Xt does this itself. */
5687 XrmDestroyDatabase (dpyinfo->xrdb);
5688#endif
7a13e894
RS
5689 free (dpyinfo->font_table);
5690 free (dpyinfo->x_id_name);
5691 free (dpyinfo);
5692}
5693\f
5694/* Set up use of X before we make the first connection. */
5695
5696x_initialize ()
5697{
f676886a 5698 clear_frame_hook = XTclear_frame;
dc6f92b8
JB
5699 clear_end_of_line_hook = XTclear_end_of_line;
5700 ins_del_lines_hook = XTins_del_lines;
5701 change_line_highlight_hook = XTchange_line_highlight;
5702 insert_glyphs_hook = XTinsert_glyphs;
5703 write_glyphs_hook = XTwrite_glyphs;
5704 delete_glyphs_hook = XTdelete_glyphs;
5705 ring_bell_hook = XTring_bell;
5706 reset_terminal_modes_hook = XTreset_terminal_modes;
5707 set_terminal_modes_hook = XTset_terminal_modes;
5708 update_begin_hook = XTupdate_begin;
5709 update_end_hook = XTupdate_end;
5710 set_terminal_window_hook = XTset_terminal_window;
5711 read_socket_hook = XTread_socket;
b8009dd1 5712 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8
JB
5713 cursor_to_hook = XTcursor_to;
5714 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 5715 mouse_position_hook = XTmouse_position;
f451eb13 5716 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 5717 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
5718 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
5719 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
5720 redeem_scroll_bar_hook = XTredeem_scroll_bar;
5721 judge_scroll_bars_hook = XTjudge_scroll_bars;
58769bee 5722
f676886a 5723 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
5724 char_ins_del_ok = 0; /* just as fast to write the line */
5725 line_ins_del_ok = 1; /* we'll just blt 'em */
5726 fast_clear_end_of_line = 1; /* X does this well */
58769bee 5727 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
5728 off the bottom */
5729 baud_rate = 19200;
5730
7a13e894
RS
5731 x_noop_count = 0;
5732
5733 x_focus_frame = x_highlight_frame = 0;
5734
b30b24cb
RS
5735 /* Try to use interrupt input; if we can't, then start polling. */
5736 Fset_input_mode (Qt, Qnil, Qt, Qnil);
5737
7f9c7f94
RS
5738#ifdef USE_X_TOOLKIT
5739 XtToolkitInitialize ();
5740 Xt_app_con = XtCreateApplicationContext ();
5741#endif
5742
58769bee 5743 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 5744 original error handler. */
334208b7
RS
5745 XSetErrorHandler (x_error_quitter);
5746 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8
JB
5747
5748 /* Disable Window Change signals; they are handled by X events. */
5749#ifdef SIGWINCH
5750 signal (SIGWINCH, SIG_DFL);
c118dd06 5751#endif /* ! defined (SIGWINCH) */
dc6f92b8 5752
c118dd06 5753 signal (SIGPIPE, x_connection_closed);
dc6f92b8 5754}
55123275
JB
5755
5756void
5757syms_of_xterm ()
5758{
7a13e894
RS
5759 staticpro (&x_display_name_list);
5760 x_display_name_list = Qnil;
334208b7 5761
ab648270 5762 staticpro (&last_mouse_scroll_bar);
e53cb100 5763 last_mouse_scroll_bar = Qnil;
55123275 5764}
c118dd06 5765#endif /* ! defined (HAVE_X_WINDOWS) */