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