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