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