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