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