(note_mouse_highlight): Reject out-of-range pos value
[emacs.git] / src / xterm.c
blob5d22c27ae1ee3bab33c189821028220fd738c16e
1 /* X Communication module for terminals which understand the X protocol.
2 Copyright (C) 1989, 1993, 1994 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* Serious problems:
22 Kludge: dup2 is used to put the X-connection socket into desc # 0
23 so that wait_reading_process_input will wait for it in place of
24 actual terminal input.
28 /* Xt features made by Fred Pierresteguy. */
30 #define NEW_SELECTIONS
32 /* On 4.3 these lose if they come after xterm.h. */
33 /* On HP-UX 8.0 signal.h loses if it comes after config.h. */
34 /* Putting these at the beginning seems to be standard for other .c files. */
35 #include <stdio.h>
36 #include <signal.h>
38 #include <config.h>
40 /* Need syssignal.h for various externs and definitions that may be required
41 by some configurations for calls to signal later in this source file. */
42 #include "syssignal.h"
44 #ifdef HAVE_X_WINDOWS
46 #include "lisp.h"
47 #include "blockinput.h"
49 /* This may include sys/types.h, and that somehow loses
50 if this is not done before the other system files. */
51 #include "xterm.h"
52 #include <X11/cursorfont.h>
54 #ifndef USG
55 /* Load sys/types.h if not already loaded.
56 In some systems loading it twice is suicidal. */
57 #ifndef makedev
58 #include <sys/types.h>
59 #endif /* makedev */
60 #endif /* USG */
62 #ifdef BSD
63 #include <sys/ioctl.h>
64 #include <strings.h>
65 #else /* ! defined (BSD) */
66 #ifndef VMS
67 #include <string.h>
68 #endif
69 #endif /* ! defined (BSD) */
71 #include "systty.h"
72 #include "systime.h"
74 #ifndef INCLUDED_FCNTL
75 #include <fcntl.h>
76 #endif
77 #include <ctype.h>
78 #include <errno.h>
79 #include <setjmp.h>
80 #include <sys/stat.h>
81 #include <sys/param.h>
83 #include "dispextern.h"
84 #include "termhooks.h"
85 #include "termopts.h"
86 #include "termchar.h"
87 #if 0
88 #include "sink.h"
89 #include "sinkmask.h"
90 #endif /* ! 0 */
91 #include "gnu.h"
92 #include "frame.h"
93 #include "disptab.h"
94 #include "buffer.h"
95 #include "window.h"
97 #ifdef USE_X_TOOLKIT
98 extern XtAppContext Xt_app_con;
99 extern Widget Xt_app_shell;
100 extern void free_frame_menubar ();
101 #endif /* USE_X_TOOLKIT */
103 #ifndef USE_X_TOOLKIT
104 #define x_any_window_to_frame x_window_to_frame
105 #endif
107 #ifdef HAVE_X11
108 #define XMapWindow XMapRaised /* Raise them when mapping. */
109 #else /* ! defined (HAVE_X11) */
110 #include <X/Xkeyboard.h>
111 /*#include <X/Xproto.h> */
112 #endif /* ! defined (HAVE_X11) */
114 #ifdef FD_SET
115 /* We could get this from param.h, but better not to depend on finding that.
116 And better not to risk that it might define other symbols used in this
117 file. */
118 #ifdef FD_SETSIZE
119 #define MAXDESC FD_SETSIZE
120 #else
121 #define MAXDESC 64
122 #endif
123 #define SELECT_TYPE fd_set
124 #else /* no FD_SET */
125 #define MAXDESC 32
126 #define SELECT_TYPE int
128 /* Define the macros to access a single-int bitmap of descriptors. */
129 #define FD_SET(n, p) (*(p) |= (1 << (n)))
130 #define FD_CLR(n, p) (*(p) &= ~(1 << (n)))
131 #define FD_ISSET(n, p) (*(p) & (1 << (n)))
132 #define FD_ZERO(p) (*(p) = 0)
133 #endif /* no FD_SET */
135 /* For sending Meta-characters. Do we need this? */
136 #define METABIT 0200
138 #define min(a,b) ((a)<(b) ? (a) : (b))
139 #define max(a,b) ((a)>(b) ? (a) : (b))
141 /* Nonzero means we must reprint all windows
142 because 1) we received an ExposeWindow event
143 or 2) we received too many ExposeRegion events to record.
145 This is never needed under X11. */
146 static int expose_all_windows;
148 /* Nonzero means we must reprint all icon windows. */
150 static int expose_all_icons;
152 #ifndef HAVE_X11
153 /* ExposeRegion events, when received, are copied into this queue
154 for later processing. */
156 static struct event_queue x_expose_queue;
158 /* ButtonPress and ButtonReleased events, when received,
159 are copied into this queue for later processing. */
161 struct event_queue x_mouse_queue;
162 #endif /* HAVE_X11 */
164 #if defined (SIGIO) && defined (FIONREAD)
165 int BLOCK_INPUT_mask;
166 #endif /* ! defined (SIGIO) && defined (FIONREAD) */
168 /* The id of a bitmap used for icon windows.
169 One such map is shared by all Emacs icon windows.
170 This is zero if we have not yet had a need to create the bitmap. */
172 static Bitmap icon_bitmap;
174 /* Font used for text icons. */
176 static FONT_TYPE *icon_font_info;
178 /* Stuff for dealing with the main icon title. */
180 extern Lisp_Object Vcommand_line_args;
181 char *hostname, *x_id_name;
183 /* This is the X connection that we are using. */
185 Display *x_current_display;
187 /* The cursor to use for vertical scroll bars on x_current_display. */
188 static Cursor x_vertical_scroll_bar_cursor;
190 /* Frame being updated by update_frame. This is declared in term.c.
191 This is set by update_begin and looked at by all the
192 XT functions. It is zero while not inside an update.
193 In that case, the XT functions assume that `selected_frame'
194 is the frame to apply to. */
195 extern struct frame *updating_frame;
197 /* The frame (if any) which has the X window that has keyboard focus.
198 Zero if none. This is examined by Ffocus_frame in frame.c. Note
199 that a mere EnterNotify event can set this; if you need to know the
200 last frame specified in a FocusIn or FocusOut event, use
201 x_focus_event_frame. */
202 struct frame *x_focus_frame;
204 /* The last frame mentioned in a FocusIn or FocusOut event. This is
205 separate from x_focus_frame, because whether or not LeaveNotify
206 events cause us to lose focus depends on whether or not we have
207 received a FocusIn event for it. */
208 struct frame *x_focus_event_frame;
210 /* The frame which currently has the visual highlight, and should get
211 keyboard input (other sorts of input have the frame encoded in the
212 event). It points to the X focus frame's selected window's
213 frame. It differs from x_focus_frame when we're using a global
214 minibuffer. */
215 static struct frame *x_highlight_frame;
217 /* From .Xdefaults, the value of "emacs.WarpMouse". If non-zero,
218 mouse is moved to inside of frame when frame is de-iconified. */
220 static int warp_mouse_on_deiconify;
222 /* During an update, maximum vpos for ins/del line operations to affect. */
224 static int flexlines;
226 /* During an update, nonzero if chars output now should be highlighted. */
228 static int highlight;
230 /* Nominal cursor position -- where to draw output.
231 During an update, these are different from the cursor-box position. */
233 static int curs_x;
234 static int curs_y;
236 /* Mouse movement.
238 In order to avoid asking for motion events and then throwing most
239 of them away or busy-polling the server for mouse positions, we ask
240 the server for pointer motion hints. This means that we get only
241 one event per group of mouse movements. "Groups" are delimited by
242 other kinds of events (focus changes and button clicks, for
243 example), or by XQueryPointer calls; when one of these happens, we
244 get another MotionNotify event the next time the mouse moves. This
245 is at least as efficient as getting motion events when mouse
246 tracking is on, and I suspect only negligibly worse when tracking
247 is off.
249 The silly O'Reilly & Associates Nutshell guides barely document
250 pointer motion hints at all (I think you have to infer how they
251 work from an example), and the description of XQueryPointer doesn't
252 mention that calling it causes you to get another motion hint from
253 the server, which is very important. */
255 /* Where the mouse was last time we reported a mouse event. */
256 static FRAME_PTR last_mouse_frame;
257 static XRectangle last_mouse_glyph;
259 /* The scroll bar in which the last X motion event occurred.
261 If the last X motion event occurred in a scroll bar, we set this
262 so XTmouse_position can know whether to report a scroll bar motion or
263 an ordinary motion.
265 If the last X motion event didn't occur in a scroll bar, we set this
266 to Qnil, to tell XTmouse_position to return an ordinary motion event. */
267 static Lisp_Object last_mouse_scroll_bar;
269 /* Record which buttons are currently pressed. */
270 unsigned int x_mouse_grabbed;
272 /* This is a hack. We would really prefer that XTmouse_position would
273 return the time associated with the position it returns, but there
274 doesn't seem to be any way to wrest the timestamp from the server
275 along with the position query. So, we just keep track of the time
276 of the last movement we received, and return that in hopes that
277 it's somewhat accurate. */
278 static Time last_mouse_movement_time;
280 /* These variables describe the range of text currently shown
281 in its mouse-face, together with the window they apply to.
282 As long as the mouse stays within this range, we need not
283 redraw anything on its account. */
284 static int mouse_face_beg, mouse_face_end;
285 static Lisp_Object mouse_face_window;
286 static int mouse_face_face_id;
288 /* FRAME and X, Y position of mouse when last checked for highlighting. */
289 static FRAME_PTR mouse_face_mouse_frame;
290 static int mouse_face_mouse_x, mouse_face_mouse_y;
292 /* Nonzero means defer mouse-motion highlighting. */
293 static int mouse_face_defer;
295 #ifdef HAVE_X11
296 /* `t' if a mouse button is depressed. */
298 extern Lisp_Object Vmouse_depressed;
300 /* Tells if a window manager is present or not. */
302 extern Lisp_Object Vx_no_window_manager;
304 /* Timestamp that we requested selection data was made. */
305 extern Time requestor_time;
307 /* ID of the window requesting selection data. */
308 extern Window requestor_window;
310 /* Nonzero enables some debugging for the X interface code. */
311 extern int _Xdebug;
313 extern Qface, Qmouse_face;
315 #else /* ! defined (HAVE_X11) */
317 /* Bit patterns for the mouse cursor. */
319 short MouseCursor[] = {
320 0x0000, 0x0008, 0x0018, 0x0038,
321 0x0078, 0x00f8, 0x01f8, 0x03f8,
322 0x07f8, 0x00f8, 0x00d8, 0x0188,
323 0x0180, 0x0300, 0x0300, 0x0000};
325 short MouseMask[] = {
326 0x000c, 0x001c, 0x003c, 0x007c,
327 0x00fc, 0x01fc, 0x03fc, 0x07fc,
328 0x0ffc, 0x0ffc, 0x01fc, 0x03dc,
329 0x03cc, 0x0780, 0x0780, 0x0300};
331 static short grey_bits[] = {
332 0x0005, 0x000a, 0x0005, 0x000a};
334 static Pixmap GreyPixmap = 0;
335 #endif /* ! defined (HAVE_X11) */
337 /* From time to time we get info on an Emacs window, here. */
339 static WINDOWINFO_TYPE windowinfo;
341 extern int errno;
343 /* A mask of extra modifier bits to put into every keyboard char. */
344 extern int extra_keyboard_modifiers;
346 extern Display *XOpenDisplay ();
347 extern Window XCreateWindow ();
349 extern Cursor XCreateCursor ();
350 extern FONT_TYPE *XOpenFont ();
352 static void flashback ();
353 static void redraw_previous_char ();
354 static unsigned int x_x_to_emacs_modifiers ();
356 static void note_mouse_highlight ();
357 static void clear_mouse_face ();
358 static void show_mouse_face ();
360 #ifndef HAVE_X11
361 static void dumpqueue ();
362 #endif /* HAVE_X11 */
364 void dumpborder ();
365 static int XTcursor_to ();
366 static int XTclear_end_of_line ();
369 /* Starting and ending updates.
371 These hooks are called by update_frame at the beginning and end
372 of a frame update. We record in `updating_frame' the identity
373 of the frame being updated, so that the XT... functions do not
374 need to take a frame as argument. Most of the XT... functions
375 should never be called except during an update, the only exceptions
376 being XTcursor_to, XTwrite_glyphs and XTreassert_line_highlight. */
378 extern int mouse_track_top, mouse_track_left, mouse_track_width;
380 static
381 XTupdate_begin (f)
382 struct frame *f;
384 int mask;
386 if (f == 0)
387 abort ();
389 flexlines = f->height;
390 highlight = 0;
392 BLOCK_INPUT;
394 if (f == mouse_face_mouse_frame)
396 mouse_face_defer = 1;
397 if (!NILP (mouse_face_window))
398 clear_mouse_face ();
400 #ifndef HAVE_X11
401 dumpqueue ();
402 #endif /* HAVE_X11 */
403 UNBLOCK_INPUT;
406 #ifndef HAVE_X11
407 static void x_do_pending_expose ();
408 #endif
410 static
411 XTupdate_end (f)
412 struct frame *f;
414 int mask;
416 BLOCK_INPUT;
417 #ifndef HAVE_X11
418 dumpqueue ();
419 x_do_pending_expose ();
420 #endif /* HAVE_X11 */
422 x_display_cursor (f, 1);
424 if (f == mouse_face_mouse_frame)
425 mouse_face_defer = 0;
426 #if 0
427 /* This fails in the case of having updated only the echo area
428 if we have switched buffers. In that case, FRAME_CURRENT_GLYPHS
429 has no relation to the current contents, and its charstarts
430 have no relation to the contents of the window-buffer.
431 I don't know a clean way to check
432 for that case. window_end_valid isn't set up yet. */
433 if (f == mouse_face_mouse_frame)
434 note_mouse_highlight (f, mouse_face_mouse_x, mouse_face_mouse_y);
435 #endif
437 XFlushQueue ();
438 UNBLOCK_INPUT;
441 /* This is called when all windows on frame F are now up to date. */
443 static
444 XTframe_up_to_date (f)
445 FRAME_PTR f;
447 if (f == mouse_face_mouse_frame)
448 note_mouse_highlight (f, mouse_face_mouse_x, mouse_face_mouse_y);
451 /* External interface to control of standout mode.
452 Call this when about to modify line at position VPOS
453 and not change whether it is highlighted. */
455 XTreassert_line_highlight (new, vpos)
456 int new, vpos;
458 highlight = new;
461 /* Call this when about to modify line at position VPOS
462 and change whether it is highlighted. */
464 static
465 XTchange_line_highlight (new_highlight, vpos, first_unused_hpos)
466 int new_highlight, vpos, first_unused_hpos;
468 highlight = new_highlight;
469 XTcursor_to (vpos, 0);
470 XTclear_end_of_line (updating_frame->width);
473 /* This is used when starting Emacs and when restarting after suspend.
474 When starting Emacs, no X window is mapped. And nothing must be done
475 to Emacs's own window if it is suspended (though that rarely happens). */
477 static
478 XTset_terminal_modes ()
482 /* This is called when exiting or suspending Emacs.
483 Exiting will make the X-windows go away, and suspending
484 requires no action. */
486 static
487 XTreset_terminal_modes ()
489 /* XTclear_frame (); */
492 /* Set the nominal cursor position of the frame.
493 This is where display update commands will take effect.
494 This does not affect the place where the cursor-box is displayed. */
496 static int
497 XTcursor_to (row, col)
498 register int row, col;
500 int mask;
501 int orow = row;
503 curs_x = col;
504 curs_y = row;
506 if (updating_frame == 0)
508 BLOCK_INPUT;
509 x_display_cursor (selected_frame, 1);
510 XFlushQueue ();
511 UNBLOCK_INPUT;
515 /* Display a sequence of N glyphs found at GP.
516 WINDOW is the x-window to output to. LEFT and TOP are starting coords.
517 HL is 1 if this text is highlighted, 2 if the cursor is on it,
518 3 if should appear in its mouse-face.
520 FONT is the default font to use (for glyphs whose font-code is 0).
522 Since the display generation code is responsible for calling
523 compute_char_face and compute_glyph_face on everything it puts in
524 the display structure, we can assume that the face code on each
525 glyph is a valid index into FRAME_COMPUTED_FACES (f), and the one
526 to which we can actually apply intern_face.
527 Call this function with input blocked. */
529 #if 1
530 /* This is the multi-face code. */
532 static void
533 dumpglyphs (f, left, top, gp, n, hl)
534 struct frame *f;
535 int left, top;
536 register GLYPH *gp; /* Points to first GLYPH. */
537 register int n; /* Number of glyphs to display. */
538 int hl;
540 /* Holds characters to be displayed. */
541 char *buf = (char *) alloca (f->width * sizeof (*buf));
542 register char *cp; /* Steps through buf[]. */
543 register int tlen = GLYPH_TABLE_LENGTH;
544 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
545 Window window = FRAME_X_WINDOW (f);
547 while (n > 0)
549 /* Get the face-code of the next GLYPH. */
550 int cf, len;
551 int g = *gp;
553 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
554 cf = FAST_GLYPH_FACE (g);
556 /* Find the run of consecutive glyphs with the same face-code.
557 Extract their character codes into BUF. */
558 cp = buf;
559 while (n > 0)
561 g = *gp;
562 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
563 if (FAST_GLYPH_FACE (g) != cf)
564 break;
566 *cp++ = FAST_GLYPH_CHAR (g);
567 --n;
568 ++gp;
571 /* LEN gets the length of the run. */
572 len = cp - buf;
574 /* Now output this run of chars, with the font and pixel values
575 determined by the face code CF. */
577 struct face *face = FRAME_DEFAULT_FACE (f);
578 FONT_TYPE *font = FACE_FONT (face);
579 GC gc = FACE_GC (face);
580 int defaulted = 1;
581 int gc_temporary = 0;
583 /* HL = 3 means use a mouse face previously chosen. */
584 if (hl == 3)
585 cf = mouse_face_face_id;
587 /* First look at the face of the text itself. */
588 if (cf != 0)
590 /* It's possible for the display table to specify
591 a face code that is out of range. Use 0 in that case. */
592 if (cf < 0 || cf >= FRAME_N_COMPUTED_FACES (f)
593 || FRAME_COMPUTED_FACES (f) [cf] == 0)
594 cf = 0;
596 if (cf == 1)
597 face = FRAME_MODE_LINE_FACE (f);
598 else
599 face = intern_face (f, FRAME_COMPUTED_FACES (f) [cf]);
600 font = FACE_FONT (face);
601 gc = FACE_GC (face);
602 defaulted = 0;
605 /* Then comes the distinction between modeline and normal text. */
606 else if (hl == 0)
608 else if (hl == 1)
610 face = FRAME_MODE_LINE_FACE (f);
611 font = FACE_FONT (face);
612 gc = FACE_GC (face);
613 defaulted = 0;
616 #define FACE_DEFAULT (~0)
618 /* Now override that if the cursor's on this character. */
619 if (hl == 2)
621 if (defaulted
622 || !face->font
623 || (int) face->font == FACE_DEFAULT)
625 gc = f->display.x->cursor_gc;
627 /* Cursor on non-default face: must merge. */
628 else
630 XGCValues xgcv;
631 unsigned long mask;
633 xgcv.background = f->display.x->cursor_pixel;
634 if (face == FRAME_DEFAULT_FACE (f))
635 xgcv.foreground = f->display.x->cursor_foreground_pixel;
636 else
637 xgcv.foreground = face->foreground;
638 /* If the glyph would be invisible,
639 try a different foreground. */
640 if (xgcv.foreground == xgcv.background)
641 xgcv.foreground = face->background;
642 if (xgcv.foreground == xgcv.background)
643 xgcv.foreground = f->display.x->cursor_foreground_pixel;
644 if (xgcv.foreground == xgcv.background)
645 xgcv.foreground = face->foreground;
646 /* Make sure the cursor is distinct from text in this face. */
647 if (xgcv.background == face->background
648 && xgcv.foreground == face->foreground)
650 xgcv.background = face->foreground;
651 xgcv.foreground = face->background;
653 xgcv.font = face->font->fid;
654 xgcv.graphics_exposures = 0;
655 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
656 gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f),
657 mask, &xgcv);
658 #if 0
659 if (face->stipple && face->stipple != FACE_DEFAULT)
660 XSetStipple (x_current_display, gc, face->stipple);
661 #endif
662 gc_temporary = 1;
666 if ((int) font == FACE_DEFAULT)
667 font = f->display.x->font;
669 XDrawImageString (x_current_display, window, gc,
670 left, top + FONT_BASE (font), buf, len);
672 if (gc_temporary)
673 XFreeGC (x_current_display, gc);
675 /* We should probably check for XA_UNDERLINE_POSITION and
676 XA_UNDERLINE_THICKNESS properties on the font, but let's
677 just get the thing working, and come back to that. */
679 int underline_position = 1;
681 if (font->descent <= underline_position)
682 underline_position = font->descent - 1;
684 if (face->underline)
685 XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
686 FACE_GC (face),
687 left, (top
688 + FONT_BASE (font)
689 + underline_position),
690 len * FONT_WIDTH (font), 1);
693 left += len * FONT_WIDTH (font);
697 #endif /* 1 */
699 #if 0
700 /* This is the old single-face code. */
702 static void
703 dumpglyphs (f, left, top, gp, n, hl, font)
704 struct frame *f;
705 int left, top;
706 register GLYPH *gp; /* Points to first GLYPH. */
707 register int n; /* Number of glyphs to display. */
708 int hl;
709 FONT_TYPE *font;
711 register int len;
712 Window window = FRAME_X_WINDOW (f);
713 GC drawing_gc = (hl == 2 ? f->display.x->cursor_gc
714 : (hl ? f->display.x->reverse_gc
715 : f->display.x->normal_gc));
717 if (sizeof (GLYPH) == sizeof (XChar2b))
718 XDrawImageString16 (x_current_display, window, drawing_gc,
719 left, top + FONT_BASE (font), (XChar2b *) gp, n);
720 else if (sizeof (GLYPH) == sizeof (unsigned char))
721 XDrawImageString (x_current_display, window, drawing_gc,
722 left, top + FONT_BASE (font), (char *) gp, n);
723 else
724 /* What size of glyph ARE you using? And does X have a function to
725 draw them? */
726 abort ();
728 #endif
730 /* Output some text at the nominal frame cursor position.
731 Advance the cursor over the text.
732 Output LEN glyphs at START.
734 `highlight', set up by XTreassert_line_highlight or XTchange_line_highlight,
735 controls the pixel values used for foreground and background. */
737 static
738 XTwrite_glyphs (start, len)
739 register GLYPH *start;
740 int len;
742 register int temp_length;
743 int mask;
744 struct frame *f;
746 BLOCK_INPUT;
748 f = updating_frame;
749 if (f == 0)
751 f = selected_frame;
752 /* If not within an update,
753 output at the frame's visible cursor. */
754 curs_x = f->cursor_x;
755 curs_y = f->cursor_y;
758 dumpglyphs (f,
759 CHAR_TO_PIXEL_COL (f, curs_x),
760 CHAR_TO_PIXEL_ROW (f, curs_y),
761 start, len, highlight);
763 /* If we drew on top of the cursor, note that it is turned off. */
764 if (curs_y == f->phys_cursor_y
765 && curs_x <= f->phys_cursor_x
766 && curs_x + len > f->phys_cursor_x)
767 f->phys_cursor_x = -1;
769 if (updating_frame == 0)
771 f->cursor_x += len;
772 x_display_cursor (f, 1);
773 f->cursor_x -= len;
775 else
776 curs_x += len;
778 UNBLOCK_INPUT;
781 /* Clear to the end of the line.
782 Erase the current text line from the nominal cursor position (inclusive)
783 to column FIRST_UNUSED (exclusive). The idea is that everything
784 from FIRST_UNUSED onward is already erased. */
786 static int
787 XTclear_end_of_line (first_unused)
788 register int first_unused;
790 struct frame *f = updating_frame;
791 int mask;
793 if (f == 0)
794 abort ();
796 if (curs_y < 0 || curs_y >= f->height)
797 return;
798 if (first_unused <= 0)
799 return;
801 if (first_unused >= f->width)
802 first_unused = f->width;
804 BLOCK_INPUT;
806 /* Notice if the cursor will be cleared by this operation. */
807 if (curs_y == f->phys_cursor_y
808 && curs_x <= f->phys_cursor_x
809 && f->phys_cursor_x < first_unused)
810 f->phys_cursor_x = -1;
812 #ifdef HAVE_X11
813 XClearArea (x_current_display, FRAME_X_WINDOW (f),
814 CHAR_TO_PIXEL_COL (f, curs_x),
815 CHAR_TO_PIXEL_ROW (f, curs_y),
816 FONT_WIDTH (f->display.x->font) * (first_unused - curs_x),
817 FONT_HEIGHT (f->display.x->font), False);
818 #if 0
819 redraw_previous_char (f, curs_x, curs_y);
820 #endif
821 #else /* ! defined (HAVE_X11) */
822 XPixSet (FRAME_X_WINDOW (f),
823 CHAR_TO_PIXEL_COL (f, curs_x),
824 CHAR_TO_PIXEL_ROW (f, curs_y),
825 FONT_WIDTH (f->display.x->font) * (first_unused - curs_x),
826 FONT_HEIGHT (f->display.x->font),
827 f->display.x->background_pixel);
828 #endif /* ! defined (HAVE_X11) */
830 UNBLOCK_INPUT;
833 /* Erase the character (if any) at the position just before X, Y in frame F,
834 then redraw it and the character before it.
835 This is necessary when we erase starting at X,
836 in case the character after X overlaps into the one before X.
837 Call this function with input blocked. */
839 static void
840 redraw_previous_char (f, x, y)
841 FRAME_PTR f;
842 int x, y;
844 /* Erase the character before the new ones, in case
845 what was here before overlaps it.
846 Reoutput that character, and the previous character
847 (in case the previous character overlaps it). */
848 if (x > 0)
850 int start_x = x - 2;
851 if (start_x < 0)
852 start_x = 0;
853 XClearArea (x_current_display, FRAME_X_WINDOW (f),
854 CHAR_TO_PIXEL_COL (f, x - 1),
855 CHAR_TO_PIXEL_ROW (f, y),
856 FONT_WIDTH (f->display.x->font),
857 FONT_HEIGHT (f->display.x->font), False);
859 dumpglyphs (f, CHAR_TO_PIXEL_COL (f, start_x),
860 CHAR_TO_PIXEL_ROW (f, y),
861 &FRAME_CURRENT_GLYPHS (f)->glyphs[y][start_x],
862 x - start_x, highlight);
866 static
867 XTclear_frame ()
869 int mask;
870 struct frame *f = updating_frame;
872 if (f == 0)
873 f = selected_frame;
875 f->phys_cursor_x = -1; /* Cursor not visible. */
876 curs_x = 0; /* Nominal cursor position is top left. */
877 curs_y = 0;
879 BLOCK_INPUT;
881 XClear (FRAME_X_WINDOW (f));
883 /* We have to clear the scroll bars, too. If we have changed
884 colors or something like that, then they should be notified. */
885 x_scroll_bar_clear (f);
887 #ifndef HAVE_X11
888 dumpborder (f, 0);
889 #endif /* HAVE_X11 */
891 XFlushQueue ();
892 UNBLOCK_INPUT;
895 /* Invert the middle quarter of the frame for .15 sec. */
897 /* We use the select system call to do the waiting, so we have to make sure
898 it's available. If it isn't, we just won't do visual bells. */
899 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
901 /* Subtract the `struct timeval' values X and Y,
902 storing the result in RESULT.
903 Return 1 if the difference is negative, otherwise 0. */
905 static int
906 timeval_subtract (result, x, y)
907 struct timeval *result, x, y;
909 /* Perform the carry for the later subtraction by updating y.
910 This is safer because on some systems
911 the tv_sec member is unsigned. */
912 if (x.tv_usec < y.tv_usec)
914 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
915 y.tv_usec -= 1000000 * nsec;
916 y.tv_sec += nsec;
918 if (x.tv_usec - y.tv_usec > 1000000)
920 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
921 y.tv_usec += 1000000 * nsec;
922 y.tv_sec -= nsec;
925 /* Compute the time remaining to wait. tv_usec is certainly positive. */
926 result->tv_sec = x.tv_sec - y.tv_sec;
927 result->tv_usec = x.tv_usec - y.tv_usec;
929 /* Return indication of whether the result should be considered negative. */
930 return x.tv_sec < y.tv_sec;
933 XTflash (f)
934 struct frame *f;
936 BLOCK_INPUT;
939 GC gc;
941 /* Create a GC that will use the GXxor function to flip foreground pixels
942 into background pixels. */
944 XGCValues values;
946 values.function = GXxor;
947 values.foreground = (f->display.x->foreground_pixel
948 ^ f->display.x->background_pixel);
950 gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f),
951 GCFunction | GCForeground, &values);
955 int width = PIXEL_WIDTH (f);
956 int height = PIXEL_HEIGHT (f);
958 XFillRectangle (x_current_display, FRAME_X_WINDOW (f), gc,
959 width/4, height/4, width/2, height/2);
960 XFlush (x_current_display);
963 struct timeval wakeup, now;
965 EMACS_GET_TIME (wakeup);
967 /* Compute time to wait until, propagating carry from usecs. */
968 wakeup.tv_usec += 150000;
969 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
970 wakeup.tv_usec %= 1000000;
972 /* Keep waiting until past the time wakeup. */
973 while (1)
975 struct timeval timeout;
977 EMACS_GET_TIME (timeout);
979 /* In effect, timeout = wakeup - timeout.
980 Break if result would be negative. */
981 if (timeval_subtract (&timeout, wakeup, timeout))
982 break;
984 /* Try to wait that long--but we might wake up sooner. */
985 select (0, 0, 0, 0, &timeout);
989 XFillRectangle (x_current_display, FRAME_X_WINDOW (f), gc,
990 width/4, height/4, width/2, height/2);
991 XFreeGC (x_current_display, gc);
992 XFlush (x_current_display);
996 UNBLOCK_INPUT;
999 #endif
1002 /* Make audible bell. */
1004 #ifdef HAVE_X11
1005 #define XRINGBELL XBell (x_current_display, 0)
1006 #else /* ! defined (HAVE_X11) */
1007 #define XRINGBELL XFeep (0);
1008 #endif /* ! defined (HAVE_X11) */
1010 XTring_bell ()
1012 if (x_current_display == 0)
1013 return;
1015 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
1016 if (visible_bell)
1017 XTflash (selected_frame);
1018 else
1019 #endif
1021 BLOCK_INPUT;
1022 XRINGBELL;
1023 XFlushQueue ();
1024 UNBLOCK_INPUT;
1028 /* Insert and delete character.
1029 These are not supposed to be used because we are supposed to turn
1030 off the feature of using them. */
1032 static
1033 XTinsert_glyphs (start, len)
1034 register char *start;
1035 register int len;
1037 abort ();
1040 static
1041 XTdelete_glyphs (n)
1042 register int n;
1044 abort ();
1047 /* Specify how many text lines, from the top of the window,
1048 should be affected by insert-lines and delete-lines operations.
1049 This, and those operations, are used only within an update
1050 that is bounded by calls to XTupdate_begin and XTupdate_end. */
1052 static
1053 XTset_terminal_window (n)
1054 register int n;
1056 if (updating_frame == 0)
1057 abort ();
1059 if ((n <= 0) || (n > updating_frame->height))
1060 flexlines = updating_frame->height;
1061 else
1062 flexlines = n;
1065 /* Perform an insert-lines operation.
1066 Insert N lines at a vertical position curs_y. */
1068 static void
1069 stufflines (n)
1070 register int n;
1072 register int topregion, bottomregion;
1073 register int length, newtop, mask;
1074 register struct frame *f = updating_frame;
1075 int intborder = f->display.x->internal_border_width;
1077 if (curs_y >= flexlines)
1078 return;
1080 topregion = curs_y;
1081 bottomregion = flexlines - (n + 1);
1082 newtop = topregion + n;
1083 length = (bottomregion - topregion) + 1;
1085 #ifndef HAVE_X11
1086 dumpqueue ();
1087 #endif /* HAVE_X11 */
1089 if ((length > 0) && (newtop <= flexlines))
1091 #ifdef HAVE_X11
1092 XCopyArea (x_current_display, FRAME_X_WINDOW (f),
1093 FRAME_X_WINDOW (f), f->display.x->normal_gc,
1094 intborder, CHAR_TO_PIXEL_ROW (f, topregion),
1095 f->width * FONT_WIDTH (f->display.x->font),
1096 length * FONT_HEIGHT (f->display.x->font), intborder,
1097 CHAR_TO_PIXEL_ROW (f, newtop));
1098 #else /* ! defined (HAVE_X11) */
1099 XMoveArea (FRAME_X_WINDOW (f),
1100 intborder, CHAR_TO_PIXEL_ROW (f, topregion),
1101 intborder, CHAR_TO_PIXEL_ROW (f, newtop),
1102 f->width * FONT_WIDTH (f->display.x->font),
1103 length * FONT_HEIGHT (f->display.x->font));
1104 /* Now we must process any ExposeRegion events that occur
1105 if the area being copied from is obscured.
1106 We can't let it wait because further i/d operations
1107 may want to copy this area to another area. */
1108 x_read_exposes ();
1109 #endif /* ! defined (HAVE_X11) */
1112 newtop = min (newtop, (flexlines - 1));
1113 length = newtop - topregion;
1114 if (length > 0)
1116 #ifdef HAVE_X11
1117 XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder,
1118 CHAR_TO_PIXEL_ROW (f, topregion),
1119 f->width * FONT_WIDTH (f->display.x->font),
1120 n * FONT_HEIGHT (f->display.x->font), False);
1121 #else /* ! defined (HAVE_X11) */
1122 XPixSet (FRAME_X_WINDOW (f),
1123 intborder,
1124 CHAR_TO_PIXEL_ROW (f, topregion),
1125 f->width * FONT_WIDTH (f->display.x->font),
1126 n * FONT_HEIGHT (f->display.x->font),
1127 f->display.x->background_pixel);
1128 #endif /* ! defined (HAVE_X11) */
1132 /* Perform a delete-lines operation, deleting N lines
1133 at a vertical position curs_y. */
1135 static void
1136 scraplines (n)
1137 register int n;
1139 int mask;
1140 register struct frame *f = updating_frame;
1141 int intborder = f->display.x->internal_border_width;
1143 if (curs_y >= flexlines)
1144 return;
1146 #ifndef HAVE_X11
1147 dumpqueue ();
1148 #endif /* HAVE_X11 */
1150 if ((curs_y + n) >= flexlines)
1152 if (flexlines >= (curs_y + 1))
1154 #ifdef HAVE_X11
1155 XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder,
1156 CHAR_TO_PIXEL_ROW (f, curs_y),
1157 f->width * FONT_WIDTH (f->display.x->font),
1158 (flexlines - curs_y) * FONT_HEIGHT (f->display.x->font), False);
1159 #else /* ! defined (HAVE_X11) */
1160 XPixSet (FRAME_X_WINDOW (f),
1161 intborder, CHAR_TO_PIXEL_ROW (f, curs_y),
1162 f->width * FONT_WIDTH (f->display.x->font),
1163 (flexlines - curs_y) * FONT_HEIGHT (f->display.x->font),
1164 f->display.x->background_pixel);
1165 #endif /* ! defined (HAVE_X11) */
1168 else
1170 #ifdef HAVE_X11
1171 XCopyArea (x_current_display, FRAME_X_WINDOW (f),
1172 FRAME_X_WINDOW (f), f->display.x->normal_gc,
1173 intborder,
1174 CHAR_TO_PIXEL_ROW (f, curs_y + n),
1175 f->width * FONT_WIDTH (f->display.x->font),
1176 (flexlines - (curs_y + n)) * FONT_HEIGHT (f->display.x->font),
1177 intborder, CHAR_TO_PIXEL_ROW (f, curs_y));
1178 XClearArea (x_current_display, FRAME_X_WINDOW (f),
1179 intborder,
1180 CHAR_TO_PIXEL_ROW (f, flexlines - n),
1181 f->width * FONT_WIDTH (f->display.x->font),
1182 n * FONT_HEIGHT (f->display.x->font), False);
1183 #else /* ! defined (HAVE_X11) */
1184 XMoveArea (FRAME_X_WINDOW (f),
1185 intborder,
1186 CHAR_TO_PIXEL_ROW (f, curs_y + n),
1187 intborder, CHAR_TO_PIXEL_ROW (f, curs_y),
1188 f->width * FONT_WIDTH (f->display.x->font),
1189 (flexlines - (curs_y + n)) * FONT_HEIGHT (f->display.x->font));
1190 /* Now we must process any ExposeRegion events that occur
1191 if the area being copied from is obscured.
1192 We can't let it wait because further i/d operations
1193 may want to copy this area to another area. */
1194 x_read_exposes ();
1195 XPixSet (FRAME_X_WINDOW (f), intborder,
1196 CHAR_TO_PIXEL_ROW (f, flexlines - n),
1197 f->width * FONT_WIDTH (f->display.x->font),
1198 n * FONT_HEIGHT (f->display.x->font), f->display.x->background_pixel);
1199 #endif /* ! defined (HAVE_X11) */
1203 /* Perform an insert-lines or delete-lines operation,
1204 inserting N lines or deleting -N lines at vertical position VPOS. */
1206 XTins_del_lines (vpos, n)
1207 int vpos, n;
1209 if (updating_frame == 0)
1210 abort ();
1212 /* Hide the cursor. */
1213 x_display_cursor (updating_frame, 0);
1215 XTcursor_to (vpos, 0);
1217 BLOCK_INPUT;
1218 if (n >= 0)
1219 stufflines (n);
1220 else
1221 scraplines (-n);
1222 XFlushQueue ();
1223 UNBLOCK_INPUT;
1226 /* Support routines for exposure events. */
1227 static void clear_cursor ();
1229 /* Output into a rectangle of an X-window (for frame F)
1230 the characters in f->phys_lines that overlap that rectangle.
1231 TOP and LEFT are the position of the upper left corner of the rectangle.
1232 ROWS and COLS are the size of the rectangle.
1233 Call this function with input blocked. */
1235 static void
1236 dumprectangle (f, left, top, cols, rows)
1237 struct frame *f;
1238 register int left, top, cols, rows;
1240 register struct frame_glyphs *active_frame = FRAME_CURRENT_GLYPHS (f);
1241 int cursor_cleared = 0;
1242 int bottom, right;
1243 register int y;
1245 if (FRAME_GARBAGED_P (f))
1246 return;
1248 /* Express rectangle as four edges, instead of position-and-size. */
1249 bottom = top + rows;
1250 right = left + cols;
1252 #ifndef HAVE_X11 /* Window manger does this for X11. */
1254 int intborder = f->display.x->internal_border_width;
1256 /* If the rectangle includes any of the internal border area,
1257 redisplay the border emphasis. */
1258 if (top < intborder || left < intborder
1259 || bottom > intborder + f->height * FONT_HEIGHT (f->display.x->font)
1260 || right > intborder + f->width * FONT_WIDTH (f->display.x->font))
1261 dumpborder (f, 0);
1263 #endif /* not HAVE_X11 Window manger does this for X11. */
1265 /* Convert rectangle edges in pixels to edges in chars.
1266 Round down for left and top, up for right and bottom. */
1267 top = PIXEL_TO_CHAR_ROW (f, top);
1268 left = PIXEL_TO_CHAR_COL (f, left);
1269 bottom += (FONT_HEIGHT (f->display.x->font) - 1);
1270 right += (FONT_WIDTH (f->display.x->font) - 1);
1271 bottom = PIXEL_TO_CHAR_ROW (f, bottom);
1272 right = PIXEL_TO_CHAR_COL (f, right);
1274 /* Clip the rectangle to what can be visible. */
1275 if (left < 0)
1276 left = 0;
1277 if (top < 0)
1278 top = 0;
1279 if (right > f->width)
1280 right = f->width;
1281 if (bottom > f->height)
1282 bottom = f->height;
1284 /* Get size in chars of the rectangle. */
1285 cols = right - left;
1286 rows = bottom - top;
1288 /* If rectangle has zero area, return. */
1289 if (rows <= 0) return;
1290 if (cols <= 0) return;
1292 /* Turn off the cursor if it is in the rectangle.
1293 We will turn it back on afterward. */
1294 if ((f->phys_cursor_x >= left) && (f->phys_cursor_x < right)
1295 && (f->phys_cursor_y >= top) && (f->phys_cursor_y < bottom))
1297 clear_cursor (f);
1298 cursor_cleared = 1;
1301 /* Display the text in the rectangle, one text line at a time. */
1303 for (y = top; y < bottom; y++)
1305 GLYPH *line = &active_frame->glyphs[y][left];
1307 if (! active_frame->enable[y] || left > active_frame->used[y])
1308 continue;
1310 dumpglyphs (f,
1311 CHAR_TO_PIXEL_COL (f, left),
1312 CHAR_TO_PIXEL_ROW (f, y),
1313 line, min (cols, active_frame->used[y] - left),
1314 active_frame->highlight[y]);
1317 /* Turn the cursor on if we turned it off. */
1319 if (cursor_cleared)
1320 x_display_cursor (f, 1);
1323 #ifndef HAVE_X11
1324 /* Process all queued ExposeRegion events. */
1326 static void
1327 dumpqueue ()
1329 register int i;
1330 XExposeRegionEvent r;
1332 while (dequeue_event (&r, &x_expose_queue))
1334 struct frame *f = x_window_to_frame (r.window);
1335 if (f->display.x->icon_desc == r.window)
1336 refreshicon (f);
1337 else
1338 dumprectangle (f, r.x, r.y, r.width, r.height);
1340 XFlushQueue ();
1342 #endif /* HAVE_X11 */
1344 /* Process all expose events that are pending, for X10.
1345 Redraws the cursor if necessary on any frame that
1346 is not in the process of being updated with update_frame. */
1348 #ifndef HAVE_X11
1349 static void
1350 x_do_pending_expose ()
1352 int mask;
1353 struct frame *f;
1354 Lisp_Object tail, frame;
1356 if (expose_all_windows)
1358 expose_all_windows = 0;
1359 for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
1361 register int temp_width, temp_height;
1362 int intborder;
1364 frame = XCONS (tail)->car;
1365 if (XGCTYPE (frame) != Lisp_Frame)
1366 continue;
1367 f = XFRAME (frame);
1368 if (! FRAME_X_P (f))
1369 continue;
1370 if (!f->async_visible)
1371 continue;
1372 if (!f->display.x->needs_exposure)
1373 continue;
1375 intborder = f->display.x->internal_border_width;
1377 clear_cursor (f);
1378 XGetWindowInfo (FRAME_X_WINDOW (f), &windowinfo);
1379 temp_width = ((windowinfo.width - 2 * intborder
1380 - f->display.x->v_scroll_bar_width)
1381 / FONT_WIDTH (f->display.x->font));
1382 temp_height = ((windowinfo.height- 2 * intborder
1383 - f->display.x->h_scroll_bar_height)
1384 / FONT_HEIGHT (f->display.x->font));
1385 if (temp_width != f->width || temp_height != f->height)
1387 change_frame_size (f, max (1, temp_height),
1388 max (1, temp_width), 0, 1);
1389 x_resize_scroll_bars (f);
1391 f->display.x->left_pos = windowinfo.x;
1392 f->display.x->top_pos = windowinfo.y;
1393 dumprectangle (f, 0, 0, PIXEL_WIDTH (f), PIXEL_HEIGHT (f));
1394 #if 0
1395 dumpborder (f, 0);
1396 #endif /* ! 0 */
1397 f->display.x->needs_exposure = 0;
1398 if (updating_frame != f)
1399 x_display_cursor (f, 1);
1400 XFlushQueue ();
1403 else
1404 /* Handle any individual-rectangle expose events queued
1405 for various windows. */
1406 #ifdef HAVE_X11
1408 #else /* ! defined (HAVE_X11) */
1409 dumpqueue ();
1410 #endif /* ! defined (HAVE_X11) */
1412 #endif
1414 #ifdef HAVE_X11
1415 static void
1416 frame_highlight (frame)
1417 struct frame *frame;
1419 /* We used to only do this if Vx_no_window_manager was non-nil, but
1420 the ICCCM (section 4.1.6) says that the window's border pixmap
1421 and border pixel are window attributes which are "private to the
1422 client", so we can always change it to whatever we want. */
1423 BLOCK_INPUT;
1424 XSetWindowBorder (x_current_display, FRAME_X_WINDOW (frame),
1425 frame->display.x->border_pixel);
1426 UNBLOCK_INPUT;
1427 x_display_cursor (frame, 1);
1430 static void
1431 frame_unhighlight (frame)
1432 struct frame *frame;
1434 /* We used to only do this if Vx_no_window_manager was non-nil, but
1435 the ICCCM (section 4.1.6) says that the window's border pixmap
1436 and border pixel are window attributes which are "private to the
1437 client", so we can always change it to whatever we want. */
1438 BLOCK_INPUT;
1439 XSetWindowBorderPixmap (x_current_display, FRAME_X_WINDOW (frame),
1440 frame->display.x->border_tile);
1441 UNBLOCK_INPUT;
1442 x_display_cursor (frame, 1);
1444 #else /* ! defined (HAVE_X11) */
1445 /* Dump the border-emphasis of frame F.
1446 If F is selected, this is a lining of the same color as the border,
1447 just within the border, occupying a portion of the internal border.
1448 If F is not selected, it is background in the same place.
1449 If ALWAYS is 0, don't bother explicitly drawing if it's background.
1451 ALWAYS = 1 is used when a frame becomes selected or deselected.
1452 In that case, we also turn the cursor off and on again
1453 so it will appear in the proper shape (solid if selected; else hollow.) */
1455 static void
1456 dumpborder (f, always)
1457 struct frame *f;
1458 int always;
1460 int thickness = f->display.x->internal_border_width / 2;
1461 int width = PIXEL_WIDTH (f);
1462 int height = PIXEL_HEIGHT (f);
1463 int pixel;
1465 if (f != selected_frame)
1467 if (!always)
1468 return;
1470 pixel = f->display.x->background_pixel;
1472 else
1474 pixel = f->display.x->border_pixel;
1477 XPixSet (FRAME_X_WINDOW (f), 0, 0, width, thickness, pixel);
1478 XPixSet (FRAME_X_WINDOW (f), 0, 0, thickness, height, pixel);
1479 XPixSet (FRAME_X_WINDOW (f), 0, height - thickness, width,
1480 thickness, pixel);
1481 XPixSet (FRAME_X_WINDOW (f), width - thickness, 0, thickness,
1482 height, pixel);
1484 if (always)
1485 x_display_cursor (f, 1);
1487 #endif /* ! defined (HAVE_X11) */
1489 static void XTframe_rehighlight ();
1491 /* The focus has changed. Update the frames as necessary to reflect
1492 the new situation. Note that we can't change the selected frame
1493 here, because the lisp code we are interrupting might become confused.
1494 Each event gets marked with the frame in which it occurred, so the
1495 lisp code can tell when the switch took place by examining the events. */
1497 static void
1498 x_new_focus_frame (frame)
1499 struct frame *frame;
1501 struct frame *old_focus = x_focus_frame;
1502 int events_enqueued = 0;
1504 if (frame != x_focus_frame)
1506 /* Set this before calling other routines, so that they see
1507 the correct value of x_focus_frame. */
1508 x_focus_frame = frame;
1510 if (old_focus && old_focus->auto_lower)
1511 x_lower_frame (old_focus);
1513 #if 0
1514 selected_frame = frame;
1515 XSET (XWINDOW (selected_frame->selected_window)->frame,
1516 Lisp_Frame, selected_frame);
1517 Fselect_window (selected_frame->selected_window);
1518 choose_minibuf_frame ();
1519 #endif /* ! 0 */
1521 if (x_focus_frame && x_focus_frame->auto_raise)
1522 x_raise_frame (x_focus_frame);
1525 XTframe_rehighlight ();
1529 /* The focus has changed, or we have redirected a frame's focus to
1530 another frame (this happens when a frame uses a surrogate
1531 minibuffer frame). Shift the highlight as appropriate. */
1532 static void
1533 XTframe_rehighlight ()
1535 struct frame *old_highlight = x_highlight_frame;
1537 if (x_focus_frame)
1539 x_highlight_frame =
1540 ((XGCTYPE (FRAME_FOCUS_FRAME (x_focus_frame)) == Lisp_Frame)
1541 ? XFRAME (FRAME_FOCUS_FRAME (x_focus_frame))
1542 : x_focus_frame);
1543 if (! FRAME_LIVE_P (x_highlight_frame))
1545 FRAME_FOCUS_FRAME (x_focus_frame) = Qnil;
1546 x_highlight_frame = x_focus_frame;
1549 else
1550 x_highlight_frame = 0;
1552 if (x_highlight_frame != old_highlight)
1554 if (old_highlight)
1555 frame_unhighlight (old_highlight);
1556 if (x_highlight_frame)
1557 frame_highlight (x_highlight_frame);
1561 /* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
1563 /* Which modifier keys are on which modifier bits?
1565 With each keystroke, X returns eight bits indicating which modifier
1566 keys were held down when the key was pressed. The interpretation
1567 of the top five modifier bits depends on what keys are attached
1568 to them. If the Meta_L and Meta_R keysyms are on mod5, then mod5
1569 is the meta bit.
1571 x_meta_mod_mask is a mask containing the bits used for the meta key.
1572 It may have more than one bit set, if more than one modifier bit
1573 has meta keys on it. Basically, if EVENT is a KeyPress event,
1574 the meta key is pressed if (EVENT.state & x_meta_mod_mask) != 0.
1576 x_shift_lock_mask is LockMask if the XK_Shift_Lock keysym is on the
1577 lock modifier bit, or zero otherwise. Non-alphabetic keys should
1578 only be affected by the lock modifier bit if XK_Shift_Lock is in
1579 use; XK_Caps_Lock should only affect alphabetic keys. With this
1580 arrangement, the lock modifier should shift the character if
1581 (EVENT.state & x_shift_lock_mask) != 0. */
1582 static int x_meta_mod_mask, x_shift_lock_mask;
1584 /* These are like x_meta_mod_mask, but for different modifiers. */
1585 static int x_alt_mod_mask, x_super_mod_mask, x_hyper_mod_mask;
1587 /* Initialize mode_switch_bit and modifier_meaning. */
1588 static void
1589 x_find_modifier_meanings ()
1591 int min_code, max_code;
1592 KeySym *syms;
1593 int syms_per_code;
1594 XModifierKeymap *mods;
1596 x_meta_mod_mask = 0;
1597 x_shift_lock_mask = 0;
1598 x_alt_mod_mask = 0;
1599 x_super_mod_mask = 0;
1600 x_hyper_mod_mask = 0;
1602 #ifdef HAVE_X11R4
1603 XDisplayKeycodes (x_current_display, &min_code, &max_code);
1604 #else
1605 min_code = x_current_display->min_keycode;
1606 max_code = x_current_display->max_keycode;
1607 #endif
1609 syms = XGetKeyboardMapping (x_current_display,
1610 min_code, max_code - min_code + 1,
1611 &syms_per_code);
1612 mods = XGetModifierMapping (x_current_display);
1614 /* Scan the modifier table to see which modifier bits the Meta and
1615 Alt keysyms are on. */
1617 int row, col; /* The row and column in the modifier table. */
1619 for (row = 3; row < 8; row++)
1620 for (col = 0; col < mods->max_keypermod; col++)
1622 KeyCode code =
1623 mods->modifiermap[(row * mods->max_keypermod) + col];
1625 /* Zeroes are used for filler. Skip them. */
1626 if (code == 0)
1627 continue;
1629 /* Are any of this keycode's keysyms a meta key? */
1631 int code_col;
1633 for (code_col = 0; code_col < syms_per_code; code_col++)
1635 int sym = syms[((code - min_code) * syms_per_code) + code_col];
1637 switch (sym)
1639 case XK_Meta_L:
1640 case XK_Meta_R:
1641 x_meta_mod_mask |= (1 << row);
1642 break;
1644 case XK_Alt_L:
1645 case XK_Alt_R:
1646 x_alt_mod_mask |= (1 << row);
1647 break;
1649 case XK_Hyper_L:
1650 case XK_Hyper_R:
1651 x_hyper_mod_mask |= (1 << row);
1652 break;
1654 case XK_Super_L:
1655 case XK_Super_R:
1656 x_super_mod_mask |= (1 << row);
1657 break;
1659 case XK_Shift_Lock:
1660 /* Ignore this if it's not on the lock modifier. */
1661 if ((1 << row) == LockMask)
1662 x_shift_lock_mask = LockMask;
1663 break;
1670 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
1671 if (! x_meta_mod_mask)
1673 x_meta_mod_mask = x_alt_mod_mask;
1674 x_alt_mod_mask = 0;
1677 /* If some keys are both alt and meta,
1678 make them just meta, not alt. */
1679 if (x_alt_mod_mask & x_meta_mod_mask)
1681 x_alt_mod_mask &= ~x_meta_mod_mask;
1684 XFree ((char *) syms);
1685 XFreeModifiermap (mods);
1688 /* Convert between the modifier bits X uses and the modifier bits
1689 Emacs uses. */
1690 static unsigned int
1691 x_x_to_emacs_modifiers (state)
1692 unsigned int state;
1694 return ( ((state & (ShiftMask | x_shift_lock_mask)) ? shift_modifier : 0)
1695 | ((state & ControlMask) ? ctrl_modifier : 0)
1696 | ((state & x_meta_mod_mask) ? meta_modifier : 0)
1697 | ((state & x_alt_mod_mask) ? alt_modifier : 0)
1698 | ((state & x_super_mod_mask) ? super_modifier : 0)
1699 | ((state & x_hyper_mod_mask) ? hyper_modifier : 0));
1702 static unsigned int
1703 x_emacs_to_x_modifiers (state)
1704 unsigned int state;
1706 return ( ((state & alt_modifier) ? x_alt_mod_mask : 0)
1707 | ((state & super_modifier) ? x_super_mod_mask : 0)
1708 | ((state & hyper_modifier) ? x_hyper_mod_mask : 0)
1709 | ((state & shift_modifier) ? ShiftMask : 0)
1710 | ((state & ctrl_modifier) ? ControlMask : 0)
1711 | ((state & meta_modifier) ? x_meta_mod_mask : 0));
1714 /* Return true iff KEYSYM is a vendor-specific keysym that we should
1715 return as a function key. If you add a keysym to this, you should
1716 make sure that the tables make_lispy_event uses contain a suitable
1717 name for it. */
1718 static int
1719 x_is_vendor_fkey (sym)
1720 KeySym sym;
1722 return 0
1723 #ifdef DXK_Remove
1724 || (sym == DXK_Remove)
1725 #endif
1730 /* Mouse clicks and mouse movement. Rah. */
1731 #ifdef HAVE_X11
1733 /* Given a pixel position (PIX_X, PIX_Y) on the frame F, return
1734 glyph co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle
1735 that the glyph at X, Y occupies, if BOUNDS != 0.
1736 If NOCLIP is nonzero, do not force the value into range. */
1738 void
1739 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1740 FRAME_PTR f;
1741 register int pix_x, pix_y;
1742 register int *x, *y;
1743 XRectangle *bounds;
1744 int noclip;
1746 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
1747 even for negative values. */
1748 if (pix_x < 0)
1749 pix_x -= FONT_WIDTH ((f)->display.x->font) - 1;
1750 if (pix_y < 0)
1751 pix_y -= FONT_HEIGHT ((f)->display.x->font) - 1;
1753 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
1754 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
1756 if (bounds)
1758 bounds->width = FONT_WIDTH (f->display.x->font);
1759 bounds->height = FONT_HEIGHT (f->display.x->font);
1760 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
1761 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
1764 if (!noclip)
1766 if (pix_x < 0)
1767 pix_x = 0;
1768 else if (pix_x > f->width)
1769 pix_x = f->width;
1771 if (pix_y < 0)
1772 pix_y = 0;
1773 else if (pix_y > f->height)
1774 pix_y = f->height;
1777 *x = pix_x;
1778 *y = pix_y;
1781 void
1782 glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
1783 FRAME_PTR f;
1784 register int x, y;
1785 register int *pix_x, *pix_y;
1787 *pix_x = CHAR_TO_PIXEL_COL (f, x);
1788 *pix_y = CHAR_TO_PIXEL_ROW (f, y);
1791 /* Prepare a mouse-event in *RESULT for placement in the input queue.
1793 If the event is a button press, then note that we have grabbed
1794 the mouse. */
1796 static Lisp_Object
1797 construct_mouse_click (result, event, f)
1798 struct input_event *result;
1799 XButtonEvent *event;
1800 struct frame *f;
1802 /* Make the event type no_event; we'll change that when we decide
1803 otherwise. */
1804 result->kind = mouse_click;
1805 result->code = event->button - Button1;
1806 result->timestamp = event->time;
1807 result->modifiers = (x_x_to_emacs_modifiers (event->state)
1808 | (event->type == ButtonRelease
1809 ? up_modifier
1810 : down_modifier));
1812 /* Notice if the mouse is still grabbed. */
1813 if (event->type == ButtonPress)
1815 if (! x_mouse_grabbed)
1816 Vmouse_depressed = Qt;
1817 x_mouse_grabbed |= (1 << event->button);
1818 last_mouse_frame = f;
1820 else if (event->type == ButtonRelease)
1822 x_mouse_grabbed &= ~(1 << event->button);
1823 if (!x_mouse_grabbed)
1824 Vmouse_depressed = Qnil;
1828 int row, column;
1830 #if 0
1831 pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL, 0);
1832 XFASTINT (result->x) = column;
1833 XFASTINT (result->y) = row;
1834 #endif
1835 XSET (result->x, Lisp_Int, event->x);
1836 XSET (result->y, Lisp_Int, event->y);
1837 XSET (result->frame_or_window, Lisp_Frame, f);
1841 /* Prepare a menu-event in *RESULT for placement in the input queue. */
1843 static Lisp_Object
1844 construct_menu_click (result, event, f)
1845 struct input_event *result;
1846 XButtonEvent *event;
1847 struct frame *f;
1849 /* Make the event type no_event; we'll change that when we decide
1850 otherwise. */
1851 result->kind = mouse_click;
1852 XSET (result->code, Lisp_Int, event->button - Button1);
1853 result->timestamp = event->time;
1854 result->modifiers = (x_x_to_emacs_modifiers (event->state)
1855 | (event->type == ButtonRelease
1856 ? up_modifier
1857 : down_modifier));
1859 XSET (result->x, Lisp_Int, event->x);
1860 XSET (result->y, Lisp_Int, -1);
1861 XSET (result->frame_or_window, Lisp_Frame, f);
1864 /* Function to report a mouse movement to the mainstream Emacs code.
1865 The input handler calls this.
1867 We have received a mouse movement event, which is given in *event.
1868 If the mouse is over a different glyph than it was last time, tell
1869 the mainstream emacs code by setting mouse_moved. If not, ask for
1870 another motion event, so we can check again the next time it moves. */
1872 static void
1873 note_mouse_movement (frame, event)
1874 FRAME_PTR frame;
1875 XMotionEvent *event;
1878 last_mouse_movement_time = event->time;
1880 /* Has the mouse moved off the glyph it was on at the last sighting? */
1881 if (event->x < last_mouse_glyph.x
1882 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
1883 || event->y < last_mouse_glyph.y
1884 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
1886 mouse_moved = 1;
1887 last_mouse_scroll_bar = Qnil;
1889 note_mouse_highlight (frame, event->x, event->y);
1891 /* Ask for another mouse motion event. */
1893 int dummy;
1895 XQueryPointer (event->display, event->window,
1896 (Window *) &dummy, (Window *) &dummy,
1897 &dummy, &dummy, &dummy, &dummy,
1898 (unsigned int *) &dummy);
1901 else
1903 /* It's on the same glyph. Call XQueryPointer so we'll get an
1904 event the next time the mouse moves and we can see if it's
1905 *still* on the same glyph. */
1906 int dummy;
1908 XQueryPointer (event->display, event->window,
1909 (Window *) &dummy, (Window *) &dummy,
1910 &dummy, &dummy, &dummy, &dummy,
1911 (unsigned int *) &dummy);
1915 /* This is used for debugging, to turn off note_mouse_highlight. */
1916 static int disable_mouse_highlight;
1918 /* Take proper action when the mouse has moved to position X, Y on frame F
1919 as regards highlighting characters that have mouse-face properties.
1920 Also dehighlighting chars where the mouse was before. */
1922 static void
1923 note_mouse_highlight (f, x, y)
1924 FRAME_PTR f;
1926 int row, column, portion;
1927 XRectangle new_glyph;
1928 Lisp_Object window;
1929 struct window *w;
1931 if (disable_mouse_highlight)
1932 return;
1934 mouse_face_mouse_x = x;
1935 mouse_face_mouse_y = y;
1936 mouse_face_mouse_frame = f;
1938 if (mouse_face_defer)
1939 return;
1941 /* Find out which glyph the mouse is on. */
1942 pixel_to_glyph_coords (f, x, y, &column, &row,
1943 &new_glyph, x_mouse_grabbed);
1945 /* Which window is that in? */
1946 window = window_from_coordinates (f, column, row, &portion);
1947 w = XWINDOW (window);
1949 /* If we were displaying active text in another window, clear that. */
1950 if (! EQ (window, mouse_face_window))
1951 clear_mouse_face ();
1953 /* Are we in a window whose display is up to date? */
1954 if (WINDOWP (window) && portion == 0
1955 && EQ (w->window_end_valid, Qt))
1957 int *ptr = FRAME_CURRENT_GLYPHS (f)->charstarts[row];
1958 int i, pos;
1960 /* Find which buffer position the mouse corresponds to. */
1961 for (i = column; i >= 0; i--)
1962 if (ptr[i] > 0)
1963 break;
1964 pos = ptr[i];
1965 /* Is it outside the displayed active region (if any)? */
1966 if (pos > 0
1967 && ! (EQ (window, mouse_face_window)
1968 && pos >= mouse_face_beg && pos < mouse_face_end))
1970 Lisp_Object mouse_face, overlay, position;
1971 Lisp_Object *overlay_vec;
1972 int len, noverlays, ignor1;
1973 struct buffer *obuf;
1975 /* If we get an out-of-range value, return now;
1976 don't get an error. */
1977 if (pos > BUF_ZV (XBUFFER (w->buffer)))
1978 return;
1980 /* Make the window's buffer temporarily current for
1981 overlays_at and compute_char_face. */
1982 obuf = current_buffer;
1983 current_buffer = XBUFFER (w->buffer);
1985 /* Yes. Clear the display of the old active region, if any. */
1986 clear_mouse_face ();
1988 /* Is this char mouse-active? */
1989 XSET (position, Lisp_Int, pos);
1991 len = 10;
1992 overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
1994 /* Put all the overlays we want in a vector in overlay_vec.
1995 Store the length in len. */
1996 noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len, &ignor1);
1997 noverlays = sort_overlays (overlay_vec, noverlays, w);
1999 /* Find the highest priority overlay that has a mouse-face prop. */
2000 overlay = Qnil;
2001 for (i = 0; i < noverlays; i++)
2003 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
2004 if (!NILP (mouse_face))
2006 overlay = overlay_vec[i];
2007 break;
2010 free (overlay_vec);
2011 /* If no overlay applies, get a text property. */
2012 if (NILP (overlay))
2013 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
2015 /* Handle the overlay case. */
2016 if (! NILP (overlay))
2018 /* Find the range of text around this char that
2019 should be active. */
2020 Lisp_Object before, after;
2021 int ignore;
2023 before = Foverlay_start (overlay);
2024 after = Foverlay_end (overlay);
2025 /* Record this as the current active region. */
2026 mouse_face_beg = XFASTINT (before);
2027 mouse_face_end = XFASTINT (after);
2028 mouse_face_window = window;
2029 mouse_face_face_id = compute_char_face (f, w, pos, 0, 0,
2030 &ignore, pos + 1, 1);
2032 /* Display it as active. */
2033 show_mouse_face (1);
2035 /* Handle the text property case. */
2036 else if (! NILP (mouse_face))
2038 /* Find the range of text around this char that
2039 should be active. */
2040 Lisp_Object before, after, beginning, end;
2041 int ignore;
2043 beginning = Fmarker_position (w->start);
2044 XSET (end, Lisp_Int,
2045 (BUF_Z (XBUFFER (w->buffer))
2046 - XFASTINT (w->window_end_pos)));
2047 before
2048 = Fprevious_single_property_change (make_number (pos + 1),
2049 Qmouse_face,
2050 w->buffer, beginning);
2051 after
2052 = Fnext_single_property_change (position, Qmouse_face,
2053 w->buffer, end);
2054 /* Record this as the current active region. */
2055 mouse_face_beg = XFASTINT (before);
2056 mouse_face_end = XFASTINT (after);
2057 mouse_face_window = window;
2058 mouse_face_face_id
2059 = compute_char_face (f, w, pos, 0, 0,
2060 &ignore, pos + 1, 1);
2062 /* Display it as active. */
2063 show_mouse_face (1);
2065 current_buffer = obuf;
2067 else if (pos <= 0)
2068 clear_mouse_face ();
2072 /* Find the row and column of position POS in window WINDOW.
2073 Store them in *COLUMNP and *ROWP.
2074 This assumes display in WINDOW is up to date.
2075 If POS is above start of WINDOW, return coords
2076 of start of first screen line.
2077 If POS is after end of WINDOW, return coords of end of last screen line. */
2079 static int
2080 fast_find_position (window, pos, columnp, rowp)
2081 Lisp_Object window;
2082 int pos;
2083 int *columnp, *rowp;
2085 struct window *w = XWINDOW (window);
2086 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2087 int i;
2088 int row;
2089 int left = w->left;
2090 int top = w->top;
2091 int height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
2092 int width = window_internal_width (w);
2093 int *charstarts;
2094 int lastcol;
2096 for (i = 0;
2097 i < height;
2098 i++)
2100 int linestart = FRAME_CURRENT_GLYPHS (f)->charstarts[top + i][left];
2101 if (linestart > pos)
2102 break;
2103 if (linestart > 0)
2104 row = i;
2107 charstarts = FRAME_CURRENT_GLYPHS (f)->charstarts[top + row];
2108 lastcol = left;
2109 for (i = 0; i < width; i++)
2111 if (charstarts[left + i] == pos)
2113 *rowp = row + top;
2114 *columnp = i + left;
2115 return 1;
2117 else if (charstarts[left + i] > pos)
2118 lastcol = left + i;
2121 *rowp = row + top;
2122 *columnp = lastcol;
2123 return 0;
2126 /* Display the active region described by mouse_face_*
2127 in its mouse-face if HL > 0, in its normal face if HL = 0. */
2129 static void
2130 show_mouse_face (hl)
2131 int hl;
2133 int begcol, begrow, endcol, endrow;
2134 struct window *w = XWINDOW (mouse_face_window);
2135 int width = window_internal_width (w);
2136 FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
2137 int i;
2139 fast_find_position (mouse_face_window, mouse_face_beg,
2140 &begcol, &begrow);
2141 fast_find_position (mouse_face_window, mouse_face_end,
2142 &endcol, &endrow);
2144 x_display_cursor (f, 0);
2146 for (i = begrow; i <= endrow; i++)
2148 int column = (i == begrow ? begcol : w->left);
2149 int endcolumn = (i == endrow ? endcol : w->left + width);
2150 endcolumn = min (endcolumn, FRAME_CURRENT_GLYPHS (f)->used[i] - w->left),
2152 dumpglyphs (f,
2153 CHAR_TO_PIXEL_COL (f, column),
2154 CHAR_TO_PIXEL_ROW (f, i),
2155 FRAME_CURRENT_GLYPHS (f)->glyphs[i] + column,
2156 endcolumn - column,
2157 /* Highlight with mouse face if hl > 0. */
2158 hl > 0 ? 3 : 0);
2161 x_display_cursor (f, 1);
2164 /* Clear out the mouse-highlighted active region.
2165 Redraw it unhighlighted first. */
2167 static void
2168 clear_mouse_face ()
2170 if (! NILP (mouse_face_window))
2171 show_mouse_face (0);
2173 mouse_face_beg = -1;
2174 mouse_face_end = -1;
2175 mouse_face_window = Qnil;
2178 static struct scroll_bar *x_window_to_scroll_bar ();
2179 static void x_scroll_bar_report_motion ();
2181 /* Return the current position of the mouse.
2183 If the mouse movement started in a scroll bar, set *f, *bar_window,
2184 and *part to the frame, window, and scroll bar part that the mouse
2185 is over. Set *x and *y to the portion and whole of the mouse's
2186 position on the scroll bar.
2188 If the mouse movement started elsewhere, set *f to the frame the
2189 mouse is on, *bar_window to nil, and *x and *y to the character cell
2190 the mouse is over.
2192 Set *time to the server timestamp for the time at which the mouse
2193 was at this position.
2195 Don't store anything if we don't have a valid set of values to report.
2197 This clears the mouse_moved flag, so we can wait for the next mouse
2198 movement. This also calls XQueryPointer, which will cause the
2199 server to give us another MotionNotify when the mouse moves
2200 again. */
2202 static void
2203 XTmouse_position (f, bar_window, part, x, y, time)
2204 FRAME_PTR *f;
2205 Lisp_Object *bar_window;
2206 enum scroll_bar_part *part;
2207 Lisp_Object *x, *y;
2208 unsigned long *time;
2210 FRAME_PTR f1;
2212 BLOCK_INPUT;
2214 if (! NILP (last_mouse_scroll_bar))
2215 x_scroll_bar_report_motion (f, bar_window, part, x, y, time);
2216 else
2218 Window root;
2219 int root_x, root_y;
2221 Window dummy_window;
2222 int dummy;
2224 mouse_moved = 0;
2225 last_mouse_scroll_bar = Qnil;
2227 /* Figure out which root window we're on. */
2228 XQueryPointer (x_current_display,
2229 DefaultRootWindow (x_current_display),
2231 /* The root window which contains the pointer. */
2232 &root,
2234 /* Trash which we can't trust if the pointer is on
2235 a different screen. */
2236 &dummy_window,
2238 /* The position on that root window. */
2239 &root_x, &root_y,
2241 /* More trash we can't trust. */
2242 &dummy, &dummy,
2244 /* Modifier keys and pointer buttons, about which
2245 we don't care. */
2246 (unsigned int *) &dummy);
2248 /* Now we have a position on the root; find the innermost window
2249 containing the pointer. */
2251 Window win, child;
2252 int win_x, win_y;
2253 int parent_x, parent_y;
2255 win = root;
2257 if (x_mouse_grabbed)
2259 /* If mouse was grabbed on a frame, give coords for that frame
2260 even if the mouse is now outside it. */
2261 XTranslateCoordinates (x_current_display,
2263 /* From-window, to-window. */
2264 root, FRAME_X_WINDOW (last_mouse_frame),
2266 /* From-position, to-position. */
2267 root_x, root_y, &win_x, &win_y,
2269 /* Child of win. */
2270 &child);
2271 f1 = last_mouse_frame;
2273 else
2275 while (1)
2277 XTranslateCoordinates (x_current_display,
2279 /* From-window, to-window. */
2280 root, win,
2282 /* From-position, to-position. */
2283 root_x, root_y, &win_x, &win_y,
2285 /* Child of win. */
2286 &child);
2288 if (child == None)
2289 break;
2291 win = child;
2292 parent_x = win_x;
2293 parent_y = win_y;
2296 /* Now we know that:
2297 win is the innermost window containing the pointer
2298 (XTC says it has no child containing the pointer),
2299 win_x and win_y are the pointer's position in it
2300 (XTC did this the last time through), and
2301 parent_x and parent_y are the pointer's position in win's parent.
2302 (They are what win_x and win_y were when win was child.
2303 If win is the root window, it has no parent, and
2304 parent_{x,y} are invalid, but that's okay, because we'll
2305 never use them in that case.) */
2307 /* Is win one of our frames? */
2308 f1 = x_any_window_to_frame (win);
2311 /* If not, is it one of our scroll bars? */
2312 if (! f1)
2314 struct scroll_bar *bar = x_window_to_scroll_bar (win);
2316 if (bar)
2318 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2319 win_x = parent_x;
2320 win_y = parent_y;
2324 if (f1)
2326 int ignore1, ignore2;
2328 /* Ok, we found a frame. Store all the values. */
2330 pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
2331 &last_mouse_glyph, x_mouse_grabbed);
2333 *bar_window = Qnil;
2334 *part = 0;
2335 *f = f1;
2336 XSET (*x, Lisp_Int, win_x);
2337 XSET (*y, Lisp_Int, win_y);
2338 *time = last_mouse_movement_time;
2343 UNBLOCK_INPUT;
2346 #else /* ! defined (HAVE_X11) */
2347 #define XEvent XKeyPressedEvent
2348 #endif /* ! defined (HAVE_X11) */
2350 /* Scroll bar support. */
2352 /* Given an X window ID, find the struct scroll_bar which manages it.
2353 This can be called in GC, so we have to make sure to strip off mark
2354 bits. */
2355 static struct scroll_bar *
2356 x_window_to_scroll_bar (window_id)
2357 Window window_id;
2359 Lisp_Object tail, frame;
2361 for (tail = Vframe_list;
2362 XGCTYPE (tail) == Lisp_Cons;
2363 tail = XCONS (tail)->cdr)
2365 Lisp_Object frame, bar, condemned;
2367 frame = XCONS (tail)->car;
2368 /* All elements of Vframe_list should be frames. */
2369 if (XGCTYPE (frame) != Lisp_Frame)
2370 abort ();
2372 /* Scan this frame's scroll bar list for a scroll bar with the
2373 right window ID. */
2374 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
2375 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
2376 /* This trick allows us to search both the ordinary and
2377 condemned scroll bar lists with one loop. */
2378 ! GC_NILP (bar) || (bar = condemned,
2379 condemned = Qnil,
2380 ! GC_NILP (bar));
2381 bar = XSCROLL_BAR (bar)->next)
2382 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
2383 return XSCROLL_BAR (bar);
2386 return 0;
2389 /* Open a new X window to serve as a scroll bar, and return the
2390 scroll bar vector for it. */
2391 static struct scroll_bar *
2392 x_scroll_bar_create (window, top, left, width, height)
2393 struct window *window;
2394 int top, left, width, height;
2396 FRAME_PTR frame = XFRAME (WINDOW_FRAME (window));
2397 struct scroll_bar *bar =
2398 XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
2400 BLOCK_INPUT;
2403 XSetWindowAttributes a;
2404 unsigned long mask;
2405 a.background_pixel = frame->display.x->background_pixel;
2406 a.event_mask = (ButtonPressMask | ButtonReleaseMask
2407 | ButtonMotionMask | PointerMotionHintMask
2408 | ExposureMask);
2409 a.cursor = x_vertical_scroll_bar_cursor;
2411 mask = (CWBackPixel | CWEventMask | CWCursor);
2413 #if 0
2415 ac = 0;
2416 XtSetArg (al[ac], XtNx, left); ac++;
2417 XtSetArg (al[ac], XtNy, top); ac++;
2418 XtSetArg (al[ac], XtNwidth, width); ac++;
2419 XtSetArg (al[ac], XtNheight, height); ac++;
2420 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
2421 sb_widget = XtCreateManagedWidget ("box",
2422 boxWidgetClass,
2423 frame->display.x->edit_widget, al, ac);
2424 SET_SCROLL_BAR_X_WINDOW
2425 (bar, sb_widget->core.window);
2426 #endif
2427 SET_SCROLL_BAR_X_WINDOW
2428 (bar,
2429 XCreateWindow (x_current_display, FRAME_X_WINDOW (frame),
2431 /* Position and size of scroll bar. */
2432 left, top, width, height,
2434 /* Border width, depth, class, and visual. */
2435 0, CopyFromParent, CopyFromParent, CopyFromParent,
2437 /* Attributes. */
2438 mask, &a));
2441 XSET (bar->window, Lisp_Window, window);
2442 XSET (bar->top, Lisp_Int, top);
2443 XSET (bar->left, Lisp_Int, left);
2444 XSET (bar->width, Lisp_Int, width);
2445 XSET (bar->height, Lisp_Int, height);
2446 XSET (bar->start, Lisp_Int, 0);
2447 XSET (bar->end, Lisp_Int, 0);
2448 bar->dragging = Qnil;
2450 /* Add bar to its frame's list of scroll bars. */
2451 bar->next = FRAME_SCROLL_BARS (frame);
2452 bar->prev = Qnil;
2453 XSET (FRAME_SCROLL_BARS (frame), Lisp_Vector, bar);
2454 if (! NILP (bar->next))
2455 XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar);
2457 XMapWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar));
2459 UNBLOCK_INPUT;
2461 return bar;
2464 /* Draw BAR's handle in the proper position.
2465 If the handle is already drawn from START to END, don't bother
2466 redrawing it, unless REBUILD is non-zero; in that case, always
2467 redraw it. (REBUILD is handy for drawing the handle after expose
2468 events.)
2470 Normally, we want to constrain the start and end of the handle to
2471 fit inside its rectangle, but if the user is dragging the scroll bar
2472 handle, we want to let them drag it down all the way, so that the
2473 bar's top is as far down as it goes; otherwise, there's no way to
2474 move to the very end of the buffer. */
2475 static void
2476 x_scroll_bar_set_handle (bar, start, end, rebuild)
2477 struct scroll_bar *bar;
2478 int start, end;
2479 int rebuild;
2481 int dragging = ! NILP (bar->dragging);
2482 Window w = SCROLL_BAR_X_WINDOW (bar);
2483 GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
2485 /* If the display is already accurate, do nothing. */
2486 if (! rebuild
2487 && start == XINT (bar->start)
2488 && end == XINT (bar->end))
2489 return;
2491 BLOCK_INPUT;
2494 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (XINT (bar->width));
2495 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2496 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2498 /* Make sure the values are reasonable, and try to preserve
2499 the distance between start and end. */
2501 int length = end - start;
2503 if (start < 0)
2504 start = 0;
2505 else if (start > top_range)
2506 start = top_range;
2507 end = start + length;
2509 if (end < start)
2510 end = start;
2511 else if (end > top_range && ! dragging)
2512 end = top_range;
2515 /* Store the adjusted setting in the scroll bar. */
2516 XSET (bar->start, Lisp_Int, start);
2517 XSET (bar->end, Lisp_Int, end);
2519 /* Clip the end position, just for display. */
2520 if (end > top_range)
2521 end = top_range;
2523 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
2524 below top positions, to make sure the handle is always at least
2525 that many pixels tall. */
2526 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
2528 /* Draw the empty space above the handle. Note that we can't clear
2529 zero-height areas; that means "clear to end of window." */
2530 if (0 < start)
2531 XClearArea (x_current_display, w,
2533 /* x, y, width, height, and exposures. */
2534 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2535 VERTICAL_SCROLL_BAR_TOP_BORDER,
2536 inside_width, start,
2537 False);
2539 /* Draw the handle itself. */
2540 XFillRectangle (x_current_display, w, gc,
2542 /* x, y, width, height */
2543 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2544 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
2545 inside_width, end - start);
2548 /* Draw the empty space below the handle. Note that we can't
2549 clear zero-height areas; that means "clear to end of window." */
2550 if (end < inside_height)
2551 XClearArea (x_current_display, w,
2553 /* x, y, width, height, and exposures. */
2554 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2555 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
2556 inside_width, inside_height - end,
2557 False);
2561 UNBLOCK_INPUT;
2564 /* Move a scroll bar around on the screen, to accommodate changing
2565 window configurations. */
2566 static void
2567 x_scroll_bar_move (bar, top, left, width, height)
2568 struct scroll_bar *bar;
2569 int top, left, width, height;
2571 BLOCK_INPUT;
2574 XWindowChanges wc;
2575 unsigned int mask = 0;
2577 wc.x = left;
2578 wc.y = top;
2579 wc.width = width;
2580 wc.height = height;
2582 if (left != XINT (bar->left)) mask |= CWX;
2583 if (top != XINT (bar->top)) mask |= CWY;
2584 if (width != XINT (bar->width)) mask |= CWWidth;
2585 if (height != XINT (bar->height)) mask |= CWHeight;
2587 if (mask)
2588 XConfigureWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar),
2589 mask, &wc);
2592 XSET (bar->left, Lisp_Int, left);
2593 XSET (bar->top, Lisp_Int, top);
2594 XSET (bar->width, Lisp_Int, width);
2595 XSET (bar->height, Lisp_Int, height);
2597 UNBLOCK_INPUT;
2600 /* Destroy the X window for BAR, and set its Emacs window's scroll bar
2601 to nil. */
2602 static void
2603 x_scroll_bar_remove (bar)
2604 struct scroll_bar *bar;
2606 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2608 BLOCK_INPUT;
2610 /* Destroy the window. */
2611 XDestroyWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar));
2613 /* Disassociate this scroll bar from its window. */
2614 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
2616 UNBLOCK_INPUT;
2619 /* Set the handle of the vertical scroll bar for WINDOW to indicate
2620 that we are displaying PORTION characters out of a total of WHOLE
2621 characters, starting at POSITION. If WINDOW has no scroll bar,
2622 create one. */
2623 static void
2624 XTset_vertical_scroll_bar (window, portion, whole, position)
2625 struct window *window;
2626 int portion, whole, position;
2628 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2629 int top = XINT (window->top);
2630 int left = WINDOW_VERTICAL_SCROLL_BAR_COLUMN (window);
2631 int height = WINDOW_VERTICAL_SCROLL_BAR_HEIGHT (window);
2633 /* Where should this scroll bar be, pixelwise? */
2634 int pixel_top = CHAR_TO_PIXEL_ROW (f, top);
2635 int pixel_left = CHAR_TO_PIXEL_COL (f, left);
2636 int pixel_width = VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f);
2637 int pixel_height = VERTICAL_SCROLL_BAR_PIXEL_HEIGHT (f, height);
2639 struct scroll_bar *bar;
2641 /* Does the scroll bar exist yet? */
2642 if (NILP (window->vertical_scroll_bar))
2643 bar = x_scroll_bar_create (window,
2644 pixel_top, pixel_left,
2645 pixel_width, pixel_height);
2646 else
2648 /* It may just need to be moved and resized. */
2649 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2650 x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
2653 /* Set the scroll bar's current state, unless we're currently being
2654 dragged. */
2655 if (NILP (bar->dragging))
2657 int top_range =
2658 VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
2660 if (whole == 0)
2661 x_scroll_bar_set_handle (bar, 0, top_range, 0);
2662 else
2664 int start = ((double) position * top_range) / whole;
2665 int end = ((double) (position + portion) * top_range) / whole;
2667 x_scroll_bar_set_handle (bar, start, end, 0);
2671 XSET (window->vertical_scroll_bar, Lisp_Vector, bar);
2675 /* The following three hooks are used when we're doing a thorough
2676 redisplay of the frame. We don't explicitly know which scroll bars
2677 are going to be deleted, because keeping track of when windows go
2678 away is a real pain - "Can you say set-window-configuration, boys
2679 and girls?" Instead, we just assert at the beginning of redisplay
2680 that *all* scroll bars are to be removed, and then save a scroll bar
2681 from the fiery pit when we actually redisplay its window. */
2683 /* Arrange for all scroll bars on FRAME to be removed at the next call
2684 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
2685 `*redeem_scroll_bar_hook' is applied to its window before the judgement. */
2686 static void
2687 XTcondemn_scroll_bars (frame)
2688 FRAME_PTR frame;
2690 /* The condemned list should be empty at this point; if it's not,
2691 then the rest of Emacs isn't using the condemn/redeem/judge
2692 protocol correctly. */
2693 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
2694 abort ();
2696 /* Move them all to the "condemned" list. */
2697 FRAME_CONDEMNED_SCROLL_BARS (frame) = FRAME_SCROLL_BARS (frame);
2698 FRAME_SCROLL_BARS (frame) = Qnil;
2701 /* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
2702 Note that WINDOW isn't necessarily condemned at all. */
2703 static void
2704 XTredeem_scroll_bar (window)
2705 struct window *window;
2707 struct scroll_bar *bar;
2709 /* We can't redeem this window's scroll bar if it doesn't have one. */
2710 if (NILP (window->vertical_scroll_bar))
2711 abort ();
2713 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2715 /* Unlink it from the condemned list. */
2717 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2719 if (NILP (bar->prev))
2721 /* If the prev pointer is nil, it must be the first in one of
2722 the lists. */
2723 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
2724 /* It's not condemned. Everything's fine. */
2725 return;
2726 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
2727 window->vertical_scroll_bar))
2728 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
2729 else
2730 /* If its prev pointer is nil, it must be at the front of
2731 one or the other! */
2732 abort ();
2734 else
2735 XSCROLL_BAR (bar->prev)->next = bar->next;
2737 if (! NILP (bar->next))
2738 XSCROLL_BAR (bar->next)->prev = bar->prev;
2740 bar->next = FRAME_SCROLL_BARS (f);
2741 bar->prev = Qnil;
2742 XSET (FRAME_SCROLL_BARS (f), Lisp_Vector, bar);
2743 if (! NILP (bar->next))
2744 XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar);
2748 /* Remove all scroll bars on FRAME that haven't been saved since the
2749 last call to `*condemn_scroll_bars_hook'. */
2750 static void
2751 XTjudge_scroll_bars (f)
2752 FRAME_PTR f;
2754 Lisp_Object bar, next;
2756 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
2758 /* Clear out the condemned list now so we won't try to process any
2759 more events on the hapless scroll bars. */
2760 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
2762 for (; ! NILP (bar); bar = next)
2764 struct scroll_bar *b = XSCROLL_BAR (bar);
2766 x_scroll_bar_remove (b);
2768 next = b->next;
2769 b->next = b->prev = Qnil;
2772 /* Now there should be no references to the condemned scroll bars,
2773 and they should get garbage-collected. */
2777 /* Handle an Expose or GraphicsExpose event on a scroll bar.
2779 This may be called from a signal handler, so we have to ignore GC
2780 mark bits. */
2781 static void
2782 x_scroll_bar_expose (bar, event)
2783 struct scroll_bar *bar;
2784 XEvent *event;
2786 Window w = SCROLL_BAR_X_WINDOW (bar);
2787 GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
2789 BLOCK_INPUT;
2791 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
2793 /* Draw a one-pixel border just inside the edges of the scroll bar. */
2794 XDrawRectangle (x_current_display, w, gc,
2796 /* x, y, width, height */
2797 0, 0, XINT (bar->width) - 1, XINT (bar->height) - 1);
2799 UNBLOCK_INPUT;
2802 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2803 is set to something other than no_event, it is enqueued.
2805 This may be called from a signal handler, so we have to ignore GC
2806 mark bits. */
2807 static void
2808 x_scroll_bar_handle_click (bar, event, emacs_event)
2809 struct scroll_bar *bar;
2810 XEvent *event;
2811 struct input_event *emacs_event;
2813 if (XGCTYPE (bar->window) != Lisp_Window)
2814 abort ();
2816 emacs_event->kind = scroll_bar_click;
2817 emacs_event->code = event->xbutton.button - Button1;
2818 emacs_event->modifiers =
2819 (x_x_to_emacs_modifiers (event->xbutton.state)
2820 | (event->type == ButtonRelease
2821 ? up_modifier
2822 : down_modifier));
2823 emacs_event->frame_or_window = bar->window;
2824 emacs_event->timestamp = event->xbutton.time;
2826 int internal_height =
2827 VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2828 int top_range =
2829 VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2830 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
2832 if (y < 0) y = 0;
2833 if (y > top_range) y = top_range;
2835 if (y < XINT (bar->start))
2836 emacs_event->part = scroll_bar_above_handle;
2837 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2838 emacs_event->part = scroll_bar_handle;
2839 else
2840 emacs_event->part = scroll_bar_below_handle;
2842 /* Just because the user has clicked on the handle doesn't mean
2843 they want to drag it. Lisp code needs to be able to decide
2844 whether or not we're dragging. */
2845 #if 0
2846 /* If the user has just clicked on the handle, record where they're
2847 holding it. */
2848 if (event->type == ButtonPress
2849 && emacs_event->part == scroll_bar_handle)
2850 XSET (bar->dragging, Lisp_Int, y - XINT (bar->start));
2851 #endif
2853 /* If the user has released the handle, set it to its final position. */
2854 if (event->type == ButtonRelease
2855 && ! NILP (bar->dragging))
2857 int new_start = y - XINT (bar->dragging);
2858 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
2860 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
2861 bar->dragging = Qnil;
2864 /* Same deal here as the other #if 0. */
2865 #if 0
2866 /* Clicks on the handle are always reported as occurring at the top of
2867 the handle. */
2868 if (emacs_event->part == scroll_bar_handle)
2869 emacs_event->x = bar->start;
2870 else
2871 XSET (emacs_event->x, Lisp_Int, y);
2872 #else
2873 XSET (emacs_event->x, Lisp_Int, y);
2874 #endif
2876 XSET (emacs_event->y, Lisp_Int, top_range);
2880 /* Handle some mouse motion while someone is dragging the scroll bar.
2882 This may be called from a signal handler, so we have to ignore GC
2883 mark bits. */
2884 static void
2885 x_scroll_bar_note_movement (bar, event)
2886 struct scroll_bar *bar;
2887 XEvent *event;
2889 last_mouse_movement_time = event->xmotion.time;
2891 mouse_moved = 1;
2892 XSET (last_mouse_scroll_bar, Lisp_Vector, bar);
2894 /* If we're dragging the bar, display it. */
2895 if (! GC_NILP (bar->dragging))
2897 /* Where should the handle be now? */
2898 int new_start = event->xmotion.y - XINT (bar->dragging);
2900 if (new_start != XINT (bar->start))
2902 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
2904 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
2908 /* Call XQueryPointer so we'll get an event the next time the mouse
2909 moves and we can see *still* on the same position. */
2911 int dummy;
2913 XQueryPointer (event->xmotion.display, event->xmotion.window,
2914 (Window *) &dummy, (Window *) &dummy,
2915 &dummy, &dummy, &dummy, &dummy,
2916 (unsigned int *) &dummy);
2920 /* Return information to the user about the current position of the mouse
2921 on the scroll bar. */
2922 static void
2923 x_scroll_bar_report_motion (f, bar_window, part, x, y, time)
2924 FRAME_PTR *f;
2925 Lisp_Object *bar_window;
2926 enum scroll_bar_part *part;
2927 Lisp_Object *x, *y;
2928 unsigned long *time;
2930 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
2931 int win_x, win_y;
2932 Window dummy_window;
2933 int dummy_coord;
2934 unsigned int dummy_mask;
2936 BLOCK_INPUT;
2938 /* Get the mouse's position relative to the scroll bar window, and
2939 report that. */
2940 if (! XQueryPointer (x_current_display,
2941 SCROLL_BAR_X_WINDOW (bar),
2943 /* Root, child, root x and root y. */
2944 &dummy_window, &dummy_window,
2945 &dummy_coord, &dummy_coord,
2947 /* Position relative to scroll bar. */
2948 &win_x, &win_y,
2950 /* Mouse buttons and modifier keys. */
2951 &dummy_mask))
2952 *f = 0;
2953 else
2955 int inside_height
2956 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2957 int top_range
2958 = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2960 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2962 if (! NILP (bar->dragging))
2963 win_y -= XINT (bar->dragging);
2965 if (win_y < 0)
2966 win_y = 0;
2967 if (win_y > top_range)
2968 win_y = top_range;
2970 *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2971 *bar_window = bar->window;
2973 if (! NILP (bar->dragging))
2974 *part = scroll_bar_handle;
2975 else if (win_y < XINT (bar->start))
2976 *part = scroll_bar_above_handle;
2977 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2978 *part = scroll_bar_handle;
2979 else
2980 *part = scroll_bar_below_handle;
2982 XSET (*x, Lisp_Int, win_y);
2983 XSET (*y, Lisp_Int, top_range);
2985 mouse_moved = 0;
2986 last_mouse_scroll_bar = Qnil;
2989 *time = last_mouse_movement_time;
2991 UNBLOCK_INPUT;
2995 /* The screen has been cleared so we may have changed foreground or
2996 background colors, and the scroll bars may need to be redrawn.
2997 Clear out the scroll bars, and ask for expose events, so we can
2998 redraw them. */
3000 x_scroll_bar_clear (f)
3001 FRAME_PTR f;
3003 Lisp_Object bar;
3005 for (bar = FRAME_SCROLL_BARS (f);
3006 XTYPE (bar) == Lisp_Vector;
3007 bar = XSCROLL_BAR (bar)->next)
3008 XClearArea (x_current_display, SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
3009 0, 0, 0, 0, True);
3012 /* This processes Expose events from the menubar specific X event
3013 loop in menubar.c. This allows to redisplay the frame if necessary
3014 when handling menubar or popup items. */
3016 void
3017 process_expose_from_menu (event)
3018 XEvent event;
3020 FRAME_PTR f;
3022 BLOCK_INPUT;
3024 f = x_window_to_frame (event.xexpose.window);
3025 if (f)
3027 if (f->async_visible == 0)
3029 f->async_visible = 1;
3030 f->async_iconified = 0;
3031 SET_FRAME_GARBAGED (f);
3033 else
3035 dumprectangle (x_window_to_frame (event.xexpose.window),
3036 event.xexpose.x, event.xexpose.y,
3037 event.xexpose.width, event.xexpose.height);
3040 else
3042 struct scroll_bar *bar
3043 = x_window_to_scroll_bar (event.xexpose.window);
3045 if (bar)
3046 x_scroll_bar_expose (bar, &event);
3049 UNBLOCK_INPUT;
3053 /* The main X event-reading loop - XTread_socket. */
3055 /* Timestamp of enter window event. This is only used by XTread_socket,
3056 but we have to put it out here, since static variables within functions
3057 sometimes don't work. */
3058 static Time enter_timestamp;
3060 /* This holds the state XLookupString needs to implement dead keys
3061 and other tricks known as "compose processing". _X Window System_
3062 says that a portable program can't use this, but Stephen Gildea assures
3063 me that letting the compiler initialize it to zeros will work okay.
3065 This must be defined outside of XTread_socket, for the same reasons
3066 given for enter_timestamp, above. */
3067 static XComposeStatus compose_status;
3069 /* Communication with window managers. */
3070 Atom Xatom_wm_protocols;
3072 /* Kinds of protocol things we may receive. */
3073 Atom Xatom_wm_take_focus;
3074 Atom Xatom_wm_save_yourself;
3075 Atom Xatom_wm_delete_window;
3077 /* Other WM communication */
3078 Atom Xatom_wm_configure_denied; /* When our config request is denied */
3079 Atom Xatom_wm_window_moved; /* When the WM moves us. */
3081 /* Window manager communication. */
3082 Atom Xatom_wm_change_state;
3084 /* Record the last 100 characters stored
3085 to help debug the loss-of-chars-during-GC problem. */
3086 int temp_index;
3087 short temp_buffer[100];
3089 /* Read events coming from the X server.
3090 This routine is called by the SIGIO handler.
3091 We return as soon as there are no more events to be read.
3093 Events representing keys are stored in buffer BUFP,
3094 which can hold up to NUMCHARS characters.
3095 We return the number of characters stored into the buffer,
3096 thus pretending to be `read'.
3098 WAITP is nonzero if we should block until input arrives.
3099 EXPECTED is nonzero if the caller knows input is available. */
3102 XTread_socket (sd, bufp, numchars, waitp, expected)
3103 register int sd;
3104 register struct input_event *bufp;
3105 register int numchars;
3106 int waitp;
3107 int expected;
3109 int count = 0;
3110 int nbytes = 0;
3111 int mask;
3112 int items_pending; /* How many items are in the X queue. */
3113 XEvent event;
3114 struct frame *f;
3115 int event_found = 0;
3116 int prefix;
3117 Lisp_Object part;
3119 if (interrupt_input_blocked)
3121 interrupt_input_pending = 1;
3122 return -1;
3125 interrupt_input_pending = 0;
3126 BLOCK_INPUT;
3128 if (numchars <= 0)
3129 abort (); /* Don't think this happens. */
3131 #ifdef FIOSNBIO
3132 /* If available, Xlib uses FIOSNBIO to make the socket
3133 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
3134 FIOSNBIO is ignored, and instead of signalling EWOULDBLOCK,
3135 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
3136 fcntl (fileno (stdin), F_SETFL, 0);
3137 #endif /* ! defined (FIOSNBIO) */
3139 #ifndef SIGIO
3140 #ifndef HAVE_SELECT
3141 if (! (fcntl (fileno (stdin), F_GETFL, 0) & O_NDELAY))
3143 extern int read_alarm_should_throw;
3144 read_alarm_should_throw = 1;
3145 XPeekEvent (XDISPLAY &event);
3146 read_alarm_should_throw = 0;
3148 #endif /* HAVE_SELECT */
3149 #endif /* SIGIO */
3151 while (XStuffPending () != 0)
3153 XNextEvent (XDISPLAY &event);
3154 event_found = 1;
3156 switch (event.type)
3158 #ifdef HAVE_X11
3159 case ClientMessage:
3161 if (event.xclient.message_type == Xatom_wm_protocols
3162 && event.xclient.format == 32)
3164 if (event.xclient.data.l[0] == Xatom_wm_take_focus)
3166 #ifdef USE_X_TOOLKIT
3167 /* f = x_any_window_to_frame (event.xclient.window); */
3168 f = x_window_to_frame (event.xclient.window);
3169 #else
3170 f = x_window_to_frame (event.xclient.window);
3171 #endif
3172 if (f)
3173 x_focus_on_frame (f);
3174 /* Not certain about handling scroll bars here */
3176 else if (event.xclient.data.l[0] == Xatom_wm_save_yourself)
3178 /* Save state modify the WM_COMMAND property to
3179 something which can reinstate us. This notifies
3180 the session manager, who's looking for such a
3181 PropertyNotify. Can restart processing when
3182 a keyboard or mouse event arrives. */
3183 if (numchars > 0)
3187 else if (event.xclient.data.l[0] == Xatom_wm_delete_window)
3189 struct frame *f = x_any_window_to_frame (event.xclient.window);
3191 if (f)
3193 if (numchars == 0)
3194 abort ();
3196 bufp->kind = delete_window_event;
3197 XSET (bufp->frame_or_window, Lisp_Frame, f);
3198 bufp++;
3200 count += 1;
3201 numchars -= 1;
3205 else if (event.xclient.message_type == Xatom_wm_configure_denied)
3208 else if (event.xclient.message_type == Xatom_wm_window_moved)
3210 int new_x, new_y;
3211 struct frame *f = x_window_to_frame (event.xclient.window);
3213 new_x = event.xclient.data.s[0];
3214 new_y = event.xclient.data.s[1];
3216 if (f)
3218 f->display.x->left_pos = new_x;
3219 f->display.x->top_pos = new_y;
3223 break;
3225 #ifdef NEW_SELECTIONS
3226 case SelectionNotify:
3227 #ifdef USE_X_TOOLKIT
3228 if (x_window_to_frame (event.xselection.requestor))
3229 x_handle_selection_notify (&event);
3230 else
3231 goto OTHER;
3232 #else /* not USE_X_TOOLKIT */
3233 x_handle_selection_notify (&event);
3234 #endif /* not USE_X_TOOLKIT */
3235 break;
3236 #endif /* NEW_SELECTIONS */
3238 case SelectionClear: /* Someone has grabbed ownership. */
3239 #ifdef NEW_SELECTIONS
3241 #ifdef USE_X_TOOLKIT
3242 if (x_window_to_frame (event.xselectionclear.window))
3244 #endif /* USE_X_TOOLKIT */
3245 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
3247 if (numchars == 0)
3248 abort ();
3250 bufp->kind = selection_clear_event;
3251 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3252 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3253 SELECTION_EVENT_TIME (bufp) = eventp->time;
3254 bufp++;
3256 count += 1;
3257 numchars -= 1;
3258 #ifdef USE_X_TOOLKIT
3260 else
3261 goto OTHER;
3262 #endif /* USE_X_TOOLKIT */
3264 #else /* not NEW_SELECTIONS */
3265 x_disown_selection (event.xselectionclear.window,
3266 event.xselectionclear.selection,
3267 event.xselectionclear.time);
3268 #endif /* not NEW_SELECTIONS */
3269 break;
3271 case SelectionRequest: /* Someone wants our selection. */
3272 #ifdef NEW_SELECTIONS
3274 #ifdef USE_X_TOOLKIT
3275 if (x_window_to_frame (event.xselectionrequest.owner))
3277 #endif /* USE_X_TOOLKIT */
3278 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
3280 if (numchars == 0)
3281 abort ();
3283 bufp->kind = selection_request_event;
3284 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3285 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
3286 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3287 SELECTION_EVENT_TARGET (bufp) = eventp->target;
3288 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
3289 SELECTION_EVENT_TIME (bufp) = eventp->time;
3290 bufp++;
3292 count += 1;
3293 numchars -= 1;
3294 #ifdef USE_X_TOOLKIT
3296 else
3297 goto OTHER;
3298 #endif /* USE_X_TOOLKIT */
3300 #else /* not NEW_SELECTIONS */
3301 x_answer_selection_request (event);
3302 #endif /* not NEW_SELECTIONS */
3303 break;
3305 case PropertyNotify:
3306 #ifdef NEW_SELECTIONS
3307 #ifdef USE_X_TOOLKIT
3308 if (x_any_window_to_frame (event.xproperty.window))
3309 x_handle_property_notify (&event);
3310 else
3311 goto OTHER;
3312 #else /* not USE_X_TOOLKIT */
3313 x_handle_property_notify (&event);
3314 #endif /* not USE_X_TOOLKIT */
3315 #else /* not NEW_SELECTIONS */
3316 /* If we're being told about a root window property, then it's
3317 a cut buffer change. */
3318 if (event.xproperty.window == ROOT_WINDOW)
3319 x_invalidate_cut_buffer_cache (&event.xproperty);
3321 /* Otherwise, we're probably handling an incremental
3322 selection transmission. */
3323 else
3325 /* If we were to do this synchronously, there'd be no worry
3326 about re-selecting. */
3327 x_send_incremental (event);
3329 #endif /* not NEW_SELECTIONS */
3330 break;
3332 case ReparentNotify:
3333 f = x_window_to_frame (event.xreparent.window);
3334 if (f)
3335 f->display.x->parent_desc = event.xreparent.parent;
3336 break;
3338 case Expose:
3339 f = x_window_to_frame (event.xexpose.window);
3340 if (f)
3342 if (f->async_visible == 0)
3344 f->async_visible = 1;
3345 f->async_iconified = 0;
3346 SET_FRAME_GARBAGED (f);
3348 else
3350 dumprectangle (x_window_to_frame (event.xexpose.window),
3351 event.xexpose.x, event.xexpose.y,
3352 event.xexpose.width, event.xexpose.height);
3355 else
3357 struct scroll_bar *bar
3358 = x_window_to_scroll_bar (event.xexpose.window);
3360 if (bar)
3361 x_scroll_bar_expose (bar, &event);
3362 #ifdef USE_X_TOOLKIT
3363 else
3364 goto OTHER;
3365 #endif /* USE_X_TOOLKIT */
3367 break;
3369 case GraphicsExpose: /* This occurs when an XCopyArea's
3370 source area was obscured or not
3371 available.*/
3372 f = x_window_to_frame (event.xgraphicsexpose.drawable);
3373 if (f)
3375 dumprectangle (f,
3376 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
3377 event.xgraphicsexpose.width,
3378 event.xgraphicsexpose.height);
3380 #ifdef USE_X_TOOLKIT
3381 else
3382 goto OTHER;
3383 #endif /* USE_X_TOOLKIT */
3384 break;
3386 case NoExpose: /* This occurs when an XCopyArea's
3387 source area was completely
3388 available */
3389 break;
3390 #else /* ! defined (HAVE_X11) */
3391 case ExposeWindow:
3392 if (event.subwindow != 0)
3393 break; /* duplicate event */
3394 f = x_window_to_frame (event.window);
3395 if (event.window == f->display.x->icon_desc)
3397 refreshicon (f);
3398 f->async_iconified = 1;
3400 if (event.window == FRAME_X_WINDOW (f))
3402 /* Say must check all windows' needs_exposure flags. */
3403 expose_all_windows = 1;
3404 f->display.x->needs_exposure = 1;
3405 f->async_visible = 1;
3407 break;
3409 case ExposeRegion:
3410 if (event.subwindow != 0)
3411 break; /* duplicate event */
3412 f = x_window_to_frame (event.window);
3413 if (event.window == f->display.x->icon_desc)
3415 refreshicon (f);
3416 break;
3418 /* If window already needs full redraw, ignore this rectangle. */
3419 if (expose_all_windows && f->display.x->needs_exposure)
3420 break;
3421 /* Put the event on the queue of rectangles to redraw. */
3422 if (enqueue_event (&event, &x_expose_queue))
3423 /* If it is full, we can't record the rectangle,
3424 so redraw this entire window. */
3426 /* Say must check all windows' needs_exposure flags. */
3427 expose_all_windows = 1;
3428 f->display.x->needs_exposure = 1;
3430 break;
3432 case ExposeCopy:
3433 /* This should happen only when we are expecting it,
3434 in x_read_exposes. */
3435 abort ();
3436 #endif /* ! defined (HAVE_X11) */
3438 #ifdef HAVE_X11
3439 case UnmapNotify:
3440 f = x_window_to_frame (event.xunmap.window);
3441 if (f) /* F may no longer exist if
3442 the frame was deleted. */
3444 /* While a frame is unmapped, display generation is
3445 disabled; you don't want to spend time updating a
3446 display that won't ever be seen. */
3447 f->async_visible = 0;
3448 /* The window manager never makes a window invisible
3449 ("withdrawn"); all it does is switch between visible
3450 and iconified. Frames get into the invisible state
3451 only through x_make_frame_invisible. */
3452 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
3453 f->async_iconified = 1;
3455 #ifdef USE_X_TOOLKIT
3456 goto OTHER;
3457 #endif /* USE_X_TOOLKIT */
3458 break;
3460 case MapNotify:
3461 #ifdef USE_X_TOOLKIT
3462 f = x_any_window_to_frame (event.xmap.window);
3463 #else /* not USE_X_TOOLKIT */
3464 f = x_window_to_frame (event.xmap.window);
3465 #endif /* not USE_X_TOOLKIT */
3466 if (f)
3468 f->async_visible = 1;
3469 f->async_iconified = 0;
3471 /* wait_reading_process_input will notice this and update
3472 the frame's display structures. */
3473 SET_FRAME_GARBAGED (f);
3475 #ifdef USE_X_TOOLKIT
3476 goto OTHER;
3477 #endif /* USE_X_TOOLKIT */
3478 break;
3480 /* Turn off processing if we become fully obscured. */
3481 case VisibilityNotify:
3482 break;
3484 #else /* ! defined (HAVE_X11) */
3485 case UnmapWindow:
3486 f = x_window_to_frame (event.window);
3487 if (event.window == f->display.x->icon_desc)
3488 f->async_iconified = 0;
3489 if (event.window == FRAME_X_WINDOW (f))
3490 f->async_visible = 0;
3491 break;
3492 #endif /* ! defined (HAVE_X11) */
3494 #ifdef HAVE_X11
3495 case KeyPress:
3496 f = x_any_window_to_frame (event.xkey.window);
3498 if (f != 0)
3500 KeySym keysym, orig_keysym;
3501 /* al%imercury@uunet.uu.net says that making this 81 instead of
3502 80 fixed a bug whereby meta chars made his Emacs hang. */
3503 unsigned char copy_buffer[81];
3504 int modifiers;
3506 event.xkey.state
3507 |= x_emacs_to_x_modifiers (extra_keyboard_modifiers);
3508 modifiers = event.xkey.state;
3510 /* This will have to go some day... */
3512 /* make_lispy_event turns chars into control chars.
3513 Don't do it here because XLookupString is too eager. */
3514 event.xkey.state &= ~ControlMask;
3515 nbytes =
3516 XLookupString (&event.xkey, copy_buffer, 80, &keysym,
3517 &compose_status);
3519 /* Strip off the vendor-specific keysym bit, and take a shot
3520 at recognizing the codes. HP servers have extra keysyms
3521 that fit into the MiscFunctionKey category. */
3522 orig_keysym = keysym;
3523 keysym &= ~(1<<28);
3525 if (numchars > 1)
3527 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
3528 || keysym == XK_Delete
3529 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
3530 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
3531 #ifdef HPUX
3532 /* This recognizes the "extended function keys".
3533 It seems there's no cleaner way.
3534 Test IsModifierKey to avoid handling mode_switch
3535 incorrectly. */
3536 || ((unsigned) (keysym) >= XK_Select
3537 && (unsigned)(keysym) < XK_KP_Space)
3538 #endif
3539 #ifdef XK_dead_circumflex
3540 || orig_keysym == XK_dead_circumflex
3541 #endif
3542 #ifdef XK_dead_grave
3543 || orig_keysym == XK_dead_grave
3544 #endif
3545 #ifdef XK_dead_tilde
3546 || orig_keysym == XK_dead_tilde
3547 #endif
3548 #ifdef XK_dead_diaeresis
3549 || orig_keysym == XK_dead_diaeresis
3550 #endif
3551 #ifdef XK_dead_macron
3552 || orig_keysym == XK_dead_macron
3553 #endif
3554 #ifdef XK_dead_degree
3555 || orig_keysym == XK_dead_degree
3556 #endif
3557 #ifdef XK_dead_acute
3558 || orig_keysym == XK_dead_acute
3559 #endif
3560 #ifdef XK_dead_cedilla
3561 || orig_keysym == XK_dead_cedilla
3562 #endif
3563 #ifdef XK_dead_breve
3564 || orig_keysym == XK_dead_breve
3565 #endif
3566 #ifdef XK_dead_ogonek
3567 || orig_keysym == XK_dead_ogonek
3568 #endif
3569 #ifdef XK_dead_caron
3570 || orig_keysym == XK_dead_caron
3571 #endif
3572 #ifdef XK_dead_doubleacute
3573 || orig_keysym == XK_dead_doubleacute
3574 #endif
3575 #ifdef XK_dead_abovedot
3576 || orig_keysym == XK_dead_abovedot
3577 #endif
3578 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
3579 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
3580 || x_is_vendor_fkey (orig_keysym))
3581 && ! (IsModifierKey (orig_keysym)
3582 #ifndef HAVE_X11R5
3583 #ifdef XK_Mode_switch
3584 || ((unsigned)(orig_keysym) == XK_Mode_switch)
3585 #endif
3586 #ifdef XK_Num_Lock
3587 || ((unsigned)(orig_keysym) == XK_Num_Lock)
3588 #endif
3589 #endif /* not HAVE_X11R5 */
3592 if (temp_index == sizeof temp_buffer / sizeof (short))
3593 temp_index = 0;
3594 temp_buffer[temp_index++] = keysym;
3595 bufp->kind = non_ascii_keystroke;
3596 bufp->code = keysym;
3597 XSET (bufp->frame_or_window, Lisp_Frame, f);
3598 bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
3599 bufp->timestamp = event.xkey.time;
3600 bufp++;
3601 count++;
3602 numchars--;
3604 else if (numchars > nbytes)
3606 register int i;
3608 for (i = 0; i < nbytes; i++)
3610 if (temp_index == sizeof temp_buffer / sizeof (short))
3611 temp_index = 0;
3612 temp_buffer[temp_index++] = copy_buffer[i];
3613 bufp->kind = ascii_keystroke;
3614 bufp->code = copy_buffer[i];
3615 XSET (bufp->frame_or_window, Lisp_Frame, f);
3616 bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
3617 bufp->timestamp = event.xkey.time;
3618 bufp++;
3621 count += nbytes;
3622 numchars -= nbytes;
3624 else
3625 abort ();
3627 else
3628 abort ();
3630 break;
3631 #else /* ! defined (HAVE_X11) */
3632 case KeyPressed:
3634 register char *where_mapping;
3636 f = x_window_to_frame (event.window);
3637 /* Ignore keys typed on icon windows. */
3638 if (f != 0 && event.window == f->display.x->icon_desc)
3639 break;
3640 where_mapping = XLookupMapping (&event, &nbytes);
3641 /* Nasty fix for arrow keys */
3642 if (!nbytes && IsCursorKey (event.detail & 0xff))
3644 switch (event.detail & 0xff)
3646 case KC_CURSOR_LEFT:
3647 where_mapping = "\002";
3648 break;
3649 case KC_CURSOR_RIGHT:
3650 where_mapping = "\006";
3651 break;
3652 case KC_CURSOR_UP:
3653 where_mapping = "\020";
3654 break;
3655 case KC_CURSOR_DOWN:
3656 where_mapping = "\016";
3657 break;
3659 nbytes = 1;
3661 if (numchars - nbytes > 0)
3663 register int i;
3665 for (i = 0; i < nbytes; i++)
3667 bufp->kind = ascii_keystroke;
3668 bufp->code = where_mapping[i];
3669 XSET (bufp->time, Lisp_Int, event.xkey.time);
3670 XSET (bufp->frame_or_window, Lisp_Frame, f);
3671 bufp++;
3673 count += nbytes;
3674 numchars -= nbytes;
3677 break;
3678 #endif /* ! defined (HAVE_X11) */
3680 #ifdef HAVE_X11
3682 /* Here's a possible interpretation of the whole
3683 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If you get a
3684 FocusIn event, you have to get a FocusOut event before you
3685 relinquish the focus. If you haven't received a FocusIn event,
3686 then a mere LeaveNotify is enough to free you. */
3688 case EnterNotify:
3689 f = x_any_window_to_frame (event.xcrossing.window);
3691 if (event.xcrossing.focus) /* Entered Window */
3693 /* Avoid nasty pop/raise loops. */
3694 if (f && (!(f->auto_raise)
3695 || !(f->auto_lower)
3696 || (event.xcrossing.time - enter_timestamp) > 500))
3698 x_new_focus_frame (f);
3699 enter_timestamp = event.xcrossing.time;
3702 else if (f == x_focus_frame)
3703 x_new_focus_frame (0);
3704 #ifdef USE_X_TOOLKIT
3705 goto OTHER;
3706 #endif /* USE_X_TOOLKIT */
3707 break;
3709 case FocusIn:
3710 f = x_any_window_to_frame (event.xfocus.window);
3711 if (event.xfocus.detail != NotifyPointer)
3712 x_focus_event_frame = f;
3713 if (f)
3714 x_new_focus_frame (f);
3715 #ifdef USE_X_TOOLKIT
3716 goto OTHER;
3717 #endif /* USE_X_TOOLKIT */
3718 break;
3721 case LeaveNotify:
3722 f = x_any_window_to_frame (event.xcrossing.window);
3724 if (f == mouse_face_mouse_frame)
3725 /* If we move outside the frame,
3726 then we're certainly no longer on any text in the frame. */
3727 clear_mouse_face ();
3729 if (event.xcrossing.focus)
3731 if (! x_focus_event_frame)
3732 x_new_focus_frame (0);
3733 else
3734 x_new_focus_frame (f);
3736 else
3738 if (f == x_focus_event_frame)
3739 x_focus_event_frame = 0;
3740 if (f == x_focus_frame)
3741 x_new_focus_frame (0);
3743 #ifdef USE_X_TOOLKIT
3744 goto OTHER;
3745 #endif /* USE_X_TOOLKIT */
3746 break;
3748 case FocusOut:
3749 f = x_any_window_to_frame (event.xfocus.window);
3750 if (event.xfocus.detail != NotifyPointer
3751 && f == x_focus_event_frame)
3752 x_focus_event_frame = 0;
3753 if (f && f == x_focus_frame)
3754 x_new_focus_frame (0);
3755 #ifdef USE_X_TOOLKIT
3756 goto OTHER;
3757 #endif /* USE_X_TOOLKIT */
3758 break;
3760 #else /* ! defined (HAVE_X11) */
3762 case EnterWindow:
3763 if ((event.detail & 0xFF) == 1)
3764 break; /* Coming from our own subwindow */
3765 if (event.subwindow != 0)
3766 break; /* Entering our own subwindow. */
3769 f = x_window_to_frame (event.window);
3770 x_mouse_frame = f;
3772 x_new_focus_frame (f);
3774 break;
3776 case LeaveWindow:
3777 if ((event.detail & 0xFF) == 1)
3778 break; /* Entering our own subwindow */
3779 if (event.subwindow != 0)
3780 break; /* Leaving our own subwindow. */
3782 x_mouse_frame = 0;
3783 if (x_focus_frame == 0
3784 && x_input_frame != 0
3785 && x_input_frame == x_window_to_frame (event.window)
3786 && event.window == FRAME_X_WINDOW (x_input_frame))
3788 f = x_input_frame;
3789 x_input_frame = 0;
3790 if (f)
3791 frame_unhighlight (f);
3793 break;
3794 #endif /* ! defined (HAVE_X11) */
3796 #ifdef HAVE_X11
3797 case MotionNotify:
3799 if (x_mouse_grabbed)
3800 f = last_mouse_frame;
3801 else
3802 f = x_window_to_frame (event.xmotion.window);
3803 if (f)
3804 note_mouse_movement (f, &event.xmotion);
3805 else
3807 struct scroll_bar *bar
3808 = x_window_to_scroll_bar (event.xmotion.window);
3810 if (bar)
3811 x_scroll_bar_note_movement (bar, &event);
3813 /* If we move outside the frame,
3814 then we're certainly no longer on any text in the frame. */
3815 clear_mouse_face ();
3818 #ifdef USE_X_TOOLKIT
3819 goto OTHER;
3820 #endif /* USE_X_TOOLKIT */
3821 break;
3823 case ConfigureNotify:
3824 f = x_any_window_to_frame (event.xconfigure.window);
3825 #ifdef USE_X_TOOLKIT
3826 if (f
3827 && ! event.xconfigure.send_event
3828 && (event.xconfigure.window == XtWindow (f->display.x->widget)))
3830 Window win, child;
3831 int win_x, win_y;
3833 /* Find the position of the outside upper-left corner of
3834 the window, in the root coordinate system. Don't
3835 refer to the parent window here; we may be processing
3836 this event after the window manager has changed our
3837 parent, but before we have reached the ReparentNotify. */
3838 XTranslateCoordinates (x_current_display,
3840 /* From-window, to-window. */
3841 XtWindow (f->display.x->widget),
3842 ROOT_WINDOW,
3844 /* From-position, to-position. */
3845 -event.xconfigure.border_width,
3846 -event.xconfigure.border_width,
3847 &win_x, &win_y,
3849 /* Child of win. */
3850 &child);
3851 event.xconfigure.x = win_x;
3852 event.xconfigure.y = win_y;
3854 f->display.x->pixel_width = event.xconfigure.width;
3855 f->display.x->pixel_height = event.xconfigure.height;
3856 f->display.x->left_pos = event.xconfigure.x;
3857 f->display.x->top_pos = event.xconfigure.y;
3859 goto OTHER;
3860 #else /* not USE_X_TOOLKIT */
3861 if (f)
3863 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
3864 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
3866 /* Even if the number of character rows and columns has
3867 not changed, the font size may have changed, so we need
3868 to check the pixel dimensions as well. */
3869 if (columns != f->width
3870 || rows != f->height
3871 || event.xconfigure.width != f->display.x->pixel_width
3872 || event.xconfigure.height != f->display.x->pixel_height)
3874 change_frame_size (f, rows, columns, 0, 1);
3875 SET_FRAME_GARBAGED (f);
3878 if (! event.xconfigure.send_event)
3880 Window win, child;
3881 int win_x, win_y;
3883 /* Find the position of the outside upper-left corner of
3884 the window, in the root coordinate system. Don't
3885 refer to the parent window here; we may be processing
3886 this event after the window manager has changed our
3887 parent, but before we have reached the ReparentNotify. */
3888 XTranslateCoordinates (x_current_display,
3890 /* From-window, to-window. */
3891 f->display.x->window_desc,
3892 ROOT_WINDOW,
3894 /* From-position, to-position. */
3895 -event.xconfigure.border_width,
3896 -event.xconfigure.border_width,
3897 &win_x, &win_y,
3899 /* Child of win. */
3900 &child);
3901 event.xconfigure.x = win_x;
3902 event.xconfigure.y = win_y;
3905 f->display.x->pixel_width = event.xconfigure.width;
3906 f->display.x->pixel_height = event.xconfigure.height;
3907 f->display.x->left_pos = event.xconfigure.x;
3908 f->display.x->top_pos = event.xconfigure.y;
3910 #endif /* not USE_X_TOOLKIT */
3911 break;
3913 case ButtonPress:
3914 case ButtonRelease:
3916 /* If we decide we want to generate an event to be seen
3917 by the rest of Emacs, we put it here. */
3918 struct input_event emacs_event;
3919 emacs_event.kind = no_event;
3921 f = x_window_to_frame (event.xbutton.window);
3922 if (f)
3924 if (!x_focus_frame || (f == x_focus_frame))
3925 construct_mouse_click (&emacs_event, &event, f);
3927 else
3929 struct scroll_bar *bar =
3930 x_window_to_scroll_bar (event.xbutton.window);
3932 if (bar)
3933 x_scroll_bar_handle_click (bar, &event, &emacs_event);
3934 #ifdef USE_X_TOOLKIT
3935 else
3937 f = x_any_window_to_frame (event.xbutton.window);
3938 if (f && event.type == ButtonPress)
3939 construct_menu_click (&emacs_event,
3940 &event, f);
3942 #endif /* USE_X_TOOLKIT */
3945 if (numchars >= 1 && emacs_event.kind != no_event)
3947 bcopy (&emacs_event, bufp, sizeof (struct input_event));
3948 bufp++;
3949 count++;
3950 numchars--;
3953 #ifdef USE_X_TOOLKIT
3954 goto OTHER;
3955 #endif /* USE_X_TOOLKIT */
3957 break;
3959 #else /* ! defined (HAVE_X11) */
3960 case ButtonPressed:
3961 case ButtonReleased:
3962 f = x_window_to_frame (event.window);
3963 if (f)
3965 if (event.window == f->display.x->icon_desc)
3967 x_make_frame_visible (f);
3969 if (warp_mouse_on_deiconify)
3970 XWarpMouse (FRAME_X_WINDOW (f), 10, 10);
3971 break;
3973 if (event.window == FRAME_X_WINDOW (f))
3975 if (f->auto_raise)
3976 x_raise_frame (f);
3979 enqueue_event (&event, &x_mouse_queue);
3980 if (numchars >= 2)
3982 bufp->kind = ascii_keystroke;
3983 bufp->code = 'X' & 037; /* C-x */
3984 XSET (bufp->frame_or_window, Lisp_Frame, f);
3985 XSET (bufp->time, Lisp_Int, event.xkey.time);
3986 bufp++;
3988 bufp->kind = ascii_keystroke;
3989 bufp->code = 0; /* C-@ */
3990 XSET (bufp->frame_or_window, Lisp_Frame, f);
3991 XSET (bufp->time, Lisp_Int, event.xkey.time);
3992 bufp++;
3994 count += 2;
3995 numchars -= 2;
3997 break;
3998 #endif /* ! defined (HAVE_X11) */
4000 #ifdef HAVE_X11
4002 case CirculateNotify:
4003 break;
4004 case CirculateRequest:
4005 break;
4007 #endif /* ! defined (HAVE_X11) */
4009 case MappingNotify:
4010 /* Someone has changed the keyboard mapping - update the
4011 local cache. */
4012 switch (event.xmapping.request)
4014 case MappingModifier:
4015 x_find_modifier_meanings ();
4016 /* This is meant to fall through. */
4017 case MappingKeyboard:
4018 XRefreshKeyboardMapping (&event.xmapping);
4020 #ifdef USE_X_TOOLKIT
4021 goto OTHER;
4022 #endif /* USE_X_TOOLKIT */
4023 break;
4025 default:
4026 #ifdef USE_X_TOOLKIT
4027 OTHER:
4028 BLOCK_INPUT;
4029 XtDispatchEvent (&event);
4030 UNBLOCK_INPUT;
4031 #endif /* USE_X_TOOLKIT */
4032 break;
4036 #ifdef X_IO_BUG
4037 if (! event_found)
4038 /* On some systems, an X bug causes Emacs to get no more events
4039 when the window is destroyed. Detect that. (1994.) */
4040 XNoOp (x_current_display);
4041 #endif /* X_IO_BUG */
4043 #if 0 /* This fails for serial-line connections to the X server,
4044 because the characters arrive one by one, and a partial
4045 command makes select return but gives nothing to read.
4046 We'll have to hope that the bug that this tried to fix
4047 in 1988 has been fixed in Xlib or the X server. */
4048 #ifdef HAVE_SELECT
4049 if (expected && ! event_found)
4051 /* AOJ 880406: if select returns true but XPending doesn't, it means that
4052 there is an EOF condition; in other words, that X has died.
4053 Act as if there had been a hangup. */
4054 int fd = ConnectionNumber (x_current_display);
4055 SELECT_TYPE mask, junk1, junk2;
4056 EMACS_TIME timeout;
4058 FD_ZERO (&mask);
4059 FD_SET (fd, &mask);
4060 EMACS_SET_SECS_USECS (timeout, 0, 0);
4061 FD_ZERO (&junk1);
4062 FD_ZERO (&junk2);
4063 if (0 != select (fd + 1, &mask, &junk1, &junk2, &timeout)
4064 && !XStuffPending ())
4065 kill (getpid (), SIGHUP);
4067 #endif /* HAVE_SELECT */
4068 #endif /* 0 */
4070 #ifndef HAVE_X11
4071 if (updating_frame == 0)
4072 x_do_pending_expose ();
4073 #endif
4075 UNBLOCK_INPUT;
4076 return count;
4079 #ifndef HAVE_X11
4080 /* Read and process only Expose events
4081 until we get an ExposeCopy event; then return.
4082 This is used in insert/delete line.
4083 We assume input is already blocked. */
4085 static void
4086 x_read_exposes ()
4088 struct frame *f;
4089 XKeyPressedEvent event;
4091 while (1)
4093 /* while there are more events*/
4094 XMaskEvent (ExposeWindow | ExposeRegion | ExposeCopy, &event);
4095 switch (event.type)
4097 case ExposeWindow:
4098 if (event.subwindow != 0)
4099 break; /* duplicate event */
4100 f = x_window_to_frame (event.window);
4101 if (event.window == f->display.x->icon_desc)
4103 refreshicon (f);
4104 break;
4106 if (event.window == FRAME_X_WINDOW (f))
4108 expose_all_windows = 1;
4109 f->display.x->needs_exposure = 1;
4110 break;
4112 break;
4114 case ExposeRegion:
4115 if (event.subwindow != 0)
4116 break; /* duplicate event */
4117 f = x_window_to_frame (event.window);
4118 if (event.window == f->display.x->icon_desc)
4120 refreshicon (f);
4121 break;
4123 /* If window already needs full redraw, ignore this rectangle. */
4124 if (expose_all_windows && f->display.x->needs_exposure)
4125 break;
4126 /* Put the event on the queue of rectangles to redraw. */
4127 if (enqueue_event (&event, &x_expose_queue))
4128 /* If it is full, we can't record the rectangle,
4129 so redraw this entire window. */
4131 /* Say must check all windows' needs_exposure flags. */
4132 expose_all_windows = 1;
4133 f->display.x->needs_exposure = 1;
4135 break;
4137 case ExposeCopy:
4138 return;
4142 #endif /* HAVE_X11 */
4145 /* Drawing the cursor. */
4148 /* Draw a hollow box cursor. Don't change the inside of the box. */
4150 static void
4151 x_draw_box (f)
4152 struct frame *f;
4154 int left = CHAR_TO_PIXEL_COL (f, f->cursor_x);
4155 int top = CHAR_TO_PIXEL_ROW (f, f->cursor_y);
4156 int width = FONT_WIDTH (f->display.x->font);
4157 int height = FONT_HEIGHT (f->display.x->font);
4159 #ifdef HAVE_X11
4160 XDrawRectangle (x_current_display, FRAME_X_WINDOW (f),
4161 f->display.x->cursor_gc,
4162 left, top, width - 1, height - 1);
4163 #else /* ! defined (HAVE_X11) */
4164 XPixSet (FRAME_X_WINDOW (f),
4165 left, top, width, 1,
4166 f->display.x->cursor_pixel);
4168 XPixSet (FRAME_X_WINDOW (f),
4169 left, top, 1, height,
4170 f->display.x->cursor_pixel);
4172 XPixSet (FRAME_X_WINDOW (f),
4173 left+width-1, top, 1, height,
4174 f->display.x->cursor_pixel);
4176 XPixSet (FRAME_X_WINDOW (f),
4177 left, top+height-1, width, 1,
4178 f->display.x->cursor_pixel);
4179 #endif /* ! defined (HAVE_X11) */
4182 /* Clear the cursor of frame F to background color,
4183 and mark the cursor as not shown.
4184 This is used when the text where the cursor is
4185 is about to be rewritten. */
4187 static void
4188 clear_cursor (f)
4189 struct frame *f;
4191 int mask;
4193 if (! FRAME_VISIBLE_P (f)
4194 || f->phys_cursor_x < 0)
4195 return;
4197 #ifdef HAVE_X11
4198 x_display_cursor (f, 0);
4199 #else /* ! defined (HAVE_X11) */
4200 XPixSet (FRAME_X_WINDOW (f),
4201 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
4202 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
4203 FONT_WIDTH (f->display.x->font), FONT_HEIGHT (f->display.x->font),
4204 f->display.x->background_pixel);
4205 #endif /* ! defined (HAVE_X11) */
4206 f->phys_cursor_x = -1;
4209 /* Redraw the glyph at ROW, COLUMN on frame F, in the style
4210 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
4211 glyph drawn. */
4213 static void
4214 x_draw_single_glyph (f, row, column, glyph, highlight)
4215 struct frame *f;
4216 int row, column;
4217 GLYPH glyph;
4218 int highlight;
4220 dumpglyphs (f,
4221 CHAR_TO_PIXEL_COL (f, column),
4222 CHAR_TO_PIXEL_ROW (f, row),
4223 &glyph, 1, highlight);
4226 static void
4227 x_display_bar_cursor (f, on)
4228 struct frame *f;
4229 int on;
4231 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4233 /* This is pointless on invisible frames, and dangerous on garbaged
4234 frames; in the latter case, the frame may be in the midst of
4235 changing its size, and curs_x and curs_y may be off the frame. */
4236 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
4237 return;
4239 if (! on && f->phys_cursor_x < 0)
4240 return;
4242 /* If we're not updating, then we want to use the current frame's
4243 cursor position, not our local idea of where the cursor ought to be. */
4244 if (f != updating_frame)
4246 curs_x = FRAME_CURSOR_X (f);
4247 curs_y = FRAME_CURSOR_Y (f);
4250 /* If there is anything wrong with the current cursor state, remove it. */
4251 if (f->phys_cursor_x >= 0
4252 && (!on
4253 || f->phys_cursor_x != curs_x
4254 || f->phys_cursor_y != curs_y
4255 || f->display.x->current_cursor != bar_cursor))
4257 /* Erase the cursor by redrawing the character underneath it. */
4258 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4259 f->phys_cursor_glyph,
4260 current_glyphs->highlight[f->phys_cursor_y]);
4261 f->phys_cursor_x = -1;
4264 /* If we now need a cursor in the new place or in the new form, do it so. */
4265 if (on
4266 && (f->phys_cursor_x < 0
4267 || (f->display.x->current_cursor != bar_cursor)))
4269 f->phys_cursor_glyph
4270 = ((current_glyphs->enable[curs_y]
4271 && curs_x < current_glyphs->used[curs_y])
4272 ? current_glyphs->glyphs[curs_y][curs_x]
4273 : SPACEGLYPH);
4274 XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
4275 f->display.x->cursor_gc,
4276 CHAR_TO_PIXEL_COL (f, curs_x),
4277 CHAR_TO_PIXEL_ROW (f, curs_y),
4278 1, FONT_HEIGHT (f->display.x->font));
4280 f->phys_cursor_x = curs_x;
4281 f->phys_cursor_y = curs_y;
4283 f->display.x->current_cursor = bar_cursor;
4286 if (updating_frame != f)
4287 XFlushQueue ();
4291 /* Turn the displayed cursor of frame F on or off according to ON.
4292 If ON is nonzero, where to put the cursor is specified
4293 by F->cursor_x and F->cursor_y. */
4295 static void
4296 x_display_box_cursor (f, on)
4297 struct frame *f;
4298 int on;
4300 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4302 /* This is pointless on invisible frames, and dangerous on garbaged
4303 frames; in the latter case, the frame may be in the midst of
4304 changing its size, and curs_x and curs_y may be off the frame. */
4305 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
4306 return;
4308 /* If cursor is off and we want it off, return quickly. */
4309 if (!on && f->phys_cursor_x < 0)
4310 return;
4312 /* If we're not updating, then we want to use the current frame's
4313 cursor position, not our local idea of where the cursor ought to be. */
4314 if (f != updating_frame)
4316 curs_x = FRAME_CURSOR_X (f);
4317 curs_y = FRAME_CURSOR_Y (f);
4320 /* If cursor is currently being shown and we don't want it to be
4321 or it is in the wrong place,
4322 or we want a hollow box and it's not so, (pout!)
4323 erase it. */
4324 if (f->phys_cursor_x >= 0
4325 && (!on
4326 || f->phys_cursor_x != curs_x
4327 || f->phys_cursor_y != curs_y
4328 || (f->display.x->current_cursor != hollow_box_cursor
4329 && (f != x_highlight_frame))))
4331 /* Erase the cursor by redrawing the character underneath it. */
4332 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4333 f->phys_cursor_glyph,
4334 current_glyphs->highlight[f->phys_cursor_y]);
4335 f->phys_cursor_x = -1;
4338 /* If we want to show a cursor,
4339 or we want a box cursor and it's not so,
4340 write it in the right place. */
4341 if (on
4342 && (f->phys_cursor_x < 0
4343 || (f->display.x->current_cursor != filled_box_cursor
4344 && f == x_highlight_frame)))
4346 f->phys_cursor_glyph
4347 = ((current_glyphs->enable[curs_y]
4348 && curs_x < current_glyphs->used[curs_y])
4349 ? current_glyphs->glyphs[curs_y][curs_x]
4350 : SPACEGLYPH);
4351 if (f != x_highlight_frame)
4353 x_draw_box (f);
4354 f->display.x->current_cursor = hollow_box_cursor;
4356 else
4358 x_draw_single_glyph (f, curs_y, curs_x,
4359 f->phys_cursor_glyph, 2);
4360 f->display.x->current_cursor = filled_box_cursor;
4363 f->phys_cursor_x = curs_x;
4364 f->phys_cursor_y = curs_y;
4367 if (updating_frame != f)
4368 XFlushQueue ();
4371 x_display_cursor (f, on)
4372 struct frame *f;
4373 int on;
4375 BLOCK_INPUT;
4377 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
4378 x_display_box_cursor (f, on);
4379 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
4380 x_display_bar_cursor (f, on);
4381 else
4382 /* Those are the only two we have implemented! */
4383 abort ();
4385 UNBLOCK_INPUT;
4388 /* Icons. */
4390 /* Refresh bitmap kitchen sink icon for frame F
4391 when we get an expose event for it. */
4393 refreshicon (f)
4394 struct frame *f;
4396 #ifdef HAVE_X11
4397 /* Normally, the window manager handles this function. */
4398 #else /* ! defined (HAVE_X11) */
4399 int mask;
4401 if (f->display.x->icon_bitmap_flag)
4402 XBitmapBitsPut (f->display.x->icon_desc, 0, 0, sink_width, sink_height,
4403 sink_bits, BlackPixel, WHITE_PIX_DEFAULT,
4404 icon_bitmap, GXcopy, AllPlanes);
4405 else
4407 extern struct frame *selected_frame;
4408 struct Lisp_String *str;
4409 unsigned char *string;
4411 string
4412 = XSTRING (XBUFFER (XWINDOW (f->selected_window)->buffer)->name)->data;
4414 if (f->display.x->icon_label != string)
4416 f->display.x->icon_label = string;
4417 XChangeWindow (f->display.x->icon_desc,
4418 XQueryWidth (string, icon_font_info->id) + 10,
4419 icon_font_info->height + 10);
4422 XText (f->display.x->icon_desc, 5, 5, string,
4423 str->size, icon_font_info->id,
4424 BLACK_PIX_DEFAULT, WHITE_PIX_DEFAULT);
4426 XFlushQueue ();
4427 #endif /* ! defined (HAVE_X11) */
4430 /* Make the x-window of frame F use the gnu icon bitmap. */
4433 x_bitmap_icon (f)
4434 struct frame *f;
4436 int mask;
4437 Window icon_window;
4439 if (FRAME_X_WINDOW (f) == 0)
4440 return 1;
4442 #ifdef HAVE_X11
4443 if (! icon_bitmap)
4444 icon_bitmap =
4445 XCreateBitmapFromData (x_current_display, FRAME_X_WINDOW (f),
4446 gnu_bits, gnu_width, gnu_height);
4447 x_wm_set_icon_pixmap (f, icon_bitmap);
4448 f->display.x->icon_bitmap_flag = 1;
4449 #else /* ! defined (HAVE_X11) */
4450 if (f->display.x->icon_desc)
4452 XClearIconWindow (FRAME_X_WINDOW (f));
4453 XDestroyWindow (f->display.x->icon_desc);
4456 icon_window = XCreateWindow (f->display.x->parent_desc,
4457 0, 0, sink_width, sink_height,
4458 2, WhitePixmap, (Pixmap) NULL);
4460 if (icon_window == 0)
4461 return 1;
4463 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
4464 XSelectInput (icon_window, ExposeWindow | UnmapWindow);
4466 f->display.x->icon_desc = icon_window;
4467 f->display.x->icon_bitmap_flag = 1;
4469 if (icon_bitmap == 0)
4470 icon_bitmap
4471 = XStoreBitmap (sink_mask_width, sink_mask_height, sink_mask_bits);
4472 #endif /* ! defined (HAVE_X11) */
4474 return 0;
4478 /* Make the x-window of frame F use a rectangle with text. */
4481 x_text_icon (f, icon_name)
4482 struct frame *f;
4483 char *icon_name;
4485 #ifndef HAVE_X11
4486 int mask;
4487 int width;
4488 Window icon_window;
4489 char *X_DefaultValue;
4490 Bitmap b1;
4492 #ifndef WhitePixel
4493 #define WhitePixel 1
4494 #endif /* WhitePixel */
4496 #ifndef BlackPixel
4497 #define BlackPixel 0
4498 #endif /* BlackPixel */
4499 #endif /* HAVE_X11 */
4501 if (FRAME_X_WINDOW (f) == 0)
4502 return 1;
4504 #ifdef HAVE_X11
4505 if (icon_name)
4506 f->display.x->icon_label = icon_name;
4507 else
4508 if (! f->display.x->icon_label)
4509 f->display.x->icon_label = " *emacs* ";
4511 #if 0
4512 XSetIconName (x_current_display, FRAME_X_WINDOW (f),
4513 (char *) f->display.x->icon_label);
4514 #endif
4516 f->display.x->icon_bitmap_flag = 0;
4517 x_wm_set_icon_pixmap (f, 0);
4518 #else /* ! defined (HAVE_X11) */
4519 if (icon_font_info == 0)
4520 icon_font_info
4521 = XGetFont (XGetDefault (XDISPLAY
4522 (char *) XSTRING (Vinvocation_name)->data,
4523 "BodyFont"));
4525 if (f->display.x->icon_desc)
4527 XClearIconWindow (XDISPLAY FRAME_X_WINDOW (f));
4528 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
4531 if (icon_name)
4532 f->display.x->icon_label = (unsigned char *) icon_name;
4533 else
4534 if (! f->display.x->icon_label)
4535 f->display.x->icon_label = XSTRING (f->name)->data;
4537 width = XStringWidth (f->display.x->icon_label, icon_font_info, 0, 0);
4538 icon_window = XCreateWindow (f->display.x->parent_desc,
4539 f->display.x->left_pos,
4540 f->display.x->top_pos,
4541 width + 10, icon_font_info->height + 10,
4542 2, BlackPixmap, WhitePixmap);
4544 if (icon_window == 0)
4545 return 1;
4547 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
4548 XSelectInput (icon_window, ExposeWindow | ExposeRegion | UnmapWindow | ButtonPressed);
4550 f->display.x->icon_desc = icon_window;
4551 f->display.x->icon_bitmap_flag = 0;
4552 f->display.x->icon_label = 0;
4553 #endif /* ! defined (HAVE_X11) */
4555 return 0;
4558 /* Handling X errors. */
4560 /* Shut down Emacs in an orderly fashion, because of a SIGPIPE on the
4561 X server's connection, or an error reported via the X protocol. */
4563 static SIGTYPE
4564 x_connection_closed ()
4566 if (_Xdebug)
4567 abort ();
4569 shut_down_emacs (0, 1, Qnil);
4571 exit (70);
4574 /* An X error handler which prints an error message and then kills
4575 Emacs. This is what's normally installed as Xlib's handler for
4576 protocol errors. */
4577 static int
4578 x_error_quitter (display, error)
4579 Display *display;
4580 XErrorEvent *error;
4582 char buf[256];
4584 /* Note that there is no real way portable across R3/R4 to get the
4585 original error handler. */
4587 XGetErrorText (display, error->error_code, buf, sizeof (buf));
4588 fprintf (stderr, "X protocol error: %s on protocol request %d\n",
4589 buf, error->request_code);
4591 #if 0
4592 /* While we're testing Emacs 19, we'll just dump core whenever we
4593 get an X error, so we can figure out why it happened. */
4594 abort ();
4595 #endif
4597 x_connection_closed ();
4600 /* A handler for X IO errors which prints an error message and then
4601 kills Emacs. This is what is always installed as Xlib's handler
4602 for I/O errors. */
4603 static int
4604 x_io_error_quitter (display)
4605 Display *display;
4607 fprintf (stderr, "Connection to X server %s lost.\n",
4608 XDisplayName (DisplayString (display)));
4610 #if 0
4611 /* While we're testing Emacs 19, we'll just dump core whenever we
4612 get an X error, so we can figure out why it happened. */
4613 abort ();
4614 #endif
4616 x_connection_closed ();
4619 /* A buffer for storing X error messages. */
4620 static char *x_caught_error_message;
4621 #define X_CAUGHT_ERROR_MESSAGE_SIZE 200
4623 /* An X error handler which stores the error message in
4624 x_caught_error_message. This is what's installed when
4625 x_catch_errors is in effect. */
4626 static int
4627 x_error_catcher (display, error)
4628 Display *display;
4629 XErrorEvent *error;
4631 XGetErrorText (display, error->error_code,
4632 x_caught_error_message, X_CAUGHT_ERROR_MESSAGE_SIZE);
4636 /* Begin trapping X errors.
4638 After calling this function, X protocol errors no longer cause
4639 Emacs to exit; instead, they are recorded in x_cfc_error_message.
4641 Calling x_check_errors signals an Emacs error if an X error has
4642 occurred since the last call to x_catch_errors or x_check_errors.
4644 Calling x_uncatch_errors resumes the normal error handling. */
4646 void x_catch_errors (), x_check_errors (), x_uncatch_errors ();
4648 void
4649 x_catch_errors ()
4651 /* Make sure any errors from previous requests have been dealt with. */
4652 XSync (x_current_display, False);
4654 /* Set up the error buffer. */
4655 x_caught_error_message
4656 = (char*) xmalloc (X_CAUGHT_ERROR_MESSAGE_SIZE);
4657 x_caught_error_message[0] = '\0';
4659 /* Install our little error handler. */
4660 XHandleError (x_error_catcher);
4663 /* If any X protocol errors have arrived since the last call to
4664 x_catch_errors or x_check_errors, signal an Emacs error using
4665 sprintf (a buffer, FORMAT, the x error message text) as the text. */
4667 void
4668 x_check_errors (format)
4669 char *format;
4671 /* Make sure to catch any errors incurred so far. */
4672 XSync (x_current_display, False);
4674 if (x_caught_error_message[0])
4676 char buf[X_CAUGHT_ERROR_MESSAGE_SIZE + 56];
4678 sprintf (buf, format, x_caught_error_message);
4679 x_uncatch_errors ();
4680 error (buf);
4684 /* Nonzero if we had any X protocol errors since we did x_catch_errors. */
4687 x_had_errors_p ()
4689 /* Make sure to catch any errors incurred so far. */
4690 XSync (x_current_display, False);
4692 return x_caught_error_message[0] != 0;
4695 /* Stop catching X protocol errors and let them make Emacs die. */
4697 void
4698 x_uncatch_errors ()
4700 xfree (x_caught_error_message);
4701 x_caught_error_message = 0;
4702 XHandleError (x_error_quitter);
4705 #if 0
4706 static unsigned int x_wire_count;
4707 x_trace_wire ()
4709 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
4711 #endif /* ! 0 */
4714 /* Changing the font of the frame. */
4716 /* Set the font of the x-window specified by frame F
4717 to the font named NEWNAME. This is safe to use
4718 even before F has an actual x-window. */
4720 #ifdef HAVE_X11
4722 struct font_info
4724 XFontStruct *font;
4725 char *name;
4728 /* A table of all the fonts we have already loaded. */
4729 static struct font_info *x_font_table;
4731 /* The current capacity of x_font_table. */
4732 static int x_font_table_size;
4734 /* The number of fonts actually stored in x_font_table.
4735 x_font_table[n] is used and valid iff 0 <= n < n_fonts.
4736 0 <= n_fonts <= x_font_table_size. */
4737 static int n_fonts;
4739 Lisp_Object
4740 x_new_font (f, fontname)
4741 struct frame *f;
4742 register char *fontname;
4744 int already_loaded;
4745 int n_matching_fonts;
4746 XFontStruct *font_info;
4747 char **font_names;
4749 /* Get a list of all the fonts that match this name. Once we
4750 have a list of matching fonts, we compare them against the fonts
4751 we already have by comparing font ids. */
4752 font_names = (char **) XListFonts (x_current_display, fontname,
4753 1024, &n_matching_fonts);
4754 /* Apparently it doesn't set n_matching_fonts to zero when it can't
4755 find any matches; font_names == 0 is the only clue. */
4756 if (! font_names)
4757 n_matching_fonts = 0;
4759 /* Don't just give up if n_matching_fonts is 0.
4760 Apparently there's a bug on Suns: XListFontsWithInfo can
4761 fail to find a font, but XLoadQueryFont may still find it. */
4763 /* See if we've already loaded a matching font. */
4764 already_loaded = -1;
4765 if (n_matching_fonts != 0)
4767 int i, j;
4769 for (i = 0; i < n_fonts; i++)
4770 for (j = 0; j < n_matching_fonts; j++)
4771 if (!strcmp (x_font_table[i].name, font_names[j]))
4773 already_loaded = i;
4774 fontname = font_names[j];
4775 goto found_font;
4778 found_font:
4780 /* If we have, just return it from the table. */
4781 if (already_loaded >= 0)
4782 f->display.x->font = x_font_table[already_loaded].font;
4784 /* Otherwise, load the font and add it to the table. */
4785 else
4787 int i;
4788 XFontStruct *font;
4790 /* Try to find a character-cell font in the list. */
4791 #if 0
4792 /* A laudable goal, but this isn't how to do it. */
4793 for (i = 0; i < n_matching_fonts; i++)
4794 if (! font_info[i].per_char)
4795 break;
4796 #else
4797 i = 0;
4798 #endif
4800 /* See comment above. */
4801 if (n_matching_fonts != 0)
4802 fontname = font_names[i];
4804 font = (XFontStruct *) XLoadQueryFont (x_current_display, fontname);
4805 if (! font)
4807 /* Free the information from XListFonts. */
4808 if (n_matching_fonts)
4809 XFreeFontNames (font_names);
4810 return Qnil;
4813 /* Do we need to create the table? */
4814 if (x_font_table_size == 0)
4816 x_font_table_size = 16;
4817 x_font_table
4818 = (struct font_info *) xmalloc (x_font_table_size
4819 * sizeof (x_font_table[0]));
4821 /* Do we need to grow the table? */
4822 else if (n_fonts >= x_font_table_size)
4824 x_font_table_size *= 2;
4825 x_font_table
4826 = (struct font_info *) xrealloc (x_font_table,
4827 (x_font_table_size
4828 * sizeof (x_font_table[0])));
4831 x_font_table[n_fonts].name = (char *) xmalloc (strlen (fontname) + 1);
4832 bcopy (fontname, x_font_table[n_fonts].name, strlen (fontname) + 1);
4833 f->display.x->font = x_font_table[n_fonts++].font = font;
4836 /* Now make the frame display the given font. */
4837 if (FRAME_X_WINDOW (f) != 0)
4839 XSetFont (x_current_display, f->display.x->normal_gc,
4840 f->display.x->font->fid);
4841 XSetFont (x_current_display, f->display.x->reverse_gc,
4842 f->display.x->font->fid);
4843 XSetFont (x_current_display, f->display.x->cursor_gc,
4844 f->display.x->font->fid);
4846 x_set_window_size (f, 0, f->width, f->height);
4850 Lisp_Object lispy_name;
4852 lispy_name = build_string (fontname);
4854 /* Free the information from XListFonts. The data
4855 we actually retain comes from XLoadQueryFont. */
4856 XFreeFontNames (font_names);
4858 return lispy_name;
4861 #else /* ! defined (HAVE_X11) */
4862 x_new_font (f, newname)
4863 struct frame *f;
4864 register char *newname;
4866 FONT_TYPE *temp;
4867 int mask;
4869 temp = XGetFont (newname);
4870 if (temp == (FONT_TYPE *) 0)
4871 return 1;
4873 if (f->display.x->font)
4874 XLoseFont (f->display.x->font);
4876 f->display.x->font = temp;
4878 if (FRAME_X_WINDOW (f) != 0)
4879 x_set_window_size (f, 0, f->width, f->height);
4881 return 0;
4883 #endif /* ! defined (HAVE_X11) */
4885 x_calc_absolute_position (f)
4886 struct frame *f;
4888 #ifdef HAVE_X11
4889 Window win, child;
4890 int win_x = 0, win_y = 0;
4892 /* Find the position of the outside upper-left corner of
4893 the inner window, with respect to the outer window. */
4894 if (f->display.x->parent_desc != ROOT_WINDOW)
4896 BLOCK_INPUT;
4897 XTranslateCoordinates (x_current_display,
4899 /* From-window, to-window. */
4900 f->display.x->window_desc,
4901 f->display.x->parent_desc,
4903 /* From-position, to-position. */
4904 0, 0, &win_x, &win_y,
4906 /* Child of win. */
4907 &child);
4908 UNBLOCK_INPUT;
4911 /* Treat negative positions as relative to the leftmost bottommost
4912 position that fits on the screen. */
4913 if (f->display.x->left_pos < 0)
4914 f->display.x->left_pos = (x_screen_width
4915 - 2 * f->display.x->border_width - win_x
4916 - PIXEL_WIDTH (f)
4917 + f->display.x->left_pos);
4919 if (f->display.x->top_pos < 0)
4920 f->display.x->top_pos = (x_screen_height
4921 - 2 * f->display.x->border_width - win_y
4922 - PIXEL_HEIGHT (f)
4923 + f->display.x->top_pos);
4925 #else /* ! defined (HAVE_X11) */
4926 WINDOWINFO_TYPE parentinfo;
4928 XGetWindowInfo (FRAME_X_WINDOW (f), &parentinfo);
4930 if (f->display.x->left_pos < 0)
4931 f->display.x->left_pos = parentinfo.width + (f->display.x->left_pos + 1)
4932 - PIXEL_WIDTH (f) - 2 * f->display.x->internal_border_width;
4934 if (f->display.x->top_pos < 0)
4935 f->display.x->top_pos = parentinfo.height + (f->display.x->top_pos + 1)
4936 - PIXEL_HEIGHT (f) - 2 * f->display.x->internal_border_width;
4937 #endif /* ! defined (HAVE_X11) */
4940 x_set_offset (f, xoff, yoff)
4941 struct frame *f;
4942 register int xoff, yoff;
4944 f->display.x->top_pos = yoff;
4945 f->display.x->left_pos = xoff;
4946 x_calc_absolute_position (f);
4948 BLOCK_INPUT;
4949 #ifdef USE_X_TOOLKIT
4950 XMoveWindow (XDISPLAY XtWindow (f->display.x->widget),
4951 f->display.x->left_pos, f->display.x->top_pos);
4952 #else /* not USE_X_TOOLKIT */
4953 XMoveWindow (XDISPLAY FRAME_X_WINDOW (f),
4954 f->display.x->left_pos, f->display.x->top_pos);
4955 #endif /* not USE_X_TOOLKIT */
4956 #ifdef HAVE_X11
4957 x_wm_set_size_hint (f, 0, 1, xoff, yoff);
4958 #endif /* ! defined (HAVE_X11) */
4959 UNBLOCK_INPUT;
4962 /* Call this to change the size of frame F's x-window.
4963 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
4964 for this size change and subsequent size changes.
4965 Otherwise we leave the window gravity unchanged. */
4967 x_set_window_size (f, change_gravity, cols, rows)
4968 struct frame *f;
4969 int change_gravity;
4970 int cols, rows;
4972 int pixelwidth, pixelheight;
4973 int mask;
4975 #ifdef USE_X_TOOLKIT
4976 BLOCK_INPUT;
4977 EmacsFrameSetCharSize (f->display.x->edit_widget, cols, rows);
4978 UNBLOCK_INPUT;
4980 #else /* not USE_X_TOOLKIT */
4982 BLOCK_INPUT;
4984 check_frame_size (f, &rows, &cols);
4985 f->display.x->vertical_scroll_bar_extra
4986 = (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4987 ? VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f)
4988 : 0);
4989 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
4990 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
4992 #ifdef HAVE_X11
4993 x_wm_set_size_hint (f, 0, change_gravity, 0, 0);
4994 #endif /* ! defined (HAVE_X11) */
4995 XChangeWindowSize (FRAME_X_WINDOW (f), pixelwidth, pixelheight);
4997 /* Now, strictly speaking, we can't be sure that this is accurate,
4998 but the window manager will get around to dealing with the size
4999 change request eventually, and we'll hear how it went when the
5000 ConfigureNotify event gets here.
5002 We could just not bother storing any of this information here,
5003 and let the ConfigureNotify event set everything up, but that
5004 might be kind of confusing to the lisp code, since size changes
5005 wouldn't be reported in the frame parameters until some random
5006 point in the future when the ConfigureNotify event arrives. */
5007 change_frame_size (f, rows, cols, 0, 0);
5008 PIXEL_WIDTH (f) = pixelwidth;
5009 PIXEL_HEIGHT (f) = pixelheight;
5011 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
5012 receive in the ConfigureNotify event; if we get what we asked
5013 for, then the event won't cause the screen to become garbaged, so
5014 we have to make sure to do it here. */
5015 SET_FRAME_GARBAGED (f);
5017 XFlushQueue ();
5018 UNBLOCK_INPUT;
5019 #endif /* not USE_X_TOOLKIT */
5022 #ifndef HAVE_X11
5023 x_set_resize_hint (f)
5024 struct frame *f;
5026 XSetResizeHint (FRAME_X_WINDOW (f),
5027 2 * f->display.x->internal_border_width,
5028 2 * f->display.x->internal_border_width,
5029 FONT_WIDTH (f->display.x->font),
5030 FONT_HEIGHT (f->display.x->font));
5032 #endif /* HAVE_X11 */
5034 /* Mouse warping, focus shifting, raising and lowering. */
5036 x_set_mouse_position (f, x, y)
5037 struct frame *f;
5038 int x, y;
5040 int pix_x, pix_y;
5042 #if 0 /* Let the user ask for this if he wants it. */
5043 x_raise_frame (f);
5044 #endif
5046 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2;
5047 pix_y = CHAR_TO_PIXEL_ROW (f, y) + FONT_HEIGHT (f->display.x->font) / 2;
5049 if (pix_x < 0) pix_x = 0;
5050 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
5052 if (pix_y < 0) pix_y = 0;
5053 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
5055 BLOCK_INPUT;
5057 XWarpMousePointer (FRAME_X_WINDOW (f), pix_x, pix_y);
5058 UNBLOCK_INPUT;
5061 #ifdef HAVE_X11
5062 x_focus_on_frame (f)
5063 struct frame *f;
5065 #if 0 /* This proves to be unpleasant. */
5066 x_raise_frame (f);
5067 #endif
5068 #if 0
5069 /* I don't think that the ICCCM allows programs to do things like this
5070 without the interaction of the window manager. Whatever you end up
5071 doing with this code, do it to x_unfocus_frame too. */
5072 XSetInputFocus (x_current_display, FRAME_X_WINDOW (f),
5073 RevertToPointerRoot, CurrentTime);
5074 #endif /* ! 0 */
5077 x_unfocus_frame (f)
5078 struct frame *f;
5080 #if 0
5081 /* Look at the remarks in x_focus_on_frame. */
5082 if (x_focus_frame == f)
5083 XSetInputFocus (x_current_display, PointerRoot,
5084 RevertToPointerRoot, CurrentTime);
5085 #endif /* ! 0 */
5088 #endif /* ! defined (HAVE_X11) */
5090 /* Raise frame F. */
5092 x_raise_frame (f)
5093 struct frame *f;
5095 if (f->async_visible)
5097 BLOCK_INPUT;
5098 #ifdef USE_X_TOOLKIT
5099 XRaiseWindow (XDISPLAY XtWindow (f->display.x->widget));
5100 #else /* not USE_X_TOOLKIT */
5101 XRaiseWindow (XDISPLAY FRAME_X_WINDOW (f));
5102 #endif /* not USE_X_TOOLKIT */
5103 XFlushQueue ();
5104 UNBLOCK_INPUT;
5108 /* Lower frame F. */
5110 x_lower_frame (f)
5111 struct frame *f;
5113 if (f->async_visible)
5115 BLOCK_INPUT;
5116 #ifdef USE_X_TOOLKIT
5117 XLowerWindow (XDISPLAY XtWindow (f->display.x->widget));
5118 #else /* not USE_X_TOOLKIT */
5119 XLowerWindow (XDISPLAY FRAME_X_WINDOW (f));
5120 #endif /* not USE_X_TOOLKIT */
5121 XFlushQueue ();
5122 UNBLOCK_INPUT;
5126 static void
5127 XTframe_raise_lower (f, raise)
5128 FRAME_PTR f;
5129 int raise;
5131 if (raise)
5132 x_raise_frame (f);
5133 else
5134 x_lower_frame (f);
5138 /* Change from withdrawn state to mapped state. */
5140 x_make_frame_visible (f)
5141 struct frame *f;
5143 int mask;
5145 BLOCK_INPUT;
5147 if (! FRAME_VISIBLE_P (f))
5149 #ifdef HAVE_X11
5150 if (! EQ (Vx_no_window_manager, Qt))
5151 x_wm_set_window_state (f, NormalState);
5152 #ifdef USE_X_TOOLKIT
5153 XtPopup (f->display.x->widget, XtGrabNone);
5154 #else /* not USE_X_TOOLKIT */
5155 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
5156 #endif /* not USE_X_TOOLKIT */
5157 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5158 XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
5159 #else /* ! defined (HAVE_X11) */
5160 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
5161 if (f->display.x->icon_desc != 0)
5162 XUnmapWindow (f->display.x->icon_desc);
5164 /* Handled by the MapNotify event for X11 */
5165 f->async_visible = 1;
5166 f->async_iconified = 0;
5168 /* NOTE: this may cause problems for the first frame. */
5169 XTcursor_to (0, 0);
5170 #endif /* ! defined (HAVE_X11) */
5173 XFlushQueue ();
5175 UNBLOCK_INPUT;
5178 /* Change from mapped state to withdrawn state. */
5180 x_make_frame_invisible (f)
5181 struct frame *f;
5183 int mask;
5185 /* Don't keep the highlight on an invisible frame. */
5186 if (x_highlight_frame == f)
5187 x_highlight_frame = 0;
5189 if (! f->async_visible && ! f->async_iconified)
5190 return;
5192 BLOCK_INPUT;
5194 #ifdef HAVE_X11R4
5196 #ifdef USE_X_TOOLKIT
5197 if (! XWithdrawWindow (x_current_display, XtWindow (f->display.x->widget),
5198 DefaultScreen (x_current_display)))
5199 #else /* not USE_X_TOOLKIT */
5200 if (! XWithdrawWindow (x_current_display, FRAME_X_WINDOW (f),
5201 DefaultScreen (x_current_display)))
5202 #endif /* not USE_X_TOOLKIT */
5204 UNBLOCK_INPUT_RESIGNAL;
5205 error ("can't notify window manager of window withdrawal");
5208 #else /* ! defined (HAVE_X11R4) */
5209 #ifdef HAVE_X11
5211 /* Tell the window manager what we're going to do. */
5212 if (! EQ (Vx_no_window_manager, Qt))
5214 XEvent unmap;
5216 unmap.xunmap.type = UnmapNotify;
5217 #ifdef USE_X_TOOLKIT
5218 unmap.xunmap.window = XtWindow (f->display.x->widget);
5219 #else /* not USE_X_TOOLKIT */
5220 unmap.xunmap.window = FRAME_X_WINDOW (f);
5221 #endif /* not USE_X_TOOLKIT */
5222 unmap.xunmap.event = DefaultRootWindow (x_current_display);
5223 unmap.xunmap.from_configure = False;
5224 if (! XSendEvent (x_current_display,
5225 DefaultRootWindow (x_current_display),
5226 False,
5227 SubstructureRedirectMask|SubstructureNotifyMask,
5228 &unmap))
5230 UNBLOCK_INPUT_RESIGNAL;
5231 error ("can't notify window manager of withdrawal");
5235 /* Unmap the window ourselves. Cheeky! */
5236 #ifdef USE_X_TOOLKIT
5237 XUnmapWindow (x_current_display, XtWindow (f->display.x->widget));
5238 #else /* not USE_X_TOOLKIT */
5239 XUnmapWindow (x_current_display, FRAME_X_WINDOW (f));
5240 #endif /* not USE_X_TOOLKIT */
5241 #else /* ! defined (HAVE_X11) */
5243 XUnmapWindow (FRAME_X_WINDOW (f));
5244 f->async_visible = 0; /* Handled by the UnMap event for X11 */
5245 if (f->display.x->icon_desc != 0)
5246 XUnmapWindow (f->display.x->icon_desc);
5248 #endif /* ! defined (HAVE_X11) */
5249 #endif /* ! defined (HAVE_X11R4) */
5251 XFlushQueue ();
5252 UNBLOCK_INPUT;
5255 /* Change window state from mapped to iconified. */
5257 x_iconify_frame (f)
5258 struct frame *f;
5260 int mask;
5261 int result;
5263 /* Don't keep the highlight on an invisible frame. */
5264 if (x_highlight_frame == f)
5265 x_highlight_frame = 0;
5267 if (f->async_iconified)
5268 return;
5270 #ifdef USE_X_TOOLKIT
5271 BLOCK_INPUT;
5272 result = XIconifyWindow (x_current_display,
5273 XtWindow (f->display.x->widget),
5274 DefaultScreen (x_current_display));
5275 UNBLOCK_INPUT;
5277 if (!result)
5278 error ("Can't notify window manager of iconification.");
5280 f->async_iconified = 1;
5282 BLOCK_INPUT;
5283 XFlushQueue ();
5284 UNBLOCK_INPUT;
5285 #else /* not USE_X_TOOLKIT */
5287 BLOCK_INPUT;
5289 #ifdef HAVE_X11
5290 /* Since we don't know which revision of X we're running, we'll use both
5291 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
5293 /* X11R4: send a ClientMessage to the window manager using the
5294 WM_CHANGE_STATE type. */
5296 XEvent message;
5298 message.xclient.window = FRAME_X_WINDOW (f);
5299 message.xclient.type = ClientMessage;
5300 message.xclient.message_type = Xatom_wm_change_state;
5301 message.xclient.format = 32;
5302 message.xclient.data.l[0] = IconicState;
5304 if (! XSendEvent (x_current_display,
5305 DefaultRootWindow (x_current_display),
5306 False,
5307 SubstructureRedirectMask | SubstructureNotifyMask,
5308 &message))
5310 UNBLOCK_INPUT_RESIGNAL;
5311 error ("Can't notify window manager of iconification.");
5315 /* X11R3: set the initial_state field of the window manager hints to
5316 IconicState. */
5317 x_wm_set_window_state (f, IconicState);
5319 if (!FRAME_VISIBLE_P (f))
5321 /* If the frame was withdrawn, before, we must map it. */
5322 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
5323 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5324 XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
5327 f->async_iconified = 1;
5328 #else /* ! defined (HAVE_X11) */
5329 XUnmapWindow (XDISPLAY FRAME_X_WINDOW (f));
5331 f->async_visible = 0; /* Handled in the UnMap event for X11. */
5332 if (f->display.x->icon_desc != 0)
5334 XMapWindow (XDISPLAY f->display.x->icon_desc);
5335 refreshicon (f);
5337 #endif /* ! defined (HAVE_X11) */
5339 XFlushQueue ();
5340 UNBLOCK_INPUT;
5341 #endif /* not USE_X_TOOLKIT */
5344 /* Destroy the X window of frame F. */
5346 x_destroy_window (f)
5347 struct frame *f;
5349 BLOCK_INPUT;
5351 if (f->display.x->icon_desc != 0)
5352 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
5353 XDestroyWindow (XDISPLAY f->display.x->window_desc);
5354 #ifdef USE_X_TOOLKIT
5355 XtDestroyWidget (f->display.x->widget);
5356 free_frame_menubar (f);
5357 #endif /* USE_X_TOOLKIT */
5359 free_frame_faces (f);
5360 XFlushQueue ();
5362 xfree (f->display.x);
5363 f->display.x = 0;
5364 if (f == x_focus_frame)
5365 x_focus_frame = 0;
5366 if (f == x_highlight_frame)
5367 x_highlight_frame = 0;
5369 UNBLOCK_INPUT;
5372 /* Manage event queues for X10. */
5374 #ifndef HAVE_X11
5376 /* Manage event queues.
5378 This code is only used by the X10 support.
5380 We cannot leave events in the X queue and get them when we are ready
5381 because X does not provide a subroutine to get only a certain kind
5382 of event but not block if there are no queued events of that kind.
5384 Therefore, we must examine events as they come in and copy events
5385 of certain kinds into our private queues.
5387 All ExposeRegion events are put in x_expose_queue.
5388 All ButtonPress and ButtonRelease events are put in x_mouse_queue. */
5391 /* Write the event *P_XREP into the event queue *QUEUE.
5392 If the queue is full, do nothing, but return nonzero. */
5395 enqueue_event (p_xrep, queue)
5396 register XEvent *p_xrep;
5397 register struct event_queue *queue;
5399 int newindex = queue->windex + 1;
5400 if (newindex == EVENT_BUFFER_SIZE)
5401 newindex = 0;
5402 if (newindex == queue->rindex)
5403 return -1;
5404 queue->xrep[queue->windex] = *p_xrep;
5405 queue->windex = newindex;
5406 return 0;
5409 /* Fetch the next event from queue *QUEUE and store it in *P_XREP.
5410 If *QUEUE is empty, do nothing and return 0. */
5413 dequeue_event (p_xrep, queue)
5414 register XEvent *p_xrep;
5415 register struct event_queue *queue;
5417 if (queue->windex == queue->rindex)
5418 return 0;
5419 *p_xrep = queue->xrep[queue->rindex++];
5420 if (queue->rindex == EVENT_BUFFER_SIZE)
5421 queue->rindex = 0;
5422 return 1;
5425 /* Return the number of events buffered in *QUEUE. */
5428 queue_event_count (queue)
5429 register struct event_queue *queue;
5431 int tem = queue->windex - queue->rindex;
5432 if (tem >= 0)
5433 return tem;
5434 return EVENT_BUFFER_SIZE + tem;
5437 /* Return nonzero if mouse input is pending. */
5440 mouse_event_pending_p ()
5442 return queue_event_count (&x_mouse_queue);
5444 #endif /* HAVE_X11 */
5446 /* Setting window manager hints. */
5448 #ifdef HAVE_X11
5450 /* Record the gravity used previously, in case CHANGE_GRAVITY is 0. */
5451 static int previous_gravity;
5453 /* SPEC_X and SPEC_Y are the specified positions.
5454 We look only at their sign, to decide the gravity.
5455 If CHANGE_GRAVITY is 0, we ignore SPEC_X and SPEC_Y
5456 and leave the gravity unchanged. */
5458 x_wm_set_size_hint (f, prompting, change_gravity, spec_x, spec_y)
5459 struct frame *f;
5460 long prompting;
5461 int change_gravity;
5462 int spec_x, spec_y;
5464 XSizeHints size_hints;
5466 #ifdef USE_X_TOOLKIT
5467 Arg al[2];
5468 int ac = 0;
5469 Dimension widget_width, widget_height;
5470 Window window = XtWindow (f->display.x->widget);
5471 #else /* not USE_X_TOOLKIT */
5472 Window window = FRAME_X_WINDOW (f);
5473 #endif /* not USE_X_TOOLKIT */
5475 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
5477 flexlines = f->height;
5479 size_hints.x = f->display.x->left_pos;
5480 size_hints.y = f->display.x->top_pos;
5481 #ifdef USE_X_TOOLKIT
5482 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
5483 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
5484 XtGetValues (f->display.x->column_widget, al, ac);
5485 size_hints.height = widget_height;
5486 size_hints.width = widget_width;
5487 #else /* not USE_X_TOOLKIT */
5488 size_hints.height = PIXEL_HEIGHT (f);
5489 size_hints.width = PIXEL_WIDTH (f);
5490 #endif /* not USE_X_TOOLKIT */
5491 size_hints.width_inc = FONT_WIDTH (f->display.x->font);
5492 size_hints.height_inc = FONT_HEIGHT (f->display.x->font);
5493 #if 0
5494 size_hints.max_width = x_screen_width - CHAR_TO_PIXEL_WIDTH (f, 0);
5495 size_hints.max_height = x_screen_height - CHAR_TO_PIXEL_HEIGHT (f, 0);
5496 #endif
5498 int base_width, base_height;
5500 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
5501 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
5504 int min_rows = 0, min_cols = 0;
5505 check_frame_size (f, &min_rows, &min_cols);
5507 /* The window manager uses the base width hints to calculate the
5508 current number of rows and columns in the frame while
5509 resizing; min_width and min_height aren't useful for this
5510 purpose, since they might not give the dimensions for a
5511 zero-row, zero-column frame.
5513 We use the base_width and base_height members if we have
5514 them; otherwise, we set the min_width and min_height members
5515 to the size for a zero x zero frame. */
5517 #ifdef HAVE_X11R4
5518 size_hints.flags |= PBaseSize;
5519 size_hints.base_width = base_width;
5520 size_hints.base_height = base_height;
5521 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
5522 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
5523 #else
5524 size_hints.min_width = base_width;
5525 size_hints.min_height = base_height;
5526 #endif
5531 if (prompting)
5532 size_hints.flags |= prompting;
5533 else
5535 XSizeHints hints; /* Sometimes I hate X Windows... */
5537 if (XGetNormalHints (x_current_display, window, &hints) == 0)
5538 hints.flags = 0;
5539 if (hints.flags & PSize)
5540 size_hints.flags |= PSize;
5541 if (hints.flags & PPosition)
5542 size_hints.flags |= PPosition;
5543 if (hints.flags & USPosition)
5544 size_hints.flags |= USPosition;
5545 if (hints.flags & USSize)
5546 size_hints.flags |= USSize;
5548 #if defined (PWinGravity)
5549 if (change_gravity)
5551 switch (((spec_x < 0) << 1) + (spec_y < 0))
5553 case 0:
5554 size_hints.win_gravity = NorthWestGravity;
5555 break;
5556 case 1:
5557 size_hints.win_gravity = NorthEastGravity;
5558 break;
5559 case 2:
5560 size_hints.win_gravity = SouthWestGravity;
5561 break;
5562 case 3:
5563 size_hints.win_gravity = SouthEastGravity;
5564 break;
5566 previous_gravity = size_hints.win_gravity;
5568 else
5569 size_hints.win_gravity = previous_gravity;
5571 size_hints.flags |= PWinGravity;
5572 #endif /* PWinGravity */
5574 #ifdef HAVE_X11R4
5575 XSetWMNormalHints (x_current_display, window, &size_hints);
5576 #else
5577 XSetNormalHints (x_current_display, window, &size_hints);
5578 #endif
5581 /* Used for IconicState or NormalState */
5582 x_wm_set_window_state (f, state)
5583 struct frame *f;
5584 int state;
5586 #ifdef USE_X_TOOLKIT
5587 Window window = XtWindow (f->display.x->widget);
5588 #else /* not USE_X_TOOLKIT */
5589 Window window = FRAME_X_WINDOW (f);
5590 #endif /* not USE_X_TOOLKIT */
5592 f->display.x->wm_hints.flags |= StateHint;
5593 f->display.x->wm_hints.initial_state = state;
5595 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
5598 x_wm_set_icon_pixmap (f, icon_pixmap)
5599 struct frame *f;
5600 Pixmap icon_pixmap;
5602 Window window = FRAME_X_WINDOW (f);
5604 if (icon_pixmap)
5606 f->display.x->wm_hints.icon_pixmap = icon_pixmap;
5607 f->display.x->wm_hints.flags |= IconPixmapHint;
5609 else
5610 f->display.x->wm_hints.flags &= ~IconPixmapHint;
5612 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
5615 x_wm_set_icon_position (f, icon_x, icon_y)
5616 struct frame *f;
5617 int icon_x, icon_y;
5619 Window window = FRAME_X_WINDOW (f);
5621 f->display.x->wm_hints.flags |= IconPositionHint;
5622 f->display.x->wm_hints.icon_x = icon_x;
5623 f->display.x->wm_hints.icon_y = icon_y;
5625 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
5629 /* Initialization. */
5631 #ifdef USE_X_TOOLKIT
5632 static XrmOptionDescRec emacs_options[] = {
5633 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
5634 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
5636 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
5637 XrmoptionSepArg, NULL},
5638 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
5640 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5641 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5642 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5643 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5644 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5645 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
5646 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
5648 #endif /* USE_X_TOOLKIT */
5650 void
5651 x_term_init (display_name)
5652 char *display_name;
5654 Lisp_Object frame;
5655 char *defaultvalue;
5656 int argc = 0;
5657 char** argv = 0;
5658 #ifndef F_SETOWN_BUG
5659 #ifdef F_SETOWN
5660 extern int old_fcntl_owner;
5661 #endif /* ! defined (F_SETOWN) */
5662 #endif /* F_SETOWN_BUG */
5664 x_focus_frame = x_highlight_frame = 0;
5666 #ifdef USE_X_TOOLKIT
5667 argv = (char **) XtMalloc (3 * sizeof (char *));
5668 argv [0] = "";
5669 argv [1] = "-display";
5670 argv [2] = display_name;
5671 argc = 3;
5672 Xt_app_shell = XtAppInitialize (&Xt_app_con, "Emacs",
5673 emacs_options, XtNumber (emacs_options),
5674 &argc, argv,
5675 NULL, NULL, 0);
5676 XtFree (argv);
5677 x_current_display = XtDisplay (Xt_app_shell);
5679 #else /* not USE_X_TOOLKIT */
5680 x_current_display = XOpenDisplay (display_name);
5681 #endif /* not USE_X_TOOLKIT */
5682 if (x_current_display == 0)
5683 fatal ("X server %s not responding.\n\
5684 Check the DISPLAY environment variable or use \"-d\"\n",
5685 display_name);
5687 #ifdef HAVE_X11
5689 #if 0
5690 XSetAfterFunction (x_current_display, x_trace_wire);
5691 #endif /* ! 0 */
5692 hostname = get_system_name ();
5693 x_id_name = (char *) xmalloc (XSTRING (Vinvocation_name)->size
5694 + strlen (hostname)
5695 + 2);
5696 sprintf (x_id_name, "%s@%s", XSTRING (Vinvocation_name)->data, hostname);
5699 /* Figure out which modifier bits mean what. */
5700 x_find_modifier_meanings ();
5702 /* Get the scroll bar cursor. */
5703 x_vertical_scroll_bar_cursor
5704 = XCreateFontCursor (x_current_display, XC_sb_v_double_arrow);
5706 #if 0
5707 /* Watch for PropertyNotify events on the root window; we use them
5708 to figure out when to invalidate our cache of the cut buffers. */
5709 x_watch_cut_buffer_cache ();
5710 #endif
5712 if (ConnectionNumber (x_current_display) != 0)
5713 change_keyboard_wait_descriptor (ConnectionNumber (x_current_display));
5714 change_input_fd (ConnectionNumber (x_current_display));
5716 #endif /* ! defined (HAVE_X11) */
5718 #ifndef F_SETOWN_BUG
5719 #ifdef F_SETOWN
5720 old_fcntl_owner = fcntl (ConnectionNumber (x_current_display), F_GETOWN, 0);
5721 #ifdef F_SETOWN_SOCK_NEG
5722 /* stdin is a socket here */
5723 fcntl (ConnectionNumber (x_current_display), F_SETOWN, -getpid ());
5724 #else /* ! defined (F_SETOWN_SOCK_NEG) */
5725 fcntl (ConnectionNumber (x_current_display), F_SETOWN, getpid ());
5726 #endif /* ! defined (F_SETOWN_SOCK_NEG) */
5727 #endif /* ! defined (F_SETOWN) */
5728 #endif /* F_SETOWN_BUG */
5730 #ifdef SIGIO
5731 init_sigio ();
5732 #endif /* ! defined (SIGIO) */
5734 expose_all_windows = 0;
5736 clear_frame_hook = XTclear_frame;
5737 clear_end_of_line_hook = XTclear_end_of_line;
5738 ins_del_lines_hook = XTins_del_lines;
5739 change_line_highlight_hook = XTchange_line_highlight;
5740 insert_glyphs_hook = XTinsert_glyphs;
5741 write_glyphs_hook = XTwrite_glyphs;
5742 delete_glyphs_hook = XTdelete_glyphs;
5743 ring_bell_hook = XTring_bell;
5744 reset_terminal_modes_hook = XTreset_terminal_modes;
5745 set_terminal_modes_hook = XTset_terminal_modes;
5746 update_begin_hook = XTupdate_begin;
5747 update_end_hook = XTupdate_end;
5748 set_terminal_window_hook = XTset_terminal_window;
5749 read_socket_hook = XTread_socket;
5750 frame_up_to_date_hook = XTframe_up_to_date;
5751 cursor_to_hook = XTcursor_to;
5752 reassert_line_highlight_hook = XTreassert_line_highlight;
5753 mouse_position_hook = XTmouse_position;
5754 frame_rehighlight_hook = XTframe_rehighlight;
5755 frame_raise_lower_hook = XTframe_raise_lower;
5756 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
5757 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
5758 redeem_scroll_bar_hook = XTredeem_scroll_bar;
5759 judge_scroll_bars_hook = XTjudge_scroll_bars;
5761 scroll_region_ok = 1; /* we'll scroll partial frames */
5762 char_ins_del_ok = 0; /* just as fast to write the line */
5763 line_ins_del_ok = 1; /* we'll just blt 'em */
5764 fast_clear_end_of_line = 1; /* X does this well */
5765 memory_below_frame = 0; /* we don't remember what scrolls
5766 off the bottom */
5767 baud_rate = 19200;
5769 /* Try to use interrupt input; if we can't, then start polling. */
5770 Fset_input_mode (Qt, Qnil, Qt, Qnil);
5772 /* Note that there is no real way portable across R3/R4 to get the
5773 original error handler. */
5774 XHandleError (x_error_quitter);
5775 XHandleIOError (x_io_error_quitter);
5777 /* Disable Window Change signals; they are handled by X events. */
5778 #ifdef SIGWINCH
5779 signal (SIGWINCH, SIG_DFL);
5780 #endif /* ! defined (SIGWINCH) */
5782 signal (SIGPIPE, x_connection_closed);
5785 void
5786 syms_of_xterm ()
5788 staticpro (&last_mouse_scroll_bar);
5789 last_mouse_scroll_bar = Qnil;
5790 staticpro (&mouse_face_window);
5791 mouse_face_window = Qnil;
5793 #endif /* ! defined (HAVE_X11) */
5794 #endif /* ! defined (HAVE_X_WINDOWS) */