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