(x_delete_display): Extract kboard deletion, for modularity.
[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, insist, bar_window, part, x, y, time)
2203 FRAME_PTR *fp;
2204 int insist;
2205 Lisp_Object *bar_window;
2206 enum scroll_bar_part *part;
2207 Lisp_Object *x, *y;
2208 unsigned long *time;
2209 {
2210 FRAME_PTR f1;
2211
2212 BLOCK_INPUT;
2213
2214 if (! NILP (last_mouse_scroll_bar))
2215 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
2216 else
2217 {
2218 Window root;
2219 int root_x, root_y;
2220
2221 Window dummy_window;
2222 int dummy;
2223
2224 mouse_moved = 0;
2225 last_mouse_scroll_bar = Qnil;
2226
2227 /* Figure out which root window we're on. */
2228 XQueryPointer (FRAME_X_DISPLAY (*fp),
2229 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
2230
2231 /* The root window which contains the pointer. */
2232 &root,
2233
2234 /* Trash which we can't trust if the pointer is on
2235 a different screen. */
2236 &dummy_window,
2237
2238 /* The position on that root window. */
2239 &root_x, &root_y,
2240
2241 /* More trash we can't trust. */
2242 &dummy, &dummy,
2243
2244 /* Modifier keys and pointer buttons, about which
2245 we don't care. */
2246 (unsigned int *) &dummy);
2247
2248 /* Now we have a position on the root; find the innermost window
2249 containing the pointer. */
2250 {
2251 Window win, child;
2252 int win_x, win_y;
2253 int parent_x, parent_y;
2254
2255 win = root;
2256
2257 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
2258 && FRAME_LIVE_P (last_mouse_frame))
2259 {
2260 /* If mouse was grabbed on a frame, give coords for that frame
2261 even if the mouse is now outside it. */
2262 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
2263
2264 /* From-window, to-window. */
2265 root, FRAME_X_WINDOW (last_mouse_frame),
2266
2267 /* From-position, to-position. */
2268 root_x, root_y, &win_x, &win_y,
2269
2270 /* Child of win. */
2271 &child);
2272 f1 = last_mouse_frame;
2273 }
2274 else
2275 {
2276 while (1)
2277 {
2278 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
2279
2280 /* From-window, to-window. */
2281 root, win,
2282
2283 /* From-position, to-position. */
2284 root_x, root_y, &win_x, &win_y,
2285
2286 /* Child of win. */
2287 &child);
2288
2289 if (child == None)
2290 break;
2291
2292 win = child;
2293 parent_x = win_x;
2294 parent_y = win_y;
2295 }
2296
2297 /* Now we know that:
2298 win is the innermost window containing the pointer
2299 (XTC says it has no child containing the pointer),
2300 win_x and win_y are the pointer's position in it
2301 (XTC did this the last time through), and
2302 parent_x and parent_y are the pointer's position in win's parent.
2303 (They are what win_x and win_y were when win was child.
2304 If win is the root window, it has no parent, and
2305 parent_{x,y} are invalid, but that's okay, because we'll
2306 never use them in that case.) */
2307
2308 /* Is win one of our frames? */
2309 f1 = x_any_window_to_frame (win);
2310 }
2311
2312 /* If not, is it one of our scroll bars? */
2313 if (! f1)
2314 {
2315 struct scroll_bar *bar = x_window_to_scroll_bar (win);
2316
2317 if (bar)
2318 {
2319 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2320 win_x = parent_x;
2321 win_y = parent_y;
2322 }
2323 }
2324
2325 if (f1 == 0 && insist)
2326 f1 = selected_frame;
2327
2328 if (f1)
2329 {
2330 int ignore1, ignore2;
2331
2332 /* Ok, we found a frame. Store all the values. */
2333
2334 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
2335 &last_mouse_glyph,
2336 FRAME_X_DISPLAY_INFO (f1)->grabbed
2337 || insist);
2338
2339 *bar_window = Qnil;
2340 *part = 0;
2341 *fp = f1;
2342 XSETINT (*x, win_x);
2343 XSETINT (*y, win_y);
2344 *time = last_mouse_movement_time;
2345 }
2346 }
2347 }
2348
2349 UNBLOCK_INPUT;
2350 }
2351 \f
2352 /* Scroll bar support. */
2353
2354 /* Given an X window ID, find the struct scroll_bar which manages it.
2355 This can be called in GC, so we have to make sure to strip off mark
2356 bits. */
2357 static struct scroll_bar *
2358 x_window_to_scroll_bar (window_id)
2359 Window window_id;
2360 {
2361 Lisp_Object tail, frame;
2362
2363 for (tail = Vframe_list;
2364 XGCTYPE (tail) == Lisp_Cons;
2365 tail = XCONS (tail)->cdr)
2366 {
2367 Lisp_Object frame, bar, condemned;
2368
2369 frame = XCONS (tail)->car;
2370 /* All elements of Vframe_list should be frames. */
2371 if (! GC_FRAMEP (frame))
2372 abort ();
2373
2374 /* Scan this frame's scroll bar list for a scroll bar with the
2375 right window ID. */
2376 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
2377 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
2378 /* This trick allows us to search both the ordinary and
2379 condemned scroll bar lists with one loop. */
2380 ! GC_NILP (bar) || (bar = condemned,
2381 condemned = Qnil,
2382 ! GC_NILP (bar));
2383 bar = XSCROLL_BAR (bar)->next)
2384 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
2385 return XSCROLL_BAR (bar);
2386 }
2387
2388 return 0;
2389 }
2390
2391 /* Open a new X window to serve as a scroll bar, and return the
2392 scroll bar vector for it. */
2393 static struct scroll_bar *
2394 x_scroll_bar_create (window, top, left, width, height)
2395 struct window *window;
2396 int top, left, width, height;
2397 {
2398 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2399 struct scroll_bar *bar
2400 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
2401
2402 BLOCK_INPUT;
2403
2404 {
2405 XSetWindowAttributes a;
2406 unsigned long mask;
2407 a.background_pixel = f->display.x->background_pixel;
2408 a.event_mask = (ButtonPressMask | ButtonReleaseMask
2409 | ButtonMotionMask | PointerMotionHintMask
2410 | ExposureMask);
2411 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
2412
2413 mask = (CWBackPixel | CWEventMask | CWCursor);
2414
2415 #if 0
2416
2417 ac = 0;
2418 XtSetArg (al[ac], XtNx, left); ac++;
2419 XtSetArg (al[ac], XtNy, top); ac++;
2420 XtSetArg (al[ac], XtNwidth, width); ac++;
2421 XtSetArg (al[ac], XtNheight, height); ac++;
2422 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
2423 sb_widget = XtCreateManagedWidget ("box",
2424 boxWidgetClass,
2425 f->display.x->edit_widget, al, ac);
2426 SET_SCROLL_BAR_X_WINDOW
2427 (bar, sb_widget->core.window);
2428 #endif
2429 SET_SCROLL_BAR_X_WINDOW
2430 (bar,
2431 XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
2432
2433 /* Position and size of scroll bar. */
2434 left, top, width, height,
2435
2436 /* Border width, depth, class, and visual. */
2437 0, CopyFromParent, CopyFromParent, CopyFromParent,
2438
2439 /* Attributes. */
2440 mask, &a));
2441 }
2442
2443 XSETWINDOW (bar->window, window);
2444 XSETINT (bar->top, top);
2445 XSETINT (bar->left, left);
2446 XSETINT (bar->width, width);
2447 XSETINT (bar->height, height);
2448 XSETINT (bar->start, 0);
2449 XSETINT (bar->end, 0);
2450 bar->dragging = Qnil;
2451
2452 /* Add bar to its frame's list of scroll bars. */
2453 bar->next = FRAME_SCROLL_BARS (f);
2454 bar->prev = Qnil;
2455 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
2456 if (! NILP (bar->next))
2457 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
2458
2459 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
2460
2461 UNBLOCK_INPUT;
2462
2463 return bar;
2464 }
2465
2466 /* Draw BAR's handle in the proper position.
2467 If the handle is already drawn from START to END, don't bother
2468 redrawing it, unless REBUILD is non-zero; in that case, always
2469 redraw it. (REBUILD is handy for drawing the handle after expose
2470 events.)
2471
2472 Normally, we want to constrain the start and end of the handle to
2473 fit inside its rectangle, but if the user is dragging the scroll bar
2474 handle, we want to let them drag it down all the way, so that the
2475 bar's top is as far down as it goes; otherwise, there's no way to
2476 move to the very end of the buffer. */
2477 static void
2478 x_scroll_bar_set_handle (bar, start, end, rebuild)
2479 struct scroll_bar *bar;
2480 int start, end;
2481 int rebuild;
2482 {
2483 int dragging = ! NILP (bar->dragging);
2484 Window w = SCROLL_BAR_X_WINDOW (bar);
2485 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2486 GC gc = f->display.x->normal_gc;
2487
2488 /* If the display is already accurate, do nothing. */
2489 if (! rebuild
2490 && start == XINT (bar->start)
2491 && end == XINT (bar->end))
2492 return;
2493
2494 BLOCK_INPUT;
2495
2496 {
2497 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (XINT (bar->width));
2498 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2499 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2500
2501 /* Make sure the values are reasonable, and try to preserve
2502 the distance between start and end. */
2503 {
2504 int length = end - start;
2505
2506 if (start < 0)
2507 start = 0;
2508 else if (start > top_range)
2509 start = top_range;
2510 end = start + length;
2511
2512 if (end < start)
2513 end = start;
2514 else if (end > top_range && ! dragging)
2515 end = top_range;
2516 }
2517
2518 /* Store the adjusted setting in the scroll bar. */
2519 XSETINT (bar->start, start);
2520 XSETINT (bar->end, end);
2521
2522 /* Clip the end position, just for display. */
2523 if (end > top_range)
2524 end = top_range;
2525
2526 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
2527 below top positions, to make sure the handle is always at least
2528 that many pixels tall. */
2529 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
2530
2531 /* Draw the empty space above the handle. Note that we can't clear
2532 zero-height areas; that means "clear to end of window." */
2533 if (0 < start)
2534 XClearArea (FRAME_X_DISPLAY (f), w,
2535
2536 /* x, y, width, height, and exposures. */
2537 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2538 VERTICAL_SCROLL_BAR_TOP_BORDER,
2539 inside_width, start,
2540 False);
2541
2542 /* Draw the handle itself. */
2543 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
2544
2545 /* x, y, width, height */
2546 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2547 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
2548 inside_width, end - start);
2549
2550
2551 /* Draw the empty space below the handle. Note that we can't
2552 clear zero-height areas; that means "clear to end of window." */
2553 if (end < inside_height)
2554 XClearArea (FRAME_X_DISPLAY (f), w,
2555
2556 /* x, y, width, height, and exposures. */
2557 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2558 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
2559 inside_width, inside_height - end,
2560 False);
2561
2562 }
2563
2564 UNBLOCK_INPUT;
2565 }
2566
2567 /* Move a scroll bar around on the screen, to accommodate changing
2568 window configurations. */
2569 static void
2570 x_scroll_bar_move (bar, top, left, width, height)
2571 struct scroll_bar *bar;
2572 int top, left, width, height;
2573 {
2574 Window w = SCROLL_BAR_X_WINDOW (bar);
2575 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2576
2577 BLOCK_INPUT;
2578
2579 {
2580 XWindowChanges wc;
2581 unsigned int mask = 0;
2582
2583 wc.x = left;
2584 wc.y = top;
2585 wc.width = width;
2586 wc.height = height;
2587
2588 if (left != XINT (bar->left)) mask |= CWX;
2589 if (top != XINT (bar->top)) mask |= CWY;
2590 if (width != XINT (bar->width)) mask |= CWWidth;
2591 if (height != XINT (bar->height)) mask |= CWHeight;
2592
2593 if (mask)
2594 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
2595 mask, &wc);
2596 }
2597
2598 XSETINT (bar->left, left);
2599 XSETINT (bar->top, top);
2600 XSETINT (bar->width, width);
2601 XSETINT (bar->height, height);
2602
2603 UNBLOCK_INPUT;
2604 }
2605
2606 /* Destroy the X window for BAR, and set its Emacs window's scroll bar
2607 to nil. */
2608 static void
2609 x_scroll_bar_remove (bar)
2610 struct scroll_bar *bar;
2611 {
2612 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2613
2614 BLOCK_INPUT;
2615
2616 /* Destroy the window. */
2617 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
2618
2619 /* Disassociate this scroll bar from its window. */
2620 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
2621
2622 UNBLOCK_INPUT;
2623 }
2624
2625 /* Set the handle of the vertical scroll bar for WINDOW to indicate
2626 that we are displaying PORTION characters out of a total of WHOLE
2627 characters, starting at POSITION. If WINDOW has no scroll bar,
2628 create one. */
2629 static void
2630 XTset_vertical_scroll_bar (window, portion, whole, position)
2631 struct window *window;
2632 int portion, whole, position;
2633 {
2634 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2635 int top = XINT (window->top);
2636 int left = WINDOW_VERTICAL_SCROLL_BAR_COLUMN (window);
2637 int height = WINDOW_VERTICAL_SCROLL_BAR_HEIGHT (window);
2638
2639 /* Where should this scroll bar be, pixelwise? */
2640 int pixel_top = CHAR_TO_PIXEL_ROW (f, top);
2641 int pixel_left = CHAR_TO_PIXEL_COL (f, left);
2642 int pixel_width
2643 = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
2644 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2645 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->display.x->font)));
2646 int pixel_height = VERTICAL_SCROLL_BAR_PIXEL_HEIGHT (f, height);
2647
2648 struct scroll_bar *bar;
2649
2650 /* Does the scroll bar exist yet? */
2651 if (NILP (window->vertical_scroll_bar))
2652 bar = x_scroll_bar_create (window,
2653 pixel_top, pixel_left,
2654 pixel_width, pixel_height);
2655 else
2656 {
2657 /* It may just need to be moved and resized. */
2658 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2659 x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
2660 }
2661
2662 /* Set the scroll bar's current state, unless we're currently being
2663 dragged. */
2664 if (NILP (bar->dragging))
2665 {
2666 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
2667
2668 if (whole == 0)
2669 x_scroll_bar_set_handle (bar, 0, top_range, 0);
2670 else
2671 {
2672 int start = ((double) position * top_range) / whole;
2673 int end = ((double) (position + portion) * top_range) / whole;
2674
2675 x_scroll_bar_set_handle (bar, start, end, 0);
2676 }
2677 }
2678
2679 XSETVECTOR (window->vertical_scroll_bar, bar);
2680 }
2681
2682
2683 /* The following three hooks are used when we're doing a thorough
2684 redisplay of the frame. We don't explicitly know which scroll bars
2685 are going to be deleted, because keeping track of when windows go
2686 away is a real pain - "Can you say set-window-configuration, boys
2687 and girls?" Instead, we just assert at the beginning of redisplay
2688 that *all* scroll bars are to be removed, and then save a scroll bar
2689 from the fiery pit when we actually redisplay its window. */
2690
2691 /* Arrange for all scroll bars on FRAME to be removed at the next call
2692 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
2693 `*redeem_scroll_bar_hook' is applied to its window before the judgement. */
2694 static void
2695 XTcondemn_scroll_bars (frame)
2696 FRAME_PTR frame;
2697 {
2698 /* The condemned list should be empty at this point; if it's not,
2699 then the rest of Emacs isn't using the condemn/redeem/judge
2700 protocol correctly. */
2701 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
2702 abort ();
2703
2704 /* Move them all to the "condemned" list. */
2705 FRAME_CONDEMNED_SCROLL_BARS (frame) = FRAME_SCROLL_BARS (frame);
2706 FRAME_SCROLL_BARS (frame) = Qnil;
2707 }
2708
2709 /* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
2710 Note that WINDOW isn't necessarily condemned at all. */
2711 static void
2712 XTredeem_scroll_bar (window)
2713 struct window *window;
2714 {
2715 struct scroll_bar *bar;
2716
2717 /* We can't redeem this window's scroll bar if it doesn't have one. */
2718 if (NILP (window->vertical_scroll_bar))
2719 abort ();
2720
2721 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2722
2723 /* Unlink it from the condemned list. */
2724 {
2725 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2726
2727 if (NILP (bar->prev))
2728 {
2729 /* If the prev pointer is nil, it must be the first in one of
2730 the lists. */
2731 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
2732 /* It's not condemned. Everything's fine. */
2733 return;
2734 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
2735 window->vertical_scroll_bar))
2736 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
2737 else
2738 /* If its prev pointer is nil, it must be at the front of
2739 one or the other! */
2740 abort ();
2741 }
2742 else
2743 XSCROLL_BAR (bar->prev)->next = bar->next;
2744
2745 if (! NILP (bar->next))
2746 XSCROLL_BAR (bar->next)->prev = bar->prev;
2747
2748 bar->next = FRAME_SCROLL_BARS (f);
2749 bar->prev = Qnil;
2750 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
2751 if (! NILP (bar->next))
2752 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
2753 }
2754 }
2755
2756 /* Remove all scroll bars on FRAME that haven't been saved since the
2757 last call to `*condemn_scroll_bars_hook'. */
2758 static void
2759 XTjudge_scroll_bars (f)
2760 FRAME_PTR f;
2761 {
2762 Lisp_Object bar, next;
2763
2764 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
2765
2766 /* Clear out the condemned list now so we won't try to process any
2767 more events on the hapless scroll bars. */
2768 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
2769
2770 for (; ! NILP (bar); bar = next)
2771 {
2772 struct scroll_bar *b = XSCROLL_BAR (bar);
2773
2774 x_scroll_bar_remove (b);
2775
2776 next = b->next;
2777 b->next = b->prev = Qnil;
2778 }
2779
2780 /* Now there should be no references to the condemned scroll bars,
2781 and they should get garbage-collected. */
2782 }
2783
2784
2785 /* Handle an Expose or GraphicsExpose event on a scroll bar.
2786
2787 This may be called from a signal handler, so we have to ignore GC
2788 mark bits. */
2789 static void
2790 x_scroll_bar_expose (bar, event)
2791 struct scroll_bar *bar;
2792 XEvent *event;
2793 {
2794 Window w = SCROLL_BAR_X_WINDOW (bar);
2795 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2796 GC gc = f->display.x->normal_gc;
2797
2798 BLOCK_INPUT;
2799
2800 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
2801
2802 /* Draw a one-pixel border just inside the edges of the scroll bar. */
2803 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
2804
2805 /* x, y, width, height */
2806 0, 0, XINT (bar->width) - 1, XINT (bar->height) - 1);
2807
2808 UNBLOCK_INPUT;
2809 }
2810
2811 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2812 is set to something other than no_event, it is enqueued.
2813
2814 This may be called from a signal handler, so we have to ignore GC
2815 mark bits. */
2816 static void
2817 x_scroll_bar_handle_click (bar, event, emacs_event)
2818 struct scroll_bar *bar;
2819 XEvent *event;
2820 struct input_event *emacs_event;
2821 {
2822 if (! GC_WINDOWP (bar->window))
2823 abort ();
2824
2825 emacs_event->kind = scroll_bar_click;
2826 emacs_event->code = event->xbutton.button - Button1;
2827 emacs_event->modifiers
2828 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
2829 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
2830 event->xbutton.state)
2831 | (event->type == ButtonRelease
2832 ? up_modifier
2833 : down_modifier));
2834 emacs_event->frame_or_window = bar->window;
2835 emacs_event->timestamp = event->xbutton.time;
2836 {
2837 int internal_height
2838 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2839 int top_range
2840 = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2841 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
2842
2843 if (y < 0) y = 0;
2844 if (y > top_range) y = top_range;
2845
2846 if (y < XINT (bar->start))
2847 emacs_event->part = scroll_bar_above_handle;
2848 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2849 emacs_event->part = scroll_bar_handle;
2850 else
2851 emacs_event->part = scroll_bar_below_handle;
2852
2853 /* Just because the user has clicked on the handle doesn't mean
2854 they want to drag it. Lisp code needs to be able to decide
2855 whether or not we're dragging. */
2856 #if 0
2857 /* If the user has just clicked on the handle, record where they're
2858 holding it. */
2859 if (event->type == ButtonPress
2860 && emacs_event->part == scroll_bar_handle)
2861 XSETINT (bar->dragging, y - XINT (bar->start));
2862 #endif
2863
2864 /* If the user has released the handle, set it to its final position. */
2865 if (event->type == ButtonRelease
2866 && ! NILP (bar->dragging))
2867 {
2868 int new_start = y - XINT (bar->dragging);
2869 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
2870
2871 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
2872 bar->dragging = Qnil;
2873 }
2874
2875 /* Same deal here as the other #if 0. */
2876 #if 0
2877 /* Clicks on the handle are always reported as occurring at the top of
2878 the handle. */
2879 if (emacs_event->part == scroll_bar_handle)
2880 emacs_event->x = bar->start;
2881 else
2882 XSETINT (emacs_event->x, y);
2883 #else
2884 XSETINT (emacs_event->x, y);
2885 #endif
2886
2887 XSETINT (emacs_event->y, top_range);
2888 }
2889 }
2890
2891 /* Handle some mouse motion while someone is dragging the scroll bar.
2892
2893 This may be called from a signal handler, so we have to ignore GC
2894 mark bits. */
2895 static void
2896 x_scroll_bar_note_movement (bar, event)
2897 struct scroll_bar *bar;
2898 XEvent *event;
2899 {
2900 last_mouse_movement_time = event->xmotion.time;
2901
2902 mouse_moved = 1;
2903 XSETVECTOR (last_mouse_scroll_bar, bar);
2904
2905 /* If we're dragging the bar, display it. */
2906 if (! GC_NILP (bar->dragging))
2907 {
2908 /* Where should the handle be now? */
2909 int new_start = event->xmotion.y - XINT (bar->dragging);
2910
2911 if (new_start != XINT (bar->start))
2912 {
2913 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
2914
2915 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
2916 }
2917 }
2918
2919 /* Call XQueryPointer so we'll get an event the next time the mouse
2920 moves and we can see *still* on the same position. */
2921 {
2922 int dummy;
2923 Window dummy_window;
2924
2925 XQueryPointer (event->xmotion.display, event->xmotion.window,
2926 &dummy_window, &dummy_window,
2927 &dummy, &dummy, &dummy, &dummy,
2928 (unsigned int *) &dummy);
2929 }
2930 }
2931
2932 /* Return information to the user about the current position of the mouse
2933 on the scroll bar. */
2934 static void
2935 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
2936 FRAME_PTR *fp;
2937 Lisp_Object *bar_window;
2938 enum scroll_bar_part *part;
2939 Lisp_Object *x, *y;
2940 unsigned long *time;
2941 {
2942 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
2943 Window w = SCROLL_BAR_X_WINDOW (bar);
2944 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2945 int win_x, win_y;
2946 Window dummy_window;
2947 int dummy_coord;
2948 unsigned int dummy_mask;
2949
2950 BLOCK_INPUT;
2951
2952 /* Get the mouse's position relative to the scroll bar window, and
2953 report that. */
2954 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
2955
2956 /* Root, child, root x and root y. */
2957 &dummy_window, &dummy_window,
2958 &dummy_coord, &dummy_coord,
2959
2960 /* Position relative to scroll bar. */
2961 &win_x, &win_y,
2962
2963 /* Mouse buttons and modifier keys. */
2964 &dummy_mask))
2965 ;
2966 else
2967 {
2968 int inside_height
2969 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2970 int top_range
2971 = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2972
2973 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2974
2975 if (! NILP (bar->dragging))
2976 win_y -= XINT (bar->dragging);
2977
2978 if (win_y < 0)
2979 win_y = 0;
2980 if (win_y > top_range)
2981 win_y = top_range;
2982
2983 *fp = f;
2984 *bar_window = bar->window;
2985
2986 if (! NILP (bar->dragging))
2987 *part = scroll_bar_handle;
2988 else if (win_y < XINT (bar->start))
2989 *part = scroll_bar_above_handle;
2990 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2991 *part = scroll_bar_handle;
2992 else
2993 *part = scroll_bar_below_handle;
2994
2995 XSETINT (*x, win_y);
2996 XSETINT (*y, top_range);
2997
2998 mouse_moved = 0;
2999 last_mouse_scroll_bar = Qnil;
3000 }
3001
3002 *time = last_mouse_movement_time;
3003
3004 UNBLOCK_INPUT;
3005 }
3006
3007
3008 /* The screen has been cleared so we may have changed foreground or
3009 background colors, and the scroll bars may need to be redrawn.
3010 Clear out the scroll bars, and ask for expose events, so we can
3011 redraw them. */
3012
3013 x_scroll_bar_clear (f)
3014 FRAME_PTR f;
3015 {
3016 Lisp_Object bar;
3017
3018 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
3019 bar = XSCROLL_BAR (bar)->next)
3020 XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
3021 0, 0, 0, 0, True);
3022 }
3023
3024 /* This processes Expose events from the menubar specific X event
3025 loop in menubar.c. This allows to redisplay the frame if necessary
3026 when handling menubar or popup items. */
3027
3028 void
3029 process_expose_from_menu (event)
3030 XEvent event;
3031 {
3032 FRAME_PTR f;
3033
3034 BLOCK_INPUT;
3035
3036 f = x_window_to_frame (event.xexpose.window);
3037 if (f)
3038 {
3039 if (f->async_visible == 0)
3040 {
3041 f->async_visible = 1;
3042 f->async_iconified = 0;
3043 SET_FRAME_GARBAGED (f);
3044 }
3045 else
3046 {
3047 dumprectangle (x_window_to_frame (event.xexpose.window),
3048 event.xexpose.x, event.xexpose.y,
3049 event.xexpose.width, event.xexpose.height);
3050 }
3051 }
3052 else
3053 {
3054 struct scroll_bar *bar
3055 = x_window_to_scroll_bar (event.xexpose.window);
3056
3057 if (bar)
3058 x_scroll_bar_expose (bar, &event);
3059 }
3060
3061 UNBLOCK_INPUT;
3062 }
3063 \f
3064 /* Define a queue to save up SelectionRequest events for later handling. */
3065
3066 struct selection_event_queue
3067 {
3068 XEvent event;
3069 struct selection_event_queue *next;
3070 };
3071
3072 static struct selection_event_queue *queue;
3073
3074 /* Nonzero means queue up certain events--don't process them yet. */
3075 static int x_queue_selection_requests;
3076
3077 /* Queue up an X event *EVENT, to be processed later. */
3078
3079 static void
3080 x_queue_event (f, event)
3081 FRAME_PTR f;
3082 XEvent *event;
3083 {
3084 struct selection_event_queue *queue_tmp
3085 = (struct selection_event_queue *) malloc (sizeof (struct selection_event_queue));
3086
3087 if (queue_tmp != NULL)
3088 {
3089 queue_tmp->event = *event;
3090 queue_tmp->next = queue;
3091 queue = queue_tmp;
3092 }
3093 }
3094
3095 /* Take all the queued events and put them back
3096 so that they get processed afresh. */
3097
3098 static void
3099 x_unqueue_events (display)
3100 Display *display;
3101 {
3102 while (queue != NULL)
3103 {
3104 struct selection_event_queue *queue_tmp = queue;
3105 XPutBackEvent (display, &queue_tmp->event);
3106 queue = queue_tmp->next;
3107 free ((char *)queue_tmp);
3108 }
3109 }
3110
3111 /* Start queuing SelectionRequest events. */
3112
3113 void
3114 x_start_queuing_selection_requests (display)
3115 Display *display;
3116 {
3117 x_queue_selection_requests++;
3118 }
3119
3120 /* Stop queuing SelectionRequest events. */
3121
3122 void
3123 x_stop_queuing_selection_requests (display)
3124 Display *display;
3125 {
3126 x_queue_selection_requests--;
3127 x_unqueue_events (display);
3128 }
3129 \f
3130 /* The main X event-reading loop - XTread_socket. */
3131
3132 /* Timestamp of enter window event. This is only used by XTread_socket,
3133 but we have to put it out here, since static variables within functions
3134 sometimes don't work. */
3135 static Time enter_timestamp;
3136
3137 /* This holds the state XLookupString needs to implement dead keys
3138 and other tricks known as "compose processing". _X Window System_
3139 says that a portable program can't use this, but Stephen Gildea assures
3140 me that letting the compiler initialize it to zeros will work okay.
3141
3142 This must be defined outside of XTread_socket, for the same reasons
3143 given for enter_timestamp, above. */
3144 static XComposeStatus compose_status;
3145
3146 /* Record the last 100 characters stored
3147 to help debug the loss-of-chars-during-GC problem. */
3148 int temp_index;
3149 short temp_buffer[100];
3150
3151 /* Set this to nonzero to fake an "X I/O error"
3152 on a particular display. */
3153 struct x_display_info *XTread_socket_fake_io_error;
3154
3155 /* Read events coming from the X server.
3156 This routine is called by the SIGIO handler.
3157 We return as soon as there are no more events to be read.
3158
3159 Events representing keys are stored in buffer BUFP,
3160 which can hold up to NUMCHARS characters.
3161 We return the number of characters stored into the buffer,
3162 thus pretending to be `read'.
3163
3164 WAITP is nonzero if we should block until input arrives.
3165 EXPECTED is nonzero if the caller knows input is available. */
3166
3167 int
3168 XTread_socket (sd, bufp, numchars, waitp, expected)
3169 register int sd;
3170 register struct input_event *bufp;
3171 register int numchars;
3172 int waitp;
3173 int expected;
3174 {
3175 int count = 0;
3176 int nbytes = 0;
3177 int mask;
3178 int items_pending; /* How many items are in the X queue. */
3179 XEvent event;
3180 struct frame *f;
3181 int event_found = 0;
3182 int prefix;
3183 Lisp_Object part;
3184 struct x_display_info *dpyinfo;
3185
3186 if (interrupt_input_blocked)
3187 {
3188 interrupt_input_pending = 1;
3189 return -1;
3190 }
3191
3192 interrupt_input_pending = 0;
3193 BLOCK_INPUT;
3194
3195 /* So people can tell when we have read the available input. */
3196 input_signal_count++;
3197
3198 if (numchars <= 0)
3199 abort (); /* Don't think this happens. */
3200
3201 /* Find the display we are supposed to read input for.
3202 It's the one communicating on descriptor SD. */
3203 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
3204 {
3205 #if 0 /* This ought to be unnecessary; let's verify it. */
3206 #ifdef FIOSNBIO
3207 /* If available, Xlib uses FIOSNBIO to make the socket
3208 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
3209 FIOSNBIO is ignored, and instead of signalling EWOULDBLOCK,
3210 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
3211 fcntl (dpyinfo->connection, F_SETFL, 0);
3212 #endif /* ! defined (FIOSNBIO) */
3213 #endif
3214
3215 #if 0 /* This code can't be made to work, with multiple displays,
3216 and appears not to be used on any system any more.
3217 Also keyboard.c doesn't turn O_NDELAY on and off
3218 for X connections. */
3219 #ifndef SIGIO
3220 #ifndef HAVE_SELECT
3221 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
3222 {
3223 extern int read_alarm_should_throw;
3224 read_alarm_should_throw = 1;
3225 XPeekEvent (dpyinfo->display, &event);
3226 read_alarm_should_throw = 0;
3227 }
3228 #endif /* HAVE_SELECT */
3229 #endif /* SIGIO */
3230 #endif
3231
3232 /* For debugging, this gives a way to fake an I/O error. */
3233 if (dpyinfo == XTread_socket_fake_io_error)
3234 {
3235 XTread_socket_fake_io_error = 0;
3236 x_io_error_quitter (dpyinfo->display);
3237 }
3238
3239 while (XPending (dpyinfo->display) != 0)
3240 {
3241 XNextEvent (dpyinfo->display, &event);
3242 event_found = 1;
3243
3244 switch (event.type)
3245 {
3246 case ClientMessage:
3247 {
3248 if (event.xclient.message_type
3249 == dpyinfo->Xatom_wm_protocols
3250 && event.xclient.format == 32)
3251 {
3252 if (event.xclient.data.l[0]
3253 == dpyinfo->Xatom_wm_take_focus)
3254 {
3255 f = x_window_to_frame (event.xclient.window);
3256 /* Since we set WM_TAKE_FOCUS, we must call
3257 XSetInputFocus explicitly. But not if f is null,
3258 since that might be an event for a deleted frame. */
3259 if (f)
3260 XSetInputFocus (event.xclient.display,
3261 event.xclient.window,
3262 RevertToPointerRoot,
3263 event.xclient.data.l[1]);
3264 /* Not certain about handling scroll bars here */
3265 }
3266 else if (event.xclient.data.l[0]
3267 == dpyinfo->Xatom_wm_save_yourself)
3268 {
3269 /* Save state modify the WM_COMMAND property to
3270 something which can reinstate us. This notifies
3271 the session manager, who's looking for such a
3272 PropertyNotify. Can restart processing when
3273 a keyboard or mouse event arrives. */
3274 if (numchars > 0)
3275 {
3276 f = x_top_window_to_frame (event.xclient.window);
3277
3278 /* This is just so we only give real data once
3279 for a single Emacs process. */
3280 if (f == selected_frame)
3281 XSetCommand (FRAME_X_DISPLAY (f),
3282 event.xclient.window,
3283 initial_argv, initial_argc);
3284 else
3285 XSetCommand (FRAME_X_DISPLAY (f),
3286 event.xclient.window,
3287 0, 0);
3288 }
3289 }
3290 else if (event.xclient.data.l[0]
3291 == dpyinfo->Xatom_wm_delete_window)
3292 {
3293 struct frame *f = x_any_window_to_frame (event.xclient.window);
3294
3295 if (f)
3296 {
3297 if (numchars == 0)
3298 abort ();
3299
3300 bufp->kind = delete_window_event;
3301 XSETFRAME (bufp->frame_or_window, f);
3302 bufp++;
3303
3304 count += 1;
3305 numchars -= 1;
3306 }
3307 }
3308 }
3309 else if (event.xclient.message_type
3310 == dpyinfo->Xatom_wm_configure_denied)
3311 {
3312 }
3313 else if (event.xclient.message_type
3314 == dpyinfo->Xatom_wm_window_moved)
3315 {
3316 int new_x, new_y;
3317 struct frame *f = x_window_to_frame (event.xclient.window);
3318
3319 new_x = event.xclient.data.s[0];
3320 new_y = event.xclient.data.s[1];
3321
3322 if (f)
3323 {
3324 f->display.x->left_pos = new_x;
3325 f->display.x->top_pos = new_y;
3326 }
3327 }
3328 #if defined (USE_X_TOOLKIT) && defined (HAVE_X11R5)
3329 else if (event.xclient.message_type
3330 == dpyinfo->Xatom_editres)
3331 {
3332 struct frame *f = x_any_window_to_frame (event.xclient.window);
3333 _XEditResCheckMessages (f->display.x->widget, NULL, &event, NULL);
3334 }
3335 #endif /* USE_X_TOOLKIT and HAVE_X11R5 */
3336 }
3337 break;
3338
3339 case SelectionNotify:
3340 #ifdef USE_X_TOOLKIT
3341 if (! x_window_to_frame (event.xselection.requestor))
3342 goto OTHER;
3343 #endif /* not USE_X_TOOLKIT */
3344 x_handle_selection_notify (&event);
3345 break;
3346
3347 case SelectionClear: /* Someone has grabbed ownership. */
3348 #ifdef USE_X_TOOLKIT
3349 if (! x_window_to_frame (event.xselectionclear.window))
3350 goto OTHER;
3351 #endif /* USE_X_TOOLKIT */
3352 {
3353 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
3354
3355 if (numchars == 0)
3356 abort ();
3357
3358 bufp->kind = selection_clear_event;
3359 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3360 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3361 SELECTION_EVENT_TIME (bufp) = eventp->time;
3362 bufp++;
3363
3364 count += 1;
3365 numchars -= 1;
3366 }
3367 break;
3368
3369 case SelectionRequest: /* Someone wants our selection. */
3370 #ifdef USE_X_TOOLKIT
3371 if (!x_window_to_frame (event.xselectionrequest.owner))
3372 goto OTHER;
3373 #endif /* USE_X_TOOLKIT */
3374 if (x_queue_selection_requests)
3375 x_queue_event (x_window_to_frame (event.xselectionrequest.owner),
3376 &event);
3377 else
3378 {
3379 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
3380
3381 if (numchars == 0)
3382 abort ();
3383
3384 bufp->kind = selection_request_event;
3385 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3386 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
3387 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3388 SELECTION_EVENT_TARGET (bufp) = eventp->target;
3389 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
3390 SELECTION_EVENT_TIME (bufp) = eventp->time;
3391 bufp++;
3392
3393 count += 1;
3394 numchars -= 1;
3395 }
3396 break;
3397
3398 case PropertyNotify:
3399 #ifdef USE_X_TOOLKIT
3400 if (!x_any_window_to_frame (event.xproperty.window))
3401 goto OTHER;
3402 #endif /* not USE_X_TOOLKIT */
3403 x_handle_property_notify (&event);
3404 break;
3405
3406 case ReparentNotify:
3407 f = x_top_window_to_frame (event.xreparent.window);
3408 if (f)
3409 {
3410 int x, y;
3411 f->display.x->parent_desc = event.xreparent.parent;
3412 x_real_positions (f, &x, &y);
3413 f->display.x->left_pos = x;
3414 f->display.x->top_pos = y;
3415 }
3416 break;
3417
3418 case Expose:
3419 f = x_window_to_frame (event.xexpose.window);
3420 if (f)
3421 {
3422 if (f->async_visible == 0)
3423 {
3424 f->async_visible = 1;
3425 f->async_iconified = 0;
3426 SET_FRAME_GARBAGED (f);
3427 }
3428 else
3429 dumprectangle (x_window_to_frame (event.xexpose.window),
3430 event.xexpose.x, event.xexpose.y,
3431 event.xexpose.width, event.xexpose.height);
3432 }
3433 else
3434 {
3435 struct scroll_bar *bar
3436 = x_window_to_scroll_bar (event.xexpose.window);
3437
3438 if (bar)
3439 x_scroll_bar_expose (bar, &event);
3440 #ifdef USE_X_TOOLKIT
3441 else
3442 goto OTHER;
3443 #endif /* USE_X_TOOLKIT */
3444 }
3445 break;
3446
3447 case GraphicsExpose: /* This occurs when an XCopyArea's
3448 source area was obscured or not
3449 available.*/
3450 f = x_window_to_frame (event.xgraphicsexpose.drawable);
3451 if (f)
3452 {
3453 dumprectangle (f,
3454 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
3455 event.xgraphicsexpose.width,
3456 event.xgraphicsexpose.height);
3457 }
3458 #ifdef USE_X_TOOLKIT
3459 else
3460 goto OTHER;
3461 #endif /* USE_X_TOOLKIT */
3462 break;
3463
3464 case NoExpose: /* This occurs when an XCopyArea's
3465 source area was completely
3466 available */
3467 break;
3468
3469 case UnmapNotify:
3470 f = x_any_window_to_frame (event.xunmap.window);
3471 if (f) /* F may no longer exist if
3472 the frame was deleted. */
3473 {
3474 /* While a frame is unmapped, display generation is
3475 disabled; you don't want to spend time updating a
3476 display that won't ever be seen. */
3477 f->async_visible = 0;
3478 /* We can't distinguish, from the event, whether the window
3479 has become iconified or invisible. So assume, if it
3480 was previously visible, than now it is iconified.
3481 We depend on x_make_frame_invisible to mark it iconified. */
3482 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
3483 f->async_iconified = 1;
3484
3485 bufp->kind = iconify_event;
3486 XSETFRAME (bufp->frame_or_window, f);
3487 bufp++;
3488 count++;
3489 numchars--;
3490 }
3491 #ifdef USE_X_TOOLKIT
3492 goto OTHER;
3493 #endif /* USE_X_TOOLKIT */
3494 break;
3495
3496 case MapNotify:
3497 /* We use x_top_window_to_frame because map events can come
3498 for subwindows and they don't mean that the frame is visible. */
3499 f = x_top_window_to_frame (event.xmap.window);
3500 if (f)
3501 {
3502 f->async_visible = 1;
3503 f->async_iconified = 0;
3504
3505 /* wait_reading_process_input will notice this and update
3506 the frame's display structures. */
3507 SET_FRAME_GARBAGED (f);
3508
3509 bufp->kind = deiconify_event;
3510 XSETFRAME (bufp->frame_or_window, f);
3511 bufp++;
3512 count++;
3513 numchars--;
3514 }
3515 #ifdef USE_X_TOOLKIT
3516 goto OTHER;
3517 #endif /* USE_X_TOOLKIT */
3518 break;
3519
3520 /* Turn off processing if we become fully obscured. */
3521 case VisibilityNotify:
3522 break;
3523
3524 case KeyPress:
3525 f = x_any_window_to_frame (event.xkey.window);
3526
3527 if (f != 0)
3528 {
3529 KeySym keysym, orig_keysym;
3530 /* al%imercury@uunet.uu.net says that making this 81 instead of
3531 80 fixed a bug whereby meta chars made his Emacs hang. */
3532 unsigned char copy_buffer[81];
3533 int modifiers;
3534
3535 event.xkey.state
3536 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
3537 extra_keyboard_modifiers);
3538 modifiers = event.xkey.state;
3539
3540 /* This will have to go some day... */
3541
3542 /* make_lispy_event turns chars into control chars.
3543 Don't do it here because XLookupString is too eager. */
3544 event.xkey.state &= ~ControlMask;
3545 nbytes = XLookupString (&event.xkey, copy_buffer,
3546 80, &keysym, &compose_status);
3547
3548 orig_keysym = keysym;
3549
3550 if (numchars > 1)
3551 {
3552 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
3553 || keysym == XK_Delete
3554 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
3555 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
3556 #ifdef HPUX
3557 /* This recognizes the "extended function keys".
3558 It seems there's no cleaner way.
3559 Test IsModifierKey to avoid handling mode_switch
3560 incorrectly. */
3561 || ((unsigned) (keysym) >= XK_Select
3562 && (unsigned)(keysym) < XK_KP_Space)
3563 #endif
3564 #ifdef XK_dead_circumflex
3565 || orig_keysym == XK_dead_circumflex
3566 #endif
3567 #ifdef XK_dead_grave
3568 || orig_keysym == XK_dead_grave
3569 #endif
3570 #ifdef XK_dead_tilde
3571 || orig_keysym == XK_dead_tilde
3572 #endif
3573 #ifdef XK_dead_diaeresis
3574 || orig_keysym == XK_dead_diaeresis
3575 #endif
3576 #ifdef XK_dead_macron
3577 || orig_keysym == XK_dead_macron
3578 #endif
3579 #ifdef XK_dead_degree
3580 || orig_keysym == XK_dead_degree
3581 #endif
3582 #ifdef XK_dead_acute
3583 || orig_keysym == XK_dead_acute
3584 #endif
3585 #ifdef XK_dead_cedilla
3586 || orig_keysym == XK_dead_cedilla
3587 #endif
3588 #ifdef XK_dead_breve
3589 || orig_keysym == XK_dead_breve
3590 #endif
3591 #ifdef XK_dead_ogonek
3592 || orig_keysym == XK_dead_ogonek
3593 #endif
3594 #ifdef XK_dead_caron
3595 || orig_keysym == XK_dead_caron
3596 #endif
3597 #ifdef XK_dead_doubleacute
3598 || orig_keysym == XK_dead_doubleacute
3599 #endif
3600 #ifdef XK_dead_abovedot
3601 || orig_keysym == XK_dead_abovedot
3602 #endif
3603 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
3604 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
3605 /* Any "vendor-specific" key is ok. */
3606 || (orig_keysym & (1 << 28)))
3607 && ! (IsModifierKey (orig_keysym)
3608 #ifndef HAVE_X11R5
3609 #ifdef XK_Mode_switch
3610 || ((unsigned)(orig_keysym) == XK_Mode_switch)
3611 #endif
3612 #ifdef XK_Num_Lock
3613 || ((unsigned)(orig_keysym) == XK_Num_Lock)
3614 #endif
3615 #endif /* not HAVE_X11R5 */
3616 ))
3617 {
3618 if (temp_index == sizeof temp_buffer / sizeof (short))
3619 temp_index = 0;
3620 temp_buffer[temp_index++] = keysym;
3621 bufp->kind = non_ascii_keystroke;
3622 bufp->code = keysym;
3623 XSETFRAME (bufp->frame_or_window, f);
3624 bufp->modifiers
3625 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
3626 modifiers);
3627 bufp->timestamp = event.xkey.time;
3628 bufp++;
3629 count++;
3630 numchars--;
3631 }
3632 else if (numchars > nbytes)
3633 {
3634 register int i;
3635
3636 for (i = 0; i < nbytes; i++)
3637 {
3638 if (temp_index == sizeof temp_buffer / sizeof (short))
3639 temp_index = 0;
3640 temp_buffer[temp_index++] = copy_buffer[i];
3641 bufp->kind = ascii_keystroke;
3642 bufp->code = copy_buffer[i];
3643 XSETFRAME (bufp->frame_or_window, f);
3644 bufp->modifiers
3645 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
3646 modifiers);
3647 bufp->timestamp = event.xkey.time;
3648 bufp++;
3649 }
3650
3651 count += nbytes;
3652 numchars -= nbytes;
3653 }
3654 else
3655 abort ();
3656 }
3657 else
3658 abort ();
3659 }
3660 break;
3661
3662 /* Here's a possible interpretation of the whole
3663 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If you get a
3664 FocusIn event, you have to get a FocusOut event before you
3665 relinquish the focus. If you haven't received a FocusIn event,
3666 then a mere LeaveNotify is enough to free you. */
3667
3668 case EnterNotify:
3669 f = x_any_window_to_frame (event.xcrossing.window);
3670
3671 if (event.xcrossing.focus) /* Entered Window */
3672 {
3673 /* Avoid nasty pop/raise loops. */
3674 if (f && (!(f->auto_raise)
3675 || !(f->auto_lower)
3676 || (event.xcrossing.time - enter_timestamp) > 500))
3677 {
3678 x_new_focus_frame (f);
3679 enter_timestamp = event.xcrossing.time;
3680 }
3681 }
3682 else if (f == x_focus_frame)
3683 x_new_focus_frame (0);
3684 /* EnterNotify counts as mouse movement,
3685 so update things that depend on mouse position. */
3686 if (f)
3687 note_mouse_movement (f, &event.xmotion);
3688 #ifdef USE_X_TOOLKIT
3689 goto OTHER;
3690 #endif /* USE_X_TOOLKIT */
3691 break;
3692
3693 case FocusIn:
3694 f = x_any_window_to_frame (event.xfocus.window);
3695 if (event.xfocus.detail != NotifyPointer)
3696 x_focus_event_frame = f;
3697 if (f)
3698 x_new_focus_frame (f);
3699 #ifdef USE_X_TOOLKIT
3700 goto OTHER;
3701 #endif /* USE_X_TOOLKIT */
3702 break;
3703
3704
3705 case LeaveNotify:
3706 f = x_top_window_to_frame (event.xcrossing.window);
3707 if (f)
3708 {
3709 if (f == dpyinfo->mouse_face_mouse_frame)
3710 /* If we move outside the frame,
3711 then we're certainly no longer on any text in the frame. */
3712 clear_mouse_face (dpyinfo);
3713
3714 if (event.xcrossing.focus)
3715 x_mouse_leave ();
3716 else
3717 {
3718 if (f == x_focus_event_frame)
3719 x_focus_event_frame = 0;
3720 if (f == x_focus_frame)
3721 x_new_focus_frame (0);
3722 }
3723 }
3724 #ifdef USE_X_TOOLKIT
3725 goto OTHER;
3726 #endif /* USE_X_TOOLKIT */
3727 break;
3728
3729 case FocusOut:
3730 f = x_any_window_to_frame (event.xfocus.window);
3731 if (event.xfocus.detail != NotifyPointer
3732 && f == x_focus_event_frame)
3733 x_focus_event_frame = 0;
3734 if (f && f == x_focus_frame)
3735 x_new_focus_frame (0);
3736 #ifdef USE_X_TOOLKIT
3737 goto OTHER;
3738 #endif /* USE_X_TOOLKIT */
3739 break;
3740
3741 case MotionNotify:
3742 {
3743 if (dpyinfo->grabbed && last_mouse_frame
3744 && FRAME_LIVE_P (last_mouse_frame))
3745 f = last_mouse_frame;
3746 else
3747 f = x_window_to_frame (event.xmotion.window);
3748 if (f)
3749 note_mouse_movement (f, &event.xmotion);
3750 else
3751 {
3752 struct scroll_bar *bar
3753 = x_window_to_scroll_bar (event.xmotion.window);
3754
3755 if (bar)
3756 x_scroll_bar_note_movement (bar, &event);
3757
3758 /* If we move outside the frame,
3759 then we're certainly no longer on any text in the frame. */
3760 clear_mouse_face (dpyinfo);
3761 }
3762 }
3763 #if 0 /* This should be unnecessary, since the toolkit has no use
3764 for motion events that happen outside of the menu event loop,
3765 and it seems to cause the bug that mouse events stop coming
3766 after a while. */
3767 #ifdef USE_X_TOOLKIT
3768 goto OTHER;
3769 #endif /* USE_X_TOOLKIT */
3770 #endif
3771 break;
3772
3773 case ConfigureNotify:
3774 f = x_any_window_to_frame (event.xconfigure.window);
3775 #ifdef USE_X_TOOLKIT
3776 if (f
3777 #if 0
3778 && ! event.xconfigure.send_event
3779 #endif
3780 && (event.xconfigure.window == XtWindow (f->display.x->widget)))
3781 {
3782 Window win, child;
3783 int win_x, win_y;
3784
3785 /* Find the position of the outside upper-left corner of
3786 the window, in the root coordinate system. Don't
3787 refer to the parent window here; we may be processing
3788 this event after the window manager has changed our
3789 parent, but before we have reached the ReparentNotify. */
3790 XTranslateCoordinates (FRAME_X_DISPLAY (f),
3791
3792 /* From-window, to-window. */
3793 XtWindow (f->display.x->widget),
3794 FRAME_X_DISPLAY_INFO (f)->root_window,
3795
3796 /* From-position, to-position. */
3797 -event.xconfigure.border_width,
3798 -event.xconfigure.border_width,
3799 &win_x, &win_y,
3800
3801 /* Child of win. */
3802 &child);
3803 event.xconfigure.x = win_x;
3804 event.xconfigure.y = win_y;
3805
3806 f->display.x->pixel_width = event.xconfigure.width;
3807 f->display.x->pixel_height = event.xconfigure.height;
3808 f->display.x->left_pos = event.xconfigure.x;
3809 f->display.x->top_pos = event.xconfigure.y;
3810
3811 /* What we have now is the position of Emacs's own window.
3812 Convert that to the position of the window manager window. */
3813 {
3814 int x, y;
3815 x_real_positions (f, &x, &y);
3816 f->display.x->left_pos = x;
3817 f->display.x->top_pos = y;
3818 }
3819 }
3820 goto OTHER;
3821 #else /* not USE_X_TOOLKIT */
3822 if (f)
3823 {
3824 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
3825 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
3826
3827 /* Even if the number of character rows and columns has
3828 not changed, the font size may have changed, so we need
3829 to check the pixel dimensions as well. */
3830 if (columns != f->width
3831 || rows != f->height
3832 || event.xconfigure.width != f->display.x->pixel_width
3833 || event.xconfigure.height != f->display.x->pixel_height)
3834 {
3835 change_frame_size (f, rows, columns, 0, 1);
3836 SET_FRAME_GARBAGED (f);
3837 }
3838
3839 if (! event.xconfigure.send_event)
3840 {
3841 Window win, child;
3842 int win_x, win_y;
3843
3844 /* Find the position of the outside upper-left corner of
3845 the window, in the root coordinate system. Don't
3846 refer to the parent window here; we may be processing
3847 this event after the window manager has changed our
3848 parent, but before we have reached the ReparentNotify. */
3849 XTranslateCoordinates (FRAME_X_DISPLAY (f),
3850
3851 /* From-window, to-window. */
3852 f->display.x->window_desc,
3853 FRAME_X_DISPLAY_INFO (f)->root_window,
3854
3855 /* From-position, to-position. */
3856 -event.xconfigure.border_width,
3857 -event.xconfigure.border_width,
3858 &win_x, &win_y,
3859
3860 /* Child of win. */
3861 &child);
3862 event.xconfigure.x = win_x;
3863 event.xconfigure.y = win_y;
3864 }
3865
3866 f->display.x->pixel_width = event.xconfigure.width;
3867 f->display.x->pixel_height = event.xconfigure.height;
3868 f->display.x->left_pos = event.xconfigure.x;
3869 f->display.x->top_pos = event.xconfigure.y;
3870
3871 /* What we have now is the position of Emacs's own window.
3872 Convert that to the position of the window manager window. */
3873 {
3874 int x, y;
3875 x_real_positions (f, &x, &y);
3876 f->display.x->left_pos = x;
3877 f->display.x->top_pos = y;
3878 if (y != event.xconfigure.y)
3879 {
3880 /* Since the WM decorations come below top_pos now,
3881 we must put them below top_pos in the future. */
3882 f->display.x->win_gravity = NorthWestGravity;
3883 x_wm_set_size_hint (f, 0, 0);
3884 }
3885 }
3886 }
3887 #endif /* not USE_X_TOOLKIT */
3888 break;
3889
3890 case ButtonPress:
3891 case ButtonRelease:
3892 {
3893 /* If we decide we want to generate an event to be seen
3894 by the rest of Emacs, we put it here. */
3895 struct input_event emacs_event;
3896 emacs_event.kind = no_event;
3897
3898 bzero (&compose_status, sizeof (compose_status));
3899
3900 if (dpyinfo->grabbed && last_mouse_frame
3901 && FRAME_LIVE_P (last_mouse_frame))
3902 f = last_mouse_frame;
3903 else
3904 f = x_window_to_frame (event.xmotion.window);
3905
3906 if (f)
3907 {
3908 if (!x_focus_frame || (f == x_focus_frame))
3909 construct_mouse_click (&emacs_event, &event, f);
3910 }
3911 else
3912 {
3913 struct scroll_bar *bar
3914 = x_window_to_scroll_bar (event.xbutton.window);
3915
3916 if (bar)
3917 x_scroll_bar_handle_click (bar, &event, &emacs_event);
3918 #ifdef USE_X_TOOLKIT
3919 else
3920 {
3921 /* Assume we have a menubar button press. A bad
3922 assumption should behave benignly. */
3923 popup_get_selection (&event);
3924 break;
3925 }
3926 #endif /* USE_X_TOOLKIT */
3927 }
3928
3929 if (event.type == ButtonPress)
3930 {
3931 dpyinfo->grabbed |= (1 << event.xbutton.button);
3932 last_mouse_frame = f;
3933 }
3934 else
3935 {
3936 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3937 }
3938
3939 if (numchars >= 1 && emacs_event.kind != no_event)
3940 {
3941 bcopy (&emacs_event, bufp, sizeof (struct input_event));
3942 bufp++;
3943 count++;
3944 numchars--;
3945 }
3946
3947 #ifdef USE_X_TOOLKIT
3948 goto OTHER;
3949 #endif /* USE_X_TOOLKIT */
3950 }
3951 break;
3952
3953 case CirculateNotify:
3954 break;
3955 case CirculateRequest:
3956 break;
3957
3958 case MappingNotify:
3959 /* Someone has changed the keyboard mapping - update the
3960 local cache. */
3961 switch (event.xmapping.request)
3962 {
3963 case MappingModifier:
3964 x_find_modifier_meanings (dpyinfo);
3965 /* This is meant to fall through. */
3966 case MappingKeyboard:
3967 XRefreshKeyboardMapping (&event.xmapping);
3968 }
3969 #ifdef USE_X_TOOLKIT
3970 goto OTHER;
3971 #endif /* USE_X_TOOLKIT */
3972 break;
3973
3974 default:
3975 #ifdef USE_X_TOOLKIT
3976 OTHER:
3977 BLOCK_INPUT;
3978 XtDispatchEvent (&event);
3979 UNBLOCK_INPUT;
3980 #endif /* USE_X_TOOLKIT */
3981 break;
3982 }
3983 }
3984 }
3985
3986 /* On some systems, an X bug causes Emacs to get no more events
3987 when the window is destroyed. Detect that. (1994.) */
3988 if (! event_found)
3989 {
3990 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
3991 One XNOOP in 100 loops will make Emacs terminate.
3992 B. Bretthauer, 1994 */
3993 x_noop_count++;
3994 if (x_noop_count >= 100)
3995 {
3996 x_noop_count=0;
3997 /* Use the first display in the list. Why not? */
3998 XNoOp (x_display_list->display);
3999 }
4000 }
4001
4002 /* If the focus was just given to an autoraising frame,
4003 raise it now. */
4004 /* ??? This ought to be able to handle more than one such frame. */
4005 if (pending_autoraise_frame)
4006 {
4007 x_raise_frame (pending_autoraise_frame);
4008 pending_autoraise_frame = 0;
4009 }
4010
4011 UNBLOCK_INPUT;
4012 return count;
4013 }
4014 \f
4015 /* Drawing the cursor. */
4016
4017
4018 /* Draw a hollow box cursor. Don't change the inside of the box. */
4019
4020 static void
4021 x_draw_box (f)
4022 struct frame *f;
4023 {
4024 int left = CHAR_TO_PIXEL_COL (f, curs_x);
4025 int top = CHAR_TO_PIXEL_ROW (f, curs_y);
4026 int width = FONT_WIDTH (f->display.x->font);
4027 int height = f->display.x->line_height;
4028
4029 XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4030 f->display.x->cursor_gc,
4031 left, top, width - 1, height - 1);
4032 }
4033
4034 /* Clear the cursor of frame F to background color,
4035 and mark the cursor as not shown.
4036 This is used when the text where the cursor is
4037 is about to be rewritten. */
4038
4039 static void
4040 clear_cursor (f)
4041 struct frame *f;
4042 {
4043 int mask;
4044
4045 if (! FRAME_VISIBLE_P (f)
4046 || f->phys_cursor_x < 0)
4047 return;
4048
4049 x_display_cursor (f, 0);
4050 f->phys_cursor_x = -1;
4051 }
4052
4053 /* Redraw the glyph at ROW, COLUMN on frame F, in the style
4054 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
4055 glyph drawn. */
4056
4057 static void
4058 x_draw_single_glyph (f, row, column, glyph, highlight)
4059 struct frame *f;
4060 int row, column;
4061 GLYPH glyph;
4062 int highlight;
4063 {
4064 dumpglyphs (f,
4065 CHAR_TO_PIXEL_COL (f, column),
4066 CHAR_TO_PIXEL_ROW (f, row),
4067 &glyph, 1, highlight, 0);
4068 }
4069
4070 static void
4071 x_display_bar_cursor (f, on)
4072 struct frame *f;
4073 int on;
4074 {
4075 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4076
4077 /* This is pointless on invisible frames, and dangerous on garbaged
4078 frames; in the latter case, the frame may be in the midst of
4079 changing its size, and curs_x and curs_y may be off the frame. */
4080 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
4081 return;
4082
4083 if (! on && f->phys_cursor_x < 0)
4084 return;
4085
4086 /* If we're not updating, then we want to use the current frame's
4087 cursor position, not our local idea of where the cursor ought to be. */
4088 if (f != updating_frame)
4089 {
4090 curs_x = FRAME_CURSOR_X (f);
4091 curs_y = FRAME_CURSOR_Y (f);
4092 }
4093
4094 /* If there is anything wrong with the current cursor state, remove it. */
4095 if (f->phys_cursor_x >= 0
4096 && (!on
4097 || f->phys_cursor_x != curs_x
4098 || f->phys_cursor_y != curs_y
4099 || f->display.x->current_cursor != bar_cursor))
4100 {
4101 /* Erase the cursor by redrawing the character underneath it. */
4102 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4103 f->phys_cursor_glyph,
4104 current_glyphs->highlight[f->phys_cursor_y]);
4105 f->phys_cursor_x = -1;
4106 }
4107
4108 /* If we now need a cursor in the new place or in the new form, do it so. */
4109 if (on
4110 && (f->phys_cursor_x < 0
4111 || (f->display.x->current_cursor != bar_cursor)))
4112 {
4113 f->phys_cursor_glyph
4114 = ((current_glyphs->enable[curs_y]
4115 && curs_x < current_glyphs->used[curs_y])
4116 ? current_glyphs->glyphs[curs_y][curs_x]
4117 : SPACEGLYPH);
4118 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4119 f->display.x->cursor_gc,
4120 CHAR_TO_PIXEL_COL (f, curs_x),
4121 CHAR_TO_PIXEL_ROW (f, curs_y),
4122 max (f->display.x->cursor_width, 1),
4123 f->display.x->line_height);
4124
4125 f->phys_cursor_x = curs_x;
4126 f->phys_cursor_y = curs_y;
4127
4128 f->display.x->current_cursor = bar_cursor;
4129 }
4130
4131 if (updating_frame != f)
4132 XFlush (FRAME_X_DISPLAY (f));
4133 }
4134
4135
4136 /* Turn the displayed cursor of frame F on or off according to ON.
4137 If ON is nonzero, where to put the cursor is specified
4138 by F->cursor_x and F->cursor_y. */
4139
4140 static void
4141 x_display_box_cursor (f, on)
4142 struct frame *f;
4143 int on;
4144 {
4145 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4146
4147 /* This is pointless on invisible frames, and dangerous on garbaged
4148 frames; in the latter case, the frame may be in the midst of
4149 changing its size, and curs_x and curs_y may be off the frame. */
4150 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
4151 return;
4152
4153 /* If cursor is off and we want it off, return quickly. */
4154 if (!on && f->phys_cursor_x < 0)
4155 return;
4156
4157 /* If we're not updating, then we want to use the current frame's
4158 cursor position, not our local idea of where the cursor ought to be. */
4159 if (f != updating_frame)
4160 {
4161 curs_x = FRAME_CURSOR_X (f);
4162 curs_y = FRAME_CURSOR_Y (f);
4163 }
4164
4165 /* If cursor is currently being shown and we don't want it to be
4166 or it is in the wrong place,
4167 or we want a hollow box and it's not so, (pout!)
4168 erase it. */
4169 if (f->phys_cursor_x >= 0
4170 && (!on
4171 || f->phys_cursor_x != curs_x
4172 || f->phys_cursor_y != curs_y
4173 || (f->display.x->current_cursor != hollow_box_cursor
4174 && (f != x_highlight_frame))))
4175 {
4176 int mouse_face_here = 0;
4177 struct frame_glyphs *active_glyphs = FRAME_CURRENT_GLYPHS (f);
4178
4179 /* If the cursor is in the mouse face area, redisplay that when
4180 we clear the cursor. */
4181 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame
4182 &&
4183 (f->phys_cursor_y > FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
4184 || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
4185 && f->phys_cursor_x >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col))
4186 &&
4187 (f->phys_cursor_y < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
4188 || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
4189 && f->phys_cursor_x < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col))
4190 /* Don't redraw the cursor's spot in mouse face
4191 if it is at the end of a line (on a newline).
4192 The cursor appears there, but mouse highlighting does not. */
4193 && active_glyphs->used[f->phys_cursor_y] > f->phys_cursor_x)
4194 mouse_face_here = 1;
4195
4196 /* If the font is not as tall as a whole line,
4197 we must explicitly clear the line's whole height. */
4198 if (FONT_HEIGHT (f->display.x->font) != f->display.x->line_height)
4199 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4200 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
4201 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
4202 FONT_WIDTH (f->display.x->font),
4203 f->display.x->line_height, False);
4204 /* Erase the cursor by redrawing the character underneath it. */
4205 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4206 f->phys_cursor_glyph,
4207 (mouse_face_here
4208 ? 3
4209 : current_glyphs->highlight[f->phys_cursor_y]));
4210 f->phys_cursor_x = -1;
4211 }
4212
4213 /* If we want to show a cursor,
4214 or we want a box cursor and it's not so,
4215 write it in the right place. */
4216 if (on
4217 && (f->phys_cursor_x < 0
4218 || (f->display.x->current_cursor != filled_box_cursor
4219 && f == x_highlight_frame)))
4220 {
4221 f->phys_cursor_glyph
4222 = ((current_glyphs->enable[curs_y]
4223 && curs_x < current_glyphs->used[curs_y])
4224 ? current_glyphs->glyphs[curs_y][curs_x]
4225 : SPACEGLYPH);
4226 if (f != x_highlight_frame)
4227 {
4228 x_draw_box (f);
4229 f->display.x->current_cursor = hollow_box_cursor;
4230 }
4231 else
4232 {
4233 x_draw_single_glyph (f, curs_y, curs_x,
4234 f->phys_cursor_glyph, 2);
4235 f->display.x->current_cursor = filled_box_cursor;
4236 }
4237
4238 f->phys_cursor_x = curs_x;
4239 f->phys_cursor_y = curs_y;
4240 }
4241
4242 if (updating_frame != f)
4243 XFlush (FRAME_X_DISPLAY (f));
4244 }
4245
4246 x_display_cursor (f, on)
4247 struct frame *f;
4248 int on;
4249 {
4250 BLOCK_INPUT;
4251
4252 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
4253 x_display_box_cursor (f, on);
4254 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
4255 x_display_bar_cursor (f, on);
4256 else
4257 /* Those are the only two we have implemented! */
4258 abort ();
4259
4260 UNBLOCK_INPUT;
4261 }
4262 \f
4263 /* Icons. */
4264
4265 /* Refresh bitmap kitchen sink icon for frame F
4266 when we get an expose event for it. */
4267
4268 refreshicon (f)
4269 struct frame *f;
4270 {
4271 /* Normally, the window manager handles this function. */
4272 }
4273
4274 /* Make the x-window of frame F use the gnu icon bitmap. */
4275
4276 int
4277 x_bitmap_icon (f, file)
4278 struct frame *f;
4279 Lisp_Object file;
4280 {
4281 int mask, bitmap_id;
4282 Window icon_window;
4283
4284 if (FRAME_X_WINDOW (f) == 0)
4285 return 1;
4286
4287 /* Free up our existing icon bitmap if any. */
4288 if (f->display.x->icon_bitmap > 0)
4289 x_destroy_bitmap (f, f->display.x->icon_bitmap);
4290 f->display.x->icon_bitmap = 0;
4291
4292 if (STRINGP (file))
4293 bitmap_id = x_create_bitmap_from_file (f, file);
4294 else
4295 {
4296 /* Create the GNU bitmap if necessary. */
4297 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
4298 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
4299 = x_create_bitmap_from_data (f, gnu_bits,
4300 gnu_width, gnu_height);
4301
4302 /* The first time we create the GNU bitmap,
4303 this increments the refcount one extra time.
4304 As a result, the GNU bitmap is never freed.
4305 That way, we don't have to worry about allocating it again. */
4306 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
4307
4308 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
4309 }
4310
4311 x_wm_set_icon_pixmap (f, bitmap_id);
4312 f->display.x->icon_bitmap = bitmap_id;
4313
4314 return 0;
4315 }
4316
4317
4318 /* Make the x-window of frame F use a rectangle with text. */
4319
4320 int
4321 x_text_icon (f, icon_name)
4322 struct frame *f;
4323 char *icon_name;
4324 {
4325 if (FRAME_X_WINDOW (f) == 0)
4326 return 1;
4327
4328 if (icon_name)
4329 f->display.x->icon_label = icon_name;
4330 else
4331 if (! f->display.x->icon_label)
4332 f->display.x->icon_label = " *emacs* ";
4333
4334 #if 0
4335 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4336 (char *) f->display.x->icon_label);
4337 #endif
4338
4339 if (f->display.x->icon_bitmap > 0)
4340 x_destroy_bitmap (f, f->display.x->icon_bitmap);
4341 f->display.x->icon_bitmap = 0;
4342 x_wm_set_icon_pixmap (f, 0);
4343
4344 return 0;
4345 }
4346 \f
4347 /* Handling X errors. */
4348
4349 /* Handle the loss of connection to display DISPLAY. */
4350
4351 static SIGTYPE
4352 x_connection_closed (display, error_message)
4353 Display *display;
4354 char *error_message;
4355 {
4356 struct x_display_info *dpyinfo = x_display_info_for_display (display);
4357 Lisp_Object frame, tail;
4358
4359 if (_Xdebug)
4360 abort ();
4361
4362 /* First delete frames whose minibuffers are on frames
4363 that are on the dead display. */
4364 FOR_EACH_FRAME (tail, frame)
4365 {
4366 Lisp_Object minibuf_frame;
4367 minibuf_frame
4368 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
4369 if (FRAME_X_P (XFRAME (frame))
4370 && FRAME_X_P (XFRAME (minibuf_frame))
4371 && ! EQ (frame, minibuf_frame)
4372 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
4373 Fdelete_frame (frame, Qt);
4374 }
4375
4376 /* Now delete all remaining frames on the dead display.
4377 We are now sure none of these is used as the minibuffer
4378 for another frame that we need to delete. */
4379 FOR_EACH_FRAME (tail, frame)
4380 if (FRAME_X_P (XFRAME (frame))
4381 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
4382 Fdelete_frame (frame, Qt);
4383
4384 x_delete_display (dpyinfo);
4385
4386 if (x_display_list == 0)
4387 {
4388 fprintf (stderr, "%s", error_message);
4389 shut_down_emacs (0, 0, Qnil);
4390 exit (70);
4391 }
4392
4393 /* Ordinary stack unwind doesn't deal with these. */
4394 #ifdef SIGIO
4395 sigunblock (sigmask (SIGIO));
4396 #endif
4397 sigunblock (sigmask (SIGALRM));
4398 TOTALLY_UNBLOCK_INPUT;
4399
4400 error ("%s", error_message);
4401 }
4402
4403 static SIGTYPE
4404 x_connection_signal (signalnum) /* If we don't have an argument, */
4405 int signalnum; /* some compilers complain in signal calls. */
4406 {
4407 /* We really ought to close the connection to the display
4408 that actually failed.
4409 But do we actually get this signal ever with X11? */
4410 fprintf (stderr, "X connection closed");
4411 shut_down_emacs (0, 0, Qnil);
4412 exit (70);
4413 }
4414
4415 /* This is the usual handler for X protocol errors.
4416 It kills all frames on the display that we got the error for.
4417 If that was the only one, it prints an error message and kills Emacs. */
4418
4419 static int
4420 x_error_quitter (display, error)
4421 Display *display;
4422 XErrorEvent *error;
4423 {
4424 char buf[256], buf1[356];
4425
4426 /* Note that there is no real way portable across R3/R4 to get the
4427 original error handler. */
4428
4429 XGetErrorText (display, error->error_code, buf, sizeof (buf));
4430 sprintf (buf1, "X protocol error: %s on protocol request %d",
4431 buf, error->request_code);
4432 x_connection_closed (display, buf1);
4433 }
4434
4435 /* This is the handler for X IO errors, always.
4436 It kills all frames on the display that we lost touch with.
4437 If that was the only one, it prints an error message and kills Emacs. */
4438
4439 static int
4440 x_io_error_quitter (display)
4441 Display *display;
4442 {
4443 char buf[256];
4444
4445 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
4446 x_connection_closed (display, buf);
4447 }
4448 \f
4449 /* A buffer for storing X error messages. */
4450 static char *x_caught_error_message;
4451 #define X_CAUGHT_ERROR_MESSAGE_SIZE 200
4452
4453 /* An X error handler which stores the error message in
4454 x_caught_error_message. This is what's installed when
4455 x_catch_errors is in effect. */
4456
4457 static int
4458 x_error_catcher (display, error)
4459 Display *display;
4460 XErrorEvent *error;
4461 {
4462 XGetErrorText (display, error->error_code,
4463 x_caught_error_message, X_CAUGHT_ERROR_MESSAGE_SIZE);
4464 }
4465
4466
4467 /* Begin trapping X errors for display DPY. Actually we trap X errors
4468 for all displays, but DPY should be the display you are actually
4469 operating on.
4470
4471 After calling this function, X protocol errors no longer cause
4472 Emacs to exit; instead, they are recorded in x_cfc_error_message.
4473
4474 Calling x_check_errors signals an Emacs error if an X error has
4475 occurred since the last call to x_catch_errors or x_check_errors.
4476
4477 Calling x_uncatch_errors resumes the normal error handling. */
4478
4479 void x_catch_errors (), x_check_errors (), x_uncatch_errors ();
4480
4481 void
4482 x_catch_errors (dpy)
4483 Display *dpy;
4484 {
4485 /* Make sure any errors from previous requests have been dealt with. */
4486 XSync (dpy, False);
4487
4488 /* Set up the error buffer. */
4489 x_caught_error_message
4490 = (char*) xmalloc (X_CAUGHT_ERROR_MESSAGE_SIZE);
4491 x_caught_error_message[0] = '\0';
4492
4493 /* Install our little error handler. */
4494 XSetErrorHandler (x_error_catcher);
4495 }
4496
4497 /* If any X protocol errors have arrived since the last call to
4498 x_catch_errors or x_check_errors, signal an Emacs error using
4499 sprintf (a buffer, FORMAT, the x error message text) as the text. */
4500
4501 void
4502 x_check_errors (dpy, format)
4503 Display *dpy;
4504 char *format;
4505 {
4506 /* Make sure to catch any errors incurred so far. */
4507 XSync (dpy, False);
4508
4509 if (x_caught_error_message[0])
4510 {
4511 char buf[X_CAUGHT_ERROR_MESSAGE_SIZE + 56];
4512
4513 sprintf (buf, format, x_caught_error_message);
4514 x_uncatch_errors (dpy);
4515 error (buf);
4516 }
4517 }
4518
4519 /* Nonzero if we had any X protocol errors since we did x_catch_errors. */
4520
4521 int
4522 x_had_errors_p (dpy)
4523 Display *dpy;
4524 {
4525 /* Make sure to catch any errors incurred so far. */
4526 XSync (dpy, False);
4527
4528 return x_caught_error_message[0] != 0;
4529 }
4530
4531 /* Stop catching X protocol errors and let them make Emacs die. */
4532
4533 void
4534 x_uncatch_errors (dpy)
4535 Display *dpy;
4536 {
4537 xfree (x_caught_error_message);
4538 x_caught_error_message = 0;
4539 XSetErrorHandler (x_error_quitter);
4540 }
4541
4542 #if 0
4543 static unsigned int x_wire_count;
4544 x_trace_wire ()
4545 {
4546 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
4547 }
4548 #endif /* ! 0 */
4549
4550 \f
4551 /* Changing the font of the frame. */
4552
4553 /* Give frame F the font named FONTNAME as its default font, and
4554 return the full name of that font. FONTNAME may be a wildcard
4555 pattern; in that case, we choose some font that fits the pattern.
4556 The return value shows which font we chose. */
4557
4558 Lisp_Object
4559 x_new_font (f, fontname)
4560 struct frame *f;
4561 register char *fontname;
4562 {
4563 int already_loaded;
4564 int n_matching_fonts;
4565 XFontStruct *font_info;
4566 char **font_names;
4567
4568 /* Get a list of all the fonts that match this name. Once we
4569 have a list of matching fonts, we compare them against the fonts
4570 we already have by comparing font ids. */
4571 font_names = (char **) XListFonts (FRAME_X_DISPLAY (f), fontname,
4572 1024, &n_matching_fonts);
4573 /* Apparently it doesn't set n_matching_fonts to zero when it can't
4574 find any matches; font_names == 0 is the only clue. */
4575 if (! font_names)
4576 n_matching_fonts = 0;
4577
4578 /* Don't just give up if n_matching_fonts is 0.
4579 Apparently there's a bug on Suns: XListFontsWithInfo can
4580 fail to find a font, but XLoadQueryFont may still find it. */
4581
4582 /* See if we've already loaded a matching font. */
4583 already_loaded = -1;
4584 if (n_matching_fonts != 0)
4585 {
4586 int i, j;
4587
4588 for (i = 0; i < FRAME_X_DISPLAY_INFO (f)->n_fonts; i++)
4589 for (j = 0; j < n_matching_fonts; j++)
4590 if (!strcmp (FRAME_X_DISPLAY_INFO (f)->font_table[i].name, font_names[j])
4591 || !strcmp (FRAME_X_DISPLAY_INFO (f)->font_table[i].full_name, font_names[j]))
4592 {
4593 already_loaded = i;
4594 fontname = FRAME_X_DISPLAY_INFO (f)->font_table[i].full_name;
4595 goto found_font;
4596 }
4597 }
4598 found_font:
4599
4600 /* If we have, just return it from the table. */
4601 if (already_loaded >= 0)
4602 f->display.x->font = FRAME_X_DISPLAY_INFO (f)->font_table[already_loaded].font;
4603 /* Otherwise, load the font and add it to the table. */
4604 else
4605 {
4606 int i;
4607 char *full_name;
4608 XFontStruct *font;
4609 int n_fonts;
4610
4611 /* Try to find a character-cell font in the list. */
4612 #if 0
4613 /* A laudable goal, but this isn't how to do it. */
4614 for (i = 0; i < n_matching_fonts; i++)
4615 if (! font_info[i].per_char)
4616 break;
4617 #else
4618 i = 0;
4619 #endif
4620
4621 /* See comment above. */
4622 if (n_matching_fonts != 0)
4623 fontname = font_names[i];
4624
4625 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
4626 if (! font)
4627 {
4628 /* Free the information from XListFonts. */
4629 if (n_matching_fonts)
4630 XFreeFontNames (font_names);
4631 return Qnil;
4632 }
4633
4634 /* Do we need to create the table? */
4635 if (FRAME_X_DISPLAY_INFO (f)->font_table_size == 0)
4636 {
4637 FRAME_X_DISPLAY_INFO (f)->font_table_size = 16;
4638 FRAME_X_DISPLAY_INFO (f)->font_table
4639 = (struct font_info *) xmalloc (FRAME_X_DISPLAY_INFO (f)->font_table_size
4640 * sizeof (struct font_info));
4641 }
4642 /* Do we need to grow the table? */
4643 else if (FRAME_X_DISPLAY_INFO (f)->n_fonts
4644 >= FRAME_X_DISPLAY_INFO (f)->font_table_size)
4645 {
4646 FRAME_X_DISPLAY_INFO (f)->font_table_size *= 2;
4647 FRAME_X_DISPLAY_INFO (f)->font_table
4648 = (struct font_info *) xrealloc (FRAME_X_DISPLAY_INFO (f)->font_table,
4649 (FRAME_X_DISPLAY_INFO (f)->font_table_size
4650 * sizeof (struct font_info)));
4651 }
4652
4653 /* Try to get the full name of FONT. Put it in full_name. */
4654 full_name = 0;
4655 for (i = 0; i < font->n_properties; i++)
4656 {
4657 char *atom
4658 = XGetAtomName (FRAME_X_DISPLAY (f), font->properties[i].name);
4659 if (!strcmp (atom, "FONT"))
4660 {
4661 char *name = XGetAtomName (FRAME_X_DISPLAY (f),
4662 (Atom) (font->properties[i].card32));
4663 char *p = name;
4664 int dashes = 0;
4665
4666 /* Count the number of dashes in the "full name".
4667 If it is too few, this isn't really the font's full name,
4668 so don't use it.
4669 In X11R4, the fonts did not come with their canonical names
4670 stored in them. */
4671 while (*p)
4672 {
4673 if (*p == '-')
4674 dashes++;
4675 p++;
4676 }
4677
4678 if (dashes >= 13)
4679 full_name = name;
4680
4681 break;
4682 }
4683
4684 XFree (atom);
4685 }
4686
4687 n_fonts = FRAME_X_DISPLAY_INFO (f)->n_fonts;
4688 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name = (char *) xmalloc (strlen (fontname) + 1);
4689 bcopy (fontname, FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name, strlen (fontname) + 1);
4690 if (full_name != 0)
4691 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].full_name = full_name;
4692 else
4693 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].full_name = FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name;
4694 f->display.x->font = FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].font = font;
4695 FRAME_X_DISPLAY_INFO (f)->n_fonts++;
4696
4697 if (full_name)
4698 fontname = full_name;
4699 }
4700
4701 /* Compute the scroll bar width in character columns. */
4702 if (f->scroll_bar_pixel_width > 0)
4703 {
4704 int wid = FONT_WIDTH (f->display.x->font);
4705 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
4706 }
4707 else
4708 f->scroll_bar_cols = 2;
4709
4710 /* Now make the frame display the given font. */
4711 if (FRAME_X_WINDOW (f) != 0)
4712 {
4713 XSetFont (FRAME_X_DISPLAY (f), f->display.x->normal_gc,
4714 f->display.x->font->fid);
4715 XSetFont (FRAME_X_DISPLAY (f), f->display.x->reverse_gc,
4716 f->display.x->font->fid);
4717 XSetFont (FRAME_X_DISPLAY (f), f->display.x->cursor_gc,
4718 f->display.x->font->fid);
4719
4720 frame_update_line_height (f);
4721 x_set_window_size (f, 0, f->width, f->height);
4722 }
4723 else
4724 /* If we are setting a new frame's font for the first time,
4725 there are no faces yet, so this font's height is the line height. */
4726 f->display.x->line_height = FONT_HEIGHT (f->display.x->font);
4727
4728 {
4729 Lisp_Object lispy_name;
4730
4731 lispy_name = build_string (fontname);
4732
4733 /* Free the information from XListFonts. The data
4734 we actually retain comes from XLoadQueryFont. */
4735 XFreeFontNames (font_names);
4736
4737 return lispy_name;
4738 }
4739 }
4740 \f
4741 x_calc_absolute_position (f)
4742 struct frame *f;
4743 {
4744 Window win, child;
4745 int win_x = 0, win_y = 0;
4746 int flags = f->display.x->size_hint_flags;
4747
4748 /* Find the position of the outside upper-left corner of
4749 the inner window, with respect to the outer window. */
4750 if (f->display.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
4751 {
4752 BLOCK_INPUT;
4753 XTranslateCoordinates (FRAME_X_DISPLAY (f),
4754
4755 /* From-window, to-window. */
4756 f->display.x->window_desc,
4757 f->display.x->parent_desc,
4758
4759 /* From-position, to-position. */
4760 0, 0, &win_x, &win_y,
4761
4762 /* Child of win. */
4763 &child);
4764 UNBLOCK_INPUT;
4765 }
4766
4767 /* Treat negative positions as relative to the leftmost bottommost
4768 position that fits on the screen. */
4769 if (flags & XNegative)
4770 f->display.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
4771 - 2 * f->display.x->border_width - win_x
4772 - PIXEL_WIDTH (f)
4773 + f->display.x->left_pos);
4774
4775 if (flags & YNegative)
4776 f->display.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
4777 - 2 * f->display.x->border_width - win_y
4778 - PIXEL_HEIGHT (f)
4779 + f->display.x->top_pos);
4780 /* The left_pos and top_pos
4781 are now relative to the top and left screen edges,
4782 so the flags should correspond. */
4783 f->display.x->size_hint_flags &= ~ (XNegative | YNegative);
4784 }
4785
4786 /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
4787 to really change the position, and 0 when calling from
4788 x_make_frame_visible (in that case, XOFF and YOFF are the current
4789 position values). */
4790
4791 x_set_offset (f, xoff, yoff, change_gravity)
4792 struct frame *f;
4793 register int xoff, yoff;
4794 int change_gravity;
4795 {
4796 if (change_gravity)
4797 {
4798 f->display.x->top_pos = yoff;
4799 f->display.x->left_pos = xoff;
4800 f->display.x->size_hint_flags &= ~ (XNegative | YNegative);
4801 if (xoff < 0)
4802 f->display.x->size_hint_flags |= XNegative;
4803 if (yoff < 0)
4804 f->display.x->size_hint_flags |= YNegative;
4805 f->display.x->win_gravity = NorthWestGravity;
4806 }
4807 x_calc_absolute_position (f);
4808
4809 BLOCK_INPUT;
4810 x_wm_set_size_hint (f, 0, 0);
4811
4812 #ifdef USE_X_TOOLKIT
4813 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget),
4814 f->display.x->left_pos, f->display.x->top_pos);
4815 #else /* not USE_X_TOOLKIT */
4816 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4817 f->display.x->left_pos, f->display.x->top_pos);
4818 #endif /* not USE_X_TOOLKIT */
4819 UNBLOCK_INPUT;
4820 }
4821
4822 /* Call this to change the size of frame F's x-window.
4823 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
4824 for this size change and subsequent size changes.
4825 Otherwise we leave the window gravity unchanged. */
4826
4827 x_set_window_size (f, change_gravity, cols, rows)
4828 struct frame *f;
4829 int change_gravity;
4830 int cols, rows;
4831 {
4832 int pixelwidth, pixelheight;
4833 int mask;
4834
4835 #ifdef USE_X_TOOLKIT
4836 BLOCK_INPUT;
4837 {
4838 /* The x and y position of the widget is clobbered by the
4839 call to XtSetValues within EmacsFrameSetCharSize.
4840 This is a real kludge, but I don't understand Xt so I can't
4841 figure out a correct fix. Can anyone else tell me? -- rms. */
4842 int xpos = f->display.x->widget->core.x;
4843 int ypos = f->display.x->widget->core.y;
4844 EmacsFrameSetCharSize (f->display.x->edit_widget, cols, rows);
4845 f->display.x->widget->core.x = xpos;
4846 f->display.x->widget->core.y = ypos;
4847 }
4848 UNBLOCK_INPUT;
4849
4850 #else /* not USE_X_TOOLKIT */
4851
4852 BLOCK_INPUT;
4853
4854 check_frame_size (f, &rows, &cols);
4855 f->display.x->vertical_scroll_bar_extra
4856 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4857 ? 0
4858 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
4859 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
4860 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->display.x->font)));
4861 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
4862 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
4863
4864 f->display.x->win_gravity = NorthWestGravity;
4865 x_wm_set_size_hint (f, 0, 0);
4866
4867 XSync (FRAME_X_DISPLAY (f), False);
4868 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4869 pixelwidth, pixelheight);
4870
4871 /* Now, strictly speaking, we can't be sure that this is accurate,
4872 but the window manager will get around to dealing with the size
4873 change request eventually, and we'll hear how it went when the
4874 ConfigureNotify event gets here.
4875
4876 We could just not bother storing any of this information here,
4877 and let the ConfigureNotify event set everything up, but that
4878 might be kind of confusing to the lisp code, since size changes
4879 wouldn't be reported in the frame parameters until some random
4880 point in the future when the ConfigureNotify event arrives. */
4881 change_frame_size (f, rows, cols, 0, 0);
4882 PIXEL_WIDTH (f) = pixelwidth;
4883 PIXEL_HEIGHT (f) = pixelheight;
4884
4885 /* If cursor was outside the new size, mark it as off. */
4886 if (f->phys_cursor_y >= rows
4887 || f->phys_cursor_x >= cols)
4888 {
4889 f->phys_cursor_x = -1;
4890 f->phys_cursor_y = -1;
4891 }
4892
4893 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
4894 receive in the ConfigureNotify event; if we get what we asked
4895 for, then the event won't cause the screen to become garbaged, so
4896 we have to make sure to do it here. */
4897 SET_FRAME_GARBAGED (f);
4898
4899 XFlush (FRAME_X_DISPLAY (f));
4900 UNBLOCK_INPUT;
4901 #endif /* not USE_X_TOOLKIT */
4902 }
4903 \f
4904 /* Mouse warping, focus shifting, raising and lowering. */
4905
4906 void
4907 x_set_mouse_position (f, x, y)
4908 struct frame *f;
4909 int x, y;
4910 {
4911 int pix_x, pix_y;
4912
4913 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2;
4914 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->display.x->line_height / 2;
4915
4916 if (pix_x < 0) pix_x = 0;
4917 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
4918
4919 if (pix_y < 0) pix_y = 0;
4920 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
4921
4922 BLOCK_INPUT;
4923
4924 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
4925 0, 0, 0, 0, pix_x, pix_y);
4926 UNBLOCK_INPUT;
4927 }
4928
4929 /* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
4930
4931 void
4932 x_set_mouse_pixel_position (f, pix_x, pix_y)
4933 struct frame *f;
4934 int pix_x, pix_y;
4935 {
4936 BLOCK_INPUT;
4937
4938 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
4939 0, 0, 0, 0, pix_x, pix_y);
4940 UNBLOCK_INPUT;
4941 }
4942
4943 x_focus_on_frame (f)
4944 struct frame *f;
4945 {
4946 #if 0 /* This proves to be unpleasant. */
4947 x_raise_frame (f);
4948 #endif
4949 #if 0
4950 /* I don't think that the ICCCM allows programs to do things like this
4951 without the interaction of the window manager. Whatever you end up
4952 doing with this code, do it to x_unfocus_frame too. */
4953 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4954 RevertToPointerRoot, CurrentTime);
4955 #endif /* ! 0 */
4956 }
4957
4958 x_unfocus_frame (f)
4959 struct frame *f;
4960 {
4961 #if 0
4962 /* Look at the remarks in x_focus_on_frame. */
4963 if (x_focus_frame == f)
4964 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
4965 RevertToPointerRoot, CurrentTime);
4966 #endif /* ! 0 */
4967 }
4968
4969 /* Raise frame F. */
4970
4971 x_raise_frame (f)
4972 struct frame *f;
4973 {
4974 if (f->async_visible)
4975 {
4976 BLOCK_INPUT;
4977 #ifdef USE_X_TOOLKIT
4978 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget));
4979 #else /* not USE_X_TOOLKIT */
4980 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
4981 #endif /* not USE_X_TOOLKIT */
4982 XFlush (FRAME_X_DISPLAY (f));
4983 UNBLOCK_INPUT;
4984 }
4985 }
4986
4987 /* Lower frame F. */
4988
4989 x_lower_frame (f)
4990 struct frame *f;
4991 {
4992 if (f->async_visible)
4993 {
4994 BLOCK_INPUT;
4995 #ifdef USE_X_TOOLKIT
4996 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget));
4997 #else /* not USE_X_TOOLKIT */
4998 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
4999 #endif /* not USE_X_TOOLKIT */
5000 XFlush (FRAME_X_DISPLAY (f));
5001 UNBLOCK_INPUT;
5002 }
5003 }
5004
5005 static void
5006 XTframe_raise_lower (f, raise)
5007 FRAME_PTR f;
5008 int raise;
5009 {
5010 if (raise)
5011 x_raise_frame (f);
5012 else
5013 x_lower_frame (f);
5014 }
5015
5016 /* Change from withdrawn state to mapped state,
5017 or deiconify. */
5018
5019 x_make_frame_visible (f)
5020 struct frame *f;
5021 {
5022 int mask;
5023 Lisp_Object type;
5024
5025 BLOCK_INPUT;
5026
5027 type = x_icon_type (f);
5028 if (!NILP (type))
5029 x_bitmap_icon (f, type);
5030
5031 if (! FRAME_VISIBLE_P (f))
5032 {
5033 #ifndef USE_X_TOOLKIT
5034 if (! FRAME_ICONIFIED_P (f))
5035 x_set_offset (f, f->display.x->left_pos, f->display.x->top_pos, 0);
5036 #endif
5037
5038 if (! EQ (Vx_no_window_manager, Qt))
5039 x_wm_set_window_state (f, NormalState);
5040 #ifdef USE_X_TOOLKIT
5041 /* This was XtPopup, but that did nothing for an iconified frame. */
5042 XtMapWidget (f->display.x->widget);
5043 #else /* not USE_X_TOOLKIT */
5044 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5045 #endif /* not USE_X_TOOLKIT */
5046 #if 0 /* This seems to bring back scroll bars in the wrong places
5047 if the window configuration has changed. They seem
5048 to come back ok without this. */
5049 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5050 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5051 #endif
5052 }
5053
5054 XFlush (FRAME_X_DISPLAY (f));
5055
5056 /* Synchronize to ensure Emacs knows the frame is visible
5057 before we do anything else. We do this loop with input not blocked
5058 so that incoming events are handled. */
5059 {
5060 Lisp_Object frame;
5061 int count = input_signal_count;
5062
5063 /* This must come after we set COUNT. */
5064 UNBLOCK_INPUT;
5065
5066 XSETFRAME (frame, f);
5067
5068 while (1)
5069 {
5070 x_sync (f);
5071 /* Once we have handled input events,
5072 we should have received the MapNotify if one is coming.
5073 So if we have not got it yet, stop looping.
5074 Some window managers make their own decisions
5075 about visibility. */
5076 if (input_signal_count != count)
5077 break;
5078 /* Machines that do polling rather than SIGIO have been observed
5079 to go into a busy-wait here. So we'll fake an alarm signal
5080 to let the handler know that there's something to be read.
5081 We used to raise a real alarm, but it seems that the handler
5082 isn't always enabled here. This is probably a bug. */
5083 if (input_polling_used ())
5084 {
5085 /* It could be confusing if a real alarm arrives while processing
5086 the fake one. Turn it off and let the handler reset it. */
5087 alarm (0);
5088 input_poll_signal ();
5089 }
5090 /* Once we have handled input events,
5091 we should have received the MapNotify if one is coming.
5092 So if we have not got it yet, stop looping.
5093 Some window managers make their own decisions
5094 about visibility. */
5095 if (input_signal_count != count)
5096 break;
5097 }
5098 FRAME_SAMPLE_VISIBILITY (f);
5099 }
5100 }
5101
5102 /* Change from mapped state to withdrawn state. */
5103
5104 x_make_frame_invisible (f)
5105 struct frame *f;
5106 {
5107 int mask;
5108 Window window;
5109
5110 #ifdef USE_X_TOOLKIT
5111 /* Use the frame's outermost window, not the one we normally draw on. */
5112 window = XtWindow (f->display.x->widget);
5113 #else /* not USE_X_TOOLKIT */
5114 window = FRAME_X_WINDOW (f);
5115 #endif /* not USE_X_TOOLKIT */
5116
5117 /* Don't keep the highlight on an invisible frame. */
5118 if (x_highlight_frame == f)
5119 x_highlight_frame = 0;
5120
5121 #if 0/* This might add unreliability; I don't trust it -- rms. */
5122 if (! f->async_visible && ! f->async_iconified)
5123 return;
5124 #endif
5125
5126 BLOCK_INPUT;
5127
5128 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
5129 that the current position of the window is user-specified, rather than
5130 program-specified, so that when the window is mapped again, it will be
5131 placed at the same location, without forcing the user to position it
5132 by hand again (they have already done that once for this window.) */
5133 x_wm_set_size_hint (f, 0, 1);
5134
5135 #ifdef HAVE_X11R4
5136
5137 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
5138 DefaultScreen (FRAME_X_DISPLAY (f))))
5139 {
5140 UNBLOCK_INPUT_RESIGNAL;
5141 error ("Can't notify window manager of window withdrawal");
5142 }
5143 #else /* ! defined (HAVE_X11R4) */
5144
5145 /* Tell the window manager what we're going to do. */
5146 if (! EQ (Vx_no_window_manager, Qt))
5147 {
5148 XEvent unmap;
5149
5150 unmap.xunmap.type = UnmapNotify;
5151 unmap.xunmap.window = window;
5152 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
5153 unmap.xunmap.from_configure = False;
5154 if (! XSendEvent (FRAME_X_DISPLAY (f),
5155 DefaultRootWindow (FRAME_X_DISPLAY (f)),
5156 False,
5157 SubstructureRedirectMask|SubstructureNotifyMask,
5158 &unmap))
5159 {
5160 UNBLOCK_INPUT_RESIGNAL;
5161 error ("Can't notify window manager of withdrawal");
5162 }
5163 }
5164
5165 /* Unmap the window ourselves. Cheeky! */
5166 XUnmapWindow (FRAME_X_DISPLAY (f), window);
5167 #endif /* ! defined (HAVE_X11R4) */
5168
5169 /* We can't distinguish this from iconification
5170 just by the event that we get from the server.
5171 So we can't win using the usual strategy of letting
5172 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
5173 and synchronize with the server to make sure we agree. */
5174 f->visible = 0;
5175 FRAME_ICONIFIED_P (f) = 0;
5176 f->async_visible = 0;
5177 f->async_iconified = 0;
5178
5179 x_sync (f);
5180
5181 UNBLOCK_INPUT;
5182 }
5183
5184 /* Change window state from mapped to iconified. */
5185
5186 x_iconify_frame (f)
5187 struct frame *f;
5188 {
5189 int mask;
5190 int result;
5191 Lisp_Object type;
5192
5193 /* Don't keep the highlight on an invisible frame. */
5194 if (x_highlight_frame == f)
5195 x_highlight_frame = 0;
5196
5197 if (f->async_iconified)
5198 return;
5199
5200 BLOCK_INPUT;
5201
5202 type = x_icon_type (f);
5203 if (!NILP (type))
5204 x_bitmap_icon (f, type);
5205
5206 #ifdef USE_X_TOOLKIT
5207
5208 if (! FRAME_VISIBLE_P (f))
5209 {
5210 if (! EQ (Vx_no_window_manager, Qt))
5211 x_wm_set_window_state (f, IconicState);
5212 /* This was XtPopup, but that did nothing for an iconified frame. */
5213 XtMapWidget (f->display.x->widget);
5214 UNBLOCK_INPUT;
5215 return;
5216 }
5217
5218 result = XIconifyWindow (FRAME_X_DISPLAY (f),
5219 XtWindow (f->display.x->widget),
5220 DefaultScreen (FRAME_X_DISPLAY (f)));
5221 UNBLOCK_INPUT;
5222
5223 if (!result)
5224 error ("Can't notify window manager of iconification");
5225
5226 f->async_iconified = 1;
5227
5228 BLOCK_INPUT;
5229 XFlush (FRAME_X_DISPLAY (f));
5230 UNBLOCK_INPUT;
5231 #else /* not USE_X_TOOLKIT */
5232
5233 /* Make sure the X server knows where the window should be positioned,
5234 in case the user deiconifies with the window manager. */
5235 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
5236 x_set_offset (f, f->display.x->left_pos, f->display.x->top_pos, 0);
5237
5238 /* Since we don't know which revision of X we're running, we'll use both
5239 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
5240
5241 /* X11R4: send a ClientMessage to the window manager using the
5242 WM_CHANGE_STATE type. */
5243 {
5244 XEvent message;
5245
5246 message.xclient.window = FRAME_X_WINDOW (f);
5247 message.xclient.type = ClientMessage;
5248 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
5249 message.xclient.format = 32;
5250 message.xclient.data.l[0] = IconicState;
5251
5252 if (! XSendEvent (FRAME_X_DISPLAY (f),
5253 DefaultRootWindow (FRAME_X_DISPLAY (f)),
5254 False,
5255 SubstructureRedirectMask | SubstructureNotifyMask,
5256 &message))
5257 {
5258 UNBLOCK_INPUT_RESIGNAL;
5259 error ("Can't notify window manager of iconification");
5260 }
5261 }
5262
5263 /* X11R3: set the initial_state field of the window manager hints to
5264 IconicState. */
5265 x_wm_set_window_state (f, IconicState);
5266
5267 if (!FRAME_VISIBLE_P (f))
5268 {
5269 /* If the frame was withdrawn, before, we must map it. */
5270 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5271 }
5272
5273 f->async_iconified = 1;
5274
5275 XFlush (FRAME_X_DISPLAY (f));
5276 UNBLOCK_INPUT;
5277 #endif /* not USE_X_TOOLKIT */
5278 }
5279
5280 /* Destroy the X window of frame F. */
5281
5282 x_destroy_window (f)
5283 struct frame *f;
5284 {
5285 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5286
5287 BLOCK_INPUT;
5288
5289 if (f->display.x->icon_desc != 0)
5290 XDestroyWindow (FRAME_X_DISPLAY (f), f->display.x->icon_desc);
5291 XDestroyWindow (FRAME_X_DISPLAY (f), f->display.x->window_desc);
5292 #ifdef USE_X_TOOLKIT
5293 XtDestroyWidget (f->display.x->widget);
5294 free_frame_menubar (f);
5295 #endif /* USE_X_TOOLKIT */
5296
5297 free_frame_faces (f);
5298 XFlush (FRAME_X_DISPLAY (f));
5299
5300 xfree (f->display.x);
5301 f->display.x = 0;
5302 if (f == x_focus_frame)
5303 x_focus_frame = 0;
5304 if (f == x_focus_event_frame)
5305 x_focus_event_frame = 0;
5306 if (f == x_highlight_frame)
5307 x_highlight_frame = 0;
5308
5309 dpyinfo->reference_count--;
5310
5311 if (f == dpyinfo->mouse_face_mouse_frame)
5312 {
5313 dpyinfo->mouse_face_beg_row
5314 = dpyinfo->mouse_face_beg_col = -1;
5315 dpyinfo->mouse_face_end_row
5316 = dpyinfo->mouse_face_end_col = -1;
5317 dpyinfo->mouse_face_window = Qnil;
5318 }
5319
5320 UNBLOCK_INPUT;
5321 }
5322 \f
5323 /* Setting window manager hints. */
5324
5325 /* Set the normal size hints for the window manager, for frame F.
5326 FLAGS is the flags word to use--or 0 meaning preserve the flags
5327 that the window now has.
5328 If USER_POSITION is nonzero, we set the USPosition
5329 flag (this is useful when FLAGS is 0). */
5330
5331 x_wm_set_size_hint (f, flags, user_position)
5332 struct frame *f;
5333 long flags;
5334 int user_position;
5335 {
5336 XSizeHints size_hints;
5337
5338 #ifdef USE_X_TOOLKIT
5339 Arg al[2];
5340 int ac = 0;
5341 Dimension widget_width, widget_height;
5342 Window window = XtWindow (f->display.x->widget);
5343 #else /* not USE_X_TOOLKIT */
5344 Window window = FRAME_X_WINDOW (f);
5345 #endif /* not USE_X_TOOLKIT */
5346
5347 /* Setting PMaxSize caused various problems. */
5348 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
5349
5350 flexlines = f->height;
5351
5352 size_hints.x = f->display.x->left_pos;
5353 size_hints.y = f->display.x->top_pos;
5354
5355 #ifdef USE_X_TOOLKIT
5356 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
5357 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
5358 XtGetValues (f->display.x->column_widget, al, ac);
5359 size_hints.height = widget_height;
5360 size_hints.width = widget_width;
5361 #else /* not USE_X_TOOLKIT */
5362 size_hints.height = PIXEL_HEIGHT (f);
5363 size_hints.width = PIXEL_WIDTH (f);
5364 #endif /* not USE_X_TOOLKIT */
5365
5366 size_hints.width_inc = FONT_WIDTH (f->display.x->font);
5367 size_hints.height_inc = f->display.x->line_height;
5368 size_hints.max_width
5369 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
5370 size_hints.max_height
5371 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
5372
5373 {
5374 int base_width, base_height;
5375 int min_rows = 0, min_cols = 0;
5376
5377 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
5378 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
5379
5380 check_frame_size (f, &min_rows, &min_cols);
5381
5382 /* The window manager uses the base width hints to calculate the
5383 current number of rows and columns in the frame while
5384 resizing; min_width and min_height aren't useful for this
5385 purpose, since they might not give the dimensions for a
5386 zero-row, zero-column frame.
5387
5388 We use the base_width and base_height members if we have
5389 them; otherwise, we set the min_width and min_height members
5390 to the size for a zero x zero frame. */
5391
5392 #ifdef HAVE_X11R4
5393 size_hints.flags |= PBaseSize;
5394 size_hints.base_width = base_width;
5395 size_hints.base_height = base_height;
5396 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
5397 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
5398 #else
5399 size_hints.min_width = base_width;
5400 size_hints.min_height = base_height;
5401 #endif
5402 }
5403
5404 if (flags)
5405 size_hints.flags |= flags;
5406 else
5407 {
5408 XSizeHints hints; /* Sometimes I hate X Windows... */
5409 long supplied_return;
5410 int value;
5411
5412 #ifdef HAVE_X11R4
5413 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
5414 &supplied_return);
5415 #else
5416 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
5417 #endif
5418
5419 if (value == 0)
5420 hints.flags = 0;
5421 if (hints.flags & PSize)
5422 size_hints.flags |= PSize;
5423 if (hints.flags & PPosition)
5424 size_hints.flags |= PPosition;
5425 if (hints.flags & USPosition)
5426 size_hints.flags |= USPosition;
5427 if (hints.flags & USSize)
5428 size_hints.flags |= USSize;
5429 }
5430
5431 #ifdef PWinGravity
5432 size_hints.win_gravity = f->display.x->win_gravity;
5433 size_hints.flags |= PWinGravity;
5434
5435 if (user_position)
5436 {
5437 size_hints.flags &= ~ PPosition;
5438 size_hints.flags |= USPosition;
5439 }
5440 #endif /* PWinGravity */
5441
5442 #ifdef HAVE_X11R4
5443 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
5444 #else
5445 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
5446 #endif
5447 }
5448
5449 /* Used for IconicState or NormalState */
5450 x_wm_set_window_state (f, state)
5451 struct frame *f;
5452 int state;
5453 {
5454 #ifdef USE_X_TOOLKIT
5455 Arg al[1];
5456
5457 XtSetArg (al[0], XtNinitialState, state);
5458 XtSetValues (f->display.x->widget, al, 1);
5459 #else /* not USE_X_TOOLKIT */
5460 Window window = FRAME_X_WINDOW (f);
5461
5462 f->display.x->wm_hints.flags |= StateHint;
5463 f->display.x->wm_hints.initial_state = state;
5464
5465 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
5466 #endif /* not USE_X_TOOLKIT */
5467 }
5468
5469 x_wm_set_icon_pixmap (f, pixmap_id)
5470 struct frame *f;
5471 int pixmap_id;
5472 {
5473 #ifdef USE_X_TOOLKIT
5474 Window window = XtWindow (f->display.x->widget);
5475 #else
5476 Window window = FRAME_X_WINDOW (f);
5477 #endif
5478
5479 if (pixmap_id > 0)
5480 {
5481 Pixmap icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
5482 f->display.x->wm_hints.icon_pixmap = icon_pixmap;
5483 f->display.x->wm_hints.flags |= IconPixmapHint;
5484 }
5485 else
5486 {
5487 f->display.x->wm_hints.icon_pixmap = None;
5488 f->display.x->wm_hints.flags &= ~IconPixmapHint;
5489 }
5490
5491 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
5492 }
5493
5494 x_wm_set_icon_position (f, icon_x, icon_y)
5495 struct frame *f;
5496 int icon_x, icon_y;
5497 {
5498 #ifdef USE_X_TOOLKIT
5499 Window window = XtWindow (f->display.x->widget);
5500 #else
5501 Window window = FRAME_X_WINDOW (f);
5502 #endif
5503
5504 f->display.x->wm_hints.flags |= IconPositionHint;
5505 f->display.x->wm_hints.icon_x = icon_x;
5506 f->display.x->wm_hints.icon_y = icon_y;
5507
5508 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
5509 }
5510
5511 \f
5512 /* Initialization. */
5513
5514 #ifdef USE_X_TOOLKIT
5515 static XrmOptionDescRec emacs_options[] = {
5516 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
5517 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
5518
5519 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
5520 XrmoptionSepArg, NULL},
5521 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
5522
5523 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5524 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5525 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5526 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5527 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5528 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
5529 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
5530 };
5531 #endif /* USE_X_TOOLKIT */
5532
5533 static int x_initialized;
5534
5535 #ifdef MULTI_KBOARD
5536 /* Test whether two display-name strings agree up to the dot that separates
5537 the screen number from the server number. */
5538 static int
5539 same_x_server (name1, name2)
5540 char *name1, *name2;
5541 {
5542 int seen_colon = 0;
5543 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
5544 {
5545 if (*name1 == ':')
5546 seen_colon++;
5547 if (seen_colon && *name1 == '.')
5548 return 1;
5549 }
5550 return (seen_colon
5551 && (*name1 == '.' || *name1 == '\0')
5552 && (*name2 == '.' || *name2 == '\0'));
5553 }
5554 #endif
5555
5556 struct x_display_info *
5557 x_term_init (display_name, xrm_option, resource_name)
5558 Lisp_Object display_name;
5559 char *xrm_option;
5560 char *resource_name;
5561 {
5562 Lisp_Object frame;
5563 char *defaultvalue;
5564 int connection;
5565 Display *dpy;
5566 struct x_display_info *dpyinfo;
5567 XrmDatabase xrdb;
5568
5569 if (!x_initialized)
5570 {
5571 x_initialize ();
5572 x_initialized = 1;
5573 }
5574
5575 #ifdef USE_X_TOOLKIT
5576 #ifdef HAVE_X11R5
5577 XtSetLanguageProc (NULL, NULL, NULL);
5578 #endif
5579
5580 {
5581 int argc = 0;
5582 char *argv[3];
5583
5584 argv[0] = "";
5585 argc = 1;
5586 if (xrm_option)
5587 {
5588 argv[argc++] = "-xrm";
5589 argv[argc++] = xrm_option;
5590 }
5591 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
5592 resource_name, EMACS_CLASS,
5593 emacs_options, XtNumber (emacs_options),
5594 &argc, argv);
5595 }
5596
5597 #else /* not USE_X_TOOLKIT */
5598 #ifdef HAVE_X11R5
5599 XSetLocaleModifiers ("");
5600 #endif
5601 dpy = XOpenDisplay (XSTRING (display_name)->data);
5602 #endif /* not USE_X_TOOLKIT */
5603
5604 /* Detect failure. */
5605 if (dpy == 0)
5606 return 0;
5607
5608 /* We have definitely succeeded. Record the new connection. */
5609
5610 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
5611
5612 #ifdef MULTI_KBOARD
5613 {
5614 struct x_display_info *share;
5615 Lisp_Object tail;
5616
5617 for (share = x_display_list, tail = x_display_name_list; share;
5618 share = share->next, tail = XCONS (tail)->cdr)
5619 if (same_x_server (XSTRING (XCONS (XCONS (tail)->car)->car)->data,
5620 XSTRING (display_name)->data))
5621 break;
5622 if (share)
5623 dpyinfo->kboard = share->kboard;
5624 else
5625 {
5626 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
5627 init_kboard (dpyinfo->kboard);
5628 dpyinfo->kboard->next_kboard = all_kboards;
5629 all_kboards = dpyinfo->kboard;
5630 }
5631 dpyinfo->kboard->reference_count++;
5632 }
5633 #endif
5634
5635 /* Put this display on the chain. */
5636 dpyinfo->next = x_display_list;
5637 x_display_list = dpyinfo;
5638
5639 /* Put it on x_display_name_list as well, to keep them parallel. */
5640 x_display_name_list = Fcons (Fcons (display_name, Qnil),
5641 x_display_name_list);
5642 dpyinfo->name_list_element = XCONS (x_display_name_list)->car;
5643
5644 dpyinfo->display = dpy;
5645
5646 #if 0
5647 XSetAfterFunction (x_current_display, x_trace_wire);
5648 #endif /* ! 0 */
5649
5650 dpyinfo->x_id_name
5651 = (char *) xmalloc (XSTRING (Vinvocation_name)->size
5652 + XSTRING (Vsystem_name)->size
5653 + 2);
5654 sprintf (dpyinfo->x_id_name, "%s@%s",
5655 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
5656
5657 /* Figure out which modifier bits mean what. */
5658 x_find_modifier_meanings (dpyinfo);
5659
5660 /* Get the scroll bar cursor. */
5661 dpyinfo->vertical_scroll_bar_cursor
5662 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
5663
5664 xrdb = x_load_resources (dpyinfo->display, xrm_option,
5665 resource_name, EMACS_CLASS);
5666 #ifdef HAVE_XRMSETDATABASE
5667 XrmSetDatabase (dpyinfo->display, xrdb);
5668 #else
5669 dpyinfo->display->db = xrdb;
5670 #endif
5671 /* Put the rdb where we can find it in a way that works on
5672 all versions. */
5673 dpyinfo->xrdb = xrdb;
5674
5675 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
5676 DefaultScreen (dpyinfo->display));
5677 dpyinfo->visual = select_visual (dpyinfo->display, dpyinfo->screen,
5678 &dpyinfo->n_planes);
5679 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
5680 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
5681 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
5682 dpyinfo->grabbed = 0;
5683 dpyinfo->reference_count = 0;
5684 dpyinfo->icon_bitmap_id = -1;
5685 dpyinfo->n_fonts = 0;
5686 dpyinfo->font_table_size = 0;
5687 dpyinfo->bitmaps = 0;
5688 dpyinfo->bitmaps_size = 0;
5689 dpyinfo->bitmaps_last = 0;
5690 dpyinfo->scratch_cursor_gc = 0;
5691 dpyinfo->mouse_face_mouse_frame = 0;
5692 dpyinfo->mouse_face_deferred_gc = 0;
5693 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
5694 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
5695 dpyinfo->mouse_face_face_id = 0;
5696 dpyinfo->mouse_face_window = Qnil;
5697 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
5698 dpyinfo->mouse_face_defer = 0;
5699
5700 dpyinfo->Xatom_wm_protocols
5701 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
5702 dpyinfo->Xatom_wm_take_focus
5703 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
5704 dpyinfo->Xatom_wm_save_yourself
5705 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
5706 dpyinfo->Xatom_wm_delete_window
5707 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
5708 dpyinfo->Xatom_wm_change_state
5709 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
5710 dpyinfo->Xatom_wm_configure_denied
5711 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
5712 dpyinfo->Xatom_wm_window_moved
5713 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
5714 dpyinfo->Xatom_editres
5715 = XInternAtom (dpyinfo->display, "Editres", False);
5716 dpyinfo->Xatom_CLIPBOARD
5717 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
5718 dpyinfo->Xatom_TIMESTAMP
5719 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
5720 dpyinfo->Xatom_TEXT
5721 = XInternAtom (dpyinfo->display, "TEXT", False);
5722 dpyinfo->Xatom_DELETE
5723 = XInternAtom (dpyinfo->display, "DELETE", False);
5724 dpyinfo->Xatom_MULTIPLE
5725 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
5726 dpyinfo->Xatom_INCR
5727 = XInternAtom (dpyinfo->display, "INCR", False);
5728 dpyinfo->Xatom_EMACS_TMP
5729 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
5730 dpyinfo->Xatom_TARGETS
5731 = XInternAtom (dpyinfo->display, "TARGETS", False);
5732 dpyinfo->Xatom_NULL
5733 = XInternAtom (dpyinfo->display, "NULL", False);
5734 dpyinfo->Xatom_ATOM_PAIR
5735 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
5736
5737 dpyinfo->cut_buffers_initialized = 0;
5738
5739 connection = ConnectionNumber (dpyinfo->display);
5740 dpyinfo->connection = connection;
5741
5742 #ifdef subprocesses
5743 /* This is only needed for distinguishing keyboard and process input. */
5744 if (connection != 0)
5745 add_keyboard_wait_descriptor (connection);
5746 #endif
5747
5748 #ifndef F_SETOWN_BUG
5749 #ifdef F_SETOWN
5750 #ifdef F_SETOWN_SOCK_NEG
5751 /* stdin is a socket here */
5752 fcntl (connection, F_SETOWN, -getpid ());
5753 #else /* ! defined (F_SETOWN_SOCK_NEG) */
5754 fcntl (connection, F_SETOWN, getpid ());
5755 #endif /* ! defined (F_SETOWN_SOCK_NEG) */
5756 #endif /* ! defined (F_SETOWN) */
5757 #endif /* F_SETOWN_BUG */
5758
5759 #ifdef SIGIO
5760 init_sigio (connection);
5761 #endif /* ! defined (SIGIO) */
5762
5763 return dpyinfo;
5764 }
5765 \f
5766 /* Get rid of display DPYINFO, assuming all frames are already gone,
5767 and without sending any more commands to the X server. */
5768
5769 void
5770 x_delete_display (dpyinfo)
5771 struct x_display_info *dpyinfo;
5772 {
5773 delete_keyboard_wait_descriptor (dpyinfo->connection);
5774
5775 /* Discard this display from x_display_name_list and x_display_list.
5776 We can't use Fdelq because that can quit. */
5777 if (! NILP (x_display_name_list)
5778 && EQ (XCONS (x_display_name_list)->car, dpyinfo->name_list_element))
5779 x_display_name_list = XCONS (x_display_name_list)->cdr;
5780 else
5781 {
5782 Lisp_Object tail;
5783
5784 tail = x_display_name_list;
5785 while (CONSP (tail) && CONSP (XCONS (tail)->cdr))
5786 {
5787 if (EQ (XCONS (XCONS (tail)->cdr)->car,
5788 dpyinfo->name_list_element))
5789 {
5790 XCONS (tail)->cdr = XCONS (XCONS (tail)->cdr)->cdr;
5791 break;
5792 }
5793 tail = XCONS (tail)->cdr;
5794 }
5795 }
5796
5797 if (x_display_list == dpyinfo)
5798 x_display_list = dpyinfo->next;
5799 else
5800 {
5801 struct x_display_info *tail;
5802
5803 for (tail = x_display_list; tail; tail = tail->next)
5804 if (tail->next == dpyinfo)
5805 tail->next = tail->next->next;
5806 }
5807
5808 #ifndef USE_X_TOOLKIT
5809 /* I'm told Xt does this itself. */
5810 XrmDestroyDatabase (dpyinfo->xrdb);
5811 #endif
5812 #ifdef MULTI_KBOARD
5813 if (--dpyinfo->kboard->reference_count == 0)
5814 delete_kboard (dpyinfo->kboard);
5815 #endif
5816 xfree (dpyinfo->font_table);
5817 xfree (dpyinfo->x_id_name);
5818 xfree (dpyinfo);
5819 }
5820 \f
5821 /* Set up use of X before we make the first connection. */
5822
5823 x_initialize ()
5824 {
5825 clear_frame_hook = XTclear_frame;
5826 clear_end_of_line_hook = XTclear_end_of_line;
5827 ins_del_lines_hook = XTins_del_lines;
5828 change_line_highlight_hook = XTchange_line_highlight;
5829 insert_glyphs_hook = XTinsert_glyphs;
5830 write_glyphs_hook = XTwrite_glyphs;
5831 delete_glyphs_hook = XTdelete_glyphs;
5832 ring_bell_hook = XTring_bell;
5833 reset_terminal_modes_hook = XTreset_terminal_modes;
5834 set_terminal_modes_hook = XTset_terminal_modes;
5835 update_begin_hook = XTupdate_begin;
5836 update_end_hook = XTupdate_end;
5837 set_terminal_window_hook = XTset_terminal_window;
5838 read_socket_hook = XTread_socket;
5839 frame_up_to_date_hook = XTframe_up_to_date;
5840 cursor_to_hook = XTcursor_to;
5841 reassert_line_highlight_hook = XTreassert_line_highlight;
5842 mouse_position_hook = XTmouse_position;
5843 frame_rehighlight_hook = XTframe_rehighlight;
5844 frame_raise_lower_hook = XTframe_raise_lower;
5845 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
5846 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
5847 redeem_scroll_bar_hook = XTredeem_scroll_bar;
5848 judge_scroll_bars_hook = XTjudge_scroll_bars;
5849
5850 scroll_region_ok = 1; /* we'll scroll partial frames */
5851 char_ins_del_ok = 0; /* just as fast to write the line */
5852 line_ins_del_ok = 1; /* we'll just blt 'em */
5853 fast_clear_end_of_line = 1; /* X does this well */
5854 memory_below_frame = 0; /* we don't remember what scrolls
5855 off the bottom */
5856 baud_rate = 19200;
5857
5858 x_noop_count = 0;
5859
5860 x_focus_frame = x_highlight_frame = 0;
5861
5862 /* Try to use interrupt input; if we can't, then start polling. */
5863 Fset_input_mode (Qt, Qnil, Qt, Qnil);
5864
5865 #ifdef USE_X_TOOLKIT
5866 XtToolkitInitialize ();
5867 Xt_app_con = XtCreateApplicationContext ();
5868 #endif
5869
5870 /* Note that there is no real way portable across R3/R4 to get the
5871 original error handler. */
5872 XSetErrorHandler (x_error_quitter);
5873 XSetIOErrorHandler (x_io_error_quitter);
5874
5875 /* Disable Window Change signals; they are handled by X events. */
5876 #ifdef SIGWINCH
5877 signal (SIGWINCH, SIG_DFL);
5878 #endif /* ! defined (SIGWINCH) */
5879
5880 signal (SIGPIPE, x_connection_signal);
5881 }
5882
5883 void
5884 syms_of_xterm ()
5885 {
5886 staticpro (&x_display_name_list);
5887 x_display_name_list = Qnil;
5888
5889 staticpro (&last_mouse_scroll_bar);
5890 last_mouse_scroll_bar = Qnil;
5891 }
5892 #endif /* ! defined (HAVE_X_WINDOWS) */