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