]> code.delx.au - gnu-emacs/blob - src/xterm.c
(merge_properties_sticky): Preserve original order of properties.
[gnu-emacs] / src / xterm.c
1 /* X Communication module for terminals which understand the X protocol.
2 Copyright (C) 1989, 1993 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 /* Serious problems:
21
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.
25
26 */
27
28 /* Xt features made by Fred Pierresteguy. */
29
30 #define NEW_SELECTIONS
31
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>
37
38 #include <config.h>
39
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 */
43 #include "syssignal.h"
44
45 #ifdef HAVE_X_WINDOWS
46
47 #include "lisp.h"
48 #include "blockinput.h"
49
50 /* This may include sys/types.h, and that somehow loses
51 if this is not done before the other system files. */
52 #include "xterm.h"
53 #include <X11/cursorfont.h>
54
55 #ifndef USG
56 /* Load sys/types.h if not already loaded.
57 In some systems loading it twice is suicidal. */
58 #ifndef makedev
59 #include <sys/types.h>
60 #endif /* makedev */
61 #endif /* USG */
62
63 #ifdef BSD
64 #include <sys/ioctl.h>
65 #include <strings.h>
66 #else /* ! defined (BSD) */
67 #ifndef VMS
68 #include <string.h>
69 #endif
70 #endif /* ! defined (BSD) */
71
72 #include "systty.h"
73 #include "systime.h"
74
75 #include <fcntl.h>
76 #include <ctype.h>
77 #include <errno.h>
78 #include <setjmp.h>
79 #include <sys/stat.h>
80 #include <sys/param.h>
81
82 #include "dispextern.h"
83 #include "termhooks.h"
84 #include "termopts.h"
85 #include "termchar.h"
86 #if 0
87 #include "sink.h"
88 #include "sinkmask.h"
89 #endif /* ! 0 */
90 #include "gnu.h"
91 #include "frame.h"
92 #include "disptab.h"
93 #include "buffer.h"
94 #include "window.h"
95
96 #ifdef USE_X_TOOLKIT
97 extern XtAppContext Xt_app_con;
98 extern Widget Xt_app_shell;
99 #endif /* USE_X_TOOLKIT */
100
101 #ifdef HAVE_X11
102 #define XMapWindow XMapRaised /* Raise them when mapping. */
103 #else /* ! defined (HAVE_X11) */
104 #include <X/Xkeyboard.h>
105 /*#include <X/Xproto.h> */
106 #endif /* ! defined (HAVE_X11) */
107
108 #ifdef FD_SET
109 /* We could get this from param.h, but better not to depend on finding that.
110 And better not to risk that it might define other symbols used in this
111 file. */
112 #ifdef FD_SETSIZE
113 #define MAXDESC FD_SETSIZE
114 #else
115 #define MAXDESC 64
116 #endif
117 #define SELECT_TYPE fd_set
118 #else /* no FD_SET */
119 #define MAXDESC 32
120 #define SELECT_TYPE int
121
122 /* Define the macros to access a single-int bitmap of descriptors. */
123 #define FD_SET(n, p) (*(p) |= (1 << (n)))
124 #define FD_CLR(n, p) (*(p) &= ~(1 << (n)))
125 #define FD_ISSET(n, p) (*(p) & (1 << (n)))
126 #define FD_ZERO(p) (*(p) = 0)
127 #endif /* no FD_SET */
128
129 /* For sending Meta-characters. Do we need this? */
130 #define METABIT 0200
131
132 #define min(a,b) ((a)<(b) ? (a) : (b))
133 #define max(a,b) ((a)>(b) ? (a) : (b))
134 \f
135 /* Nonzero means we must reprint all windows
136 because 1) we received an ExposeWindow event
137 or 2) we received too many ExposeRegion events to record.
138
139 This is never needed under X11. */
140 static int expose_all_windows;
141
142 /* Nonzero means we must reprint all icon windows. */
143
144 static int expose_all_icons;
145
146 #ifndef HAVE_X11
147 /* ExposeRegion events, when received, are copied into this queue
148 for later processing. */
149
150 static struct event_queue x_expose_queue;
151
152 /* ButtonPress and ButtonReleased events, when received,
153 are copied into this queue for later processing. */
154
155 struct event_queue x_mouse_queue;
156 #endif /* HAVE_X11 */
157
158 #if defined (SIGIO) && defined (FIONREAD)
159 int BLOCK_INPUT_mask;
160 #endif /* ! defined (SIGIO) && defined (FIONREAD) */
161
162 /* The id of a bitmap used for icon windows.
163 One such map is shared by all Emacs icon windows.
164 This is zero if we have not yet had a need to create the bitmap. */
165
166 static Bitmap icon_bitmap;
167
168 /* Font used for text icons. */
169
170 static FONT_TYPE *icon_font_info;
171
172 /* Stuff for dealing with the main icon title. */
173
174 extern Lisp_Object Vcommand_line_args;
175 char *hostname, *x_id_name;
176
177 /* This is the X connection that we are using. */
178
179 Display *x_current_display;
180
181 /* The cursor to use for vertical scroll bars on x_current_display. */
182 static Cursor x_vertical_scroll_bar_cursor;
183
184 /* Frame being updated by update_frame. This is declared in term.c.
185 This is set by update_begin and looked at by all the
186 XT functions. It is zero while not inside an update.
187 In that case, the XT functions assume that `selected_frame'
188 is the frame to apply to. */
189 extern struct frame *updating_frame;
190
191 /* The frame (if any) which has the X window that has keyboard focus.
192 Zero if none. This is examined by Ffocus_frame in frame.c. Note
193 that a mere EnterNotify event can set this; if you need to know the
194 last frame specified in a FocusIn or FocusOut event, use
195 x_focus_event_frame. */
196 struct frame *x_focus_frame;
197
198 /* The last frame mentioned in a FocusIn or FocusOut event. This is
199 separate from x_focus_frame, because whether or not LeaveNotify
200 events cause us to lose focus depends on whether or not we have
201 received a FocusIn event for it. */
202 struct frame *x_focus_event_frame;
203
204 /* The frame which currently has the visual highlight, and should get
205 keyboard input (other sorts of input have the frame encoded in the
206 event). It points to the X focus frame's selected window's
207 frame. It differs from x_focus_frame when we're using a global
208 minibuffer. */
209 static struct frame *x_highlight_frame;
210
211 /* From .Xdefaults, the value of "emacs.WarpMouse". If non-zero,
212 mouse is moved to inside of frame when frame is de-iconified. */
213
214 static int warp_mouse_on_deiconify;
215
216 /* During an update, maximum vpos for ins/del line operations to affect. */
217
218 static int flexlines;
219
220 /* During an update, nonzero if chars output now should be highlighted. */
221
222 static int highlight;
223
224 /* Nominal cursor position -- where to draw output.
225 During an update, these are different from the cursor-box position. */
226
227 static int curs_x;
228 static int curs_y;
229
230 /* Mouse movement.
231
232 In order to avoid asking for motion events and then throwing most
233 of them away or busy-polling the server for mouse positions, we ask
234 the server for pointer motion hints. This means that we get only
235 one event per group of mouse movements. "Groups" are delimited by
236 other kinds of events (focus changes and button clicks, for
237 example), or by XQueryPointer calls; when one of these happens, we
238 get another MotionNotify event the next time the mouse moves. This
239 is at least as efficient as getting motion events when mouse
240 tracking is on, and I suspect only negligibly worse when tracking
241 is off.
242
243 The silly O'Reilly & Associates Nutshell guides barely document
244 pointer motion hints at all (I think you have to infer how they
245 work from an example), and the description of XQueryPointer doesn't
246 mention that calling it causes you to get another motion hint from
247 the server, which is very important. */
248
249 /* Where the mouse was last time we reported a mouse event. */
250 static FRAME_PTR last_mouse_frame;
251 static XRectangle last_mouse_glyph;
252
253 /* The scroll bar in which the last X motion event occurred.
254
255 If the last X motion event occurred in a scroll bar, we set this
256 so XTmouse_position can know whether to report a scroll bar motion or
257 an ordinary motion.
258
259 If the last X motion event didn't occur in a scroll bar, we set this
260 to Qnil, to tell XTmouse_position to return an ordinary motion event. */
261 static Lisp_Object last_mouse_scroll_bar;
262
263 /* Record which buttons are currently pressed. */
264 unsigned int x_mouse_grabbed;
265
266 /* This is a hack. We would really prefer that XTmouse_position would
267 return the time associated with the position it returns, but there
268 doesn't seem to be any way to wrest the timestamp from the server
269 along with the position query. So, we just keep track of the time
270 of the last movement we received, and return that in hopes that
271 it's somewhat accurate. */
272 static Time last_mouse_movement_time;
273
274 #ifdef HAVE_X11
275 /* `t' if a mouse button is depressed. */
276
277 extern Lisp_Object Vmouse_depressed;
278
279 /* Tells if a window manager is present or not. */
280
281 extern Lisp_Object Vx_no_window_manager;
282
283 /* Timestamp that we requested selection data was made. */
284 extern Time requestor_time;
285
286 /* ID of the window requesting selection data. */
287 extern Window requestor_window;
288
289 /* Nonzero enables some debugging for the X interface code. */
290 extern int _Xdebug;
291
292 #else /* ! defined (HAVE_X11) */
293
294 /* Bit patterns for the mouse cursor. */
295
296 short MouseCursor[] = {
297 0x0000, 0x0008, 0x0018, 0x0038,
298 0x0078, 0x00f8, 0x01f8, 0x03f8,
299 0x07f8, 0x00f8, 0x00d8, 0x0188,
300 0x0180, 0x0300, 0x0300, 0x0000};
301
302 short MouseMask[] = {
303 0x000c, 0x001c, 0x003c, 0x007c,
304 0x00fc, 0x01fc, 0x03fc, 0x07fc,
305 0x0ffc, 0x0ffc, 0x01fc, 0x03dc,
306 0x03cc, 0x0780, 0x0780, 0x0300};
307
308 static short grey_bits[] = {
309 0x0005, 0x000a, 0x0005, 0x000a};
310
311 static Pixmap GreyPixmap = 0;
312 #endif /* ! defined (HAVE_X11) */
313
314 /* From time to time we get info on an Emacs window, here. */
315
316 static WINDOWINFO_TYPE windowinfo;
317
318 extern int errno;
319
320 /* A mask of extra modifier bits to put into every keyboard char. */
321 extern int extra_keyboard_modifiers;
322
323 extern Display *XOpenDisplay ();
324 extern Window XCreateWindow ();
325
326 extern Cursor XCreateCursor ();
327 extern FONT_TYPE *XOpenFont ();
328
329 static void flashback ();
330 static void redraw_previous_char ();
331 static unsigned int x_x_to_emacs_modifiers ();
332
333 #ifndef HAVE_X11
334 static void dumpqueue ();
335 #endif /* HAVE_X11 */
336
337 void dumpborder ();
338 static int XTcursor_to ();
339 static int XTclear_end_of_line ();
340
341 \f
342 /* Starting and ending updates.
343
344 These hooks are called by update_frame at the beginning and end
345 of a frame update. We record in `updating_frame' the identity
346 of the frame being updated, so that the XT... functions do not
347 need to take a frame as argument. Most of the XT... functions
348 should never be called except during an update, the only exceptions
349 being XTcursor_to, XTwrite_glyphs and XTreassert_line_highlight. */
350
351 extern int mouse_track_top, mouse_track_left, mouse_track_width;
352
353 static
354 XTupdate_begin (f)
355 struct frame *f;
356 {
357 int mask;
358
359 if (f == 0)
360 abort ();
361
362 flexlines = f->height;
363 highlight = 0;
364
365 BLOCK_INPUT;
366 #ifndef HAVE_X11
367 dumpqueue ();
368 #endif /* HAVE_X11 */
369 UNBLOCK_INPUT;
370 }
371
372 #ifndef HAVE_X11
373 static void x_do_pending_expose ();
374 #endif
375
376 static
377 XTupdate_end (f)
378 struct frame *f;
379 {
380 int mask;
381
382 BLOCK_INPUT;
383 #ifndef HAVE_X11
384 dumpqueue ();
385 x_do_pending_expose ();
386 #endif /* HAVE_X11 */
387
388 x_display_cursor (f, 1);
389
390 XFlushQueue ();
391 UNBLOCK_INPUT;
392 }
393 \f
394 /* External interface to control of standout mode.
395 Call this when about to modify line at position VPOS
396 and not change whether it is highlighted. */
397
398 XTreassert_line_highlight (new, vpos)
399 int new, vpos;
400 {
401 highlight = new;
402 }
403
404 /* Call this when about to modify line at position VPOS
405 and change whether it is highlighted. */
406
407 static
408 XTchange_line_highlight (new_highlight, vpos, first_unused_hpos)
409 int new_highlight, vpos, first_unused_hpos;
410 {
411 highlight = new_highlight;
412 XTcursor_to (vpos, 0);
413 XTclear_end_of_line (updating_frame->width);
414 }
415
416 /* This is used when starting Emacs and when restarting after suspend.
417 When starting Emacs, no X window is mapped. And nothing must be done
418 to Emacs's own window if it is suspended (though that rarely happens). */
419
420 static
421 XTset_terminal_modes ()
422 {
423 }
424
425 /* This is called when exiting or suspending Emacs.
426 Exiting will make the X-windows go away, and suspending
427 requires no action. */
428
429 static
430 XTreset_terminal_modes ()
431 {
432 /* XTclear_frame (); */
433 }
434 \f
435 /* Set the nominal cursor position of the frame.
436 This is where display update commands will take effect.
437 This does not affect the place where the cursor-box is displayed. */
438
439 static int
440 XTcursor_to (row, col)
441 register int row, col;
442 {
443 int mask;
444 int orow = row;
445
446 curs_x = col;
447 curs_y = row;
448
449 if (updating_frame == 0)
450 {
451 BLOCK_INPUT;
452 x_display_cursor (selected_frame, 1);
453 XFlushQueue ();
454 UNBLOCK_INPUT;
455 }
456 }
457 \f
458 /* Display a sequence of N glyphs found at GP.
459 WINDOW is the x-window to output to. LEFT and TOP are starting coords.
460 HL is 1 if this text is highlighted, 2 if the cursor is on it.
461
462 FONT is the default font to use (for glyphs whose font-code is 0).
463
464 Since the display generation code is responsible for calling
465 compute_char_face and compute_glyph_face on everything it puts in
466 the display structure, we can assume that the face code on each
467 glyph is a valid index into FRAME_COMPUTED_FACES (f), and the one
468 to which we can actually apply intern_face. */
469
470 #if 1
471 /* This is the multi-face code. */
472
473 static void
474 dumpglyphs (f, left, top, gp, n, hl)
475 struct frame *f;
476 int left, top;
477 register GLYPH *gp; /* Points to first GLYPH. */
478 register int n; /* Number of glyphs to display. */
479 int hl;
480 {
481 /* Holds characters to be displayed. */
482 char *buf = (char *) alloca (f->width * sizeof (*buf));
483 register char *cp; /* Steps through buf[]. */
484 register int tlen = GLYPH_TABLE_LENGTH;
485 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
486 Window window = FRAME_X_WINDOW (f);
487
488 while (n > 0)
489 {
490 /* Get the face-code of the next GLYPH. */
491 int cf, len;
492 int g = *gp;
493
494 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
495 cf = GLYPH_FACE (g);
496
497 /* Find the run of consecutive glyphs with the same face-code.
498 Extract their character codes into BUF. */
499 cp = buf;
500 while (n > 0)
501 {
502 g = *gp;
503 GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
504 if (GLYPH_FACE (g) != cf)
505 break;
506
507 *cp++ = GLYPH_CHAR (g);
508 --n;
509 ++gp;
510 }
511
512 /* LEN gets the length of the run. */
513 len = cp - buf;
514
515 /* Now output this run of chars, with the font and pixel values
516 determined by the face code CF. */
517 {
518 struct face *face = FRAME_DEFAULT_FACE (f);
519 FONT_TYPE *font = FACE_FONT (face);
520 GC gc = FACE_GC (face);
521 int defaulted = 1;
522 int gc_temporary = 0;
523
524 /* First look at the face of the text itself. */
525 if (cf != 0)
526 {
527 /* It's possible for the display table to specify
528 a face code that is out of range. Use 0 in that case. */
529 if (cf < 0 || cf >= FRAME_N_COMPUTED_FACES (f)
530 || FRAME_COMPUTED_FACES (f) [cf] == 0)
531 cf = 0;
532
533 if (cf == 1)
534 face = FRAME_MODE_LINE_FACE (f);
535 else
536 face = intern_face (f, FRAME_COMPUTED_FACES (f) [cf]);
537 font = FACE_FONT (face);
538 gc = FACE_GC (face);
539 defaulted = 0;
540 }
541
542 /* Then comes the distinction between modeline and normal text. */
543 else if (hl == 0)
544 ;
545 else if (hl == 1)
546 {
547 face = FRAME_MODE_LINE_FACE (f);
548 font = FACE_FONT (face);
549 gc = FACE_GC (face);
550 defaulted = 0;
551 }
552
553 #define FACE_DEFAULT (~0)
554
555 /* Now override that if the cursor's on this character. */
556 if (hl == 2)
557 {
558 if (defaulted
559 || !face->font
560 || (int) face->font == FACE_DEFAULT)
561 {
562 gc = f->display.x->cursor_gc;
563 }
564 /* Cursor on non-default face: must merge. */
565 else
566 {
567 XGCValues xgcv;
568 unsigned long mask;
569
570 xgcv.background = f->display.x->cursor_pixel;
571 xgcv.foreground = f->display.x->cursor_foreground_pixel;
572 xgcv.font = face->font->fid;
573 xgcv.graphics_exposures = 0;
574 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
575 gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f),
576 mask, &xgcv);
577 #if 0
578 if (face->stipple && face->stipple != FACE_DEFAULT)
579 XSetStipple (x_current_display, gc, face->stipple);
580 #endif
581 gc_temporary = 1;
582 }
583 }
584
585 if ((int) font == FACE_DEFAULT)
586 font = f->display.x->font;
587
588 XDrawImageString (x_current_display, window, gc,
589 left, top + FONT_BASE (font), buf, len);
590
591 if (gc_temporary)
592 XFreeGC (x_current_display, gc);
593
594 /* We should probably check for XA_UNDERLINE_POSITION and
595 XA_UNDERLINE_THICKNESS properties on the font, but let's
596 just get the thing working, and come back to that. */
597 {
598 int underline_position = 1;
599
600 if (font->descent <= underline_position)
601 underline_position = font->descent - 1;
602
603 if (face->underline)
604 XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
605 FACE_GC (face),
606 left, (top
607 + FONT_BASE (font)
608 + underline_position),
609 len * FONT_WIDTH (font), 1);
610 }
611
612 left += len * FONT_WIDTH (font);
613 }
614 }
615 }
616 #endif /* 1 */
617
618 #if 0
619 /* This is the old single-face code. */
620
621 static void
622 dumpglyphs (f, left, top, gp, n, hl, font)
623 struct frame *f;
624 int left, top;
625 register GLYPH *gp; /* Points to first GLYPH. */
626 register int n; /* Number of glyphs to display. */
627 int hl;
628 FONT_TYPE *font;
629 {
630 register int len;
631 Window window = FRAME_X_WINDOW (f);
632 GC drawing_gc = (hl == 2 ? f->display.x->cursor_gc
633 : (hl ? f->display.x->reverse_gc
634 : f->display.x->normal_gc));
635
636 if (sizeof (GLYPH) == sizeof (XChar2b))
637 XDrawImageString16 (x_current_display, window, drawing_gc,
638 left, top + FONT_BASE (font), (XChar2b *) gp, n);
639 else if (sizeof (GLYPH) == sizeof (unsigned char))
640 XDrawImageString (x_current_display, window, drawing_gc,
641 left, top + FONT_BASE (font), (char *) gp, n);
642 else
643 /* What size of glyph ARE you using? And does X have a function to
644 draw them? */
645 abort ();
646 }
647 #endif
648 \f
649 /* Output some text at the nominal frame cursor position.
650 Advance the cursor over the text.
651 Output LEN glyphs at START.
652
653 `highlight', set up by XTreassert_line_highlight or XTchange_line_highlight,
654 controls the pixel values used for foreground and background. */
655
656 static
657 XTwrite_glyphs (start, len)
658 register GLYPH *start;
659 int len;
660 {
661 register int temp_length;
662 int mask;
663 struct frame *f;
664
665 BLOCK_INPUT;
666
667 f = updating_frame;
668 if (f == 0)
669 {
670 f = selected_frame;
671 /* If not within an update,
672 output at the frame's visible cursor. */
673 curs_x = f->cursor_x;
674 curs_y = f->cursor_y;
675 }
676
677 dumpglyphs (f,
678 CHAR_TO_PIXEL_COL (f, curs_x),
679 CHAR_TO_PIXEL_ROW (f, curs_y),
680 start, len, highlight);
681
682 /* If we drew on top of the cursor, note that it is turned off. */
683 if (curs_y == f->phys_cursor_y
684 && curs_x <= f->phys_cursor_x
685 && curs_x + len > f->phys_cursor_x)
686 f->phys_cursor_x = -1;
687
688 if (updating_frame == 0)
689 {
690 f->cursor_x += len;
691 x_display_cursor (f, 1);
692 f->cursor_x -= len;
693 }
694 else
695 curs_x += len;
696
697 UNBLOCK_INPUT;
698 }
699 \f
700 /* Clear to the end of the line.
701 Erase the current text line from the nominal cursor position (inclusive)
702 to column FIRST_UNUSED (exclusive). The idea is that everything
703 from FIRST_UNUSED onward is already erased. */
704
705 static int
706 XTclear_end_of_line (first_unused)
707 register int first_unused;
708 {
709 struct frame *f = updating_frame;
710 int mask;
711
712 if (f == 0)
713 abort ();
714
715 if (curs_y < 0 || curs_y >= f->height)
716 return;
717 if (first_unused <= 0)
718 return;
719
720 if (first_unused >= f->width)
721 first_unused = f->width;
722
723 BLOCK_INPUT;
724
725 /* Notice if the cursor will be cleared by this operation. */
726 if (curs_y == f->phys_cursor_y
727 && curs_x <= f->phys_cursor_x
728 && f->phys_cursor_x < first_unused)
729 f->phys_cursor_x = -1;
730
731 #ifdef HAVE_X11
732 XClearArea (x_current_display, FRAME_X_WINDOW (f),
733 CHAR_TO_PIXEL_COL (f, curs_x),
734 CHAR_TO_PIXEL_ROW (f, curs_y),
735 FONT_WIDTH (f->display.x->font) * (first_unused - curs_x),
736 FONT_HEIGHT (f->display.x->font), False);
737 #if 0
738 redraw_previous_char (f, curs_x, curs_y);
739 #endif
740 #else /* ! defined (HAVE_X11) */
741 XPixSet (FRAME_X_WINDOW (f),
742 CHAR_TO_PIXEL_COL (f, curs_x),
743 CHAR_TO_PIXEL_ROW (f, curs_y),
744 FONT_WIDTH (f->display.x->font) * (first_unused - curs_x),
745 FONT_HEIGHT (f->display.x->font),
746 f->display.x->background_pixel);
747 #endif /* ! defined (HAVE_X11) */
748
749 UNBLOCK_INPUT;
750 }
751
752 /* Erase the character (if any) at the position just before X, Y in frame F,
753 then redraw it and the character before it.
754 This is necessary when we erase starting at X,
755 in case the character after X overlaps into the one before X. */
756
757 static void
758 redraw_previous_char (f, x, y)
759 FRAME_PTR f;
760 int x, y;
761 {
762 /* Erase the character before the new ones, in case
763 what was here before overlaps it.
764 Reoutput that character, and the previous character
765 (in case the previous character overlaps it). */
766 if (x > 0)
767 {
768 int start_x = x - 2;
769 if (start_x < 0)
770 start_x = 0;
771 XClearArea (x_current_display, FRAME_X_WINDOW (f),
772 CHAR_TO_PIXEL_COL (f, x - 1),
773 CHAR_TO_PIXEL_ROW (f, y),
774 FONT_WIDTH (f->display.x->font),
775 FONT_HEIGHT (f->display.x->font), False);
776
777 dumpglyphs (f, CHAR_TO_PIXEL_COL (f, start_x),
778 CHAR_TO_PIXEL_ROW (f, y),
779 &FRAME_CURRENT_GLYPHS (f)->glyphs[y][start_x],
780 x - start_x, highlight);
781 }
782 }
783
784 static
785 XTclear_frame ()
786 {
787 int mask;
788 struct frame *f = updating_frame;
789
790 if (f == 0)
791 f = selected_frame;
792
793 f->phys_cursor_x = -1; /* Cursor not visible. */
794 curs_x = 0; /* Nominal cursor position is top left. */
795 curs_y = 0;
796
797 BLOCK_INPUT;
798
799 XClear (FRAME_X_WINDOW (f));
800
801 /* We have to clear the scroll bars, too. If we have changed
802 colors or something like that, then they should be notified. */
803 x_scroll_bar_clear (f);
804
805 #ifndef HAVE_X11
806 dumpborder (f, 0);
807 #endif /* HAVE_X11 */
808
809 XFlushQueue ();
810 UNBLOCK_INPUT;
811 }
812 \f
813 /* Invert the middle quarter of the frame for .15 sec. */
814
815 /* We use the select system call to do the waiting, so we have to make sure
816 it's available. If it isn't, we just won't do visual bells. */
817 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
818
819 /* Subtract the `struct timeval' values X and Y,
820 storing the result in RESULT.
821 Return 1 if the difference is negative, otherwise 0. */
822
823 static int
824 timeval_subtract (result, x, y)
825 struct timeval *result, x, y;
826 {
827 /* Perform the carry for the later subtraction by updating y.
828 This is safer because on some systems
829 the tv_sec member is unsigned. */
830 if (x.tv_usec < y.tv_usec)
831 {
832 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
833 y.tv_usec -= 1000000 * nsec;
834 y.tv_sec += nsec;
835 }
836 if (x.tv_usec - y.tv_usec > 1000000)
837 {
838 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
839 y.tv_usec += 1000000 * nsec;
840 y.tv_sec -= nsec;
841 }
842
843 /* Compute the time remaining to wait. tv_usec is certainly positive. */
844 result->tv_sec = x.tv_sec - y.tv_sec;
845 result->tv_usec = x.tv_usec - y.tv_usec;
846
847 /* Return indication of whether the result should be considered negative. */
848 return x.tv_sec < y.tv_sec;
849 }
850
851 XTflash (f)
852 struct frame *f;
853 {
854 BLOCK_INPUT;
855
856 {
857 GC gc;
858
859 /* Create a GC that will use the GXxor function to flip foreground pixels
860 into background pixels. */
861 {
862 XGCValues values;
863
864 values.function = GXxor;
865 values.foreground = (f->display.x->foreground_pixel
866 ^ f->display.x->background_pixel);
867
868 gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f),
869 GCFunction | GCForeground, &values);
870 }
871
872 {
873 int width = PIXEL_WIDTH (f);
874 int height = PIXEL_HEIGHT (f);
875
876 XFillRectangle (x_current_display, FRAME_X_WINDOW (f), gc,
877 width/4, height/4, width/2, height/2);
878 XFlush (x_current_display);
879
880 {
881 struct timeval wakeup, now;
882
883 EMACS_GET_TIME (wakeup);
884
885 /* Compute time to wait until, propagating carry from usecs. */
886 wakeup.tv_usec += 150000;
887 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
888 wakeup.tv_usec %= 1000000;
889
890 /* Keep waiting until past the time wakeup. */
891 while (1)
892 {
893 struct timeval timeout;
894
895 EMACS_GET_TIME (timeout);
896
897 /* In effect, timeout = wakeup - timeout.
898 Break if result would be negative. */
899 if (timeval_subtract (&timeout, wakeup, timeout))
900 break;
901
902 /* Try to wait that long--but we might wake up sooner. */
903 select (0, 0, 0, 0, &timeout);
904 }
905 }
906
907 XFillRectangle (x_current_display, FRAME_X_WINDOW (f), gc,
908 width/4, height/4, width/2, height/2);
909 XFreeGC (x_current_display, gc);
910 XFlush (x_current_display);
911 }
912 }
913
914 UNBLOCK_INPUT;
915 }
916
917 #endif
918
919
920 /* Make audible bell. */
921
922 #ifdef HAVE_X11
923 #define XRINGBELL XBell(x_current_display, 0)
924 #else /* ! defined (HAVE_X11) */
925 #define XRINGBELL XFeep(0);
926 #endif /* ! defined (HAVE_X11) */
927
928 XTring_bell ()
929 {
930 if (x_current_display == 0)
931 return;
932
933 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
934 if (visible_bell)
935 XTflash (selected_frame);
936 else
937 #endif
938 {
939 BLOCK_INPUT;
940 XRINGBELL;
941 XFlushQueue ();
942 UNBLOCK_INPUT;
943 }
944 }
945 \f
946 /* Insert and delete character.
947 These are not supposed to be used because we are supposed to turn
948 off the feature of using them. */
949
950 static
951 XTinsert_glyphs (start, len)
952 register char *start;
953 register int len;
954 {
955 abort ();
956 }
957
958 static
959 XTdelete_glyphs (n)
960 register int n;
961 {
962 abort ();
963 }
964 \f
965 /* Specify how many text lines, from the top of the window,
966 should be affected by insert-lines and delete-lines operations.
967 This, and those operations, are used only within an update
968 that is bounded by calls to XTupdate_begin and XTupdate_end. */
969
970 static
971 XTset_terminal_window (n)
972 register int n;
973 {
974 if (updating_frame == 0)
975 abort ();
976
977 if ((n <= 0) || (n > updating_frame->height))
978 flexlines = updating_frame->height;
979 else
980 flexlines = n;
981 }
982 \f
983 /* Perform an insert-lines operation.
984 Insert N lines at a vertical position curs_y. */
985
986 static void
987 stufflines (n)
988 register int n;
989 {
990 register int topregion, bottomregion;
991 register int length, newtop, mask;
992 register struct frame *f = updating_frame;
993 int intborder = f->display.x->internal_border_width;
994
995 if (curs_y >= flexlines)
996 return;
997
998 topregion = curs_y;
999 bottomregion = flexlines - (n + 1);
1000 newtop = topregion + n;
1001 length = (bottomregion - topregion) + 1;
1002
1003 #ifndef HAVE_X11
1004 dumpqueue ();
1005 #endif /* HAVE_X11 */
1006
1007 if ((length > 0) && (newtop <= flexlines))
1008 {
1009 #ifdef HAVE_X11
1010 XCopyArea (x_current_display, FRAME_X_WINDOW (f),
1011 FRAME_X_WINDOW (f), f->display.x->normal_gc,
1012 intborder, CHAR_TO_PIXEL_ROW (f, topregion),
1013 f->width * FONT_WIDTH (f->display.x->font),
1014 length * FONT_HEIGHT (f->display.x->font), intborder,
1015 CHAR_TO_PIXEL_ROW (f, newtop));
1016 #else /* ! defined (HAVE_X11) */
1017 XMoveArea (FRAME_X_WINDOW (f),
1018 intborder, CHAR_TO_PIXEL_ROW (f, topregion),
1019 intborder, CHAR_TO_PIXEL_ROW (f, newtop),
1020 f->width * FONT_WIDTH (f->display.x->font),
1021 length * FONT_HEIGHT (f->display.x->font));
1022 /* Now we must process any ExposeRegion events that occur
1023 if the area being copied from is obscured.
1024 We can't let it wait because further i/d operations
1025 may want to copy this area to another area. */
1026 x_read_exposes ();
1027 #endif /* ! defined (HAVE_X11) */
1028 }
1029
1030 newtop = min (newtop, (flexlines - 1));
1031 length = newtop - topregion;
1032 if (length > 0)
1033 {
1034 #ifdef HAVE_X11
1035 XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder,
1036 CHAR_TO_PIXEL_ROW (f, topregion),
1037 f->width * FONT_WIDTH (f->display.x->font),
1038 n * FONT_HEIGHT (f->display.x->font), False);
1039 #else /* ! defined (HAVE_X11) */
1040 XPixSet (FRAME_X_WINDOW (f),
1041 intborder,
1042 CHAR_TO_PIXEL_ROW (f, topregion),
1043 f->width * FONT_WIDTH (f->display.x->font),
1044 n * FONT_HEIGHT (f->display.x->font),
1045 f->display.x->background_pixel);
1046 #endif /* ! defined (HAVE_X11) */
1047 }
1048 }
1049
1050 /* Perform a delete-lines operation, deleting N lines
1051 at a vertical position curs_y. */
1052
1053 static void
1054 scraplines (n)
1055 register int n;
1056 {
1057 int mask;
1058 register struct frame *f = updating_frame;
1059 int intborder = f->display.x->internal_border_width;
1060
1061 if (curs_y >= flexlines)
1062 return;
1063
1064 #ifndef HAVE_X11
1065 dumpqueue ();
1066 #endif /* HAVE_X11 */
1067
1068 if ((curs_y + n) >= flexlines)
1069 {
1070 if (flexlines >= (curs_y + 1))
1071 {
1072 #ifdef HAVE_X11
1073 XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder,
1074 CHAR_TO_PIXEL_ROW (f, curs_y),
1075 f->width * FONT_WIDTH (f->display.x->font),
1076 (flexlines - curs_y) * FONT_HEIGHT (f->display.x->font), False);
1077 #else /* ! defined (HAVE_X11) */
1078 XPixSet (FRAME_X_WINDOW (f),
1079 intborder, CHAR_TO_PIXEL_ROW (f, curs_y),
1080 f->width * FONT_WIDTH (f->display.x->font),
1081 (flexlines - curs_y) * FONT_HEIGHT (f->display.x->font),
1082 f->display.x->background_pixel);
1083 #endif /* ! defined (HAVE_X11) */
1084 }
1085 }
1086 else
1087 {
1088 #ifdef HAVE_X11
1089 XCopyArea (x_current_display, FRAME_X_WINDOW (f),
1090 FRAME_X_WINDOW (f), f->display.x->normal_gc,
1091 intborder,
1092 CHAR_TO_PIXEL_ROW (f, curs_y + n),
1093 f->width * FONT_WIDTH (f->display.x->font),
1094 (flexlines - (curs_y + n)) * FONT_HEIGHT (f->display.x->font),
1095 intborder, CHAR_TO_PIXEL_ROW (f, curs_y));
1096 XClearArea (x_current_display, FRAME_X_WINDOW (f),
1097 intborder,
1098 CHAR_TO_PIXEL_ROW (f, flexlines - n),
1099 f->width * FONT_WIDTH (f->display.x->font),
1100 n * FONT_HEIGHT (f->display.x->font), False);
1101 #else /* ! defined (HAVE_X11) */
1102 XMoveArea (FRAME_X_WINDOW (f),
1103 intborder,
1104 CHAR_TO_PIXEL_ROW (f, curs_y + n),
1105 intborder, CHAR_TO_PIXEL_ROW (f, curs_y),
1106 f->width * FONT_WIDTH (f->display.x->font),
1107 (flexlines - (curs_y + n)) * FONT_HEIGHT (f->display.x->font));
1108 /* Now we must process any ExposeRegion events that occur
1109 if the area being copied from is obscured.
1110 We can't let it wait because further i/d operations
1111 may want to copy this area to another area. */
1112 x_read_exposes ();
1113 XPixSet (FRAME_X_WINDOW (f), intborder,
1114 CHAR_TO_PIXEL_ROW (f, flexlines - n),
1115 f->width * FONT_WIDTH (f->display.x->font),
1116 n * FONT_HEIGHT (f->display.x->font), f->display.x->background_pixel);
1117 #endif /* ! defined (HAVE_X11) */
1118 }
1119 }
1120
1121 /* Perform an insert-lines or delete-lines operation,
1122 inserting N lines or deleting -N lines at vertical position VPOS. */
1123
1124 XTins_del_lines (vpos, n)
1125 int vpos, n;
1126 {
1127 if (updating_frame == 0)
1128 abort ();
1129
1130 /* Hide the cursor. */
1131 x_display_cursor (updating_frame, 0);
1132
1133 XTcursor_to (vpos, 0);
1134
1135 BLOCK_INPUT;
1136 if (n >= 0)
1137 stufflines (n);
1138 else
1139 scraplines (-n);
1140 XFlushQueue ();
1141 UNBLOCK_INPUT;
1142 }
1143 \f
1144 /* Support routines for exposure events. */
1145 static void clear_cursor ();
1146
1147 /* Output into a rectangle of an X-window (for frame F)
1148 the characters in f->phys_lines that overlap that rectangle.
1149 TOP and LEFT are the position of the upper left corner of the rectangle.
1150 ROWS and COLS are the size of the rectangle. */
1151
1152 static void
1153 dumprectangle (f, left, top, cols, rows)
1154 struct frame *f;
1155 register int left, top, cols, rows;
1156 {
1157 register struct frame_glyphs *active_frame = FRAME_CURRENT_GLYPHS (f);
1158 int cursor_cleared = 0;
1159 int bottom, right;
1160 register int y;
1161
1162 if (FRAME_GARBAGED_P (f))
1163 return;
1164
1165 /* Express rectangle as four edges, instead of position-and-size. */
1166 bottom = top + rows;
1167 right = left + cols;
1168
1169 #ifndef HAVE_X11 /* Window manger does this for X11. */
1170 {
1171 int intborder = f->display.x->internal_border_width;
1172
1173 /* If the rectangle includes any of the internal border area,
1174 redisplay the border emphasis. */
1175 if (top < intborder || left < intborder
1176 || bottom > intborder + f->height * FONT_HEIGHT (f->display.x->font)
1177 || right > intborder + f->width * FONT_WIDTH (f->display.x->font))
1178 dumpborder (f, 0);
1179 }
1180 #endif /* HAVE_X11 Window manger does this for X11. */
1181
1182 /* Convert rectangle edges in pixels to edges in chars.
1183 Round down for left and top, up for right and bottom. */
1184 top = PIXEL_TO_CHAR_ROW (f, top);
1185 left = PIXEL_TO_CHAR_COL (f, left);
1186 bottom += (FONT_HEIGHT (f->display.x->font) - 1);
1187 right += (FONT_WIDTH (f->display.x->font) - 1);
1188 bottom = PIXEL_TO_CHAR_ROW (f, bottom);
1189 right = PIXEL_TO_CHAR_COL (f, right);
1190
1191 /* Clip the rectangle to what can be visible. */
1192 if (left < 0)
1193 left = 0;
1194 if (top < 0)
1195 top = 0;
1196 if (right > f->width)
1197 right = f->width;
1198 if (bottom > f->height)
1199 bottom = f->height;
1200
1201 /* Get size in chars of the rectangle. */
1202 cols = right - left;
1203 rows = bottom - top;
1204
1205 /* If rectangle has zero area, return. */
1206 if (rows <= 0) return;
1207 if (cols <= 0) return;
1208
1209 /* Turn off the cursor if it is in the rectangle.
1210 We will turn it back on afterward. */
1211 if ((f->phys_cursor_x >= left) && (f->phys_cursor_x < right)
1212 && (f->phys_cursor_y >= top) && (f->phys_cursor_y < bottom))
1213 {
1214 clear_cursor (f);
1215 cursor_cleared = 1;
1216 }
1217
1218 /* Display the text in the rectangle, one text line at a time. */
1219
1220 for (y = top; y < bottom; y++)
1221 {
1222 GLYPH *line = &active_frame->glyphs[y][left];
1223
1224 if (! active_frame->enable[y] || left > active_frame->used[y])
1225 continue;
1226
1227 dumpglyphs (f,
1228 CHAR_TO_PIXEL_COL (f, left),
1229 CHAR_TO_PIXEL_ROW (f, y),
1230 line, min (cols, active_frame->used[y] - left),
1231 active_frame->highlight[y]);
1232 }
1233
1234 /* Turn the cursor on if we turned it off. */
1235
1236 if (cursor_cleared)
1237 x_display_cursor (f, 1);
1238 }
1239
1240 #ifndef HAVE_X11
1241 /* Process all queued ExposeRegion events. */
1242
1243 static void
1244 dumpqueue ()
1245 {
1246 register int i;
1247 XExposeRegionEvent r;
1248
1249 while (dequeue_event (&r, &x_expose_queue))
1250 {
1251 struct frame *f = x_window_to_frame (r.window);
1252 if (f->display.x->icon_desc == r.window)
1253 refreshicon (f);
1254 else
1255 dumprectangle (f, r.x, r.y, r.width, r.height);
1256 }
1257 XFlushQueue ();
1258 }
1259 #endif /* HAVE_X11 */
1260 \f
1261 /* Process all expose events that are pending, for X10.
1262 Redraws the cursor if necessary on any frame that
1263 is not in the process of being updated with update_frame. */
1264
1265 #ifndef HAVE_X11
1266 static void
1267 x_do_pending_expose ()
1268 {
1269 int mask;
1270 struct frame *f;
1271 Lisp_Object tail, frame;
1272
1273 if (expose_all_windows)
1274 {
1275 expose_all_windows = 0;
1276 for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
1277 {
1278 register int temp_width, temp_height;
1279 int intborder;
1280
1281 frame = XCONS (tail)->car;
1282 if (XGCTYPE (frame) != Lisp_Frame)
1283 continue;
1284 f = XFRAME (frame);
1285 if (! FRAME_X_P (f))
1286 continue;
1287 if (!f->async_visible)
1288 continue;
1289 if (!f->display.x->needs_exposure)
1290 continue;
1291
1292 intborder = f->display.x->internal_border_width;
1293
1294 clear_cursor (f);
1295 XGetWindowInfo (FRAME_X_WINDOW (f), &windowinfo);
1296 temp_width = ((windowinfo.width - 2 * intborder
1297 - f->display.x->v_scroll_bar_width)
1298 / FONT_WIDTH (f->display.x->font));
1299 temp_height = ((windowinfo.height- 2 * intborder
1300 - f->display.x->h_scroll_bar_height)
1301 / FONT_HEIGHT (f->display.x->font));
1302 if (temp_width != f->width || temp_height != f->height)
1303 {
1304 change_frame_size (f, max (1, temp_height),
1305 max (1, temp_width), 0, 1);
1306 x_resize_scroll_bars (f);
1307 }
1308 f->display.x->left_pos = windowinfo.x;
1309 f->display.x->top_pos = windowinfo.y;
1310 dumprectangle (f, 0, 0, PIXEL_WIDTH (f), PIXEL_HEIGHT (f));
1311 #if 0
1312 dumpborder (f, 0);
1313 #endif /* ! 0 */
1314 f->display.x->needs_exposure = 0;
1315 if (updating_frame != f)
1316 x_display_cursor (f, 1);
1317 XFlushQueue ();
1318 }
1319 }
1320 else
1321 /* Handle any individual-rectangle expose events queued
1322 for various windows. */
1323 #ifdef HAVE_X11
1324 ;
1325 #else /* ! defined (HAVE_X11) */
1326 dumpqueue ();
1327 #endif /* ! defined (HAVE_X11) */
1328 }
1329 #endif
1330
1331 #ifdef HAVE_X11
1332 static void
1333 frame_highlight (frame)
1334 struct frame *frame;
1335 {
1336 /* We used to only do this if Vx_no_window_manager was non-nil, but
1337 the ICCCM (section 4.1.6) says that the window's border pixmap
1338 and border pixel are window attributes which are "private to the
1339 client", so we can always change it to whatever we want. */
1340 BLOCK_INPUT;
1341 XSetWindowBorder (x_current_display, FRAME_X_WINDOW (frame),
1342 frame->display.x->border_pixel);
1343 UNBLOCK_INPUT;
1344 x_display_cursor (frame, 1);
1345 }
1346
1347 static void
1348 frame_unhighlight (frame)
1349 struct frame *frame;
1350 {
1351 /* We used to only do this if Vx_no_window_manager was non-nil, but
1352 the ICCCM (section 4.1.6) says that the window's border pixmap
1353 and border pixel are window attributes which are "private to the
1354 client", so we can always change it to whatever we want. */
1355 BLOCK_INPUT;
1356 XSetWindowBorderPixmap (x_current_display, FRAME_X_WINDOW (frame),
1357 frame->display.x->border_tile);
1358 UNBLOCK_INPUT;
1359 x_display_cursor (frame, 1);
1360 }
1361 #else /* ! defined (HAVE_X11) */
1362 /* Dump the border-emphasis of frame F.
1363 If F is selected, this is a lining of the same color as the border,
1364 just within the border, occupying a portion of the internal border.
1365 If F is not selected, it is background in the same place.
1366 If ALWAYS is 0, don't bother explicitly drawing if it's background.
1367
1368 ALWAYS = 1 is used when a frame becomes selected or deselected.
1369 In that case, we also turn the cursor off and on again
1370 so it will appear in the proper shape (solid if selected; else hollow.) */
1371
1372 static void
1373 dumpborder (f, always)
1374 struct frame *f;
1375 int always;
1376 {
1377 int thickness = f->display.x->internal_border_width / 2;
1378 int width = PIXEL_WIDTH (f);
1379 int height = PIXEL_HEIGHT (f);
1380 int pixel;
1381
1382 if (f != selected_frame)
1383 {
1384 if (!always)
1385 return;
1386
1387 pixel = f->display.x->background_pixel;
1388 }
1389 else
1390 {
1391 pixel = f->display.x->border_pixel;
1392 }
1393
1394 XPixSet (FRAME_X_WINDOW (f), 0, 0, width, thickness, pixel);
1395 XPixSet (FRAME_X_WINDOW (f), 0, 0, thickness, height, pixel);
1396 XPixSet (FRAME_X_WINDOW (f), 0, height - thickness, width,
1397 thickness, pixel);
1398 XPixSet (FRAME_X_WINDOW (f), width - thickness, 0, thickness,
1399 height, pixel);
1400
1401 if (always)
1402 x_display_cursor (f, 1);
1403 }
1404 #endif /* ! defined (HAVE_X11) */
1405
1406 static void XTframe_rehighlight ();
1407
1408 /* The focus has changed. Update the frames as necessary to reflect
1409 the new situation. Note that we can't change the selected frame
1410 here, because the lisp code we are interrupting might become confused.
1411 Each event gets marked with the frame in which it occurred, so the
1412 lisp code can tell when the switch took place by examining the events. */
1413
1414 static void
1415 x_new_focus_frame (frame)
1416 struct frame *frame;
1417 {
1418 struct frame *old_focus = x_focus_frame;
1419 int events_enqueued = 0;
1420
1421 if (frame != x_focus_frame)
1422 {
1423 /* Set this before calling other routines, so that they see
1424 the correct value of x_focus_frame. */
1425 x_focus_frame = frame;
1426
1427 if (old_focus && old_focus->auto_lower)
1428 x_lower_frame (old_focus);
1429
1430 #if 0
1431 selected_frame = frame;
1432 XSET (XWINDOW (selected_frame->selected_window)->frame,
1433 Lisp_Frame, selected_frame);
1434 Fselect_window (selected_frame->selected_window);
1435 choose_minibuf_frame ();
1436 #endif /* ! 0 */
1437
1438 if (x_focus_frame && x_focus_frame->auto_raise)
1439 x_raise_frame (x_focus_frame);
1440 }
1441
1442 XTframe_rehighlight ();
1443 }
1444
1445
1446 /* The focus has changed, or we have redirected a frame's focus to
1447 another frame (this happens when a frame uses a surrogate
1448 minibuffer frame). Shift the highlight as appropriate. */
1449 static void
1450 XTframe_rehighlight ()
1451 {
1452 struct frame *old_highlight = x_highlight_frame;
1453
1454 if (x_focus_frame)
1455 {
1456 x_highlight_frame =
1457 ((XGCTYPE (FRAME_FOCUS_FRAME (x_focus_frame)) == Lisp_Frame)
1458 ? XFRAME (FRAME_FOCUS_FRAME (x_focus_frame))
1459 : x_focus_frame);
1460 if (! FRAME_LIVE_P (x_highlight_frame))
1461 {
1462 FRAME_FOCUS_FRAME (x_focus_frame) = Qnil;
1463 x_highlight_frame = x_focus_frame;
1464 }
1465 }
1466 else
1467 x_highlight_frame = 0;
1468
1469 if (x_highlight_frame != old_highlight)
1470 {
1471 if (old_highlight)
1472 frame_unhighlight (old_highlight);
1473 if (x_highlight_frame)
1474 frame_highlight (x_highlight_frame);
1475 }
1476 }
1477 \f
1478 /* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
1479
1480 /* Which modifier keys are on which modifier bits?
1481
1482 With each keystroke, X returns eight bits indicating which modifier
1483 keys were held down when the key was pressed. The interpretation
1484 of the top five modifier bits depends on what keys are attached
1485 to them. If the Meta_L and Meta_R keysyms are on mod5, then mod5
1486 is the meta bit.
1487
1488 x_meta_mod_mask is a mask containing the bits used for the meta key.
1489 It may have more than one bit set, if more than one modifier bit
1490 has meta keys on it. Basically, if EVENT is a KeyPress event,
1491 the meta key is pressed if (EVENT.state & x_meta_mod_mask) != 0.
1492
1493 x_shift_lock_mask is LockMask if the XK_Shift_Lock keysym is on the
1494 lock modifier bit, or zero otherwise. Non-alphabetic keys should
1495 only be affected by the lock modifier bit if XK_Shift_Lock is in
1496 use; XK_Caps_Lock should only affect alphabetic keys. With this
1497 arrangement, the lock modifier should shift the character if
1498 (EVENT.state & x_shift_lock_mask) != 0. */
1499 static int x_meta_mod_mask, x_shift_lock_mask;
1500
1501 /* These are like x_meta_mod_mask, but for different modifiers. */
1502 static int x_alt_mod_mask, x_super_mod_mask, x_hyper_mod_mask;
1503
1504 /* Initialize mode_switch_bit and modifier_meaning. */
1505 static void
1506 x_find_modifier_meanings ()
1507 {
1508 int min_code, max_code;
1509 KeySym *syms;
1510 int syms_per_code;
1511 XModifierKeymap *mods;
1512
1513 x_meta_mod_mask = 0;
1514 x_shift_lock_mask = 0;
1515 x_alt_mod_mask = 0;
1516 x_super_mod_mask = 0;
1517 x_hyper_mod_mask = 0;
1518
1519 #ifdef HAVE_X11R4
1520 XDisplayKeycodes (x_current_display, &min_code, &max_code);
1521 #else
1522 min_code = x_current_display->min_keycode;
1523 max_code = x_current_display->max_keycode;
1524 #endif
1525
1526 syms = XGetKeyboardMapping (x_current_display,
1527 min_code, max_code - min_code + 1,
1528 &syms_per_code);
1529 mods = XGetModifierMapping (x_current_display);
1530
1531 /* Scan the modifier table to see which modifier bits the Meta and
1532 Alt keysyms are on. */
1533 {
1534 int row, col; /* The row and column in the modifier table. */
1535
1536 for (row = 3; row < 8; row++)
1537 for (col = 0; col < mods->max_keypermod; col++)
1538 {
1539 KeyCode code =
1540 mods->modifiermap[(row * mods->max_keypermod) + col];
1541
1542 /* Are any of this keycode's keysyms a meta key? */
1543 {
1544 int code_col;
1545
1546 for (code_col = 0; code_col < syms_per_code; code_col++)
1547 {
1548 int sym = syms[((code - min_code) * syms_per_code) + code_col];
1549
1550 switch (sym)
1551 {
1552 case XK_Meta_L:
1553 case XK_Meta_R:
1554 x_meta_mod_mask |= (1 << row);
1555 break;
1556
1557 case XK_Alt_L:
1558 case XK_Alt_R:
1559 x_alt_mod_mask |= (1 << row);
1560 break;
1561
1562 case XK_Hyper_L:
1563 case XK_Hyper_R:
1564 x_hyper_mod_mask |= (1 << row);
1565 break;
1566
1567 case XK_Super_L:
1568 case XK_Super_R:
1569 x_super_mod_mask |= (1 << row);
1570 break;
1571
1572 case XK_Shift_Lock:
1573 /* Ignore this if it's not on the lock modifier. */
1574 if ((1 << row) == LockMask)
1575 x_shift_lock_mask = LockMask;
1576 break;
1577 }
1578 }
1579 }
1580 }
1581 }
1582
1583 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
1584 if (! x_meta_mod_mask)
1585 {
1586 x_meta_mod_mask = x_alt_mod_mask;
1587 x_alt_mod_mask = 0;
1588 }
1589
1590 /* If some keys are both alt and meta,
1591 make them just meta, not alt. */
1592 if (x_alt_mod_mask & x_meta_mod_mask)
1593 {
1594 x_alt_mod_mask &= ~x_meta_mod_mask;
1595 }
1596
1597 XFree ((char *) syms);
1598 XFreeModifiermap (mods);
1599 }
1600
1601 /* Prepare a menu-event in *RESULT for placement in the input queue. */
1602
1603 static Lisp_Object
1604 construct_menu_click (result, event, f)
1605 struct input_event *result;
1606 XButtonEvent *event;
1607 struct frame *f;
1608 {
1609 /* Make the event type no_event; we'll change that when we decide
1610 otherwise. */
1611 result->kind = mouse_click;
1612 XSET (result->code, Lisp_Int, event->button - Button1);
1613 result->timestamp = event->time;
1614 result->modifiers = (x_x_to_emacs_modifiers (event->state)
1615 | (event->type == ButtonRelease
1616 ? up_modifier
1617 : down_modifier));
1618
1619 {
1620 XFASTINT (result->x) = event->x;
1621 XFASTINT (result->y) = -1; /* special meaning for menubar */
1622 XSET (result->frame_or_window, Lisp_Frame, f);
1623 }
1624 }
1625
1626 /* Convert between the modifier bits X uses and the modifier bits
1627 Emacs uses. */
1628 static unsigned int
1629 x_x_to_emacs_modifiers (state)
1630 unsigned int state;
1631 {
1632 return ( ((state & (ShiftMask | x_shift_lock_mask)) ? shift_modifier : 0)
1633 | ((state & ControlMask) ? ctrl_modifier : 0)
1634 | ((state & x_meta_mod_mask) ? meta_modifier : 0)
1635 | ((state & x_alt_mod_mask) ? alt_modifier : 0)
1636 | ((state & x_super_mod_mask) ? super_modifier : 0)
1637 | ((state & x_hyper_mod_mask) ? hyper_modifier : 0));
1638 }
1639
1640 static unsigned int
1641 x_emacs_to_x_modifiers (state)
1642 unsigned int state;
1643 {
1644 return ( ((state & alt_modifier) ? x_alt_mod_mask : 0)
1645 | ((state & super_modifier) ? x_super_mod_mask : 0)
1646 | ((state & hyper_modifier) ? x_hyper_mod_mask : 0)
1647 | ((state & shift_modifier) ? ShiftMask : 0)
1648 | ((state & ctrl_modifier) ? ControlMask : 0)
1649 | ((state & meta_modifier) ? x_meta_mod_mask : 0));
1650 }
1651
1652 /* Return true iff KEYSYM is a vendor-specific keysym that we should
1653 return as a function key. If you add a keysym to this, you should
1654 make sure that the tables make_lispy_event uses contain a suitable
1655 name for it. */
1656 static int
1657 x_is_vendor_fkey (sym)
1658 KeySym sym;
1659 {
1660 return 0
1661 #ifdef DXK_Remove
1662 || (sym == DXK_Remove)
1663 #endif
1664 ;
1665 }
1666
1667 \f
1668 /* Mouse clicks and mouse movement. Rah. */
1669 #ifdef HAVE_X11
1670
1671 /* Given a pixel position (PIX_X, PIX_Y) on the frame F, return
1672 glyph co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle
1673 that the glyph at X, Y occupies, if BOUNDS != 0.
1674 If NOCLIP is nonzero, do not force the value into range. */
1675
1676 static void
1677 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
1678 FRAME_PTR f;
1679 register int pix_x, pix_y;
1680 register int *x, *y;
1681 XRectangle *bounds;
1682 int noclip;
1683 {
1684 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
1685 even for negative values. */
1686 if (pix_x < 0)
1687 pix_x -= FONT_WIDTH ((f)->display.x->font) - 1;
1688 if (pix_y < 0)
1689 pix_y -= FONT_HEIGHT ((f)->display.x->font) - 1;
1690
1691 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
1692 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
1693
1694 if (bounds)
1695 {
1696 bounds->width = FONT_WIDTH (f->display.x->font);
1697 bounds->height = FONT_HEIGHT (f->display.x->font);
1698 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
1699 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
1700 }
1701
1702 if (!noclip)
1703 {
1704 if (pix_x < 0)
1705 pix_x = 0;
1706 else if (pix_x > f->width)
1707 pix_x = f->width;
1708
1709 if (pix_y < 0)
1710 pix_y = 0;
1711 else if (pix_y > f->height)
1712 pix_y = f->height;
1713 }
1714
1715 *x = pix_x;
1716 *y = pix_y;
1717 }
1718
1719 /* Prepare a mouse-event in *RESULT for placement in the input queue.
1720
1721 If the event is a button press, then note that we have grabbed
1722 the mouse. */
1723
1724 static Lisp_Object
1725 construct_mouse_click (result, event, f)
1726 struct input_event *result;
1727 XButtonEvent *event;
1728 struct frame *f;
1729 {
1730 /* Make the event type no_event; we'll change that when we decide
1731 otherwise. */
1732 result->kind = mouse_click;
1733 result->code = event->button - Button1;
1734 result->timestamp = event->time;
1735 result->modifiers = (x_x_to_emacs_modifiers (event->state)
1736 | (event->type == ButtonRelease
1737 ? up_modifier
1738 : down_modifier));
1739
1740 /* Notice if the mouse is still grabbed. */
1741 if (event->type == ButtonPress)
1742 {
1743 if (! x_mouse_grabbed)
1744 Vmouse_depressed = Qt;
1745 x_mouse_grabbed |= (1 << event->button);
1746 last_mouse_frame = f;
1747 }
1748 else if (event->type == ButtonRelease)
1749 {
1750 x_mouse_grabbed &= ~(1 << event->button);
1751 if (!x_mouse_grabbed)
1752 Vmouse_depressed = Qnil;
1753 }
1754
1755 {
1756 int row, column;
1757
1758 pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL, 0);
1759 XFASTINT (result->x) = column;
1760 XFASTINT (result->y) = row;
1761 XSET (result->frame_or_window, Lisp_Frame, f);
1762 }
1763 }
1764 \f
1765 /* Function to report a mouse movement to the mainstream Emacs code.
1766 The input handler calls this.
1767
1768 We have received a mouse movement event, which is given in *event.
1769 If the mouse is over a different glyph than it was last time, tell
1770 the mainstream emacs code by setting mouse_moved. If not, ask for
1771 another motion event, so we can check again the next time it moves. */
1772 static void
1773 note_mouse_movement (frame, event)
1774 FRAME_PTR frame;
1775 XMotionEvent *event;
1776
1777 {
1778 last_mouse_movement_time = event->time;
1779
1780 /* Has the mouse moved off the glyph it was on at the last sighting? */
1781 if (event->x < last_mouse_glyph.x
1782 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
1783 || event->y < last_mouse_glyph.y
1784 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
1785 {
1786 mouse_moved = 1;
1787 last_mouse_scroll_bar = Qnil;
1788 }
1789 else
1790 {
1791 /* It's on the same glyph. Call XQueryPointer so we'll get an
1792 event the next time the mouse moves and we can see if it's
1793 *still* on the same glyph. */
1794 int dummy;
1795
1796 XQueryPointer (event->display, event->window,
1797 (Window *) &dummy, (Window *) &dummy,
1798 &dummy, &dummy, &dummy, &dummy,
1799 (unsigned int *) &dummy);
1800 }
1801 }
1802
1803 static struct scroll_bar *x_window_to_scroll_bar ();
1804 static void x_scroll_bar_report_motion ();
1805
1806 /* Return the current position of the mouse.
1807
1808 If the mouse movement started in a scroll bar, set *f, *bar_window,
1809 and *part to the frame, window, and scroll bar part that the mouse
1810 is over. Set *x and *y to the portion and whole of the mouse's
1811 position on the scroll bar.
1812
1813 If the mouse movement started elsewhere, set *f to the frame the
1814 mouse is on, *bar_window to nil, and *x and *y to the character cell
1815 the mouse is over.
1816
1817 Set *time to the server timestamp for the time at which the mouse
1818 was at this position.
1819
1820 Don't store anything if we don't have a valid set of values to report.
1821
1822 This clears the mouse_moved flag, so we can wait for the next mouse
1823 movement. This also calls XQueryPointer, which will cause the
1824 server to give us another MotionNotify when the mouse moves
1825 again. */
1826
1827 static void
1828 XTmouse_position (f, bar_window, part, x, y, time)
1829 FRAME_PTR *f;
1830 Lisp_Object *bar_window;
1831 enum scroll_bar_part *part;
1832 Lisp_Object *x, *y;
1833 unsigned long *time;
1834 {
1835 FRAME_PTR f1;
1836
1837 BLOCK_INPUT;
1838
1839 if (! NILP (last_mouse_scroll_bar))
1840 x_scroll_bar_report_motion (f, bar_window, part, x, y, time);
1841 else
1842 {
1843 Window root;
1844 int root_x, root_y;
1845
1846 Window dummy_window;
1847 int dummy;
1848
1849 mouse_moved = 0;
1850 last_mouse_scroll_bar = Qnil;
1851
1852 /* Figure out which root window we're on. */
1853 XQueryPointer (x_current_display,
1854 DefaultRootWindow (x_current_display),
1855
1856 /* The root window which contains the pointer. */
1857 &root,
1858
1859 /* Trash which we can't trust if the pointer is on
1860 a different screen. */
1861 &dummy_window,
1862
1863 /* The position on that root window. */
1864 &root_x, &root_y,
1865
1866 /* More trash we can't trust. */
1867 &dummy, &dummy,
1868
1869 /* Modifier keys and pointer buttons, about which
1870 we don't care. */
1871 (unsigned int *) &dummy);
1872
1873 /* Now we have a position on the root; find the innermost window
1874 containing the pointer. */
1875 {
1876 Window win, child;
1877 int win_x, win_y;
1878 int parent_x, parent_y;
1879
1880 win = root;
1881
1882 if (x_mouse_grabbed)
1883 {
1884 /* If mouse was grabbed on a frame, give coords for that frame
1885 even if the mouse is now outside it. */
1886 XTranslateCoordinates (x_current_display,
1887
1888 /* From-window, to-window. */
1889 root, FRAME_X_WINDOW (last_mouse_frame),
1890
1891 /* From-position, to-position. */
1892 root_x, root_y, &win_x, &win_y,
1893
1894 /* Child of win. */
1895 &child);
1896 f1 = last_mouse_frame;
1897 }
1898 else
1899 {
1900 while (1)
1901 {
1902 XTranslateCoordinates (x_current_display,
1903
1904 /* From-window, to-window. */
1905 root, win,
1906
1907 /* From-position, to-position. */
1908 root_x, root_y, &win_x, &win_y,
1909
1910 /* Child of win. */
1911 &child);
1912
1913 if (child == None)
1914 break;
1915
1916 win = child;
1917 parent_x = win_x;
1918 parent_y = win_y;
1919 }
1920
1921 /* Now we know that:
1922 win is the innermost window containing the pointer
1923 (XTC says it has no child containing the pointer),
1924 win_x and win_y are the pointer's position in it
1925 (XTC did this the last time through), and
1926 parent_x and parent_y are the pointer's position in win's parent.
1927 (They are what win_x and win_y were when win was child.
1928 If win is the root window, it has no parent, and
1929 parent_{x,y} are invalid, but that's okay, because we'll
1930 never use them in that case.) */
1931
1932 /* Is win one of our frames? */
1933 f1 = x_window_to_frame (win);
1934 }
1935
1936 /* If not, is it one of our scroll bars? */
1937 if (! f1)
1938 {
1939 struct scroll_bar *bar = x_window_to_scroll_bar (win);
1940
1941 if (bar)
1942 {
1943 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
1944 win_x = parent_x;
1945 win_y = parent_y;
1946 }
1947 }
1948
1949 if (f1)
1950 {
1951 /* Ok, we found a frame. Convert from pixels to characters
1952 and store all the values. */
1953
1954 pixel_to_glyph_coords (f1, win_x, win_y, &win_x, &win_y,
1955 &last_mouse_glyph, x_mouse_grabbed);
1956
1957 *bar_window = Qnil;
1958 *part = 0;
1959 *f = f1;
1960 XSET (*x, Lisp_Int, win_x);
1961 XSET (*y, Lisp_Int, win_y);
1962 *time = last_mouse_movement_time;
1963 }
1964 }
1965 }
1966
1967 UNBLOCK_INPUT;
1968 }
1969
1970 #else /* ! defined (HAVE_X11) */
1971 #define XEvent XKeyPressedEvent
1972 #endif /* ! defined (HAVE_X11) */
1973 \f
1974 /* Scroll bar support. */
1975
1976 /* Given an X window ID, find the struct scroll_bar which manages it.
1977 This can be called in GC, so we have to make sure to strip off mark
1978 bits. */
1979 static struct scroll_bar *
1980 x_window_to_scroll_bar (window_id)
1981 Window window_id;
1982 {
1983 Lisp_Object tail, frame;
1984
1985 for (tail = Vframe_list;
1986 XGCTYPE (tail) == Lisp_Cons;
1987 tail = XCONS (tail)->cdr)
1988 {
1989 Lisp_Object frame = XCONS (tail)->car;
1990 Lisp_Object bar, condemned;
1991
1992 /* All elements of Vframe_list should be frames. */
1993 if (XGCTYPE (frame) != Lisp_Frame)
1994 abort ();
1995
1996 /* Scan this frame's scroll bar list for a scroll bar with the
1997 right window ID. */
1998 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
1999 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
2000 /* This trick allows us to search both the ordinary and
2001 condemned scroll bar lists with one loop. */
2002 ! GC_NILP (bar) || (bar = condemned,
2003 condemned = Qnil,
2004 ! GC_NILP (bar));
2005 bar = XSCROLL_BAR(bar)->next)
2006 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
2007 return XSCROLL_BAR (bar);
2008 }
2009
2010 return 0;
2011 }
2012
2013 /* Open a new X window to serve as a scroll bar, and return the
2014 scroll bar vector for it. */
2015 static struct scroll_bar *
2016 x_scroll_bar_create (window, top, left, width, height)
2017 struct window *window;
2018 int top, left, width, height;
2019 {
2020 FRAME_PTR frame = XFRAME (WINDOW_FRAME (window));
2021 struct scroll_bar *bar =
2022 XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
2023
2024 BLOCK_INPUT;
2025
2026 {
2027 XSetWindowAttributes a;
2028 unsigned long mask;
2029 a.background_pixel = frame->display.x->background_pixel;
2030 a.event_mask = (ButtonPressMask | ButtonReleaseMask
2031 | ButtonMotionMask | PointerMotionHintMask
2032 | ExposureMask);
2033 a.cursor = x_vertical_scroll_bar_cursor;
2034
2035 mask = (CWBackPixel | CWEventMask | CWCursor);
2036
2037 #if 0
2038
2039 ac = 0;
2040 XtSetArg (al[ac], XtNx, left); ac++;
2041 XtSetArg (al[ac], XtNy, top); ac++;
2042 XtSetArg (al[ac], XtNwidth, width); ac++;
2043 XtSetArg (al[ac], XtNheight, height); ac++;
2044 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
2045 sb_widget = XtCreateManagedWidget ("box",
2046 boxWidgetClass,
2047 frame->display.x->edit_widget, al, ac);
2048 SET_SCROLL_BAR_X_WINDOW
2049 (bar, sb_widget->core.window);
2050 #endif
2051 SET_SCROLL_BAR_X_WINDOW
2052 (bar,
2053 XCreateWindow (x_current_display, FRAME_X_WINDOW (frame),
2054
2055 /* Position and size of scroll bar. */
2056 left, top, width, height,
2057
2058 /* Border width, depth, class, and visual. */
2059 0, CopyFromParent, CopyFromParent, CopyFromParent,
2060
2061 /* Attributes. */
2062 mask, &a));
2063 }
2064
2065 XSET (bar->window, Lisp_Window, window);
2066 XSET (bar->top, Lisp_Int, top);
2067 XSET (bar->left, Lisp_Int, left);
2068 XSET (bar->width, Lisp_Int, width);
2069 XSET (bar->height, Lisp_Int, height);
2070 XSET (bar->start, Lisp_Int, 0);
2071 XSET (bar->end, Lisp_Int, 0);
2072 bar->dragging = Qnil;
2073
2074 /* Add bar to its frame's list of scroll bars. */
2075 bar->next = FRAME_SCROLL_BARS (frame);
2076 bar->prev = Qnil;
2077 XSET (FRAME_SCROLL_BARS (frame), Lisp_Vector, bar);
2078 if (! NILP (bar->next))
2079 XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar);
2080
2081 XMapWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar));
2082
2083 UNBLOCK_INPUT;
2084
2085 return bar;
2086 }
2087
2088 /* Draw BAR's handle in the proper position.
2089 If the handle is already drawn from START to END, don't bother
2090 redrawing it, unless REBUILD is non-zero; in that case, always
2091 redraw it. (REBUILD is handy for drawing the handle after expose
2092 events.)
2093
2094 Normally, we want to constrain the start and end of the handle to
2095 fit inside its rectangle, but if the user is dragging the scroll bar
2096 handle, we want to let them drag it down all the way, so that the
2097 bar's top is as far down as it goes; otherwise, there's no way to
2098 move to the very end of the buffer. */
2099 static void
2100 x_scroll_bar_set_handle (bar, start, end, rebuild)
2101 struct scroll_bar *bar;
2102 int start, end;
2103 int rebuild;
2104 {
2105 int dragging = ! NILP (bar->dragging);
2106 Window w = SCROLL_BAR_X_WINDOW (bar);
2107 GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
2108
2109 /* If the display is already accurate, do nothing. */
2110 if (! rebuild
2111 && start == XINT (bar->start)
2112 && end == XINT (bar->end))
2113 return;
2114
2115 BLOCK_INPUT;
2116
2117 {
2118 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (XINT (bar->width));
2119 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2120 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2121
2122 /* Make sure the values are reasonable, and try to preserve
2123 the distance between start and end. */
2124 {
2125 int length = end - start;
2126
2127 if (start < 0)
2128 start = 0;
2129 else if (start > top_range)
2130 start = top_range;
2131 end = start + length;
2132
2133 if (end < start)
2134 end = start;
2135 else if (end > top_range && ! dragging)
2136 end = top_range;
2137 }
2138
2139 /* Store the adjusted setting in the scroll bar. */
2140 XSET (bar->start, Lisp_Int, start);
2141 XSET (bar->end, Lisp_Int, end);
2142
2143 /* Clip the end position, just for display. */
2144 if (end > top_range)
2145 end = top_range;
2146
2147 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
2148 below top positions, to make sure the handle is always at least
2149 that many pixels tall. */
2150 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
2151
2152 /* Draw the empty space above the handle. Note that we can't clear
2153 zero-height areas; that means "clear to end of window." */
2154 if (0 < start)
2155 XClearArea (x_current_display, w,
2156
2157 /* x, y, width, height, and exposures. */
2158 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2159 VERTICAL_SCROLL_BAR_TOP_BORDER,
2160 inside_width, start,
2161 False);
2162
2163 /* Draw the handle itself. */
2164 XFillRectangle (x_current_display, w, gc,
2165
2166 /* x, y, width, height */
2167 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2168 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
2169 inside_width, end - start);
2170
2171
2172 /* Draw the empty space below the handle. Note that we can't
2173 clear zero-height areas; that means "clear to end of window." */
2174 if (end < inside_height)
2175 XClearArea (x_current_display, w,
2176
2177 /* x, y, width, height, and exposures. */
2178 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2179 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
2180 inside_width, inside_height - end,
2181 False);
2182
2183 }
2184
2185 UNBLOCK_INPUT;
2186 }
2187
2188 /* Move a scroll bar around on the screen, to accommodate changing
2189 window configurations. */
2190 static void
2191 x_scroll_bar_move (bar, top, left, width, height)
2192 struct scroll_bar *bar;
2193 int top, left, width, height;
2194 {
2195 BLOCK_INPUT;
2196
2197 {
2198 XWindowChanges wc;
2199 unsigned int mask = 0;
2200
2201 wc.x = left;
2202 wc.y = top;
2203 wc.width = width;
2204 wc.height = height;
2205
2206 if (left != XINT (bar->left)) mask |= CWX;
2207 if (top != XINT (bar->top)) mask |= CWY;
2208 if (width != XINT (bar->width)) mask |= CWWidth;
2209 if (height != XINT (bar->height)) mask |= CWHeight;
2210
2211 if (mask)
2212 XConfigureWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar),
2213 mask, &wc);
2214 }
2215
2216 XSET (bar->left, Lisp_Int, left);
2217 XSET (bar->top, Lisp_Int, top);
2218 XSET (bar->width, Lisp_Int, width);
2219 XSET (bar->height, Lisp_Int, height);
2220
2221 UNBLOCK_INPUT;
2222 }
2223
2224 /* Destroy the X window for BAR, and set its Emacs window's scroll bar
2225 to nil. */
2226 static void
2227 x_scroll_bar_remove (bar)
2228 struct scroll_bar *bar;
2229 {
2230 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2231
2232 BLOCK_INPUT;
2233
2234 /* Destroy the window. */
2235 XDestroyWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar));
2236
2237 /* Disassociate this scroll bar from its window. */
2238 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
2239
2240 UNBLOCK_INPUT;
2241 }
2242
2243 /* Set the handle of the vertical scroll bar for WINDOW to indicate
2244 that we are displaying PORTION characters out of a total of WHOLE
2245 characters, starting at POSITION. If WINDOW has no scroll bar,
2246 create one. */
2247 static void
2248 XTset_vertical_scroll_bar (window, portion, whole, position)
2249 struct window *window;
2250 int portion, whole, position;
2251 {
2252 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2253 int top = XINT (window->top);
2254 int left = WINDOW_VERTICAL_SCROLL_BAR_COLUMN (window);
2255 int height = WINDOW_VERTICAL_SCROLL_BAR_HEIGHT (window);
2256
2257 /* Where should this scroll bar be, pixelwise? */
2258 int pixel_top = CHAR_TO_PIXEL_ROW (f, top);
2259 int pixel_left = CHAR_TO_PIXEL_COL (f, left);
2260 int pixel_width = VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f);
2261 int pixel_height = VERTICAL_SCROLL_BAR_PIXEL_HEIGHT (f, height);
2262
2263 struct scroll_bar *bar;
2264
2265 /* Does the scroll bar exist yet? */
2266 if (NILP (window->vertical_scroll_bar))
2267 bar = x_scroll_bar_create (window,
2268 pixel_top, pixel_left,
2269 pixel_width, pixel_height);
2270 else
2271 {
2272 /* It may just need to be moved and resized. */
2273 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2274 x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
2275 }
2276
2277 /* Set the scroll bar's current state, unless we're currently being
2278 dragged. */
2279 if (NILP (bar->dragging))
2280 {
2281 int top_range =
2282 VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
2283
2284 if (whole == 0)
2285 x_scroll_bar_set_handle (bar, 0, top_range, 0);
2286 else
2287 {
2288 int start = ((double) position * top_range) / whole;
2289 int end = ((double) (position + portion) * top_range) / whole;
2290
2291 x_scroll_bar_set_handle (bar, start, end, 0);
2292 }
2293 }
2294
2295 XSET (window->vertical_scroll_bar, Lisp_Vector, bar);
2296 }
2297
2298
2299 /* The following three hooks are used when we're doing a thorough
2300 redisplay of the frame. We don't explicitly know which scroll bars
2301 are going to be deleted, because keeping track of when windows go
2302 away is a real pain - "Can you say set-window-configuration, boys
2303 and girls?" Instead, we just assert at the beginning of redisplay
2304 that *all* scroll bars are to be removed, and then save a scroll bar
2305 from the fiery pit when we actually redisplay its window. */
2306
2307 /* Arrange for all scroll bars on FRAME to be removed at the next call
2308 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
2309 `*redeem_scroll_bar_hook' is applied to its window before the judgement. */
2310 static void
2311 XTcondemn_scroll_bars (frame)
2312 FRAME_PTR frame;
2313 {
2314 /* The condemned list should be empty at this point; if it's not,
2315 then the rest of Emacs isn't using the condemn/redeem/judge
2316 protocol correctly. */
2317 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
2318 abort ();
2319
2320 /* Move them all to the "condemned" list. */
2321 FRAME_CONDEMNED_SCROLL_BARS (frame) = FRAME_SCROLL_BARS (frame);
2322 FRAME_SCROLL_BARS (frame) = Qnil;
2323 }
2324
2325 /* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
2326 Note that WINDOW isn't necessarily condemned at all. */
2327 static void
2328 XTredeem_scroll_bar (window)
2329 struct window *window;
2330 {
2331 struct scroll_bar *bar;
2332
2333 /* We can't redeem this window's scroll bar if it doesn't have one. */
2334 if (NILP (window->vertical_scroll_bar))
2335 abort ();
2336
2337 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2338
2339 /* Unlink it from the condemned list. */
2340 {
2341 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2342
2343 if (NILP (bar->prev))
2344 {
2345 /* If the prev pointer is nil, it must be the first in one of
2346 the lists. */
2347 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
2348 /* It's not condemned. Everything's fine. */
2349 return;
2350 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
2351 window->vertical_scroll_bar))
2352 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
2353 else
2354 /* If its prev pointer is nil, it must be at the front of
2355 one or the other! */
2356 abort ();
2357 }
2358 else
2359 XSCROLL_BAR (bar->prev)->next = bar->next;
2360
2361 if (! NILP (bar->next))
2362 XSCROLL_BAR (bar->next)->prev = bar->prev;
2363
2364 bar->next = FRAME_SCROLL_BARS (f);
2365 bar->prev = Qnil;
2366 XSET (FRAME_SCROLL_BARS (f), Lisp_Vector, bar);
2367 if (! NILP (bar->next))
2368 XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar);
2369 }
2370 }
2371
2372 /* Remove all scroll bars on FRAME that haven't been saved since the
2373 last call to `*condemn_scroll_bars_hook'. */
2374 static void
2375 XTjudge_scroll_bars (f)
2376 FRAME_PTR f;
2377 {
2378 Lisp_Object bar, next;
2379
2380 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
2381
2382 /* Clear out the condemned list now so we won't try to process any
2383 more events on the hapless scroll bars. */
2384 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
2385
2386 for (; ! NILP (bar); bar = next)
2387 {
2388 struct scroll_bar *b = XSCROLL_BAR (bar);
2389
2390 x_scroll_bar_remove (b);
2391
2392 next = b->next;
2393 b->next = b->prev = Qnil;
2394 }
2395
2396 /* Now there should be no references to the condemned scroll bars,
2397 and they should get garbage-collected. */
2398 }
2399
2400
2401 /* Handle an Expose or GraphicsExpose event on a scroll bar.
2402
2403 This may be called from a signal handler, so we have to ignore GC
2404 mark bits. */
2405 static void
2406 x_scroll_bar_expose (bar, event)
2407 struct scroll_bar *bar;
2408 XEvent *event;
2409 {
2410 Window w = SCROLL_BAR_X_WINDOW (bar);
2411 GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
2412
2413 BLOCK_INPUT;
2414
2415 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
2416
2417 /* Draw a one-pixel border just inside the edges of the scroll bar. */
2418 XDrawRectangle (x_current_display, w, gc,
2419
2420 /* x, y, width, height */
2421 0, 0, XINT (bar->width) - 1, XINT (bar->height) - 1);
2422
2423 /* Draw another line to make the extra-thick border on the right. */
2424 XFillRectangle (x_current_display, w, gc,
2425
2426 /* x, y, width, height */
2427 XINT (bar->width) - 2, 1, 1, XINT (bar->height) - 2);
2428
2429 UNBLOCK_INPUT;
2430 }
2431
2432 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2433 is set to something other than no_event, it is enqueued.
2434
2435 This may be called from a signal handler, so we have to ignore GC
2436 mark bits. */
2437 static void
2438 x_scroll_bar_handle_click (bar, event, emacs_event)
2439 struct scroll_bar *bar;
2440 XEvent *event;
2441 struct input_event *emacs_event;
2442 {
2443 if (XGCTYPE (bar->window) != Lisp_Window)
2444 abort ();
2445
2446 emacs_event->kind = scroll_bar_click;
2447 emacs_event->code = event->xbutton.button - Button1;
2448 emacs_event->modifiers =
2449 (x_x_to_emacs_modifiers (event->xbutton.state)
2450 | (event->type == ButtonRelease
2451 ? up_modifier
2452 : down_modifier));
2453 emacs_event->frame_or_window = bar->window;
2454 emacs_event->timestamp = event->xbutton.time;
2455 {
2456 int internal_height =
2457 VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2458 int top_range =
2459 VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2460 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
2461
2462 if (y < 0) y = 0;
2463 if (y > top_range) y = top_range;
2464
2465 if (y < XINT (bar->start))
2466 emacs_event->part = scroll_bar_above_handle;
2467 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2468 emacs_event->part = scroll_bar_handle;
2469 else
2470 emacs_event->part = scroll_bar_below_handle;
2471
2472 /* Just because the user has clicked on the handle doesn't mean
2473 they want to drag it. Lisp code needs to be able to decide
2474 whether or not we're dragging. */
2475 #if 0
2476 /* If the user has just clicked on the handle, record where they're
2477 holding it. */
2478 if (event->type == ButtonPress
2479 && emacs_event->part == scroll_bar_handle)
2480 XSET (bar->dragging, Lisp_Int, y - XINT (bar->start));
2481 #endif
2482
2483 /* If the user has released the handle, set it to its final position. */
2484 if (event->type == ButtonRelease
2485 && ! NILP (bar->dragging))
2486 {
2487 int new_start = y - XINT (bar->dragging);
2488 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
2489
2490 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
2491 bar->dragging = Qnil;
2492 }
2493
2494 /* Same deal here as the other #if 0. */
2495 #if 0
2496 /* Clicks on the handle are always reported as occurring at the top of
2497 the handle. */
2498 if (emacs_event->part == scroll_bar_handle)
2499 emacs_event->x = bar->start;
2500 else
2501 XSET (emacs_event->x, Lisp_Int, y);
2502 #else
2503 XSET (emacs_event->x, Lisp_Int, y);
2504 #endif
2505
2506 XSET (emacs_event->y, Lisp_Int, top_range);
2507 }
2508 }
2509
2510 /* Handle some mouse motion while someone is dragging the scroll bar.
2511
2512 This may be called from a signal handler, so we have to ignore GC
2513 mark bits. */
2514 static void
2515 x_scroll_bar_note_movement (bar, event)
2516 struct scroll_bar *bar;
2517 XEvent *event;
2518 {
2519 last_mouse_movement_time = event->xmotion.time;
2520
2521 mouse_moved = 1;
2522 XSET (last_mouse_scroll_bar, Lisp_Vector, bar);
2523
2524 /* If we're dragging the bar, display it. */
2525 if (! GC_NILP (bar->dragging))
2526 {
2527 /* Where should the handle be now? */
2528 int new_start = event->xmotion.y - XINT (bar->dragging);
2529
2530 if (new_start != XINT (bar->start))
2531 {
2532 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
2533
2534 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
2535 }
2536 }
2537
2538 /* Call XQueryPointer so we'll get an event the next time the mouse
2539 moves and we can see *still* on the same position. */
2540 {
2541 int dummy;
2542
2543 XQueryPointer (event->xmotion.display, event->xmotion.window,
2544 (Window *) &dummy, (Window *) &dummy,
2545 &dummy, &dummy, &dummy, &dummy,
2546 (unsigned int *) &dummy);
2547 }
2548 }
2549
2550 /* Return information to the user about the current position of the mouse
2551 on the scroll bar. */
2552 static void
2553 x_scroll_bar_report_motion (f, bar_window, part, x, y, time)
2554 FRAME_PTR *f;
2555 Lisp_Object *bar_window;
2556 enum scroll_bar_part *part;
2557 Lisp_Object *x, *y;
2558 unsigned long *time;
2559 {
2560 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
2561 int win_x, win_y;
2562 Window dummy_window;
2563 int dummy_coord;
2564 unsigned int dummy_mask;
2565
2566 BLOCK_INPUT;
2567
2568 /* Get the mouse's position relative to the scroll bar window, and
2569 report that. */
2570 if (! XQueryPointer (x_current_display,
2571 SCROLL_BAR_X_WINDOW (bar),
2572
2573 /* Root, child, root x and root y. */
2574 &dummy_window, &dummy_window,
2575 &dummy_coord, &dummy_coord,
2576
2577 /* Position relative to scroll bar. */
2578 &win_x, &win_y,
2579
2580 /* Mouse buttons and modifier keys. */
2581 &dummy_mask))
2582 *f = 0;
2583 else
2584 {
2585 int inside_height
2586 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2587 int top_range
2588 = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2589
2590 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2591
2592 if (! NILP (bar->dragging))
2593 win_y -= XINT (bar->dragging);
2594
2595 if (win_y < 0)
2596 win_y = 0;
2597 if (win_y > top_range)
2598 win_y = top_range;
2599
2600 *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2601 *bar_window = bar->window;
2602
2603 if (! NILP (bar->dragging))
2604 *part = scroll_bar_handle;
2605 else if (win_y < XINT (bar->start))
2606 *part = scroll_bar_above_handle;
2607 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2608 *part = scroll_bar_handle;
2609 else
2610 *part = scroll_bar_below_handle;
2611
2612 XSET (*x, Lisp_Int, win_y);
2613 XSET (*y, Lisp_Int, top_range);
2614
2615 mouse_moved = 0;
2616 last_mouse_scroll_bar = Qnil;
2617 }
2618
2619 *time = last_mouse_movement_time;
2620
2621 UNBLOCK_INPUT;
2622 }
2623
2624
2625 /* The screen has been cleared so we may have changed foreground or
2626 background colors, and the scroll bars may need to be redrawn.
2627 Clear out the scroll bars, and ask for expose events, so we can
2628 redraw them. */
2629
2630 x_scroll_bar_clear (f)
2631 FRAME_PTR f;
2632 {
2633 Lisp_Object bar;
2634
2635 for (bar = FRAME_SCROLL_BARS (f);
2636 XTYPE (bar) == Lisp_Vector;
2637 bar = XSCROLL_BAR (bar)->next)
2638 XClearArea (x_current_display, SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
2639 0, 0, 0, 0, True);
2640 }
2641
2642 /* This processes Expose events from the menubar specific X event
2643 loop in menubar.c. This allows to redisplay the frame if necessary
2644 when handling menubar or popup items. */
2645
2646 void
2647 process_expose_from_menu (event)
2648 XEvent event;
2649 {
2650 FRAME_PTR f;
2651
2652 f = x_window_to_frame (event.xexpose.window);
2653 if (f)
2654 {
2655 if (f->async_visible == 0)
2656 {
2657 f->async_visible = 1;
2658 f->async_iconified = 0;
2659 SET_FRAME_GARBAGED (f);
2660 }
2661 else
2662 {
2663 dumprectangle (x_window_to_frame (event.xexpose.window),
2664 event.xexpose.x, event.xexpose.y,
2665 event.xexpose.width, event.xexpose.height);
2666 }
2667 }
2668 else
2669 {
2670 struct scroll_bar *bar
2671 = x_window_to_scroll_bar (event.xexpose.window);
2672
2673 if (bar)
2674 x_scroll_bar_expose (bar, &event);
2675 }
2676 }
2677
2678 \f
2679 /* The main X event-reading loop - XTread_socket. */
2680
2681 /* Timestamp of enter window event. This is only used by XTread_socket,
2682 but we have to put it out here, since static variables within functions
2683 sometimes don't work. */
2684 static Time enter_timestamp;
2685
2686 /* This holds the state XLookupString needs to implement dead keys
2687 and other tricks known as "compose processing". _X Window System_
2688 says that a portable program can't use this, but Stephen Gildea assures
2689 me that letting the compiler initialize it to zeros will work okay.
2690
2691 This must be defined outside of XTread_socket, for the same reasons
2692 given for enter_timestamp, above. */
2693 static XComposeStatus compose_status;
2694
2695 /* Communication with window managers. */
2696 Atom Xatom_wm_protocols;
2697
2698 /* Kinds of protocol things we may receive. */
2699 Atom Xatom_wm_take_focus;
2700 Atom Xatom_wm_save_yourself;
2701 Atom Xatom_wm_delete_window;
2702
2703 /* Other WM communication */
2704 Atom Xatom_wm_configure_denied; /* When our config request is denied */
2705 Atom Xatom_wm_window_moved; /* When the WM moves us. */
2706
2707 /* Window manager communication. */
2708 Atom Xatom_wm_change_state;
2709
2710 /* Record the last 100 characters stored
2711 to help debug the loss-of-chars-during-GC problem. */
2712 int temp_index;
2713 short temp_buffer[100];
2714
2715 /* Read events coming from the X server.
2716 This routine is called by the SIGIO handler.
2717 We return as soon as there are no more events to be read.
2718
2719 Events representing keys are stored in buffer BUFP,
2720 which can hold up to NUMCHARS characters.
2721 We return the number of characters stored into the buffer,
2722 thus pretending to be `read'.
2723
2724 WAITP is nonzero if we should block until input arrives.
2725 EXPECTED is nonzero if the caller knows input is available. */
2726
2727 int
2728 XTread_socket (sd, bufp, numchars, waitp, expected)
2729 register int sd;
2730 register struct input_event *bufp;
2731 register int numchars;
2732 int waitp;
2733 int expected;
2734 {
2735 int count = 0;
2736 int nbytes = 0;
2737 int mask;
2738 int items_pending; /* How many items are in the X queue. */
2739 XEvent event;
2740 struct frame *f;
2741 int event_found = 0;
2742 int prefix;
2743 Lisp_Object part;
2744
2745 if (interrupt_input_blocked)
2746 {
2747 interrupt_input_pending = 1;
2748 return -1;
2749 }
2750
2751 interrupt_input_pending = 0;
2752 BLOCK_INPUT;
2753
2754 if (numchars <= 0)
2755 abort (); /* Don't think this happens. */
2756
2757 #ifdef FIOSNBIO
2758 /* If available, Xlib uses FIOSNBIO to make the socket
2759 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
2760 FIOSNBIO is ignored, and instead of signalling EWOULDBLOCK,
2761 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
2762 fcntl (fileno (stdin), F_SETFL, 0);
2763 #endif /* ! defined (FIOSNBIO) */
2764
2765 #ifndef SIGIO
2766 #ifndef HAVE_SELECT
2767 if (! (fcntl (fileno (stdin), F_GETFL, 0) & O_NDELAY))
2768 {
2769 extern int read_alarm_should_throw;
2770 read_alarm_should_throw = 1;
2771 XPeekEvent (XDISPLAY &event);
2772 read_alarm_should_throw = 0;
2773 }
2774 #endif /* HAVE_SELECT */
2775 #endif /* SIGIO */
2776
2777 while (XStuffPending () != 0)
2778 {
2779 XNextEvent (XDISPLAY &event);
2780 event_found = 1;
2781
2782 switch (event.type)
2783 {
2784 #ifdef HAVE_X11
2785 case ClientMessage:
2786 {
2787 if (event.xclient.message_type == Xatom_wm_protocols
2788 && event.xclient.format == 32)
2789 {
2790 if (event.xclient.data.l[0] == Xatom_wm_take_focus)
2791 {
2792 #ifdef USE_X_TOOLKIT
2793 /* f = x_any_window_to_frame (event.xclient.window); */
2794 f = x_window_to_frame (event.xclient.window);
2795 #else
2796 f = x_window_to_frame (event.xclient.window);
2797 #endif
2798 if (f)
2799 x_focus_on_frame (f);
2800 /* Not certain about handling scroll bars here */
2801 }
2802 else if (event.xclient.data.l[0] == Xatom_wm_save_yourself)
2803 {
2804 /* Save state modify the WM_COMMAND property to
2805 something which can reinstate us. This notifies
2806 the session manager, who's looking for such a
2807 PropertyNotify. Can restart processing when
2808 a keyboard or mouse event arrives. */
2809 if (numchars > 0)
2810 {
2811 }
2812 }
2813 else if (event.xclient.data.l[0] == Xatom_wm_delete_window)
2814 {
2815 struct frame *f = x_window_to_frame (event.xclient.window);
2816
2817 if (f)
2818 {
2819 if (numchars == 0)
2820 abort ();
2821
2822 bufp->kind = delete_window_event;
2823 XSET (bufp->frame_or_window, Lisp_Frame, f);
2824 bufp++;
2825
2826 count += 1;
2827 numchars -= 1;
2828 }
2829 }
2830 }
2831 else if (event.xclient.message_type == Xatom_wm_configure_denied)
2832 {
2833 }
2834 else if (event.xclient.message_type == Xatom_wm_window_moved)
2835 {
2836 int new_x, new_y;
2837 struct frame *f = x_window_to_frame (event.xclient.window);
2838
2839 new_x = event.xclient.data.s[0];
2840 new_y = event.xclient.data.s[1];
2841
2842 if (f)
2843 {
2844 f->display.x->left_pos = new_x;
2845 f->display.x->top_pos = new_y;
2846 }
2847 }
2848 }
2849 break;
2850
2851 #ifdef NEW_SELECTIONS
2852 case SelectionNotify:
2853 #ifdef USE_X_TOOLKIT
2854 if (x_window_to_frame (event.xselection.requestor))
2855 x_handle_selection_notify (&event);
2856 else
2857 goto OTHER;
2858 #else /* not USE_X_TOOLKIT */
2859 x_handle_selection_notify (&event);
2860 #endif /* not USE_X_TOOLKIT */
2861 break;
2862 #endif /* NEW_SELECTIONS */
2863
2864 case SelectionClear: /* Someone has grabbed ownership. */
2865 #ifdef NEW_SELECTIONS
2866 {
2867 #ifdef USE_X_TOOLKIT
2868 if (x_window_to_frame (event.xselectionclear.window))
2869 {
2870 #endif /* USE_X_TOOLKIT */
2871 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
2872
2873 if (numchars == 0)
2874 abort ();
2875
2876 bufp->kind = selection_clear_event;
2877 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
2878 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
2879 SELECTION_EVENT_TIME (bufp) = eventp->time;
2880 bufp++;
2881
2882 count += 1;
2883 numchars -= 1;
2884 #ifdef USE_X_TOOLKIT
2885 }
2886 else
2887 goto OTHER;
2888 #endif /* USE_X_TOOLKIT */
2889 }
2890 #else /* not NEW_SELECTIONS */
2891 x_disown_selection (event.xselectionclear.window,
2892 event.xselectionclear.selection,
2893 event.xselectionclear.time);
2894 #endif /* not NEW_SELECTIONS */
2895 break;
2896
2897 case SelectionRequest: /* Someone wants our selection. */
2898 #ifdef NEW_SELECTIONS
2899 {
2900 #ifdef USE_X_TOOLKIT
2901 if (x_window_to_frame (event.xselectionrequest.owner))
2902 {
2903 #endif /* USE_X_TOOLKIT */
2904 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
2905
2906 if (numchars == 0)
2907 abort ();
2908
2909 bufp->kind = selection_request_event;
2910 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
2911 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
2912 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
2913 SELECTION_EVENT_TARGET (bufp) = eventp->target;
2914 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
2915 SELECTION_EVENT_TIME (bufp) = eventp->time;
2916 bufp++;
2917
2918 count += 1;
2919 numchars -= 1;
2920 #ifdef USE_X_TOOLKIT
2921 }
2922 else
2923 goto OTHER;
2924 #endif /* USE_X_TOOLKIT */
2925 }
2926 #else /* not NEW_SELECTIONS */
2927 x_answer_selection_request (event);
2928 #endif /* not NEW_SELECTIONS */
2929 break;
2930
2931 case PropertyNotify:
2932 #ifdef NEW_SELECTIONS
2933 #ifdef USE_X_TOOLKIT
2934 if (x_any_window_to_frame (event.xproperty.window))
2935 x_handle_property_notify (&event);
2936 else
2937 goto OTHER;
2938 #else /* not USE_X_TOOLKIT */
2939 x_handle_property_notify (&event);
2940 #endif /* not USE_X_TOOLKIT */
2941 #else /* not NEW_SELECTIONS */
2942 /* If we're being told about a root window property, then it's
2943 a cut buffer change. */
2944 if (event.xproperty.window == ROOT_WINDOW)
2945 x_invalidate_cut_buffer_cache (&event.xproperty);
2946
2947 /* Otherwise, we're probably handling an incremental
2948 selection transmission. */
2949 else
2950 {
2951 /* If we were to do this synchronously, there'd be no worry
2952 about re-selecting. */
2953 x_send_incremental (event);
2954 }
2955 #endif /* not NEW_SELECTIONS */
2956 break;
2957
2958 case ReparentNotify:
2959 f = x_window_to_frame (event.xreparent.window);
2960 if (f)
2961 f->display.x->parent_desc = event.xreparent.parent;
2962 break;
2963
2964 case Expose:
2965 f = x_window_to_frame (event.xexpose.window);
2966 if (f)
2967 {
2968 if (f->async_visible == 0)
2969 {
2970 f->async_visible = 1;
2971 f->async_iconified = 0;
2972 SET_FRAME_GARBAGED (f);
2973 }
2974 else
2975 {
2976 dumprectangle (x_window_to_frame (event.xexpose.window),
2977 event.xexpose.x, event.xexpose.y,
2978 event.xexpose.width, event.xexpose.height);
2979 }
2980 }
2981 else
2982 {
2983 struct scroll_bar *bar
2984 = x_window_to_scroll_bar (event.xexpose.window);
2985
2986 if (bar)
2987 x_scroll_bar_expose (bar, &event);
2988 #ifdef USE_X_TOOLKIT
2989 else
2990 goto OTHER;
2991 #endif /* USE_X_TOOLKIT */
2992 }
2993 break;
2994
2995 case GraphicsExpose: /* This occurs when an XCopyArea's
2996 source area was obscured or not
2997 available.*/
2998 f = x_window_to_frame (event.xgraphicsexpose.drawable);
2999 if (f)
3000 {
3001 dumprectangle (f,
3002 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
3003 event.xgraphicsexpose.width,
3004 event.xgraphicsexpose.height);
3005 }
3006 #ifdef USE_X_TOOLKIT
3007 else
3008 goto OTHER;
3009 #endif /* USE_X_TOOLKIT */
3010 break;
3011
3012 case NoExpose: /* This occurs when an XCopyArea's
3013 source area was completely
3014 available */
3015 break;
3016 #else /* ! defined (HAVE_X11) */
3017 case ExposeWindow:
3018 if (event.subwindow != 0)
3019 break; /* duplicate event */
3020 f = x_window_to_frame (event.window);
3021 if (event.window == f->display.x->icon_desc)
3022 {
3023 refreshicon (f);
3024 f->async_iconified = 1;
3025 }
3026 if (event.window == FRAME_X_WINDOW (f))
3027 {
3028 /* Say must check all windows' needs_exposure flags. */
3029 expose_all_windows = 1;
3030 f->display.x->needs_exposure = 1;
3031 f->async_visible = 1;
3032 }
3033 break;
3034
3035 case ExposeRegion:
3036 if (event.subwindow != 0)
3037 break; /* duplicate event */
3038 f = x_window_to_frame (event.window);
3039 if (event.window == f->display.x->icon_desc)
3040 {
3041 refreshicon (f);
3042 break;
3043 }
3044 /* If window already needs full redraw, ignore this rectangle. */
3045 if (expose_all_windows && f->display.x->needs_exposure)
3046 break;
3047 /* Put the event on the queue of rectangles to redraw. */
3048 if (enqueue_event (&event, &x_expose_queue))
3049 /* If it is full, we can't record the rectangle,
3050 so redraw this entire window. */
3051 {
3052 /* Say must check all windows' needs_exposure flags. */
3053 expose_all_windows = 1;
3054 f->display.x->needs_exposure = 1;
3055 }
3056 break;
3057
3058 case ExposeCopy:
3059 /* This should happen only when we are expecting it,
3060 in x_read_exposes. */
3061 abort ();
3062 #endif /* ! defined (HAVE_X11) */
3063
3064 #ifdef HAVE_X11
3065 case UnmapNotify:
3066 f = x_window_to_frame (event.xunmap.window);
3067 if (f) /* F may no longer exist if
3068 the frame was deleted. */
3069 {
3070 /* While a frame is unmapped, display generation is
3071 disabled; you don't want to spend time updating a
3072 display that won't ever be seen. */
3073 f->async_visible = 0;
3074 /* The window manager never makes a window invisible
3075 ("withdrawn"); all it does is switch between visible
3076 and iconified. Frames get into the invisible state
3077 only through x_make_frame_invisible. */
3078 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
3079 f->async_iconified = 1;
3080 }
3081 #ifdef USE_X_TOOLKIT
3082 goto OTHER;
3083 #endif /* USE_X_TOOLKIT */
3084 break;
3085
3086 case MapNotify:
3087 #ifdef USE_X_TOOLKIT
3088 f = x_any_window_to_frame (event.xmap.window);
3089 #else /* not USE_X_TOOLKIT */
3090 f = x_window_to_frame (event.xmap.window);
3091 #endif /* not USE_X_TOOLKIT */
3092 if (f)
3093 {
3094 f->async_visible = 1;
3095 f->async_iconified = 0;
3096
3097 /* wait_reading_process_input will notice this and update
3098 the frame's display structures. */
3099 SET_FRAME_GARBAGED (f);
3100 }
3101 #ifdef USE_X_TOOLKIT
3102 goto OTHER;
3103 #endif /* USE_X_TOOLKIT */
3104 break;
3105
3106 /* Turn off processing if we become fully obscured. */
3107 case VisibilityNotify:
3108 break;
3109
3110 #else /* ! defined (HAVE_X11) */
3111 case UnmapWindow:
3112 f = x_window_to_frame (event.window);
3113 if (event.window == f->display.x->icon_desc)
3114 f->async_iconified = 0;
3115 if (event.window == FRAME_X_WINDOW (f))
3116 f->async_visible = 0;
3117 break;
3118 #endif /* ! defined (HAVE_X11) */
3119
3120 #ifdef HAVE_X11
3121 case KeyPress:
3122 f = x_window_to_frame (event.xkey.window);
3123
3124 if (f != 0)
3125 {
3126 KeySym keysym, orig_keysym;
3127 /* al%imercury@uunet.uu.net says that making this 81 instead of
3128 80 fixed a bug whereby meta chars made his Emacs hang. */
3129 unsigned char copy_buffer[81];
3130 int modifiers;
3131
3132 event.xkey.state
3133 |= x_emacs_to_x_modifiers (extra_keyboard_modifiers);
3134 modifiers = event.xkey.state;
3135
3136 /* This will have to go some day... */
3137
3138 /* make_lispy_event turns chars into control chars.
3139 Don't do it here because XLookupString is too eager. */
3140 event.xkey.state &= ~ControlMask;
3141 nbytes =
3142 XLookupString (&event.xkey, copy_buffer, 80, &keysym,
3143 &compose_status);
3144
3145 /* Strip off the vendor-specific keysym bit, and take a shot
3146 at recognizing the codes. HP servers have extra keysyms
3147 that fit into the MiscFunctionKey category. */
3148 orig_keysym = keysym;
3149 keysym &= ~(1<<28);
3150
3151 if (numchars > 1)
3152 {
3153 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
3154 || keysym == XK_Delete
3155 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
3156 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
3157 #ifdef HPUX
3158 /* This recognizes the "extended function keys".
3159 It seems there's no cleaner way.
3160 Test IsModifierKey to avoid handling mode_switch
3161 incorrectly. */
3162 || ((unsigned) (keysym) >= XK_Select
3163 && (unsigned)(keysym) < XK_KP_Space)
3164 #endif
3165 #ifdef XK_dead_circumflex
3166 || orig_keysym == XK_dead_circumflex
3167 #endif
3168 #ifdef XK_dead_grave
3169 || orig_keysym == XK_dead_grave
3170 #endif
3171 #ifdef XK_dead_tilde
3172 || orig_keysym == XK_dead_tilde
3173 #endif
3174 #ifdef XK_dead_diaeresis
3175 || orig_keysym == XK_dead_diaeresis
3176 #endif
3177 #ifdef XK_dead_macron
3178 || orig_keysym == XK_dead_macron
3179 #endif
3180 #ifdef XK_dead_degree
3181 || orig_keysym == XK_dead_degree
3182 #endif
3183 #ifdef XK_dead_acute
3184 || orig_keysym == XK_dead_acute
3185 #endif
3186 #ifdef XK_dead_cedilla
3187 || orig_keysym == XK_dead_cedilla
3188 #endif
3189 #ifdef XK_dead_breve
3190 || orig_keysym == XK_dead_breve
3191 #endif
3192 #ifdef XK_dead_ogonek
3193 || orig_keysym == XK_dead_ogonek
3194 #endif
3195 #ifdef XK_dead_caron
3196 || orig_keysym == XK_dead_caron
3197 #endif
3198 #ifdef XK_dead_doubleacute
3199 || orig_keysym == XK_dead_doubleacute
3200 #endif
3201 #ifdef XK_dead_abovedot
3202 || orig_keysym == XK_dead_abovedot
3203 #endif
3204 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
3205 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
3206 || x_is_vendor_fkey (orig_keysym))
3207 && ! (IsModifierKey (orig_keysym)
3208 #ifndef HAVE_X11R5
3209 #ifdef XK_Mode_switch
3210 || ((unsigned)(orig_keysym) == XK_Mode_switch)
3211 #endif
3212 #ifdef XK_Num_Lock
3213 || ((unsigned)(orig_keysym) == XK_Num_Lock)
3214 #endif
3215 #endif /* not HAVE_X11R5 */
3216 ))
3217 {
3218 if (temp_index == sizeof temp_buffer / sizeof (short))
3219 temp_index = 0;
3220 temp_buffer[temp_index++] = keysym;
3221 bufp->kind = non_ascii_keystroke;
3222 bufp->code = keysym;
3223 XSET (bufp->frame_or_window, Lisp_Frame, f);
3224 bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
3225 bufp->timestamp = event.xkey.time;
3226 bufp++;
3227 count++;
3228 numchars--;
3229 }
3230 else if (numchars > nbytes)
3231 {
3232 register int i;
3233
3234 for (i = 0; i < nbytes; i++)
3235 {
3236 if (temp_index == sizeof temp_buffer / sizeof (short))
3237 temp_index = 0;
3238 temp_buffer[temp_index++] = copy_buffer[i];
3239 bufp->kind = ascii_keystroke;
3240 bufp->code = copy_buffer[i];
3241 XSET (bufp->frame_or_window, Lisp_Frame, f);
3242 bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
3243 bufp->timestamp = event.xkey.time;
3244 bufp++;
3245 }
3246
3247 count += nbytes;
3248 numchars -= nbytes;
3249 }
3250 else
3251 abort ();
3252 }
3253 else
3254 abort ();
3255 }
3256 break;
3257 #else /* ! defined (HAVE_X11) */
3258 case KeyPressed:
3259 {
3260 register char *where_mapping;
3261
3262 f = x_window_to_frame (event.window);
3263 /* Ignore keys typed on icon windows. */
3264 if (f != 0 && event.window == f->display.x->icon_desc)
3265 break;
3266 where_mapping = XLookupMapping (&event, &nbytes);
3267 /* Nasty fix for arrow keys */
3268 if (!nbytes && IsCursorKey (event.detail & 0xff))
3269 {
3270 switch (event.detail & 0xff)
3271 {
3272 case KC_CURSOR_LEFT:
3273 where_mapping = "\002";
3274 break;
3275 case KC_CURSOR_RIGHT:
3276 where_mapping = "\006";
3277 break;
3278 case KC_CURSOR_UP:
3279 where_mapping = "\020";
3280 break;
3281 case KC_CURSOR_DOWN:
3282 where_mapping = "\016";
3283 break;
3284 }
3285 nbytes = 1;
3286 }
3287 if (numchars - nbytes > 0)
3288 {
3289 register int i;
3290
3291 for (i = 0; i < nbytes; i++)
3292 {
3293 bufp->kind = ascii_keystroke;
3294 bufp->code = where_mapping[i];
3295 XSET (bufp->time, Lisp_Int, event.xkey.time);
3296 XSET (bufp->frame_or_window, Lisp_Frame, f);
3297 bufp++;
3298 }
3299 count += nbytes;
3300 numchars -= nbytes;
3301 }
3302 }
3303 break;
3304 #endif /* ! defined (HAVE_X11) */
3305
3306 #ifdef HAVE_X11
3307
3308 /* Here's a possible interpretation of the whole
3309 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If you get a
3310 FocusIn event, you have to get a FocusOut event before you
3311 relinquish the focus. If you haven't received a FocusIn event,
3312 then a mere LeaveNotify is enough to free you. */
3313
3314 case EnterNotify:
3315 f = x_window_to_frame (event.xcrossing.window);
3316
3317 if (event.xcrossing.focus) /* Entered Window */
3318 {
3319 /* Avoid nasty pop/raise loops. */
3320 if (f && (!(f->auto_raise)
3321 || !(f->auto_lower)
3322 || (event.xcrossing.time - enter_timestamp) > 500))
3323 {
3324 x_new_focus_frame (f);
3325 enter_timestamp = event.xcrossing.time;
3326 }
3327 }
3328 else if (f == x_focus_frame)
3329 x_new_focus_frame (0);
3330 #ifdef USE_X_TOOLKIT
3331 goto OTHER;
3332 #endif /* USE_X_TOOLKIT */
3333 break;
3334
3335 case FocusIn:
3336 f = x_window_to_frame (event.xfocus.window);
3337 if (event.xfocus.detail != NotifyPointer)
3338 x_focus_event_frame = f;
3339 if (f)
3340 x_new_focus_frame (f);
3341 #ifdef USE_X_TOOLKIT
3342 goto OTHER;
3343 #endif /* USE_X_TOOLKIT */
3344 break;
3345
3346
3347 case LeaveNotify:
3348 f = x_window_to_frame (event.xcrossing.window);
3349
3350 if (event.xcrossing.focus)
3351 {
3352 if (! x_focus_event_frame)
3353 x_new_focus_frame (0);
3354 else
3355 x_new_focus_frame (f);
3356 }
3357 else
3358 {
3359 if (f == x_focus_event_frame)
3360 x_focus_event_frame = 0;
3361 if (f == x_focus_frame)
3362 x_new_focus_frame (0);
3363 }
3364 #ifdef USE_X_TOOLKIT
3365 goto OTHER;
3366 #endif /* USE_X_TOOLKIT */
3367 break;
3368
3369 case FocusOut:
3370 f = x_window_to_frame (event.xfocus.window);
3371 if (event.xfocus.detail != NotifyPointer
3372 && f == x_focus_event_frame)
3373 x_focus_event_frame = 0;
3374 if (f && f == x_focus_frame)
3375 x_new_focus_frame (0);
3376 #ifdef USE_X_TOOLKIT
3377 goto OTHER;
3378 #endif /* USE_X_TOOLKIT */
3379 break;
3380
3381 #else /* ! defined (HAVE_X11) */
3382
3383 case EnterWindow:
3384 if ((event.detail & 0xFF) == 1)
3385 break; /* Coming from our own subwindow */
3386 if (event.subwindow != 0)
3387 break; /* Entering our own subwindow. */
3388
3389 {
3390 f = x_window_to_frame (event.window);
3391 x_mouse_frame = f;
3392
3393 x_new_focus_frame (f);
3394 }
3395 break;
3396
3397 case LeaveWindow:
3398 if ((event.detail & 0xFF) == 1)
3399 break; /* Entering our own subwindow */
3400 if (event.subwindow != 0)
3401 break; /* Leaving our own subwindow. */
3402
3403 x_mouse_frame = 0;
3404 if (x_focus_frame == 0
3405 && x_input_frame != 0
3406 && x_input_frame == x_window_to_frame (event.window)
3407 && event.window == FRAME_X_WINDOW (x_input_frame))
3408 {
3409 f = x_input_frame;
3410 x_input_frame = 0;
3411 if (f)
3412 frame_unhighlight (f);
3413 }
3414 break;
3415 #endif /* ! defined (HAVE_X11) */
3416
3417 #ifdef HAVE_X11
3418 case MotionNotify:
3419 {
3420 if (x_mouse_grabbed)
3421 f = last_mouse_frame;
3422 else
3423 f = x_window_to_frame (event.xmotion.window);
3424 if (f)
3425 note_mouse_movement (f, &event.xmotion);
3426 else
3427 {
3428 struct scroll_bar *bar
3429 = x_window_to_scroll_bar (event.xmotion.window);
3430
3431 if (bar)
3432 x_scroll_bar_note_movement (bar, &event);
3433 }
3434 }
3435 #ifdef USE_X_TOOLKIT
3436 goto OTHER;
3437 #endif /* USE_X_TOOLKIT */
3438 break;
3439
3440 case ConfigureNotify:
3441 #ifdef USE_X_TOOLKIT
3442 /* process done in widget.c */
3443 goto OTHER;
3444 #else /* not USE_X_TOOLKIT */
3445 f = x_window_to_frame (event.xconfigure.window);
3446 if (f)
3447 {
3448 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
3449 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
3450
3451 /* Even if the number of character rows and columns has
3452 not changed, the font size may have changed, so we need
3453 to check the pixel dimensions as well. */
3454 if (columns != f->width
3455 || rows != f->height
3456 || event.xconfigure.width != f->display.x->pixel_width
3457 || event.xconfigure.height != f->display.x->pixel_height)
3458 {
3459 change_frame_size (f, rows, columns, 0, 1);
3460 SET_FRAME_GARBAGED (f);
3461 }
3462
3463 if (! event.xconfigure.send_event)
3464 {
3465 Window win, child;
3466 int win_x, win_y;
3467
3468 /* Find the position of the outside upper-left corner of
3469 the window, in the root coordinate system. Don't
3470 refer to the parent window here; we may be processing
3471 this event after the window manager has changed our
3472 parent, but before we have reached the ReparentNotify. */
3473 XTranslateCoordinates (x_current_display,
3474
3475 /* From-window, to-window. */
3476 f->display.x->window_desc,
3477 ROOT_WINDOW,
3478
3479 /* From-position, to-position. */
3480 -event.xconfigure.border_width,
3481 -event.xconfigure.border_width,
3482 &win_x, &win_y,
3483
3484 /* Child of win. */
3485 &child);
3486 event.xconfigure.x = win_x;
3487 event.xconfigure.y = win_y;
3488 }
3489
3490 f->display.x->pixel_width = event.xconfigure.width;
3491 f->display.x->pixel_height = event.xconfigure.height;
3492 f->display.x->left_pos = event.xconfigure.x;
3493 f->display.x->top_pos = event.xconfigure.y;
3494 }
3495 #endif /* not USE_X_TOOLKIT */
3496 break;
3497
3498 case ButtonPress:
3499 case ButtonRelease:
3500 {
3501 /* If we decide we want to generate an event to be seen
3502 by the rest of Emacs, we put it here. */
3503 struct input_event emacs_event;
3504 emacs_event.kind = no_event;
3505
3506 f = x_window_to_frame (event.xbutton.window);
3507 if (f)
3508 {
3509 if (!x_focus_frame || (f == x_focus_frame))
3510 construct_mouse_click (&emacs_event, &event, f);
3511 }
3512 else
3513 {
3514 struct scroll_bar *bar =
3515 x_window_to_scroll_bar (event.xbutton.window);
3516
3517 if (bar)
3518 x_scroll_bar_handle_click (bar, &event, &emacs_event);
3519 #ifdef USE_X_TOOLKIT
3520 else
3521 {
3522 f = x_any_window_to_frame (event.xbutton.window);
3523 if (f && event.type == ButtonPress)
3524 construct_menu_click (&emacs_event,
3525 &event, f);
3526 }
3527 #endif /* USE_X_TOOLKIT */
3528 }
3529
3530 if (numchars >= 1 && emacs_event.kind != no_event)
3531 {
3532 bcopy (&emacs_event, bufp, sizeof (struct input_event));
3533 bufp++;
3534 count++;
3535 numchars--;
3536 }
3537
3538 #ifdef USE_X_TOOLKIT
3539 goto OTHER;
3540 #endif /* USE_X_TOOLKIT */
3541 }
3542 break;
3543
3544 #else /* ! defined (HAVE_X11) */
3545 case ButtonPressed:
3546 case ButtonReleased:
3547 f = x_window_to_frame (event.window);
3548 if (f)
3549 {
3550 if (event.window == f->display.x->icon_desc)
3551 {
3552 x_make_frame_visible (f);
3553
3554 if (warp_mouse_on_deiconify)
3555 XWarpMouse (FRAME_X_WINDOW (f), 10, 10);
3556 break;
3557 }
3558 if (event.window == FRAME_X_WINDOW (f))
3559 {
3560 if (f->auto_raise)
3561 x_raise_frame (f);
3562 }
3563 }
3564 enqueue_event (&event, &x_mouse_queue);
3565 if (numchars >= 2)
3566 {
3567 bufp->kind = ascii_keystroke;
3568 bufp->code = 'X' & 037; /* C-x */
3569 XSET (bufp->frame_or_window, Lisp_Frame, f);
3570 XSET (bufp->time, Lisp_Int, event.xkey.time);
3571 bufp++;
3572
3573 bufp->kind = ascii_keystroke;
3574 bufp->code = 0; /* C-@ */
3575 XSET (bufp->frame_or_window, Lisp_Frame, f);
3576 XSET (bufp->time, Lisp_Int, event.xkey.time);
3577 bufp++;
3578
3579 count += 2;
3580 numchars -= 2;
3581 }
3582 break;
3583 #endif /* ! defined (HAVE_X11) */
3584
3585 #ifdef HAVE_X11
3586
3587 case CirculateNotify:
3588 break;
3589 case CirculateRequest:
3590 break;
3591
3592 #endif /* ! defined (HAVE_X11) */
3593
3594 case MappingNotify:
3595 /* Someone has changed the keyboard mapping - update the
3596 local cache. */
3597 switch (event.xmapping.request)
3598 {
3599 case MappingModifier:
3600 x_find_modifier_meanings ();
3601 /* This is meant to fall through. */
3602 case MappingKeyboard:
3603 XRefreshKeyboardMapping (&event.xmapping);
3604 }
3605 #ifdef USE_X_TOOLKIT
3606 goto OTHER;
3607 #endif /* USE_X_TOOLKIT */
3608 break;
3609
3610 default:
3611 #ifdef USE_X_TOOLKIT
3612 OTHER:
3613 BLOCK_INPUT;
3614 XtDispatchEvent (&event);
3615 UNBLOCK_INPUT;
3616 #endif /* USE_X_TOOLKIT */
3617 break;
3618 }
3619 }
3620
3621 #ifdef X_IO_BUG
3622 if (! event_found)
3623 /* On some systems, an X bug causes Emacs to get no more events
3624 when the window is destroyed. Detect that. */
3625 XNoOp (x_current_display);
3626 #endif /* X_IO_BUG */
3627
3628 #ifdef HAVE_SELECT
3629 if (expected && ! event_found)
3630 {
3631 /* AOJ 880406: if select returns true but XPending doesn't, it means that
3632 there is an EOF condition; in other words, that X has died.
3633 Act as if there had been a hangup. */
3634 int fd = ConnectionNumber (x_current_display);
3635 SELECT_TYPE mask, junk1, junk2;
3636 EMACS_TIME timeout;
3637
3638 FD_ZERO (&mask);
3639 FD_SET (fd, &mask);
3640 EMACS_SET_SECS_USECS (timeout, 0, 0);
3641 FD_ZERO (&junk1);
3642 FD_ZERO (&junk2);
3643 if (0 != select (fd + 1, &mask, &junk1, &junk2, &timeout)
3644 && !XStuffPending ())
3645 kill (getpid (), SIGHUP);
3646 }
3647 #endif /* HAVE_SELECT */
3648
3649 #ifndef HAVE_X11
3650 if (updating_frame == 0)
3651 x_do_pending_expose ();
3652 #endif
3653
3654 UNBLOCK_INPUT;
3655 return count;
3656 }
3657
3658 #ifndef HAVE_X11
3659 /* Read and process only Expose events
3660 until we get an ExposeCopy event; then return.
3661 This is used in insert/delete line.
3662 We assume input is already blocked. */
3663
3664 static void
3665 x_read_exposes ()
3666 {
3667 struct frame *f;
3668 XKeyPressedEvent event;
3669
3670 while (1)
3671 {
3672 /* while there are more events*/
3673 XMaskEvent (ExposeWindow | ExposeRegion | ExposeCopy, &event);
3674 switch (event.type)
3675 {
3676 case ExposeWindow:
3677 if (event.subwindow != 0)
3678 break; /* duplicate event */
3679 f = x_window_to_frame (event.window);
3680 if (event.window == f->display.x->icon_desc)
3681 {
3682 refreshicon (f);
3683 break;
3684 }
3685 if (event.window == FRAME_X_WINDOW (f))
3686 {
3687 expose_all_windows = 1;
3688 f->display.x->needs_exposure = 1;
3689 break;
3690 }
3691 break;
3692
3693 case ExposeRegion:
3694 if (event.subwindow != 0)
3695 break; /* duplicate event */
3696 f = x_window_to_frame (event.window);
3697 if (event.window == f->display.x->icon_desc)
3698 {
3699 refreshicon (f);
3700 break;
3701 }
3702 /* If window already needs full redraw, ignore this rectangle. */
3703 if (expose_all_windows && f->display.x->needs_exposure)
3704 break;
3705 /* Put the event on the queue of rectangles to redraw. */
3706 if (enqueue_event (&event, &x_expose_queue))
3707 /* If it is full, we can't record the rectangle,
3708 so redraw this entire window. */
3709 {
3710 /* Say must check all windows' needs_exposure flags. */
3711 expose_all_windows = 1;
3712 f->display.x->needs_exposure = 1;
3713 }
3714 break;
3715
3716 case ExposeCopy:
3717 return;
3718 }
3719 }
3720 }
3721 #endif /* HAVE_X11 */
3722
3723 \f
3724 /* Drawing the cursor. */
3725
3726
3727 /* Draw a hollow box cursor. Don't change the inside of the box. */
3728
3729 static void
3730 x_draw_box (f)
3731 struct frame *f;
3732 {
3733 int left = CHAR_TO_PIXEL_COL (f, f->cursor_x);
3734 int top = CHAR_TO_PIXEL_ROW (f, f->cursor_y);
3735 int width = FONT_WIDTH (f->display.x->font);
3736 int height = FONT_HEIGHT (f->display.x->font);
3737
3738 #ifdef HAVE_X11
3739 XDrawRectangle (x_current_display, FRAME_X_WINDOW (f),
3740 f->display.x->cursor_gc,
3741 left, top, width - 1, height - 1);
3742 #else /* ! defined (HAVE_X11) */
3743 XPixSet (FRAME_X_WINDOW (f),
3744 left, top, width, 1,
3745 f->display.x->cursor_pixel);
3746
3747 XPixSet (FRAME_X_WINDOW (f),
3748 left, top, 1, height,
3749 f->display.x->cursor_pixel);
3750
3751 XPixSet (FRAME_X_WINDOW (f),
3752 left+width-1, top, 1, height,
3753 f->display.x->cursor_pixel);
3754
3755 XPixSet (FRAME_X_WINDOW (f),
3756 left, top+height-1, width, 1,
3757 f->display.x->cursor_pixel);
3758 #endif /* ! defined (HAVE_X11) */
3759 }
3760
3761 /* Clear the cursor of frame F to background color,
3762 and mark the cursor as not shown.
3763 This is used when the text where the cursor is
3764 is about to be rewritten. */
3765
3766 static void
3767 clear_cursor (f)
3768 struct frame *f;
3769 {
3770 int mask;
3771
3772 if (! FRAME_VISIBLE_P (f)
3773 || f->phys_cursor_x < 0)
3774 return;
3775
3776 #ifdef HAVE_X11
3777 x_display_cursor (f, 0);
3778 #else /* ! defined (HAVE_X11) */
3779 XPixSet (FRAME_X_WINDOW (f),
3780 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
3781 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
3782 FONT_WIDTH (f->display.x->font), FONT_HEIGHT (f->display.x->font),
3783 f->display.x->background_pixel);
3784 #endif /* ! defined (HAVE_X11) */
3785 f->phys_cursor_x = -1;
3786 }
3787
3788 /* Redraw the glyph at ROW, COLUMN on frame F, in the style
3789 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
3790 glyph drawn. */
3791
3792 static void
3793 x_draw_single_glyph (f, row, column, glyph, highlight)
3794 struct frame *f;
3795 int row, column;
3796 GLYPH glyph;
3797 int highlight;
3798 {
3799 dumpglyphs (f,
3800 CHAR_TO_PIXEL_COL (f, column),
3801 CHAR_TO_PIXEL_ROW (f, row),
3802 &glyph, 1, highlight);
3803 }
3804
3805 static void
3806 x_display_bar_cursor (f, on)
3807 struct frame *f;
3808 int on;
3809 {
3810 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
3811
3812 /* This is pointless on invisible frames, and dangerous on garbaged
3813 frames; in the latter case, the frame may be in the midst of
3814 changing its size, and curs_x and curs_y may be off the frame. */
3815 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
3816 return;
3817
3818 if (! on && f->phys_cursor_x < 0)
3819 return;
3820
3821 /* If we're not updating, then we want to use the current frame's
3822 cursor position, not our local idea of where the cursor ought to be. */
3823 if (f != updating_frame)
3824 {
3825 curs_x = FRAME_CURSOR_X (f);
3826 curs_y = FRAME_CURSOR_Y (f);
3827 }
3828
3829 /* If there is anything wrong with the current cursor state, remove it. */
3830 if (f->phys_cursor_x >= 0
3831 && (!on
3832 || f->phys_cursor_x != curs_x
3833 || f->phys_cursor_y != curs_y
3834 || f->display.x->current_cursor != bar_cursor))
3835 {
3836 /* Erase the cursor by redrawing the character underneath it. */
3837 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
3838 f->phys_cursor_glyph,
3839 current_glyphs->highlight[f->phys_cursor_y]);
3840 f->phys_cursor_x = -1;
3841 }
3842
3843 /* If we now need a cursor in the new place or in the new form, do it so. */
3844 if (on
3845 && (f->phys_cursor_x < 0
3846 || (f->display.x->current_cursor != bar_cursor)))
3847 {
3848 f->phys_cursor_glyph
3849 = ((current_glyphs->enable[curs_y]
3850 && curs_x < current_glyphs->used[curs_y])
3851 ? current_glyphs->glyphs[curs_y][curs_x]
3852 : SPACEGLYPH);
3853 XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
3854 f->display.x->cursor_gc,
3855 CHAR_TO_PIXEL_COL (f, curs_x),
3856 CHAR_TO_PIXEL_ROW (f, curs_y),
3857 1, FONT_HEIGHT (f->display.x->font));
3858
3859 f->phys_cursor_x = curs_x;
3860 f->phys_cursor_y = curs_y;
3861
3862 f->display.x->current_cursor = bar_cursor;
3863 }
3864
3865 if (updating_frame != f)
3866 XFlushQueue ();
3867 }
3868
3869
3870 /* Turn the displayed cursor of frame F on or off according to ON.
3871 If ON is nonzero, where to put the cursor is specified
3872 by F->cursor_x and F->cursor_y. */
3873
3874 static void
3875 x_display_box_cursor (f, on)
3876 struct frame *f;
3877 int on;
3878 {
3879 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
3880
3881 /* This is pointless on invisible frames, and dangerous on garbaged
3882 frames; in the latter case, the frame may be in the midst of
3883 changing its size, and curs_x and curs_y may be off the frame. */
3884 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
3885 return;
3886
3887 /* If cursor is off and we want it off, return quickly. */
3888 if (!on && f->phys_cursor_x < 0)
3889 return;
3890
3891 /* If we're not updating, then we want to use the current frame's
3892 cursor position, not our local idea of where the cursor ought to be. */
3893 if (f != updating_frame)
3894 {
3895 curs_x = FRAME_CURSOR_X (f);
3896 curs_y = FRAME_CURSOR_Y (f);
3897 }
3898
3899 /* If cursor is currently being shown and we don't want it to be
3900 or it is in the wrong place,
3901 or we want a hollow box and it's not so, (pout!)
3902 erase it. */
3903 if (f->phys_cursor_x >= 0
3904 && (!on
3905 || f->phys_cursor_x != curs_x
3906 || f->phys_cursor_y != curs_y
3907 || (f->display.x->current_cursor != hollow_box_cursor
3908 && (f != x_highlight_frame))))
3909 {
3910 /* Erase the cursor by redrawing the character underneath it. */
3911 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
3912 f->phys_cursor_glyph,
3913 current_glyphs->highlight[f->phys_cursor_y]);
3914 f->phys_cursor_x = -1;
3915 }
3916
3917 /* If we want to show a cursor,
3918 or we want a box cursor and it's not so,
3919 write it in the right place. */
3920 if (on
3921 && (f->phys_cursor_x < 0
3922 || (f->display.x->current_cursor != filled_box_cursor
3923 && f == x_highlight_frame)))
3924 {
3925 f->phys_cursor_glyph
3926 = ((current_glyphs->enable[curs_y]
3927 && curs_x < current_glyphs->used[curs_y])
3928 ? current_glyphs->glyphs[curs_y][curs_x]
3929 : SPACEGLYPH);
3930 if (f != x_highlight_frame)
3931 {
3932 x_draw_box (f);
3933 f->display.x->current_cursor = hollow_box_cursor;
3934 }
3935 else
3936 {
3937 x_draw_single_glyph (f, curs_y, curs_x,
3938 f->phys_cursor_glyph, 2);
3939 f->display.x->current_cursor = filled_box_cursor;
3940 }
3941
3942 f->phys_cursor_x = curs_x;
3943 f->phys_cursor_y = curs_y;
3944 }
3945
3946 if (updating_frame != f)
3947 XFlushQueue ();
3948 }
3949
3950 x_display_cursor (f, on)
3951 struct frame *f;
3952 int on;
3953 {
3954 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
3955 x_display_box_cursor (f, on);
3956 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
3957 x_display_bar_cursor (f, on);
3958 else
3959 /* Those are the only two we have implemented! */
3960 abort ();
3961 }
3962 \f
3963 /* Icons. */
3964
3965 /* Refresh bitmap kitchen sink icon for frame F
3966 when we get an expose event for it. */
3967
3968 refreshicon (f)
3969 struct frame *f;
3970 {
3971 #ifdef HAVE_X11
3972 /* Normally, the window manager handles this function. */
3973 #else /* ! defined (HAVE_X11) */
3974 int mask;
3975
3976 if (f->display.x->icon_bitmap_flag)
3977 XBitmapBitsPut (f->display.x->icon_desc, 0, 0, sink_width, sink_height,
3978 sink_bits, BlackPixel, WHITE_PIX_DEFAULT,
3979 icon_bitmap, GXcopy, AllPlanes);
3980 else
3981 {
3982 extern struct frame *selected_frame;
3983 struct Lisp_String *str;
3984 unsigned char *string;
3985
3986 string
3987 = XSTRING (XBUFFER (XWINDOW (f->selected_window)->buffer)->name)->data;
3988
3989 if (f->display.x->icon_label != string)
3990 {
3991 f->display.x->icon_label = string;
3992 XChangeWindow (f->display.x->icon_desc,
3993 XQueryWidth (string, icon_font_info->id) + 10,
3994 icon_font_info->height + 10);
3995 }
3996
3997 XText (f->display.x->icon_desc, 5, 5, string,
3998 str->size, icon_font_info->id,
3999 BLACK_PIX_DEFAULT, WHITE_PIX_DEFAULT);
4000 }
4001 XFlushQueue ();
4002 #endif /* ! defined (HAVE_X11) */
4003 }
4004
4005 /* Make the x-window of frame F use the gnu icon bitmap. */
4006
4007 int
4008 x_bitmap_icon (f)
4009 struct frame *f;
4010 {
4011 int mask;
4012 Window icon_window;
4013
4014 if (FRAME_X_WINDOW (f) == 0)
4015 return 1;
4016
4017 #ifdef HAVE_X11
4018 if (! icon_bitmap)
4019 icon_bitmap =
4020 XCreateBitmapFromData (x_current_display, FRAME_X_WINDOW (f),
4021 gnu_bits, gnu_width, gnu_height);
4022 x_wm_set_icon_pixmap (f, icon_bitmap);
4023 f->display.x->icon_bitmap_flag = 1;
4024 #else /* ! defined (HAVE_X11) */
4025 if (f->display.x->icon_desc)
4026 {
4027 XClearIconWindow (FRAME_X_WINDOW (f));
4028 XDestroyWindow (f->display.x->icon_desc);
4029 }
4030
4031 icon_window = XCreateWindow (f->display.x->parent_desc,
4032 0, 0, sink_width, sink_height,
4033 2, WhitePixmap, (Pixmap) NULL);
4034
4035 if (icon_window == 0)
4036 return 1;
4037
4038 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
4039 XSelectInput (icon_window, ExposeWindow | UnmapWindow);
4040
4041 f->display.x->icon_desc = icon_window;
4042 f->display.x->icon_bitmap_flag = 1;
4043
4044 if (icon_bitmap == 0)
4045 icon_bitmap
4046 = XStoreBitmap (sink_mask_width, sink_mask_height, sink_mask_bits);
4047 #endif /* ! defined (HAVE_X11) */
4048
4049 return 0;
4050 }
4051
4052
4053 /* Make the x-window of frame F use a rectangle with text. */
4054
4055 int
4056 x_text_icon (f, icon_name)
4057 struct frame *f;
4058 char *icon_name;
4059 {
4060 #ifndef HAVE_X11
4061 int mask;
4062 int width;
4063 Window icon_window;
4064 char *X_DefaultValue;
4065 Bitmap b1;
4066
4067 #ifndef WhitePixel
4068 #define WhitePixel 1
4069 #endif /* WhitePixel */
4070
4071 #ifndef BlackPixel
4072 #define BlackPixel 0
4073 #endif /* BlackPixel */
4074 #endif /* HAVE_X11 */
4075
4076 if (FRAME_X_WINDOW (f) == 0)
4077 return 1;
4078
4079 #ifdef HAVE_X11
4080 if (icon_name)
4081 f->display.x->icon_label = icon_name;
4082 else
4083 if (! f->display.x->icon_label)
4084 f->display.x->icon_label = " *emacs* ";
4085
4086 #if 0
4087 XSetIconName (x_current_display, FRAME_X_WINDOW (f),
4088 (char *) f->display.x->icon_label);
4089 #endif
4090
4091 f->display.x->icon_bitmap_flag = 0;
4092 x_wm_set_icon_pixmap (f, 0);
4093 #else /* ! defined (HAVE_X11) */
4094 if (icon_font_info == 0)
4095 icon_font_info
4096 = XGetFont (XGetDefault (XDISPLAY
4097 (char *) XSTRING (Vinvocation_name)->data,
4098 "BodyFont"));
4099
4100 if (f->display.x->icon_desc)
4101 {
4102 XClearIconWindow (XDISPLAY FRAME_X_WINDOW (f));
4103 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
4104 }
4105
4106 if (icon_name)
4107 f->display.x->icon_label = (unsigned char *) icon_name;
4108 else
4109 if (! f->display.x->icon_label)
4110 f->display.x->icon_label = XSTRING (f->name)->data;
4111
4112 width = XStringWidth (f->display.x->icon_label, icon_font_info, 0, 0);
4113 icon_window = XCreateWindow (f->display.x->parent_desc,
4114 f->display.x->left_pos,
4115 f->display.x->top_pos,
4116 width + 10, icon_font_info->height + 10,
4117 2, BlackPixmap, WhitePixmap);
4118
4119 if (icon_window == 0)
4120 return 1;
4121
4122 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
4123 XSelectInput (icon_window, ExposeWindow | ExposeRegion | UnmapWindow | ButtonPressed);
4124
4125 f->display.x->icon_desc = icon_window;
4126 f->display.x->icon_bitmap_flag = 0;
4127 f->display.x->icon_label = 0;
4128 #endif /* ! defined (HAVE_X11) */
4129
4130 return 0;
4131 }
4132 \f
4133 /* Handling X errors. */
4134
4135 /* Shut down Emacs in an orderly fashion, because of a SIGPIPE on the
4136 X server's connection, or an error reported via the X protocol. */
4137
4138 static SIGTYPE
4139 x_connection_closed ()
4140 {
4141 if (_Xdebug)
4142 abort ();
4143
4144 shut_down_emacs (0, 1, Qnil);
4145
4146 exit (70);
4147 }
4148
4149 /* An X error handler which prints an error message and then kills
4150 Emacs. This is what's normally installed as Xlib's handler for
4151 protocol errors. */
4152 static int
4153 x_error_quitter (display, error)
4154 Display *display;
4155 XErrorEvent *error;
4156 {
4157 char buf[256];
4158
4159 /* Note that there is no real way portable across R3/R4 to get the
4160 original error handler. */
4161
4162 XGetErrorText (display, error->error_code, buf, sizeof (buf));
4163 fprintf (stderr, "X protocol error: %s on protocol request %d\n",
4164 buf, error->request_code);
4165
4166 #if 0
4167 /* While we're testing Emacs 19, we'll just dump core whenever we
4168 get an X error, so we can figure out why it happened. */
4169 abort ();
4170 #endif
4171
4172 x_connection_closed ();
4173 }
4174
4175 /* A handler for X IO errors which prints an error message and then
4176 kills Emacs. This is what is always installed as Xlib's handler
4177 for I/O errors. */
4178 static int
4179 x_io_error_quitter (display)
4180 Display *display;
4181 {
4182 fprintf (stderr, "Connection to X server %s lost.\n",
4183 XDisplayName (DisplayString (display)));
4184
4185 #if 0
4186 /* While we're testing Emacs 19, we'll just dump core whenever we
4187 get an X error, so we can figure out why it happened. */
4188 abort ();
4189 #endif
4190
4191 x_connection_closed ();
4192 }
4193
4194 /* A buffer for storing X error messages. */
4195 static char *x_caught_error_message;
4196 #define X_CAUGHT_ERROR_MESSAGE_SIZE 200
4197
4198 /* An X error handler which stores the error message in
4199 x_caught_error_message. This is what's installed when
4200 x_catch_errors is in effect. */
4201 static int
4202 x_error_catcher (display, error)
4203 Display *display;
4204 XErrorEvent *error;
4205 {
4206 XGetErrorText (display, error->error_code,
4207 x_caught_error_message, X_CAUGHT_ERROR_MESSAGE_SIZE);
4208 }
4209
4210
4211 /* Begin trapping X errors.
4212
4213 After calling this function, X protocol errors no longer cause
4214 Emacs to exit; instead, they are recorded in x_cfc_error_message.
4215
4216 Calling x_check_errors signals an Emacs error if an X error has
4217 occurred since the last call to x_catch_errors or x_check_errors.
4218
4219 Calling x_uncatch_errors resumes the normal error handling. */
4220
4221 void x_catch_errors(), x_check_errors (), x_uncatch_errors ();
4222
4223 void
4224 x_catch_errors ()
4225 {
4226 /* Make sure any errors from previous requests have been dealt with. */
4227 XSync (x_current_display, False);
4228
4229 /* Set up the error buffer. */
4230 x_caught_error_message
4231 = (char*) xmalloc (X_CAUGHT_ERROR_MESSAGE_SIZE);
4232 x_caught_error_message[0] = '\0';
4233
4234 /* Install our little error handler. */
4235 XHandleError (x_error_catcher);
4236 }
4237
4238 /* If any X protocol errors have arrived since the last call to
4239 x_catch_errors or x_check_errors, signal an Emacs error using
4240 sprintf (a buffer, FORMAT, the x error message text) as the text. */
4241 void
4242 x_check_errors (format)
4243 char *format;
4244 {
4245 /* Make sure to catch any errors incurred so far. */
4246 XSync (x_current_display, False);
4247
4248 if (x_caught_error_message[0])
4249 {
4250 char buf[X_CAUGHT_ERROR_MESSAGE_SIZE + 56];
4251
4252 sprintf (buf, format, x_caught_error_message);
4253 x_uncatch_errors ();
4254 error (buf);
4255 }
4256 }
4257
4258 void
4259 x_uncatch_errors ()
4260 {
4261 xfree (x_caught_error_message);
4262 x_caught_error_message = 0;
4263 XHandleError (x_error_quitter);
4264 }
4265
4266 #if 0
4267 static unsigned int x_wire_count;
4268 x_trace_wire ()
4269 {
4270 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
4271 }
4272 #endif /* ! 0 */
4273
4274 \f
4275 /* Changing the font of the frame. */
4276
4277 /* Set the font of the x-window specified by frame F
4278 to the font named NEWNAME. This is safe to use
4279 even before F has an actual x-window. */
4280
4281 #ifdef HAVE_X11
4282
4283 struct font_info
4284 {
4285 XFontStruct *font;
4286 char *name;
4287 };
4288
4289 /* A table of all the fonts we have already loaded. */
4290 static struct font_info *x_font_table;
4291
4292 /* The current capacity of x_font_table. */
4293 static int x_font_table_size;
4294
4295 /* The number of fonts actually stored in x_font_table.
4296 x_font_table[n] is used and valid iff 0 <= n < n_fonts.
4297 0 <= n_fonts <= x_font_table_size. */
4298 static int n_fonts;
4299
4300 Lisp_Object
4301 x_new_font (f, fontname)
4302 struct frame *f;
4303 register char *fontname;
4304 {
4305 int already_loaded;
4306 int n_matching_fonts;
4307 XFontStruct *font_info;
4308 char **font_names;
4309
4310 /* Get a list of all the fonts that match this name. Once we
4311 have a list of matching fonts, we compare them against the fonts
4312 we already have by comparing font ids. */
4313 font_names = (char **) XListFonts (x_current_display, fontname,
4314 1024, &n_matching_fonts);
4315 /* Apparently it doesn't set n_matching_fonts to zero when it can't
4316 find any matches; font_names == 0 is the only clue. */
4317 if (! font_names)
4318 n_matching_fonts = 0;
4319
4320 /* Don't just give up if n_matching_fonts is 0.
4321 Apparently there's a bug on Suns: XListFontsWithInfo can
4322 fail to find a font, but XLoadQueryFont may still find it. */
4323
4324 /* See if we've already loaded a matching font. */
4325 already_loaded = -1;
4326 if (n_matching_fonts != 0)
4327 {
4328 int i, j;
4329
4330 for (i = 0; i < n_fonts; i++)
4331 for (j = 0; j < n_matching_fonts; j++)
4332 if (!strcmp (x_font_table[i].name, font_names[j]))
4333 {
4334 already_loaded = i;
4335 fontname = font_names[j];
4336 goto found_font;
4337 }
4338 }
4339 found_font:
4340
4341 /* If we have, just return it from the table. */
4342 if (already_loaded >= 0)
4343 f->display.x->font = x_font_table[already_loaded].font;
4344
4345 /* Otherwise, load the font and add it to the table. */
4346 else
4347 {
4348 int i;
4349 XFontStruct *font;
4350
4351 /* Try to find a character-cell font in the list. */
4352 #if 0
4353 /* A laudable goal, but this isn't how to do it. */
4354 for (i = 0; i < n_matching_fonts; i++)
4355 if (! font_info[i].per_char)
4356 break;
4357 #else
4358 i = 0;
4359 #endif
4360
4361 /* See comment above. */
4362 if (n_matching_fonts != 0)
4363 fontname = font_names[i];
4364
4365 font = (XFontStruct *) XLoadQueryFont (x_current_display, fontname);
4366 if (! font)
4367 {
4368 /* Free the information from XListFonts. */
4369 if (n_matching_fonts)
4370 XFreeFontNames (font_names);
4371 return Qnil;
4372 }
4373
4374 /* Do we need to create the table? */
4375 if (x_font_table_size == 0)
4376 {
4377 x_font_table_size = 16;
4378 x_font_table
4379 = (struct font_info *) xmalloc (x_font_table_size
4380 * sizeof (x_font_table[0]));
4381 }
4382 /* Do we need to grow the table? */
4383 else if (n_fonts >= x_font_table_size)
4384 {
4385 x_font_table_size *= 2;
4386 x_font_table
4387 = (struct font_info *) xrealloc (x_font_table,
4388 (x_font_table_size
4389 * sizeof (x_font_table[0])));
4390 }
4391
4392 x_font_table[n_fonts].name = (char *) xmalloc (strlen (fontname) + 1);
4393 bcopy (fontname, x_font_table[n_fonts].name, strlen (fontname) + 1);
4394 f->display.x->font = x_font_table[n_fonts++].font = font;
4395 }
4396
4397 /* Now make the frame display the given font. */
4398 if (FRAME_X_WINDOW (f) != 0)
4399 {
4400 XSetFont (x_current_display, f->display.x->normal_gc,
4401 f->display.x->font->fid);
4402 XSetFont (x_current_display, f->display.x->reverse_gc,
4403 f->display.x->font->fid);
4404 XSetFont (x_current_display, f->display.x->cursor_gc,
4405 f->display.x->font->fid);
4406
4407 x_set_window_size (f, f->width, f->height);
4408 }
4409
4410 {
4411 Lisp_Object lispy_name = build_string (fontname);
4412
4413
4414 /* Free the information from XListFonts. The data
4415 we actually retain comes from XLoadQueryFont. */
4416 XFreeFontNames (font_names);
4417
4418 return lispy_name;
4419 }
4420 }
4421 #else /* ! defined (HAVE_X11) */
4422 x_new_font (f, newname)
4423 struct frame *f;
4424 register char *newname;
4425 {
4426 FONT_TYPE *temp;
4427 int mask;
4428
4429 temp = XGetFont (newname);
4430 if (temp == (FONT_TYPE *) 0)
4431 return 1;
4432
4433 if (f->display.x->font)
4434 XLoseFont (f->display.x->font);
4435
4436 f->display.x->font = temp;
4437
4438 if (FRAME_X_WINDOW (f) != 0)
4439 x_set_window_size (f, f->width, f->height);
4440
4441 return 0;
4442 }
4443 #endif /* ! defined (HAVE_X11) */
4444 \f
4445 x_calc_absolute_position (f)
4446 struct frame *f;
4447 {
4448 #ifdef HAVE_X11
4449 Window win, child;
4450 int win_x = 0, win_y = 0;
4451
4452 /* Find the position of the outside upper-left corner of
4453 the inner window, with respect to the outer window. */
4454 if (f->display.x->parent_desc != ROOT_WINDOW)
4455 {
4456 BLOCK_INPUT;
4457 XTranslateCoordinates (x_current_display,
4458
4459 /* From-window, to-window. */
4460 f->display.x->window_desc,
4461 f->display.x->parent_desc,
4462
4463 /* From-position, to-position. */
4464 0, 0, &win_x, &win_y,
4465
4466 /* Child of win. */
4467 &child);
4468 UNBLOCK_INPUT;
4469 }
4470
4471 /* Treat negative positions as relative to the leftmost bottommost
4472 position that fits on the screen. */
4473 if (f->display.x->left_pos < 0)
4474 f->display.x->left_pos = (x_screen_width
4475 - 2 * f->display.x->border_width - win_x
4476 - PIXEL_WIDTH (f)
4477 + f->display.x->left_pos);
4478
4479 if (f->display.x->top_pos < 0)
4480 f->display.x->top_pos = (x_screen_height
4481 - 2 * f->display.x->border_width - win_y
4482 - PIXEL_HEIGHT (f)
4483 + f->display.x->top_pos);
4484
4485 #else /* ! defined (HAVE_X11) */
4486 WINDOWINFO_TYPE parentinfo;
4487
4488 XGetWindowInfo (FRAME_X_WINDOW (f), &parentinfo);
4489
4490 if (f->display.x->left_pos < 0)
4491 f->display.x->left_pos = parentinfo.width + (f->display.x->left_pos + 1)
4492 - PIXEL_WIDTH (f) - 2 * f->display.x->internal_border_width;
4493
4494 if (f->display.x->top_pos < 0)
4495 f->display.x->top_pos = parentinfo.height + (f->display.x->top_pos + 1)
4496 - PIXEL_HEIGHT (f) - 2 * f->display.x->internal_border_width;
4497 #endif /* ! defined (HAVE_X11) */
4498 }
4499
4500 x_set_offset (f, xoff, yoff)
4501 struct frame *f;
4502 register int xoff, yoff;
4503 {
4504 f->display.x->top_pos = yoff;
4505 f->display.x->left_pos = xoff;
4506 x_calc_absolute_position (f);
4507
4508 BLOCK_INPUT;
4509 #ifdef USE_X_TOOLKIT
4510 XMoveWindow (XDISPLAY XtWindow (f->display.x->widget),
4511 f->display.x->left_pos, f->display.x->top_pos);
4512 #else /* not USE_X_TOOLKIT */
4513 XMoveWindow (XDISPLAY FRAME_X_WINDOW (f),
4514 f->display.x->left_pos, f->display.x->top_pos);
4515 #endif /* not USE_X_TOOLKIT */
4516 #ifdef HAVE_X11
4517 x_wm_set_size_hint (f, 0, xoff, yoff);
4518 #endif /* ! defined (HAVE_X11) */
4519 UNBLOCK_INPUT;
4520 }
4521
4522 /* Call this to change the size of frame F's x-window. */
4523
4524 x_set_window_size (f, cols, rows)
4525 struct frame *f;
4526 int cols, rows;
4527 {
4528 int pixelwidth, pixelheight;
4529 int mask;
4530
4531 #ifdef USE_X_TOOLKIT
4532 BLOCK_INPUT;
4533 EmacsFrameSetCharSize (f->display.x->edit_widget, cols, rows);
4534 UNBLOCK_INPUT;
4535
4536 #else /* not USE_X_TOOLKIT */
4537
4538 BLOCK_INPUT;
4539
4540 check_frame_size (f, &rows, &cols);
4541 f->display.x->vertical_scroll_bar_extra
4542 = (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4543 ? VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f)
4544 : 0);
4545 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
4546 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
4547
4548 #ifdef HAVE_X11
4549 x_wm_set_size_hint (f, 0, 0, 0);
4550 #endif /* ! defined (HAVE_X11) */
4551 XChangeWindowSize (FRAME_X_WINDOW (f), pixelwidth, pixelheight);
4552
4553 /* Now, strictly speaking, we can't be sure that this is accurate,
4554 but the window manager will get around to dealing with the size
4555 change request eventually, and we'll hear how it went when the
4556 ConfigureNotify event gets here.
4557
4558 We could just not bother storing any of this information here,
4559 and let the ConfigureNotify event set everything up, but that
4560 might be kind of confusing to the lisp code, since size changes
4561 wouldn't be reported in the frame parameters until some random
4562 point in the future when the ConfigureNotify event arrives. */
4563 change_frame_size (f, rows, cols, 0, 0);
4564 PIXEL_WIDTH (f) = pixelwidth;
4565 PIXEL_HEIGHT (f) = pixelheight;
4566
4567 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
4568 receive in the ConfigureNotify event; if we get what we asked
4569 for, then the event won't cause the screen to become garbaged, so
4570 we have to make sure to do it here. */
4571 SET_FRAME_GARBAGED (f);
4572
4573 XFlushQueue ();
4574 UNBLOCK_INPUT;
4575 #endif /* not USE_X_TOOLKIT */
4576 }
4577
4578 #ifndef HAVE_X11
4579 x_set_resize_hint (f)
4580 struct frame *f;
4581 {
4582 XSetResizeHint (FRAME_X_WINDOW (f),
4583 2 * f->display.x->internal_border_width,
4584 2 * f->display.x->internal_border_width,
4585 FONT_WIDTH (f->display.x->font),
4586 FONT_HEIGHT (f->display.x->font));
4587 }
4588 #endif /* HAVE_X11 */
4589 \f
4590 /* Mouse warping, focus shifting, raising and lowering. */
4591
4592 x_set_mouse_position (f, x, y)
4593 struct frame *f;
4594 int x, y;
4595 {
4596 int pix_x, pix_y;
4597
4598 #if 0 /* Let the user ask for this if he wants it. */
4599 x_raise_frame (f);
4600 #endif
4601
4602 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2;
4603 pix_y = CHAR_TO_PIXEL_ROW (f, y) + FONT_HEIGHT (f->display.x->font) / 2;
4604
4605 if (pix_x < 0) pix_x = 0;
4606 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
4607
4608 if (pix_y < 0) pix_y = 0;
4609 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
4610
4611 BLOCK_INPUT;
4612
4613 XWarpMousePointer (FRAME_X_WINDOW (f), pix_x, pix_y);
4614 UNBLOCK_INPUT;
4615 }
4616
4617 #ifdef HAVE_X11
4618 x_focus_on_frame (f)
4619 struct frame *f;
4620 {
4621 #if 0 /* This proves to be unpleasant. */
4622 x_raise_frame (f);
4623 #endif
4624 #if 0
4625 /* I don't think that the ICCCM allows programs to do things like this
4626 without the interaction of the window manager. Whatever you end up
4627 doing with this code, do it to x_unfocus_frame too. */
4628 XSetInputFocus (x_current_display, FRAME_X_WINDOW (f),
4629 RevertToPointerRoot, CurrentTime);
4630 #endif /* ! 0 */
4631 }
4632
4633 x_unfocus_frame (f)
4634 struct frame *f;
4635 {
4636 #if 0
4637 /* Look at the remarks in x_focus_on_frame. */
4638 if (x_focus_frame == f)
4639 XSetInputFocus (x_current_display, PointerRoot,
4640 RevertToPointerRoot, CurrentTime);
4641 #endif /* ! 0 */
4642 }
4643
4644 #endif /* ! defined (HAVE_X11) */
4645
4646 /* Raise frame F. */
4647
4648 x_raise_frame (f)
4649 struct frame *f;
4650 {
4651 if (f->async_visible)
4652 {
4653 BLOCK_INPUT;
4654 #ifdef USE_X_TOOLKIT
4655 XRaiseWindow (XDISPLAY XtWindow (f->display.x->widget));
4656 #else /* not USE_X_TOOLKIT */
4657 XRaiseWindow (XDISPLAY FRAME_X_WINDOW (f));
4658 #endif /* not USE_X_TOOLKIT */
4659 XFlushQueue ();
4660 UNBLOCK_INPUT;
4661 }
4662 }
4663
4664 /* Lower frame F. */
4665
4666 x_lower_frame (f)
4667 struct frame *f;
4668 {
4669 if (f->async_visible)
4670 {
4671 BLOCK_INPUT;
4672 #ifdef USE_X_TOOLKIT
4673 XLowerWindow (XDISPLAY XtWindow (f->display.x->widget));
4674 #else /* not USE_X_TOOLKIT */
4675 XLowerWindow (XDISPLAY FRAME_X_WINDOW (f));
4676 #endif /* not USE_X_TOOLKIT */
4677 XFlushQueue ();
4678 UNBLOCK_INPUT;
4679 }
4680 }
4681
4682 static void
4683 XTframe_raise_lower (f, raise)
4684 FRAME_PTR f;
4685 int raise;
4686 {
4687 if (raise)
4688 x_raise_frame (f);
4689 else
4690 x_lower_frame (f);
4691 }
4692
4693
4694 /* Change from withdrawn state to mapped state. */
4695
4696 x_make_frame_visible (f)
4697 struct frame *f;
4698 {
4699 int mask;
4700
4701 BLOCK_INPUT;
4702
4703 if (! FRAME_VISIBLE_P (f))
4704 {
4705 #ifdef HAVE_X11
4706 if (! EQ (Vx_no_window_manager, Qt))
4707 x_wm_set_window_state (f, NormalState);
4708 #ifdef USE_X_TOOLKIT
4709 XtPopup (f->display.x->widget, XtGrabNone);
4710 #else /* not USE_X_TOOLKIT */
4711 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
4712 #endif /* not USE_X_TOOLKIT */
4713 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4714 XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
4715 #else /* ! defined (HAVE_X11) */
4716 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
4717 if (f->display.x->icon_desc != 0)
4718 XUnmapWindow (f->display.x->icon_desc);
4719
4720 /* Handled by the MapNotify event for X11 */
4721 f->async_visible = 1;
4722 f->async_iconified = 0;
4723
4724 /* NOTE: this may cause problems for the first frame. */
4725 XTcursor_to (0, 0);
4726 #endif /* ! defined (HAVE_X11) */
4727 }
4728
4729 XFlushQueue ();
4730
4731 UNBLOCK_INPUT;
4732 }
4733
4734 /* Change from mapped state to withdrawn state. */
4735
4736 x_make_frame_invisible (f)
4737 struct frame *f;
4738 {
4739 int mask;
4740
4741 /* Don't keep the highlight on an invisible frame. */
4742 if (x_highlight_frame == f)
4743 x_highlight_frame = 0;
4744
4745 if (! f->async_visible && ! f->async_iconified)
4746 return;
4747
4748 BLOCK_INPUT;
4749
4750 #ifdef HAVE_X11R4
4751
4752 if (! XWithdrawWindow (x_current_display, FRAME_X_WINDOW (f),
4753 DefaultScreen (x_current_display)))
4754 {
4755 UNBLOCK_INPUT_RESIGNAL;
4756 error ("can't notify window manager of window withdrawal");
4757 }
4758
4759 #else /* ! defined (HAVE_X11R4) */
4760 #ifdef HAVE_X11
4761
4762 /* Tell the window manager what we're going to do. */
4763 if (! EQ (Vx_no_window_manager, Qt))
4764 {
4765 XEvent unmap;
4766
4767 unmap.xunmap.type = UnmapNotify;
4768 unmap.xunmap.window = FRAME_X_WINDOW (f);
4769 unmap.xunmap.event = DefaultRootWindow (x_current_display);
4770 unmap.xunmap.from_configure = False;
4771 if (! XSendEvent (x_current_display,
4772 DefaultRootWindow (x_current_display),
4773 False,
4774 SubstructureRedirectMask|SubstructureNotifyMask,
4775 &unmap))
4776 {
4777 UNBLOCK_INPUT_RESIGNAL;
4778 error ("can't notify window manager of withdrawal");
4779 }
4780 }
4781
4782 /* Unmap the window ourselves. Cheeky! */
4783 XUnmapWindow (x_current_display, FRAME_X_WINDOW (f));
4784
4785 #else /* ! defined (HAVE_X11) */
4786
4787 XUnmapWindow (FRAME_X_WINDOW (f));
4788 f->async_visible = 0; /* Handled by the UnMap event for X11 */
4789 if (f->display.x->icon_desc != 0)
4790 XUnmapWindow (f->display.x->icon_desc);
4791
4792 #endif /* ! defined (HAVE_X11) */
4793 #endif /* ! defined (HAVE_X11R4) */
4794
4795 XFlushQueue ();
4796 UNBLOCK_INPUT;
4797 }
4798
4799 /* Change window state from mapped to iconified. */
4800
4801 x_iconify_frame (f)
4802 struct frame *f;
4803 {
4804 int mask;
4805 int result;
4806
4807 /* Don't keep the highlight on an invisible frame. */
4808 if (x_highlight_frame == f)
4809 x_highlight_frame = 0;
4810
4811 if (f->async_iconified)
4812 return;
4813
4814 #ifdef USE_X_TOOLKIT
4815 BLOCK_INPUT;
4816 result = XIconifyWindow (x_current_display,
4817 XtWindow(f->display.x->widget),
4818 DefaultScreen (x_current_display));
4819 UNBLOCK_INPUT;
4820
4821 if (!result)
4822 error ("Can't notify window manager of iconification.");
4823
4824 f->async_iconified = 1;
4825
4826 BLOCK_INPUT;
4827 XFlushQueue ();
4828 UNBLOCK_INPUT;
4829 #else /* not USE_X_TOOLKIT */
4830
4831 BLOCK_INPUT;
4832
4833 #ifdef HAVE_X11
4834 /* Since we don't know which revision of X we're running, we'll use both
4835 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
4836
4837 /* X11R4: send a ClientMessage to the window manager using the
4838 WM_CHANGE_STATE type. */
4839 {
4840 XEvent message;
4841
4842 message.xclient.window = FRAME_X_WINDOW (f);
4843 message.xclient.type = ClientMessage;
4844 message.xclient.message_type = Xatom_wm_change_state;
4845 message.xclient.format = 32;
4846 message.xclient.data.l[0] = IconicState;
4847
4848 if (! XSendEvent (x_current_display,
4849 DefaultRootWindow (x_current_display),
4850 False,
4851 SubstructureRedirectMask | SubstructureNotifyMask,
4852 &message))
4853 {
4854 UNBLOCK_INPUT_RESIGNAL;
4855 error ("Can't notify window manager of iconification.");
4856 }
4857 }
4858
4859 /* X11R3: set the initial_state field of the window manager hints to
4860 IconicState. */
4861 x_wm_set_window_state (f, IconicState);
4862
4863 if (!FRAME_VISIBLE_P (f))
4864 {
4865 /* If the frame was withdrawn, before, we must map it. */
4866 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
4867 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4868 XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
4869 }
4870
4871 f->async_iconified = 1;
4872 #else /* ! defined (HAVE_X11) */
4873 XUnmapWindow (XDISPLAY FRAME_X_WINDOW (f));
4874
4875 f->async_visible = 0; /* Handled in the UnMap event for X11. */
4876 if (f->display.x->icon_desc != 0)
4877 {
4878 XMapWindow (XDISPLAY f->display.x->icon_desc);
4879 refreshicon (f);
4880 }
4881 #endif /* ! defined (HAVE_X11) */
4882
4883 XFlushQueue ();
4884 UNBLOCK_INPUT;
4885 #endif /* not USE_X_TOOLKIT */
4886 }
4887
4888 /* Destroy the X window of frame F. */
4889
4890 x_destroy_window (f)
4891 struct frame *f;
4892 {
4893 BLOCK_INPUT;
4894
4895 if (f->display.x->icon_desc != 0)
4896 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
4897 XDestroyWindow (XDISPLAY f->display.x->window_desc);
4898 #ifdef USE_X_TOOLKIT
4899 XtDestroyWidget (f->display.x->widget);
4900 #endif /* USE_X_TOOLKIT */
4901
4902 free_frame_faces (f);
4903 XFlushQueue ();
4904
4905 xfree (f->display.x);
4906 f->display.x = 0;
4907 if (f == x_focus_frame)
4908 x_focus_frame = 0;
4909 if (f == x_highlight_frame)
4910 x_highlight_frame = 0;
4911
4912 UNBLOCK_INPUT;
4913 }
4914 \f
4915 /* Manage event queues for X10. */
4916
4917 #ifndef HAVE_X11
4918
4919 /* Manage event queues.
4920
4921 This code is only used by the X10 support.
4922
4923 We cannot leave events in the X queue and get them when we are ready
4924 because X does not provide a subroutine to get only a certain kind
4925 of event but not block if there are no queued events of that kind.
4926
4927 Therefore, we must examine events as they come in and copy events
4928 of certain kinds into our private queues.
4929
4930 All ExposeRegion events are put in x_expose_queue.
4931 All ButtonPress and ButtonRelease events are put in x_mouse_queue. */
4932
4933
4934 /* Write the event *P_XREP into the event queue *QUEUE.
4935 If the queue is full, do nothing, but return nonzero. */
4936
4937 int
4938 enqueue_event (p_xrep, queue)
4939 register XEvent *p_xrep;
4940 register struct event_queue *queue;
4941 {
4942 int newindex = queue->windex + 1;
4943 if (newindex == EVENT_BUFFER_SIZE)
4944 newindex = 0;
4945 if (newindex == queue->rindex)
4946 return -1;
4947 queue->xrep[queue->windex] = *p_xrep;
4948 queue->windex = newindex;
4949 return 0;
4950 }
4951
4952 /* Fetch the next event from queue *QUEUE and store it in *P_XREP.
4953 If *QUEUE is empty, do nothing and return 0. */
4954
4955 int
4956 dequeue_event (p_xrep, queue)
4957 register XEvent *p_xrep;
4958 register struct event_queue *queue;
4959 {
4960 if (queue->windex == queue->rindex)
4961 return 0;
4962 *p_xrep = queue->xrep[queue->rindex++];
4963 if (queue->rindex == EVENT_BUFFER_SIZE)
4964 queue->rindex = 0;
4965 return 1;
4966 }
4967
4968 /* Return the number of events buffered in *QUEUE. */
4969
4970 int
4971 queue_event_count (queue)
4972 register struct event_queue *queue;
4973 {
4974 int tem = queue->windex - queue->rindex;
4975 if (tem >= 0)
4976 return tem;
4977 return EVENT_BUFFER_SIZE + tem;
4978 }
4979
4980 /* Return nonzero if mouse input is pending. */
4981
4982 int
4983 mouse_event_pending_p ()
4984 {
4985 return queue_event_count (&x_mouse_queue);
4986 }
4987 #endif /* HAVE_X11 */
4988 \f
4989 /* Setting window manager hints. */
4990
4991 #ifdef HAVE_X11
4992
4993 /* SPEC_X and SPEC_Y are the specified positions.
4994 We look only at their sign, to decide the gravity. */
4995
4996 x_wm_set_size_hint (f, prompting, spec_x, spec_y)
4997 struct frame *f;
4998 long prompting;
4999 int spec_x, spec_y;
5000 {
5001 XSizeHints size_hints;
5002
5003 #ifdef USE_X_TOOLKIT
5004 Window window = XtWindow(f->display.x->widget);
5005 #else /* not USE_X_TOOLKIT */
5006 Window window = FRAME_X_WINDOW (f);
5007 #endif /* not USE_X_TOOLKIT */
5008
5009 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
5010
5011 flexlines = f->height;
5012
5013 size_hints.x = f->display.x->left_pos;
5014 size_hints.y = f->display.x->top_pos;
5015 size_hints.height = PIXEL_HEIGHT (f);
5016 size_hints.width = PIXEL_WIDTH (f);
5017 size_hints.width_inc = FONT_WIDTH (f->display.x->font);
5018 size_hints.height_inc = FONT_HEIGHT (f->display.x->font);
5019 #if 0
5020 size_hints.max_width = x_screen_width - CHAR_TO_PIXEL_WIDTH (f, 0);
5021 size_hints.max_height = x_screen_height - CHAR_TO_PIXEL_HEIGHT (f, 0);
5022 #endif
5023 {
5024 int base_width, base_height;
5025
5026 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
5027 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
5028
5029 {
5030 int min_rows = 0, min_cols = 0;
5031 check_frame_size (f, &min_rows, &min_cols);
5032
5033 /* The window manager uses the base width hints to calculate the
5034 current number of rows and columns in the frame while
5035 resizing; min_width and min_height aren't useful for this
5036 purpose, since they might not give the dimensions for a
5037 zero-row, zero-column frame.
5038
5039 We use the base_width and base_height members if we have
5040 them; otherwise, we set the min_width and min_height members
5041 to the size for a zero x zero frame. */
5042
5043 #ifdef HAVE_X11R4
5044 size_hints.flags |= PBaseSize;
5045 size_hints.base_width = base_width;
5046 size_hints.base_height = base_height;
5047 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
5048 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
5049 #else
5050 size_hints.min_width = base_width;
5051 size_hints.min_height = base_height;
5052 #endif
5053 }
5054
5055 }
5056
5057 if (prompting)
5058 size_hints.flags |= prompting;
5059 else
5060 {
5061 XSizeHints hints; /* Sometimes I hate X Windows... */
5062
5063 if (XGetNormalHints (x_current_display, window, &hints) == 0)
5064 hints.flags = 0;
5065 if (hints.flags & PSize)
5066 size_hints.flags |= PSize;
5067 if (hints.flags & PPosition)
5068 size_hints.flags |= PPosition;
5069 if (hints.flags & USPosition)
5070 size_hints.flags |= USPosition;
5071 if (hints.flags & USSize)
5072 size_hints.flags |= USSize;
5073 }
5074 #if defined (PWinGravity)
5075 switch (((spec_x < 0) << 1) + (spec_y < 0))
5076 {
5077 case 0:
5078 size_hints.win_gravity = NorthWestGravity;
5079 break;
5080 case 1:
5081 size_hints.win_gravity = NorthEastGravity;
5082 break;
5083 case 2:
5084 size_hints.win_gravity = SouthWestGravity;
5085 break;
5086 case 3:
5087 size_hints.win_gravity = SouthEastGravity;
5088 break;
5089 }
5090 size_hints.flags |= PWinGravity;
5091 #endif /* PWinGravity */
5092
5093 #ifdef HAVE_X11R4
5094 XSetWMNormalHints (x_current_display, window, &size_hints);
5095 #else
5096 XSetNormalHints (x_current_display, window, &size_hints);
5097 #endif
5098 }
5099
5100 /* Used for IconicState or NormalState */
5101 x_wm_set_window_state (f, state)
5102 struct frame *f;
5103 int state;
5104 {
5105 #ifdef USE_X_TOOLKIT
5106 Window window = XtWindow(f->display.x->widget);
5107 #else /* not USE_X_TOOLKIT */
5108 Window window = FRAME_X_WINDOW (f);
5109 #endif /* not USE_X_TOOLKIT */
5110
5111 f->display.x->wm_hints.flags |= StateHint;
5112 f->display.x->wm_hints.initial_state = state;
5113
5114 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
5115 }
5116
5117 x_wm_set_icon_pixmap (f, icon_pixmap)
5118 struct frame *f;
5119 Pixmap icon_pixmap;
5120 {
5121 Window window = FRAME_X_WINDOW (f);
5122
5123 if (icon_pixmap)
5124 {
5125 f->display.x->wm_hints.icon_pixmap = icon_pixmap;
5126 f->display.x->wm_hints.flags |= IconPixmapHint;
5127 }
5128 else
5129 f->display.x->wm_hints.flags &= ~IconPixmapHint;
5130
5131 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
5132 }
5133
5134 x_wm_set_icon_position (f, icon_x, icon_y)
5135 struct frame *f;
5136 int icon_x, icon_y;
5137 {
5138 Window window = FRAME_X_WINDOW (f);
5139
5140 f->display.x->wm_hints.flags |= IconPositionHint;
5141 f->display.x->wm_hints.icon_x = icon_x;
5142 f->display.x->wm_hints.icon_y = icon_y;
5143
5144 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
5145 }
5146
5147 \f
5148 /* Initialization. */
5149
5150 #ifdef USE_X_TOOLKIT
5151 static XrmOptionDescRec emacs_options[] = {
5152 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
5153 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
5154
5155 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
5156 XrmoptionSepArg, NULL},
5157 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
5158
5159 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5160 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5161 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5162 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5163 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5164 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
5165 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
5166 };
5167 #endif /* USE_X_TOOLKIT */
5168
5169 void
5170 x_term_init (display_name)
5171 char *display_name;
5172 {
5173 Lisp_Object frame;
5174 char *defaultvalue;
5175 int argc = 0;
5176 char** argv = 0;
5177 #ifndef F_SETOWN_BUG
5178 #ifdef F_SETOWN
5179 extern int old_fcntl_owner;
5180 #endif /* ! defined (F_SETOWN) */
5181 #endif /* F_SETOWN_BUG */
5182
5183 x_focus_frame = x_highlight_frame = 0;
5184
5185 #ifdef USE_X_TOOLKIT
5186 argv = (char **) XtMalloc (3 * sizeof (char *));
5187 argv [0] = "";
5188 argv [1] = "-display";
5189 argv [2] = display_name;
5190 argc = 3;
5191 Xt_app_shell = XtAppInitialize (&Xt_app_con, "Emacs",
5192 emacs_options, XtNumber(emacs_options),
5193 &argc, argv,
5194 NULL, NULL, 0);
5195 XtFree (argv);
5196 x_current_display = XtDisplay (Xt_app_shell);
5197
5198 #else /* not USE_X_TOOLKIT */
5199 x_current_display = XOpenDisplay (display_name);
5200 #endif /* not USE_X_TOOLKIT */
5201 if (x_current_display == 0)
5202 fatal ("X server %s not responding.\n\
5203 Check the DISPLAY environment variable or use \"-d\"\n",
5204 display_name);
5205
5206 #ifdef HAVE_X11
5207 {
5208 #if 0
5209 XSetAfterFunction (x_current_display, x_trace_wire);
5210 #endif /* ! 0 */
5211 hostname = get_system_name ();
5212 x_id_name = (char *) xmalloc (XSTRING (Vinvocation_name)->size
5213 + strlen (hostname)
5214 + 2);
5215 sprintf (x_id_name, "%s@%s", XSTRING (Vinvocation_name)->data, hostname);
5216 }
5217
5218 /* Figure out which modifier bits mean what. */
5219 x_find_modifier_meanings ();
5220
5221 /* Get the scroll bar cursor. */
5222 x_vertical_scroll_bar_cursor
5223 = XCreateFontCursor (x_current_display, XC_sb_v_double_arrow);
5224
5225 #if 0
5226 /* Watch for PropertyNotify events on the root window; we use them
5227 to figure out when to invalidate our cache of the cut buffers. */
5228 x_watch_cut_buffer_cache ();
5229 #endif
5230
5231 if (ConnectionNumber (x_current_display) != 0)
5232 change_keyboard_wait_descriptor (ConnectionNumber (x_current_display));
5233 change_input_fd (ConnectionNumber (x_current_display));
5234
5235 #endif /* ! defined (HAVE_X11) */
5236
5237 #ifndef F_SETOWN_BUG
5238 #ifdef F_SETOWN
5239 old_fcntl_owner = fcntl (ConnectionNumber (x_current_display), F_GETOWN, 0);
5240 #ifdef F_SETOWN_SOCK_NEG
5241 /* stdin is a socket here */
5242 fcntl (ConnectionNumber (x_current_display), F_SETOWN, -getpid ());
5243 #else /* ! defined (F_SETOWN_SOCK_NEG) */
5244 fcntl (ConnectionNumber (x_current_display), F_SETOWN, getpid ());
5245 #endif /* ! defined (F_SETOWN_SOCK_NEG) */
5246 #endif /* ! defined (F_SETOWN) */
5247 #endif /* F_SETOWN_BUG */
5248
5249 #ifdef SIGIO
5250 init_sigio ();
5251 #endif /* ! defined (SIGIO) */
5252
5253 expose_all_windows = 0;
5254
5255 clear_frame_hook = XTclear_frame;
5256 clear_end_of_line_hook = XTclear_end_of_line;
5257 ins_del_lines_hook = XTins_del_lines;
5258 change_line_highlight_hook = XTchange_line_highlight;
5259 insert_glyphs_hook = XTinsert_glyphs;
5260 write_glyphs_hook = XTwrite_glyphs;
5261 delete_glyphs_hook = XTdelete_glyphs;
5262 ring_bell_hook = XTring_bell;
5263 reset_terminal_modes_hook = XTreset_terminal_modes;
5264 set_terminal_modes_hook = XTset_terminal_modes;
5265 update_begin_hook = XTupdate_begin;
5266 update_end_hook = XTupdate_end;
5267 set_terminal_window_hook = XTset_terminal_window;
5268 read_socket_hook = XTread_socket;
5269 cursor_to_hook = XTcursor_to;
5270 reassert_line_highlight_hook = XTreassert_line_highlight;
5271 mouse_position_hook = XTmouse_position;
5272 frame_rehighlight_hook = XTframe_rehighlight;
5273 frame_raise_lower_hook = XTframe_raise_lower;
5274 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
5275 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
5276 redeem_scroll_bar_hook = XTredeem_scroll_bar;
5277 judge_scroll_bars_hook = XTjudge_scroll_bars;
5278
5279 scroll_region_ok = 1; /* we'll scroll partial frames */
5280 char_ins_del_ok = 0; /* just as fast to write the line */
5281 line_ins_del_ok = 1; /* we'll just blt 'em */
5282 fast_clear_end_of_line = 1; /* X does this well */
5283 memory_below_frame = 0; /* we don't remember what scrolls
5284 off the bottom */
5285 baud_rate = 19200;
5286
5287 /* Try to use interrupt input; if we can't, then start polling. */
5288 Fset_input_mode (Qt, Qnil, Qt, Qnil);
5289
5290 /* Note that there is no real way portable across R3/R4 to get the
5291 original error handler. */
5292 XHandleError (x_error_quitter);
5293 XHandleIOError (x_io_error_quitter);
5294
5295 /* Disable Window Change signals; they are handled by X events. */
5296 #ifdef SIGWINCH
5297 signal (SIGWINCH, SIG_DFL);
5298 #endif /* ! defined (SIGWINCH) */
5299
5300 signal (SIGPIPE, x_connection_closed);
5301 }
5302
5303 void
5304 syms_of_xterm ()
5305 {
5306 staticpro (&last_mouse_scroll_bar);
5307 last_mouse_scroll_bar = Qnil;
5308 }
5309 #endif /* ! defined (HAVE_X11) */
5310 #endif /* ! defined (HAVE_X_WINDOWS) */