(event-modifiers): Function deleted.
[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
148c4b70
RS
1508 /* If some keys are both alt and meta,
1509 make them just meta, not alt. */
1510 if (x_alt_mod_mask & x_meta_mod_mask)
1511 {
1512 x_alt_mod_mask &= ~x_meta_mod_mask;
1513 }
1514
28430d3c 1515 XFree ((char *) syms);
f689eb05 1516 XFreeModifiermap (mods);
28430d3c
JB
1517}
1518
1519
dfeccd2d
JB
1520/* Convert between the modifier bits X uses and the modifier bits
1521 Emacs uses. */
7c5283e4 1522static unsigned int
dfeccd2d 1523x_x_to_emacs_modifiers (state)
dc6f92b8
JB
1524 unsigned int state;
1525{
11edeb03
JB
1526 return ( ((state & (ShiftMask | x_shift_lock_mask)) ? shift_modifier : 0)
1527 | ((state & ControlMask) ? ctrl_modifier : 0)
a3c44b14
RS
1528 | ((state & x_meta_mod_mask) ? meta_modifier : 0)
1529 | ((state & x_alt_mod_mask) ? alt_modifier : 0)
1530 | ((state & x_super_mod_mask) ? super_modifier : 0)
1531 | ((state & x_hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
1532}
1533
dfeccd2d
JB
1534static unsigned int
1535x_emacs_to_x_modifiers (state)
1536 unsigned int state;
1537{
1538 return ( ((state & alt_modifier) ? x_alt_mod_mask : 0)
1539 | ((state & super_modifier) ? x_super_mod_mask : 0)
1540 | ((state & hyper_modifier) ? x_hyper_mod_mask : 0)
1541 | ((state & shift_modifier) ? ShiftMask : 0)
1542 | ((state & ctrl_modifier) ? ControlMask : 0)
1543 | ((state & meta_modifier) ? x_meta_mod_mask : 0));
1544}
1545
dc6f92b8
JB
1546/* Prepare a mouse-event in *RESULT for placement in the input queue.
1547
1548 If the event is a button press, then note that we have grabbed
f451eb13 1549 the mouse. */
dc6f92b8
JB
1550
1551static Lisp_Object
f451eb13 1552construct_mouse_click (result, event, f)
dc6f92b8
JB
1553 struct input_event *result;
1554 XButtonEvent *event;
f676886a 1555 struct frame *f;
dc6f92b8 1556{
f451eb13 1557 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 1558 otherwise. */
f451eb13
JB
1559 result->kind = mouse_click;
1560 XSET (result->code, Lisp_Int, event->button - Button1);
1113d9db 1561 result->timestamp = event->time;
dfeccd2d 1562 result->modifiers = (x_x_to_emacs_modifiers (event->state)
f689eb05
JB
1563 | (event->type == ButtonRelease
1564 ? up_modifier
1565 : down_modifier));
dc6f92b8
JB
1566
1567 /* Notice if the mouse is still grabbed. */
1568 if (event->type == ButtonPress)
1569 {
1570 if (! x_mouse_grabbed)
1571 Vmouse_depressed = Qt;
90e65f07 1572 x_mouse_grabbed |= (1 << event->button);
dc6f92b8
JB
1573 }
1574 else if (event->type == ButtonRelease)
1575 {
90e65f07 1576 x_mouse_grabbed &= ~(1 << event->button);
dc6f92b8
JB
1577 if (!x_mouse_grabbed)
1578 Vmouse_depressed = Qnil;
1579 }
1580
f451eb13
JB
1581 {
1582 int row, column;
dc6f92b8 1583
f451eb13
JB
1584 pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL);
1585 XFASTINT (result->x) = column;
1586 XFASTINT (result->y) = row;
12ba150f 1587 XSET (result->frame_or_window, Lisp_Frame, f);
f451eb13 1588 }
dc6f92b8
JB
1589}
1590
1591
90e65f07
JB
1592/* Mouse movement. Rah.
1593
1594 In order to avoid asking for motion events and then throwing most
1595 of them away or busy-polling the server for mouse positions, we ask
1596 the server for pointer motion hints. This means that we get only
1597 one event per group of mouse movements. "Groups" are delimited by
1598 other kinds of events (focus changes and button clicks, for
1599 example), or by XQueryPointer calls; when one of these happens, we
1600 get another MotionNotify event the next time the mouse moves. This
e5d77022 1601 is at least as efficient as getting motion events when mouse
90e65f07
JB
1602 tracking is on, and I suspect only negligibly worse when tracking
1603 is off.
1604
1605 The silly O'Reilly & Associates Nutshell guides barely document
1606 pointer motion hints at all (I think you have to infer how they
1607 work from an example), and the description of XQueryPointer doesn't
1608 mention that calling it causes you to get another motion hint from
1609 the server, which is very important. */
1610
1611/* Where the mouse was last time we reported a mouse event. */
f676886a 1612static FRAME_PTR last_mouse_frame;
90e65f07
JB
1613static XRectangle last_mouse_glyph;
1614
ab648270 1615/* The scroll bar in which the last X motion event occurred.
12ba150f 1616
ab648270
JB
1617 If the last X motion event occured in a scroll bar, we set this
1618 so XTmouse_position can know whether to report a scroll bar motion or
12ba150f
JB
1619 an ordinary motion.
1620
ab648270 1621 If the last X motion event didn't occur in a scroll bar, we set this
12ba150f 1622 to Qnil, to tell XTmouse_position to return an ordinary motion event. */
ab648270 1623static Lisp_Object last_mouse_scroll_bar;
f451eb13 1624
e5d77022
JB
1625/* This is a hack. We would really prefer that XTmouse_position would
1626 return the time associated with the position it returns, but there
1627 doesn't seem to be any way to wrest the timestamp from the server
1628 along with the position query. So, we just keep track of the time
1629 of the last movement we received, and return that in hopes that
1630 it's somewhat accurate. */
1631static Time last_mouse_movement_time;
1632
90e65f07
JB
1633/* Function to report a mouse movement to the mainstream Emacs code.
1634 The input handler calls this.
1635
1636 We have received a mouse movement event, which is given in *event.
1637 If the mouse is over a different glyph than it was last time, tell
1638 the mainstream emacs code by setting mouse_moved. If not, ask for
1639 another motion event, so we can check again the next time it moves. */
1640static void
12ba150f 1641note_mouse_movement (frame, event)
f676886a 1642 FRAME_PTR frame;
90e65f07
JB
1643 XMotionEvent *event;
1644
1645{
e5d77022
JB
1646 last_mouse_movement_time = event->time;
1647
90e65f07
JB
1648 /* Has the mouse moved off the glyph it was on at the last sighting? */
1649 if (event->x < last_mouse_glyph.x
1650 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
1651 || event->y < last_mouse_glyph.y
1652 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f
JB
1653 {
1654 mouse_moved = 1;
ab648270 1655 last_mouse_scroll_bar = Qnil;
12ba150f 1656 }
90e65f07
JB
1657 else
1658 {
1659 /* It's on the same glyph. Call XQueryPointer so we'll get an
1660 event the next time the mouse moves and we can see if it's
1661 *still* on the same glyph. */
1662 int dummy;
1663
1664 XQueryPointer (event->display, event->window,
1665 (Window *) &dummy, (Window *) &dummy,
1666 &dummy, &dummy, &dummy, &dummy,
1667 (unsigned int *) &dummy);
1668 }
1669}
1670
ab648270
JB
1671static struct scroll_bar *x_window_to_scroll_bar ();
1672static void x_scroll_bar_report_motion ();
12ba150f 1673
90e65f07
JB
1674/* Return the current position of the mouse.
1675
ab648270
JB
1676 If the mouse movement started in a scroll bar, set *f, *bar_window,
1677 and *part to the frame, window, and scroll bar part that the mouse
12ba150f 1678 is over. Set *x and *y to the portion and whole of the mouse's
ab648270 1679 position on the scroll bar.
12ba150f
JB
1680
1681 If the mouse movement started elsewhere, set *f to the frame the
1682 mouse is on, *bar_window to nil, and *x and *y to the character cell
1683 the mouse is over.
1684
1685 Set *time to the server timestamp for the time at which the mouse
1686 was at this position.
1687
90e65f07 1688 This clears the mouse_moved flag, so we can wait for the next mouse
12ba150f
JB
1689 movement. This also calls XQueryPointer, which will cause the
1690 server to give us another MotionNotify when the mouse moves
1691 again. */
90e65f07
JB
1692
1693static void
12ba150f 1694XTmouse_position (f, bar_window, part, x, y, time)
f676886a 1695 FRAME_PTR *f;
12ba150f 1696 Lisp_Object *bar_window;
ab648270 1697 enum scroll_bar_part *part;
90e65f07 1698 Lisp_Object *x, *y;
e5d77022 1699 unsigned long *time;
90e65f07 1700{
90e65f07
JB
1701 BLOCK_INPUT;
1702
ab648270
JB
1703 if (! NILP (last_mouse_scroll_bar))
1704 x_scroll_bar_report_motion (f, bar_window, part, x, y, time);
90e65f07
JB
1705 else
1706 {
12ba150f
JB
1707 Window root;
1708 int root_x, root_y;
90e65f07 1709
12ba150f
JB
1710 Window dummy_window;
1711 int dummy;
1712
1713 mouse_moved = 0;
ab648270 1714 last_mouse_scroll_bar = Qnil;
12ba150f
JB
1715
1716 /* Figure out which root window we're on. */
1717 XQueryPointer (x_current_display,
1718 DefaultRootWindow (x_current_display),
1719
1720 /* The root window which contains the pointer. */
1721 &root,
1722
1723 /* Trash which we can't trust if the pointer is on
1724 a different screen. */
1725 &dummy_window,
1726
1727 /* The position on that root window. */
1728 &root_x, &root_y,
1729
1730 /* More trash we can't trust. */
1731 &dummy, &dummy,
1732
1733 /* Modifier keys and pointer buttons, about which
1734 we don't care. */
1735 (unsigned int *) &dummy);
1736
1737 /* Now we have a position on the root; find the innermost window
1738 containing the pointer. */
1739 {
1740 Window win, child;
1741 int win_x, win_y;
1742 int parent_x, parent_y;
1743
1744 win = root;
1745 for (;;)
1746 {
1747 XTranslateCoordinates (x_current_display,
1748
1749 /* From-window, to-window. */
1750 root, win,
1751
1752 /* From-position, to-position. */
1753 root_x, root_y, &win_x, &win_y,
1754
1755 /* Child of win. */
1756 &child);
1757
1758 if (child == None)
1759 break;
1760
1761 win = child;
1762 parent_x = win_x;
1763 parent_y = win_y;
1764 }
1765
1766 /* Now we know that:
1767 win is the innermost window containing the pointer
1768 (XTC says it has no child containing the pointer),
1769 win_x and win_y are the pointer's position in it
1770 (XTC did this the last time through), and
1771 parent_x and parent_y are the pointer's position in win's parent.
1772 (They are what win_x and win_y were when win was child.
1773 If win is the root window, it has no parent, and
1774 parent_{x,y} are invalid, but that's okay, because we'll
1775 never use them in that case.) */
1776
1777 /* Is win one of our frames? */
1778 *f = x_window_to_frame (win);
1779
ab648270 1780 /* If not, is it one of our scroll bars? */
12ba150f
JB
1781 if (! *f)
1782 {
ab648270 1783 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
1784
1785 if (bar)
1786 {
1787 *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
1788 win_x = parent_x;
1789 win_y = parent_y;
1790 }
1791 }
90e65f07 1792
12ba150f
JB
1793 if (*f)
1794 {
1795 pixel_to_glyph_coords (*f, win_x, win_y, &win_x, &win_y,
1796 &last_mouse_glyph);
1797
1798 *bar_window = Qnil;
1799 *part = 0;
1800 XSET (*x, Lisp_Int, win_x);
1801 XSET (*y, Lisp_Int, win_y);
1802 *time = last_mouse_movement_time;
1803 }
1804 }
1805 }
90e65f07
JB
1806
1807 UNBLOCK_INPUT;
1808}
1809
c118dd06 1810#else /* ! defined (HAVE_X11) */
dc6f92b8 1811#define XEvent XKeyPressedEvent
c118dd06
JB
1812#endif /* ! defined (HAVE_X11) */
1813\f
ab648270 1814/* Scroll bar support. */
f451eb13 1815
ab648270
JB
1816/* Given an X window ID, find the struct scroll_bar which manages it.
1817 This can be called in GC, so we have to make sure to strip off mark
1818 bits. */
1819static struct scroll_bar *
1820x_window_to_scroll_bar (window_id)
f451eb13
JB
1821 Window window_id;
1822{
1823 Lisp_Object tail, frame;
f451eb13 1824
ab648270
JB
1825 for (tail = Vframe_list;
1826 XGCTYPE (tail) == Lisp_Cons;
1827 tail = XCONS (tail)->cdr)
f451eb13 1828 {
f451eb13 1829 Lisp_Object frame = XCONS (tail)->car;
cf7cb199 1830 Lisp_Object bar, condemned;
f451eb13
JB
1831
1832 /* All elements of Vframe_list should be frames. */
ab648270 1833 if (XGCTYPE (frame) != Lisp_Frame)
f451eb13
JB
1834 abort ();
1835
ab648270 1836 /* Scan this frame's scroll bar list for a scroll bar with the
f451eb13 1837 right window ID. */
ab648270
JB
1838 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
1839 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
cf7cb199 1840 /* This trick allows us to search both the ordinary and
ab648270
JB
1841 condemned scroll bar lists with one loop. */
1842 ! GC_NILP (bar) || (bar = condemned,
1843 condemned = Qnil,
1844 ! GC_NILP (bar));
1845 bar = XSCROLL_BAR(bar)->next)
1846 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
1847 return XSCROLL_BAR (bar);
f451eb13
JB
1848 }
1849
1850 return 0;
1851}
1852
ab648270
JB
1853/* Open a new X window to serve as a scroll bar, and return the
1854 scroll bar vector for it. */
1855static struct scroll_bar *
1856x_scroll_bar_create (window, top, left, width, height)
12ba150f 1857 struct window *window;
f451eb13
JB
1858 int top, left, width, height;
1859{
12ba150f 1860 FRAME_PTR frame = XFRAME (WINDOW_FRAME (window));
ab648270
JB
1861 struct scroll_bar *bar =
1862 XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
1863
1864 BLOCK_INPUT;
1865
1866 {
1867 XSetWindowAttributes a;
1868 unsigned long mask;
1869
12ba150f
JB
1870 a.background_pixel = frame->display.x->background_pixel;
1871 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 1872 | ButtonMotionMask | PointerMotionHintMask
12ba150f 1873 | ExposureMask);
ab648270 1874 a.cursor = x_vertical_scroll_bar_cursor;
f451eb13 1875
dbc4e1c1 1876 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 1877
ab648270 1878 SET_SCROLL_BAR_X_WINDOW
12ba150f
JB
1879 (bar,
1880 XCreateWindow (x_current_display, FRAME_X_WINDOW (frame),
f451eb13 1881
ab648270 1882 /* Position and size of scroll bar. */
12ba150f 1883 left, top, width, height,
f451eb13 1884
12ba150f
JB
1885 /* Border width, depth, class, and visual. */
1886 0, CopyFromParent, CopyFromParent, CopyFromParent,
f451eb13 1887
12ba150f
JB
1888 /* Attributes. */
1889 mask, &a));
f451eb13
JB
1890 }
1891
12ba150f
JB
1892 XSET (bar->window, Lisp_Window, window);
1893 XSET (bar->top, Lisp_Int, top);
1894 XSET (bar->left, Lisp_Int, left);
1895 XSET (bar->width, Lisp_Int, width);
1896 XSET (bar->height, Lisp_Int, height);
1897 XSET (bar->start, Lisp_Int, 0);
1898 XSET (bar->end, Lisp_Int, 0);
1899 bar->dragging = Qnil;
f451eb13
JB
1900
1901 /* Add bar to its frame's list of scroll bars. */
ab648270 1902 bar->next = FRAME_SCROLL_BARS (frame);
12ba150f 1903 bar->prev = Qnil;
ab648270 1904 XSET (FRAME_SCROLL_BARS (frame), Lisp_Vector, bar);
12ba150f 1905 if (! NILP (bar->next))
ab648270 1906 XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar);
f451eb13 1907
ab648270 1908 XMapWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar));
f451eb13
JB
1909
1910 UNBLOCK_INPUT;
12ba150f
JB
1911
1912 return bar;
f451eb13
JB
1913}
1914
12ba150f
JB
1915/* Draw BAR's handle in the proper position.
1916 If the handle is already drawn from START to END, don't bother
1917 redrawing it, unless REBUILD is non-zero; in that case, always
1918 redraw it. (REBUILD is handy for drawing the handle after expose
1919 events.)
1920
1921 Normally, we want to constrain the start and end of the handle to
ab648270 1922 fit inside its rectangle, but if the user is dragging the scroll bar
12ba150f
JB
1923 handle, we want to let them drag it down all the way, so that the
1924 bar's top is as far down as it goes; otherwise, there's no way to
1925 move to the very end of the buffer. */
f451eb13 1926static void
ab648270
JB
1927x_scroll_bar_set_handle (bar, start, end, rebuild)
1928 struct scroll_bar *bar;
f451eb13 1929 int start, end;
12ba150f 1930 int rebuild;
f451eb13 1931{
12ba150f 1932 int dragging = ! NILP (bar->dragging);
ab648270 1933 Window w = SCROLL_BAR_X_WINDOW (bar);
12ba150f
JB
1934 GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
1935
1936 /* If the display is already accurate, do nothing. */
1937 if (! rebuild
1938 && start == XINT (bar->start)
1939 && end == XINT (bar->end))
1940 return;
1941
f451eb13
JB
1942 BLOCK_INPUT;
1943
1944 {
ab648270
JB
1945 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (XINT (bar->width));
1946 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
1947 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
f451eb13
JB
1948
1949 /* Make sure the values are reasonable, and try to preserve
1950 the distance between start and end. */
12ba150f
JB
1951 {
1952 int length = end - start;
1953
1954 if (start < 0)
1955 start = 0;
1956 else if (start > top_range)
1957 start = top_range;
1958 end = start + length;
1959
1960 if (end < start)
1961 end = start;
1962 else if (end > top_range && ! dragging)
1963 end = top_range;
1964 }
f451eb13 1965
ab648270 1966 /* Store the adjusted setting in the scroll bar. */
12ba150f
JB
1967 XSET (bar->start, Lisp_Int, start);
1968 XSET (bar->end, Lisp_Int, end);
f451eb13 1969
12ba150f
JB
1970 /* Clip the end position, just for display. */
1971 if (end > top_range)
1972 end = top_range;
f451eb13 1973
ab648270 1974 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
1975 below top positions, to make sure the handle is always at least
1976 that many pixels tall. */
ab648270 1977 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 1978
12ba150f
JB
1979 /* Draw the empty space above the handle. Note that we can't clear
1980 zero-height areas; that means "clear to end of window." */
1981 if (0 < start)
1982 XClearArea (x_current_display, w,
f451eb13 1983
12ba150f 1984 /* x, y, width, height, and exposures. */
ab648270
JB
1985 VERTICAL_SCROLL_BAR_LEFT_BORDER,
1986 VERTICAL_SCROLL_BAR_TOP_BORDER,
12ba150f
JB
1987 inside_width, start,
1988 False);
f451eb13 1989
12ba150f
JB
1990 /* Draw the handle itself. */
1991 XFillRectangle (x_current_display, w, gc,
f451eb13 1992
12ba150f 1993 /* x, y, width, height */
ab648270
JB
1994 VERTICAL_SCROLL_BAR_LEFT_BORDER,
1995 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 1996 inside_width, end - start);
f451eb13 1997
f451eb13 1998
12ba150f
JB
1999 /* Draw the empty space below the handle. Note that we can't
2000 clear zero-height areas; that means "clear to end of window." */
2001 if (end < inside_height)
2002 XClearArea (x_current_display, w,
f451eb13 2003
12ba150f 2004 /* x, y, width, height, and exposures. */
ab648270
JB
2005 VERTICAL_SCROLL_BAR_LEFT_BORDER,
2006 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
12ba150f
JB
2007 inside_width, inside_height - end,
2008 False);
f451eb13 2009
f451eb13
JB
2010 }
2011
f451eb13
JB
2012 UNBLOCK_INPUT;
2013}
2014
ab648270 2015/* Move a scroll bar around on the screen, to accomodate changing
12ba150f 2016 window configurations. */
f451eb13 2017static void
ab648270
JB
2018x_scroll_bar_move (bar, top, left, width, height)
2019 struct scroll_bar *bar;
f451eb13
JB
2020 int top, left, width, height;
2021{
2022 BLOCK_INPUT;
2023
2024 {
2025 XWindowChanges wc;
2026 unsigned int mask = 0;
2027
2028 wc.x = left;
2029 wc.y = top;
2030 wc.width = width;
2031 wc.height = height;
2032
12ba150f
JB
2033 if (left != XINT (bar->left)) mask |= CWX;
2034 if (top != XINT (bar->top)) mask |= CWY;
2035 if (width != XINT (bar->width)) mask |= CWWidth;
2036 if (height != XINT (bar->height)) mask |= CWHeight;
2037
2038 if (mask)
ab648270 2039 XConfigureWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar),
12ba150f 2040 mask, &wc);
f451eb13
JB
2041 }
2042
12ba150f
JB
2043 XSET (bar->left, Lisp_Int, left);
2044 XSET (bar->top, Lisp_Int, top);
2045 XSET (bar->width, Lisp_Int, width);
2046 XSET (bar->height, Lisp_Int, height);
2047
f451eb13
JB
2048 UNBLOCK_INPUT;
2049}
2050
ab648270 2051/* Destroy the X window for BAR, and set its Emacs window's scroll bar
12ba150f
JB
2052 to nil. */
2053static void
ab648270
JB
2054x_scroll_bar_remove (bar)
2055 struct scroll_bar *bar;
12ba150f
JB
2056{
2057 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2058
2059 BLOCK_INPUT;
2060
2061 /* Destroy the window. */
ab648270 2062 XDestroyWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar));
12ba150f 2063
ab648270
JB
2064 /* Disassociate this scroll bar from its window. */
2065 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
2066
2067 UNBLOCK_INPUT;
2068}
2069
2070/* Set the handle of the vertical scroll bar for WINDOW to indicate
2071 that we are displaying PORTION characters out of a total of WHOLE
ab648270 2072 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f
JB
2073 create one. */
2074static void
ab648270 2075XTset_vertical_scroll_bar (window, portion, whole, position)
f451eb13
JB
2076 struct window *window;
2077 int portion, whole, position;
2078{
2079 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
f451eb13 2080 int top = XINT (window->top);
ab648270
JB
2081 int left = WINDOW_VERTICAL_SCROLL_BAR_COLUMN (window);
2082 int height = WINDOW_VERTICAL_SCROLL_BAR_HEIGHT (window);
f451eb13 2083
ab648270 2084 /* Where should this scroll bar be, pixelwise? */
12ba150f
JB
2085 int pixel_top = CHAR_TO_PIXEL_ROW (f, top);
2086 int pixel_left = CHAR_TO_PIXEL_COL (f, left);
ab648270
JB
2087 int pixel_width = VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f);
2088 int pixel_height = VERTICAL_SCROLL_BAR_PIXEL_HEIGHT (f, height);
f451eb13 2089
ab648270 2090 struct scroll_bar *bar;
12ba150f 2091
ab648270
JB
2092 /* Does the scroll bar exist yet? */
2093 if (NILP (window->vertical_scroll_bar))
2094 bar = x_scroll_bar_create (window,
f451eb13
JB
2095 pixel_top, pixel_left,
2096 pixel_width, pixel_height);
2097 else
12ba150f
JB
2098 {
2099 /* It may just need to be moved and resized. */
ab648270
JB
2100 bar = XSCROLL_BAR (window->vertical_scroll_bar);
2101 x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
12ba150f 2102 }
f451eb13 2103
ab648270 2104 /* Set the scroll bar's current state, unless we're currently being
f451eb13 2105 dragged. */
12ba150f 2106 if (NILP (bar->dragging))
f451eb13 2107 {
12ba150f 2108 int top_range =
ab648270 2109 VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
f451eb13 2110
12ba150f 2111 if (whole == 0)
ab648270 2112 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
2113 else
2114 {
2115 int start = (position * top_range) / whole;
2116 int end = ((position + portion) * top_range) / whole;
2117
ab648270 2118 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 2119 }
f451eb13
JB
2120 }
2121
ab648270 2122 XSET (window->vertical_scroll_bar, Lisp_Vector, bar);
f451eb13
JB
2123}
2124
12ba150f 2125
f451eb13 2126/* The following three hooks are used when we're doing a thorough
ab648270 2127 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 2128 are going to be deleted, because keeping track of when windows go
12ba150f
JB
2129 away is a real pain - "Can you say set-window-configuration, boys
2130 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 2131 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 2132 from the fiery pit when we actually redisplay its window. */
f451eb13 2133
ab648270
JB
2134/* Arrange for all scroll bars on FRAME to be removed at the next call
2135 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
2136 `*redeem_scroll_bar_hook' is applied to its window before the judgement. */
f451eb13 2137static void
ab648270 2138XTcondemn_scroll_bars (frame)
f451eb13
JB
2139 FRAME_PTR frame;
2140{
12ba150f
JB
2141 /* The condemned list should be empty at this point; if it's not,
2142 then the rest of Emacs isn't using the condemn/redeem/judge
2143 protocol correctly. */
ab648270 2144 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
12ba150f
JB
2145 abort ();
2146
2147 /* Move them all to the "condemned" list. */
ab648270
JB
2148 FRAME_CONDEMNED_SCROLL_BARS (frame) = FRAME_SCROLL_BARS (frame);
2149 FRAME_SCROLL_BARS (frame) = Qnil;
f451eb13
JB
2150}
2151
ab648270 2152/* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
12ba150f 2153 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 2154static void
ab648270 2155XTredeem_scroll_bar (window)
12ba150f 2156 struct window *window;
f451eb13 2157{
ab648270 2158 struct scroll_bar *bar;
12ba150f 2159
ab648270
JB
2160 /* We can't redeem this window's scroll bar if it doesn't have one. */
2161 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
2162 abort ();
2163
ab648270 2164 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
2165
2166 /* Unlink it from the condemned list. */
2167 {
2168 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2169
2170 if (NILP (bar->prev))
2171 {
2172 /* If the prev pointer is nil, it must be the first in one of
2173 the lists. */
ab648270 2174 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
12ba150f
JB
2175 /* It's not condemned. Everything's fine. */
2176 return;
ab648270
JB
2177 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
2178 window->vertical_scroll_bar))
2179 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
12ba150f
JB
2180 else
2181 /* If its prev pointer is nil, it must be at the front of
2182 one or the other! */
2183 abort ();
2184 }
2185 else
ab648270 2186 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f
JB
2187
2188 if (! NILP (bar->next))
ab648270 2189 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 2190
ab648270 2191 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 2192 bar->prev = Qnil;
ab648270 2193 XSET (FRAME_SCROLL_BARS (f), Lisp_Vector, bar);
12ba150f 2194 if (! NILP (bar->next))
ab648270 2195 XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar);
12ba150f 2196 }
f451eb13
JB
2197}
2198
ab648270
JB
2199/* Remove all scroll bars on FRAME that haven't been saved since the
2200 last call to `*condemn_scroll_bars_hook'. */
f451eb13 2201static void
ab648270 2202XTjudge_scroll_bars (f)
12ba150f 2203 FRAME_PTR f;
f451eb13 2204{
12ba150f 2205 Lisp_Object bar, next;
f451eb13 2206
ab648270 2207 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
2208
2209 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
2210 more events on the hapless scroll bars. */
2211 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
2212
2213 for (; ! NILP (bar); bar = next)
f451eb13 2214 {
ab648270 2215 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 2216
ab648270 2217 x_scroll_bar_remove (b);
12ba150f
JB
2218
2219 next = b->next;
2220 b->next = b->prev = Qnil;
f451eb13 2221 }
12ba150f 2222
ab648270 2223 /* Now there should be no references to the condemned scroll bars,
12ba150f 2224 and they should get garbage-collected. */
f451eb13
JB
2225}
2226
2227
ab648270
JB
2228/* Handle an Expose or GraphicsExpose event on a scroll bar.
2229
2230 This may be called from a signal handler, so we have to ignore GC
2231 mark bits. */
f451eb13 2232static void
ab648270
JB
2233x_scroll_bar_expose (bar, event)
2234 struct scroll_bar *bar;
f451eb13
JB
2235 XEvent *event;
2236{
ab648270 2237 Window w = SCROLL_BAR_X_WINDOW (bar);
12ba150f
JB
2238 GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
2239
f451eb13
JB
2240 BLOCK_INPUT;
2241
ab648270 2242 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 2243
ab648270 2244 /* Draw a one-pixel border just inside the edges of the scroll bar. */
12ba150f 2245 XDrawRectangle (x_current_display, w, gc,
f451eb13
JB
2246
2247 /* x, y, width, height */
12ba150f 2248 0, 0, XINT (bar->width) - 1, XINT (bar->height) - 1);
f451eb13 2249
12ba150f
JB
2250 /* Draw another line to make the extra-thick border on the right. */
2251 XFillRectangle (x_current_display, w, gc,
f451eb13 2252
12ba150f
JB
2253 /* x, y, width, height */
2254 XINT (bar->width) - 2, 1, 1, XINT (bar->height) - 2);
f451eb13
JB
2255
2256 UNBLOCK_INPUT;
2257}
2258
ab648270
JB
2259/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2260 is set to something other than no_event, it is enqueued.
2261
2262 This may be called from a signal handler, so we have to ignore GC
2263 mark bits. */
f451eb13 2264static void
ab648270
JB
2265x_scroll_bar_handle_click (bar, event, emacs_event)
2266 struct scroll_bar *bar;
f451eb13
JB
2267 XEvent *event;
2268 struct input_event *emacs_event;
2269{
ab648270 2270 if (XGCTYPE (bar->window) != Lisp_Window)
12ba150f
JB
2271 abort ();
2272
ab648270 2273 emacs_event->kind = scroll_bar_click;
12ba150f 2274 XSET (emacs_event->code, Lisp_Int, event->xbutton.button - Button1);
f451eb13 2275 emacs_event->modifiers =
dfeccd2d 2276 (x_x_to_emacs_modifiers (event->xbutton.state)
f451eb13
JB
2277 | (event->type == ButtonRelease
2278 ? up_modifier
2279 : down_modifier));
12ba150f 2280 emacs_event->frame_or_window = bar->window;
f451eb13 2281 emacs_event->timestamp = event->xbutton.time;
12ba150f
JB
2282 {
2283 int internal_height =
ab648270 2284 VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
12ba150f 2285 int top_range =
ab648270
JB
2286 VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
2287 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
2288
2289 if (y < 0) y = 0;
2290 if (y > top_range) y = top_range;
2291
2292 if (y < XINT (bar->start))
ab648270
JB
2293 emacs_event->part = scroll_bar_above_handle;
2294 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2295 emacs_event->part = scroll_bar_handle;
12ba150f 2296 else
ab648270 2297 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
2298
2299 /* Just because the user has clicked on the handle doesn't mean
2300 they want to drag it. */
2301#if 0
12ba150f
JB
2302 /* If the user has just clicked on the handle, record where they're
2303 holding it. */
2304 if (event->type == ButtonPress
ab648270 2305 && emacs_event->part == scroll_bar_handle)
12ba150f 2306 XSET (bar->dragging, Lisp_Int, y - XINT (bar->start));
929787e1 2307#endif
12ba150f
JB
2308
2309 /* If the user has released the handle, set it to its final position. */
2310 if (event->type == ButtonRelease
2311 && ! NILP (bar->dragging))
2312 {
2313 int new_start = y - XINT (bar->dragging);
2314 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 2315
ab648270 2316 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
2317 bar->dragging = Qnil;
2318 }
f451eb13 2319
12ba150f
JB
2320 /* Clicks on the handle are always reported as occuring at the top of
2321 the handle. */
ab648270 2322 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
2323 emacs_event->x = bar->start;
2324 else
2325 XSET (emacs_event->x, Lisp_Int, y);
f451eb13 2326
12ba150f
JB
2327 XSET (emacs_event->y, Lisp_Int, top_range);
2328 }
2329}
f451eb13 2330
ab648270
JB
2331/* Handle some mouse motion while someone is dragging the scroll bar.
2332
2333 This may be called from a signal handler, so we have to ignore GC
2334 mark bits. */
f451eb13 2335static void
ab648270
JB
2336x_scroll_bar_note_movement (bar, event)
2337 struct scroll_bar *bar;
f451eb13
JB
2338 XEvent *event;
2339{
2340 last_mouse_movement_time = event->xmotion.time;
2341
2342 mouse_moved = 1;
ab648270 2343 XSET (last_mouse_scroll_bar, Lisp_Vector, bar);
f451eb13
JB
2344
2345 /* If we're dragging the bar, display it. */
ab648270 2346 if (! GC_NILP (bar->dragging))
f451eb13
JB
2347 {
2348 /* Where should the handle be now? */
12ba150f 2349 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 2350
12ba150f 2351 if (new_start != XINT (bar->start))
f451eb13 2352 {
12ba150f 2353 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 2354
ab648270 2355 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
2356 }
2357 }
2358
2359 /* Call XQueryPointer so we'll get an event the next time the mouse
2360 moves and we can see *still* on the same position. */
2361 {
2362 int dummy;
2363
2364 XQueryPointer (event->xmotion.display, event->xmotion.window,
2365 (Window *) &dummy, (Window *) &dummy,
2366 &dummy, &dummy, &dummy, &dummy,
2367 (unsigned int *) &dummy);
2368 }
2369}
2370
12ba150f 2371/* Return information to the user about the current position of the mouse
ab648270 2372 on the scroll bar. */
12ba150f 2373static void
ab648270 2374x_scroll_bar_report_motion (f, bar_window, part, x, y, time)
12ba150f
JB
2375 FRAME_PTR *f;
2376 Lisp_Object *bar_window;
ab648270 2377 enum scroll_bar_part *part;
12ba150f
JB
2378 Lisp_Object *x, *y;
2379 unsigned long *time;
2380{
ab648270 2381 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
12ba150f
JB
2382 int win_x, win_y;
2383
cf7cb199
JB
2384 BLOCK_INPUT;
2385
ab648270 2386 /* Get the mouse's position relative to the scroll bar window, and
12ba150f
JB
2387 report that. */
2388 {
2389 Window dummy_window;
2390 int dummy_coord;
2391 unsigned int dummy_mask;
2392
2393 if (! XQueryPointer (x_current_display,
ab648270 2394 SCROLL_BAR_X_WINDOW (bar),
12ba150f
JB
2395
2396 /* Root, child, root x and root y. */
2397 &dummy_window, &dummy_window,
2398 &dummy_coord, &dummy_coord,
2399
ab648270 2400 /* Position relative to scroll bar. */
12ba150f
JB
2401 &win_x, &win_y,
2402
2403 /* Mouse buttons and modifier keys. */
2404 &dummy_mask))
2405 {
2406 *f = 0;
cf7cb199 2407 goto done;
12ba150f
JB
2408 }
2409 }
2410
2411 {
ab648270
JB
2412 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
2413 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
12ba150f 2414
ab648270 2415 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
2416
2417 if (! NILP (bar->dragging))
2418 win_y -= XINT (bar->dragging);
2419
2420 if (win_y < 0)
2421 win_y = 0;
2422 if (win_y > top_range)
2423 win_y = top_range;
2424
2425 *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2426 *bar_window = bar->window;
2427
2428 if (! NILP (bar->dragging))
ab648270 2429 *part = scroll_bar_handle;
12ba150f 2430 else if (win_y < XINT (bar->start))
ab648270
JB
2431 *part = scroll_bar_above_handle;
2432 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2433 *part = scroll_bar_handle;
12ba150f 2434 else
ab648270 2435 *part = scroll_bar_below_handle;
12ba150f
JB
2436
2437 XSET (*x, Lisp_Int, win_y);
2438 XSET (*y, Lisp_Int, top_range);
2439 *time = last_mouse_movement_time;
2440 }
2441
2442 mouse_moved = 0;
ab648270 2443 last_mouse_scroll_bar = Qnil;
cf7cb199
JB
2444
2445 done:
2446 UNBLOCK_INPUT;
12ba150f
JB
2447}
2448
f451eb13 2449
dbc4e1c1 2450/* The screen has been cleared so we may have changed foreground or
ab648270
JB
2451 background colors, and the scroll bars may need to be redrawn.
2452 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
2453 redraw them. */
2454
ab648270 2455x_scroll_bar_clear (f)
dbc4e1c1
JB
2456 FRAME_PTR f;
2457{
2458 Lisp_Object bar;
2459
ab648270 2460 for (bar = FRAME_SCROLL_BARS (f);
dbc4e1c1 2461 XTYPE (bar) == Lisp_Vector;
ab648270
JB
2462 bar = XSCROLL_BAR (bar)->next)
2463 XClearArea (x_current_display, SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
dbc4e1c1
JB
2464 0, 0, 0, 0, True);
2465}
2466
2467
f451eb13
JB
2468\f
2469/* The main X event-reading loop - XTread_socket. */
dc6f92b8 2470
dc6f92b8
JB
2471/* Timestamp of enter window event. This is only used by XTread_socket,
2472 but we have to put it out here, since static variables within functions
2473 sometimes don't work. */
2474static Time enter_timestamp;
2475
11edeb03
JB
2476/* This holds the state XLookupString needs to implement dead keys
2477 and other tricks known as "compose processing". _X Window System_
2478 says that a portable program can't use this, but Stephen Gildea assures
2479 me that letting the compiler initialize it to zeros will work okay.
2480
2481 This must be defined outside of XTread_socket, for the same reasons
2482 given for enter_timestamp, above. */
2483static XComposeStatus compose_status;
2484
c047688c
JA
2485/* Communication with window managers. */
2486Atom Xatom_wm_protocols;
2487
2488/* Kinds of protocol things we may receive. */
2489Atom Xatom_wm_take_focus;
2490Atom Xatom_wm_save_yourself;
2491Atom Xatom_wm_delete_window;
2492
2493/* Other WM communication */
2494Atom Xatom_wm_configure_denied; /* When our config request is denied */
2495Atom Xatom_wm_window_moved; /* When the WM moves us. */
2496
d56a553a
RS
2497/* Window manager communication. */
2498Atom Xatom_wm_change_state;
2499
10e6549c
RS
2500/* Record the last 100 characters stored
2501 to help debug the loss-of-chars-during-GC problem. */
2502int temp_index;
2503short temp_buffer[100];
2504
dc6f92b8
JB
2505/* Read events coming from the X server.
2506 This routine is called by the SIGIO handler.
2507 We return as soon as there are no more events to be read.
2508
2509 Events representing keys are stored in buffer BUFP,
2510 which can hold up to NUMCHARS characters.
2511 We return the number of characters stored into the buffer,
2512 thus pretending to be `read'.
2513
2514 WAITP is nonzero if we should block until input arrives.
2515 EXPECTED is nonzero if the caller knows input is available. */
2516
7c5283e4 2517int
dc6f92b8
JB
2518XTread_socket (sd, bufp, numchars, waitp, expected)
2519 register int sd;
2520 register struct input_event *bufp;
2521 register int numchars;
2522 int waitp;
2523 int expected;
2524{
2525 int count = 0;
2526 int nbytes = 0;
2527 int mask;
2528 int items_pending; /* How many items are in the X queue. */
2529 XEvent event;
f676886a 2530 struct frame *f;
dc6f92b8
JB
2531 int event_found;
2532 int prefix;
2533 Lisp_Object part;
2534
9ac0d9e0 2535 if (interrupt_input_blocked)
dc6f92b8 2536 {
9ac0d9e0 2537 interrupt_input_pending = 1;
dc6f92b8
JB
2538 return -1;
2539 }
2540
9ac0d9e0 2541 interrupt_input_pending = 0;
dc6f92b8
JB
2542 BLOCK_INPUT;
2543
2544 if (numchars <= 0)
2545 abort (); /* Don't think this happens. */
2546
2547#ifdef FIOSNBIO
2548 /* If available, Xlib uses FIOSNBIO to make the socket
2549 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
2550 FIOSNBIO is ignored, and instead of signalling EWOULDBLOCK,
2551 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
2552 fcntl (fileno (stdin), F_SETFL, 0);
c118dd06 2553#endif /* ! defined (FIOSNBIO) */
dc6f92b8
JB
2554
2555#ifndef SIGIO
2556#ifndef HAVE_SELECT
2557 if (! (fcntl (fileno (stdin), F_GETFL, 0) & O_NDELAY))
2558 {
2559 extern int read_alarm_should_throw;
2560 read_alarm_should_throw = 1;
2561 XPeekEvent (XDISPLAY &event);
2562 read_alarm_should_throw = 0;
2563 }
c118dd06
JB
2564#endif /* HAVE_SELECT */
2565#endif /* SIGIO */
dc6f92b8
JB
2566
2567 while (XStuffPending () != 0)
2568 {
2569 XNextEvent (XDISPLAY &event);
2570 event_found = 1;
2571
2572 switch (event.type)
2573 {
2574#ifdef HAVE_X11
c047688c
JA
2575 case ClientMessage:
2576 {
2577 if (event.xclient.message_type == Xatom_wm_protocols
2578 && event.xclient.format == 32)
2579 {
2580 if (event.xclient.data.l[0] == Xatom_wm_take_focus)
2581 {
f676886a
JB
2582 f = x_window_to_frame (event.xclient.window);
2583 if (f)
2584 x_focus_on_frame (f);
ab648270 2585 /* Not certain about handling scroll bars here */
c047688c
JA
2586 }
2587 else if (event.xclient.data.l[0] == Xatom_wm_save_yourself)
2588 {
2589 /* Save state modify the WM_COMMAND property to
2590 something which can reinstate us. This notifies
2591 the session manager, who's looking for such a
2592 PropertyNotify. Can restart processing when
2593 a keyboard or mouse event arrives. */
2594 if (numchars > 0)
2595 {
2596 }
2597 }
2598 else if (event.xclient.data.l[0] == Xatom_wm_delete_window)
2599 {
f676886a 2600 struct frame *f = x_window_to_frame (event.xclient.window);
c047688c 2601
f676886a 2602 if (f)
c047688c
JA
2603 if (numchars > 0)
2604 {
2605 }
2606 }
2607 }
2608 else if (event.xclient.message_type == Xatom_wm_configure_denied)
2609 {
2610 }
2611 else if (event.xclient.message_type == Xatom_wm_window_moved)
2612 {
2613 int new_x, new_y;
2614
4357eba7
JB
2615 new_x = event.xclient.data.s[0];
2616 new_y = event.xclient.data.s[1];
c047688c
JA
2617 }
2618 }
2619 break;
dc6f92b8 2620
d56a553a
RS
2621#ifdef NEW_SELECTIONS
2622 case SelectionNotify:
2623 x_handle_selection_notify (&event);
2624 break;
2625#endif
2626
dc6f92b8 2627 case SelectionClear: /* Someone has grabbed ownership. */
d56a553a
RS
2628#ifdef NEW_SELECTIONS
2629 {
2630 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
2631
2632 if (numchars == 0)
2633 abort ();
2634
2635 bufp->kind = selection_clear_event;
2636 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
2637 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
2638 SELECTION_EVENT_TIME (bufp) = eventp->time;
2639 bufp++;
2640
2641 count += 1;
2642 numchars -= 1;
2643 }
2644#else
dc6f92b8
JB
2645 x_disown_selection (event.xselectionclear.window,
2646 event.xselectionclear.selection,
2647 event.xselectionclear.time);
d56a553a 2648#endif
dc6f92b8
JB
2649 break;
2650
2651 case SelectionRequest: /* Someone wants our selection. */
d56a553a
RS
2652#ifdef NEW_SELECTIONS
2653 {
2654 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
2655
2656 if (numchars == 0)
2657 abort ();
2658
2659 bufp->kind = selection_request_event;
2660 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
2661 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
2662 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
2663 SELECTION_EVENT_TARGET (bufp) = eventp->target;
2664 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
2665 SELECTION_EVENT_TIME (bufp) = eventp->time;
2666 bufp++;
2667
2668 count += 1;
2669 numchars -= 1;
2670 }
2671#else
dc6f92b8 2672 x_answer_selection_request (event);
d56a553a 2673#endif
dc6f92b8
JB
2674 break;
2675
2676 case PropertyNotify:
d56a553a
RS
2677#ifdef NEW_SELECTIONS
2678 x_handle_property_notify (&event);
2679#else
28430d3c
JB
2680 /* If we're being told about a root window property, then it's
2681 a cut buffer change. */
2682 if (event.xproperty.window == ROOT_WINDOW)
2683 x_invalidate_cut_buffer_cache (&event.xproperty);
2684
2685 /* Otherwise, we're probably handling an incremental
2686 selection transmission. */
2687 else
2688 {
2689 /* If we were to do this synchronously, there'd be no worry
2690 about re-selecting. */
2691 x_send_incremental (event);
2692 }
d56a553a 2693#endif
dc6f92b8
JB
2694 break;
2695
2696 case Expose:
f676886a
JB
2697 f = x_window_to_frame (event.xexpose.window);
2698 if (f)
dc6f92b8 2699 {
3a88c238 2700 if (f->async_visible == 0)
dc6f92b8 2701 {
3a88c238
JB
2702 f->async_visible = 1;
2703 f->async_iconified = 0;
f676886a 2704 SET_FRAME_GARBAGED (f);
dc6f92b8
JB
2705 }
2706 else
f451eb13
JB
2707 {
2708 dumprectangle (x_window_to_frame (event.xexpose.window),
2709 event.xexpose.x, event.xexpose.y,
2710 event.xexpose.width, event.xexpose.height);
f451eb13
JB
2711 }
2712 }
2713 else
2714 {
ab648270
JB
2715 struct scroll_bar *bar
2716 = x_window_to_scroll_bar (event.xexpose.window);
f451eb13
JB
2717
2718 if (bar)
ab648270 2719 x_scroll_bar_expose (bar, &event);
dc6f92b8
JB
2720 }
2721 break;
2722
2723 case GraphicsExpose: /* This occurs when an XCopyArea's
2724 source area was obscured or not
2725 available.*/
f451eb13
JB
2726 f = x_window_to_frame (event.xgraphicsexpose.drawable);
2727 if (f)
2728 {
2729 dumprectangle (f,
2730 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
2731 event.xgraphicsexpose.width,
2732 event.xgraphicsexpose.height);
f451eb13 2733 }
dc6f92b8
JB
2734 break;
2735
2736 case NoExpose: /* This occurs when an XCopyArea's
2737 source area was completely
2738 available */
2739 break;
c118dd06 2740#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
2741 case ExposeWindow:
2742 if (event.subwindow != 0)
2743 break; /* duplicate event */
f676886a
JB
2744 f = x_window_to_frame (event.window);
2745 if (event.window == f->display.x->icon_desc)
dc6f92b8 2746 {
f676886a 2747 refreshicon (f);
3a88c238 2748 f->async_iconified = 1;
dc6f92b8 2749 }
c118dd06 2750 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8
JB
2751 {
2752 /* Say must check all windows' needs_exposure flags. */
2753 expose_all_windows = 1;
f676886a 2754 f->display.x->needs_exposure = 1;
3a88c238 2755 f->async_visible = 1;
dc6f92b8
JB
2756 }
2757 break;
2758
2759 case ExposeRegion:
2760 if (event.subwindow != 0)
2761 break; /* duplicate event */
f676886a
JB
2762 f = x_window_to_frame (event.window);
2763 if (event.window == f->display.x->icon_desc)
dc6f92b8 2764 {
f676886a 2765 refreshicon (f);
dc6f92b8
JB
2766 break;
2767 }
2768 /* If window already needs full redraw, ignore this rectangle. */
f676886a 2769 if (expose_all_windows && f->display.x->needs_exposure)
dc6f92b8
JB
2770 break;
2771 /* Put the event on the queue of rectangles to redraw. */
2772 if (enqueue_event (&event, &x_expose_queue))
2773 /* If it is full, we can't record the rectangle,
2774 so redraw this entire window. */
2775 {
2776 /* Say must check all windows' needs_exposure flags. */
2777 expose_all_windows = 1;
f676886a 2778 f->display.x->needs_exposure = 1;
dc6f92b8
JB
2779 }
2780 break;
2781
2782 case ExposeCopy:
2783 /* This should happen only when we are expecting it,
2784 in x_read_exposes. */
2785 abort ();
c118dd06 2786#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
2787
2788#ifdef HAVE_X11
2789 case UnmapNotify:
f451eb13
JB
2790 f = x_window_to_frame (event.xunmap.window);
2791 if (f) /* F may no longer exist if
f676886a 2792 the frame was deleted. */
f451eb13
JB
2793 {
2794 /* While a frame is unmapped, display generation is
2795 disabled; you don't want to spend time updating a
2796 display that won't ever be seen. */
2797 f->async_visible = 0;
2798 }
dc6f92b8
JB
2799 break;
2800
2801 case MapNotify:
f676886a
JB
2802 f = x_window_to_frame (event.xmap.window);
2803 if (f)
dc6f92b8 2804 {
3a88c238
JB
2805 f->async_visible = 1;
2806 f->async_iconified = 0;
dc6f92b8
JB
2807
2808 /* wait_reading_process_input will notice this and update
f676886a
JB
2809 the frame's display structures. */
2810 SET_FRAME_GARBAGED (f);
dc6f92b8
JB
2811 }
2812 break;
2813
2814 /* Turn off processing if we become fully obscured. */
2815 case VisibilityNotify:
2816 break;
2817
c118dd06 2818#else /* ! defined (HAVE_X11) */
dc6f92b8 2819 case UnmapWindow:
f676886a
JB
2820 f = x_window_to_frame (event.window);
2821 if (event.window == f->display.x->icon_desc)
3a88c238 2822 f->async_iconified = 0;
c118dd06 2823 if (event.window == FRAME_X_WINDOW (f))
3a88c238 2824 f->async_visible = 0;
dc6f92b8 2825 break;
c118dd06 2826#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
2827
2828#ifdef HAVE_X11
2829 case KeyPress:
f676886a 2830 f = x_window_to_frame (event.xkey.window);
f451eb13 2831
f676886a 2832 if (f != 0)
dc6f92b8
JB
2833 {
2834 KeySym keysym;
dc6f92b8 2835 char copy_buffer[80];
64bb1782
RS
2836 int modifiers;
2837
dfeccd2d
JB
2838 event.xkey.state
2839 |= x_emacs_to_x_modifiers (extra_keyboard_modifiers);
64bb1782 2840 modifiers = event.xkey.state;
3a2712f9 2841
11edeb03 2842 /* This will have to go some day... */
752a043f
JB
2843
2844 /* make_lispy_event turns chars into control chars.
2845 Don't do it here because XLookupString is too eager. */
2846 event.xkey.state &= ~ControlMask;
11edeb03
JB
2847 nbytes =
2848 XLookupString (&event.xkey, copy_buffer, 80, &keysym,
2849 &compose_status);
dc6f92b8 2850
55123275
JB
2851 /* Strip off the vendor-specific keysym bit, and take a shot
2852 at recognizing the codes. HP servers have extra keysyms
2853 that fit into the MiscFunctionKey category. */
2854 keysym &= ~(1<<28);
2855
dc6f92b8
JB
2856 if (numchars > 1)
2857 {
a3c44b14
RS
2858 if ((keysym >= XK_BackSpace && keysym <= XK_Escape)
2859 || keysym == XK_Delete
2860 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
55123275
JB
2861 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < 0xff80 */
2862 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
2863 || IsFunctionKey (keysym)) /* 0xffbe <= x < 0xffe1 */
dc6f92b8 2864 {
10e6549c
RS
2865 if (temp_index == sizeof temp_buffer / sizeof (short))
2866 temp_index = 0;
2867 temp_buffer[temp_index++] = keysym;
dc6f92b8 2868 bufp->kind = non_ascii_keystroke;
a3c44b14 2869 XSET (bufp->code, Lisp_Int, (unsigned) keysym - 0xff00);
12ba150f 2870 XSET (bufp->frame_or_window, Lisp_Frame, f);
dfeccd2d 2871 bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
1113d9db 2872 bufp->timestamp = event.xkey.time;
dc6f92b8
JB
2873 bufp++;
2874 count++;
2875 numchars--;
2876 }
2877 else if (numchars > nbytes)
2878 {
2879 register int i;
2880
10e6549c 2881 for (i = 0; i < nbytes; i++)
dc6f92b8 2882 {
10e6549c
RS
2883 if (temp_index == sizeof temp_buffer / sizeof (short))
2884 temp_index = 0;
2885 temp_buffer[temp_index++] = copy_buffer[i];
dc6f92b8 2886 bufp->kind = ascii_keystroke;
10e6549c 2887 XSET (bufp->code, Lisp_Int, copy_buffer[i]);
12ba150f 2888 XSET (bufp->frame_or_window, Lisp_Frame, f);
dfeccd2d 2889 bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
1113d9db 2890 bufp->timestamp = event.xkey.time;
dc6f92b8
JB
2891 bufp++;
2892 }
dc6f92b8
JB
2893
2894 count += nbytes;
2895 numchars -= nbytes;
2896 }
10e6549c
RS
2897 else
2898 abort ();
dc6f92b8 2899 }
10e6549c
RS
2900 else
2901 abort ();
dc6f92b8
JB
2902 }
2903 break;
c118dd06 2904#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
2905 case KeyPressed:
2906 {
2907 register char *where_mapping;
2908
f676886a 2909 f = x_window_to_frame (event.window);
dc6f92b8 2910 /* Ignore keys typed on icon windows. */
f676886a 2911 if (f != 0 && event.window == f->display.x->icon_desc)
dc6f92b8
JB
2912 break;
2913 where_mapping = XLookupMapping (&event, &nbytes);
2914 /* Nasty fix for arrow keys */
2915 if (!nbytes && IsCursorKey (event.detail & 0xff))
2916 {
2917 switch (event.detail & 0xff)
2918 {
2919 case KC_CURSOR_LEFT:
2920 where_mapping = "\002";
2921 break;
2922 case KC_CURSOR_RIGHT:
2923 where_mapping = "\006";
2924 break;
2925 case KC_CURSOR_UP:
2926 where_mapping = "\020";
2927 break;
2928 case KC_CURSOR_DOWN:
2929 where_mapping = "\016";
2930 break;
2931 }
2932 nbytes = 1;
2933 }
2934 if (numchars - nbytes > 0)
2935 {
2936 register int i;
2937
2938 for (i = 0; i < nbytes; i++)
2939 {
2940 bufp->kind = ascii_keystroke;
2941 XSET (bufp->code, Lisp_Int, where_mapping[i]);
90e65f07 2942 XSET (bufp->time, Lisp_Int, event.xkey.time);
12ba150f 2943 XSET (bufp->frame_or_window, Lisp_Frame, f);
dc6f92b8
JB
2944 bufp++;
2945 }
2946 count += nbytes;
2947 numchars -= nbytes;
2948 }
2949 }
2950 break;
c118dd06 2951#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
2952
2953#ifdef HAVE_X11
f451eb13
JB
2954
2955 /* Here's a possible interpretation of the whole
2956 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If you get a
2957 FocusIn event, you have to get a FocusOut event before you
2958 relinquish the focus. If you haven't received a FocusIn event,
2959 then a mere LeaveNotify is enough to free you. */
2960
dc6f92b8 2961 case EnterNotify:
f676886a 2962 f = x_window_to_frame (event.xcrossing.window);
6d4238f3 2963
f451eb13 2964 if (event.xcrossing.focus) /* Entered Window */
dc6f92b8 2965 {
dc6f92b8 2966 /* Avoid nasty pop/raise loops. */
f676886a
JB
2967 if (f && (!(f->auto_raise)
2968 || !(f->auto_lower)
dc6f92b8
JB
2969 || (event.xcrossing.time - enter_timestamp) > 500))
2970 {
f676886a 2971 x_new_focus_frame (f);
dc6f92b8
JB
2972 enter_timestamp = event.xcrossing.time;
2973 }
dc6f92b8 2974 }
f676886a
JB
2975 else if (f == x_focus_frame)
2976 x_new_focus_frame (0);
dc6f92b8
JB
2977
2978 break;
2979
2980 case FocusIn:
f676886a 2981 f = x_window_to_frame (event.xfocus.window);
f451eb13
JB
2982 if (event.xfocus.detail != NotifyPointer)
2983 x_focus_event_frame = f;
f676886a
JB
2984 if (f)
2985 x_new_focus_frame (f);
dc6f92b8
JB
2986 break;
2987
f451eb13 2988
dc6f92b8 2989 case LeaveNotify:
f451eb13 2990 f = x_window_to_frame (event.xcrossing.window);
b1c884c3 2991
f451eb13
JB
2992 if (event.xcrossing.focus)
2993 {
2994 if (! x_focus_event_frame)
2995 x_new_focus_frame (0);
2996 else
f676886a 2997 x_new_focus_frame (f);
f451eb13
JB
2998 }
2999 else
3000 {
3001 if (f == x_focus_event_frame)
3002 x_focus_event_frame = 0;
3003 if (f == x_focus_frame)
f676886a 3004 x_new_focus_frame (0);
dc6f92b8
JB
3005 }
3006 break;
3007
3008 case FocusOut:
f676886a 3009 f = x_window_to_frame (event.xfocus.window);
f451eb13
JB
3010 if (event.xfocus.detail != NotifyPointer
3011 && f == x_focus_event_frame)
3012 x_focus_event_frame = 0;
f676886a
JB
3013 if (f && f == x_focus_frame)
3014 x_new_focus_frame (0);
dc6f92b8
JB
3015 break;
3016
c118dd06 3017#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3018
3019 case EnterWindow:
3020 if ((event.detail & 0xFF) == 1)
3021 break; /* Coming from our own subwindow */
3022 if (event.subwindow != 0)
3023 break; /* Entering our own subwindow. */
3024
3025 {
f676886a
JB
3026 f = x_window_to_frame (event.window);
3027 x_mouse_frame = f;
dc6f92b8 3028
f676886a 3029 x_new_focus_frame (f);
dc6f92b8
JB
3030 }
3031 break;
3032
3033 case LeaveWindow:
3034 if ((event.detail & 0xFF) == 1)
3035 break; /* Entering our own subwindow */
3036 if (event.subwindow != 0)
3037 break; /* Leaving our own subwindow. */
3038
f676886a
JB
3039 x_mouse_frame = 0;
3040 if (x_focus_frame == 0
3041 && x_input_frame != 0
3042 && x_input_frame == x_window_to_frame (event.window)
c118dd06 3043 && event.window == FRAME_X_WINDOW (x_input_frame))
dc6f92b8 3044 {
f676886a
JB
3045 f = x_input_frame;
3046 x_input_frame = 0;
3047 if (f)
3048 frame_unhighlight (f);
dc6f92b8
JB
3049 }
3050 break;
c118dd06 3051#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3052
3053#ifdef HAVE_X11
3054 case MotionNotify:
3055 {
f676886a
JB
3056 f = x_window_to_frame (event.xmotion.window);
3057 if (f)
12ba150f 3058 note_mouse_movement (f, &event.xmotion);
f451eb13 3059 else
dc6f92b8 3060 {
ab648270
JB
3061 struct scroll_bar *bar =
3062 x_window_to_scroll_bar (event.xmotion.window);
f451eb13
JB
3063
3064 if (bar)
ab648270 3065 x_scroll_bar_note_movement (bar, &event);
dc6f92b8 3066 }
dc6f92b8
JB
3067 }
3068 break;
3069
3070 case ConfigureNotify:
dbc4e1c1
JB
3071 f = x_window_to_frame (event.xconfigure.window);
3072 if (f)
3073 {
3074 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
3075 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
3076
3077 /* Even if the number of character rows and columns has
3078 not changed, the font size may have changed, so we need
3079 to check the pixel dimensions as well. */
3080 if (columns != f->width
3081 || rows != f->height
3082 || event.xconfigure.width != f->display.x->pixel_width
3083 || event.xconfigure.height != f->display.x->pixel_height)
3084 {
3085 change_frame_size (f, rows, columns, 0, 1);
3086 SET_FRAME_GARBAGED (f);
3087 }
dc6f92b8 3088
dbc4e1c1
JB
3089 f->display.x->pixel_width = event.xconfigure.width;
3090 f->display.x->pixel_height = event.xconfigure.height;
3091 f->display.x->left_pos = event.xconfigure.x;
3092 f->display.x->top_pos = event.xconfigure.y;
3093 }
3094 break;
dc6f92b8
JB
3095
3096 case ButtonPress:
3097 case ButtonRelease:
3098 {
3099 /* If we decide we want to generate an event to be seen
3100 by the rest of Emacs, we put it here. */
3101 struct input_event emacs_event;
3102 emacs_event.kind = no_event;
3103
f676886a
JB
3104 f = x_window_to_frame (event.xbutton.window);
3105 if (f)
f451eb13
JB
3106 {
3107 if (!x_focus_frame || (f == x_focus_frame))
3108 construct_mouse_click (&emacs_event,
b10fd412 3109 &event, f);
f451eb13 3110 }
dc6f92b8 3111 else
f451eb13 3112 {
ab648270
JB
3113 struct scroll_bar *bar =
3114 x_window_to_scroll_bar (event.xbutton.window);
f451eb13
JB
3115
3116 if (bar)
ab648270 3117 x_scroll_bar_handle_click (bar, &event, &emacs_event);
f451eb13 3118 }
dc6f92b8
JB
3119
3120 if (numchars >= 1 && emacs_event.kind != no_event)
3121 {
3122 bcopy (&emacs_event, bufp, sizeof (struct input_event));
3123 bufp++;
3124 count++;
3125 numchars--;
3126 }
3127 }
3128 break;
3129
c118dd06 3130#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3131 case ButtonPressed:
3132 case ButtonReleased:
f676886a
JB
3133 f = x_window_to_frame (event.window);
3134 if (f)
dc6f92b8 3135 {
f676886a 3136 if (event.window == f->display.x->icon_desc)
dc6f92b8 3137 {
f676886a 3138 x_make_frame_visible (f);
dc6f92b8
JB
3139
3140 if (warp_mouse_on_deiconify)
c118dd06 3141 XWarpMouse (FRAME_X_WINDOW (f), 10, 10);
dc6f92b8
JB
3142 break;
3143 }
c118dd06 3144 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8 3145 {
f676886a
JB
3146 if (f->auto_raise)
3147 x_raise_frame (f);
dc6f92b8
JB
3148 }
3149 }
3150 enqueue_event (&event, &x_mouse_queue);
3151 if (numchars >= 2)
3152 {
3153 bufp->kind = ascii_keystroke;
3154 bufp->code = (char) 'X' & 037; /* C-x */
12ba150f 3155 XSET (bufp->frame_or_window, Lisp_Frame, f);
90e65f07 3156 XSET (bufp->time, Lisp_Int, event.xkey.time);
dc6f92b8
JB
3157 bufp++;
3158
3159 bufp->kind = ascii_keystroke;
3160 bufp->code = (char) 0; /* C-@ */
12ba150f 3161 XSET (bufp->frame_or_window, Lisp_Frame, f);
90e65f07 3162 XSET (bufp->time, Lisp_Int, event.xkey.time);
dc6f92b8
JB
3163 bufp++;
3164
3165 count += 2;
3166 numchars -= 2;
3167 }
3168 break;
c118dd06 3169#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3170
3171#ifdef HAVE_X11
3172
3173 case CirculateNotify:
3174 break;
3175 case CirculateRequest:
3176 break;
3177
c118dd06 3178#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3179
3180 case MappingNotify:
11edeb03
JB
3181 /* Someone has changed the keyboard mapping - update the
3182 local cache. */
3183 switch (event.xmapping.request)
3184 {
3185 case MappingModifier:
3186 x_find_modifier_meanings ();
3187 /* This is meant to fall through. */
3188 case MappingKeyboard:
3189 XRefreshKeyboardMapping (&event.xmapping);
3190 }
dc6f92b8
JB
3191 break;
3192
3193 default:
3194 break;
3195 }
3196 }
3197
3198#if 0
3199#ifdef HAVE_SELECT
3200 if (expected && ! event_found)
3201 {
3202 /* AOJ 880406: if select returns true but XPending doesn't, it means that
3203 there is an EOF condition; in other words, that X has died.
3204 Act as if there had been a hangup. */
3205
3206 int fd = ConnectionNumber (x_current_display);
3207 int mask = 1 << fd;
3208
3209 if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0,
3a2712f9 3210 (EMACS_TIME) 0)
dc6f92b8
JB
3211 && !XStuffPending ())
3212 kill (getpid (), SIGHUP);
3213 }
c118dd06
JB
3214#endif /* ! defined (HAVE_SELECT) */
3215#endif /* ! 0 */
dc6f92b8 3216
f451eb13 3217#ifndef HAVE_X11
f676886a 3218 if (updating_frame == 0)
dc6f92b8 3219 x_do_pending_expose ();
f451eb13 3220#endif
dc6f92b8
JB
3221
3222 UNBLOCK_INPUT;
3223 return count;
3224}
3225
3226#ifndef HAVE_X11
3227/* Read and process only Expose events
3228 until we get an ExposeCopy event; then return.
3229 This is used in insert/delete line.
3230 We assume input is already blocked. */
3231
3232static void
3233x_read_exposes ()
3234{
f676886a 3235 struct frame *f;
dc6f92b8
JB
3236 XKeyPressedEvent event;
3237
3238 while (1)
3239 {
3240 /* while there are more events*/
3241 XMaskEvent (ExposeWindow | ExposeRegion | ExposeCopy, &event);
3242 switch (event.type)
3243 {
3244 case ExposeWindow:
3245 if (event.subwindow != 0)
3246 break; /* duplicate event */
f676886a
JB
3247 f = x_window_to_frame (event.window);
3248 if (event.window == f->display.x->icon_desc)
dc6f92b8 3249 {
f676886a 3250 refreshicon (f);
dc6f92b8
JB
3251 break;
3252 }
c118dd06 3253 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8
JB
3254 {
3255 expose_all_windows = 1;
f676886a 3256 f->display.x->needs_exposure = 1;
dc6f92b8
JB
3257 break;
3258 }
3259 break;
3260
3261 case ExposeRegion:
3262 if (event.subwindow != 0)
3263 break; /* duplicate event */
f676886a
JB
3264 f = x_window_to_frame (event.window);
3265 if (event.window == f->display.x->icon_desc)
dc6f92b8 3266 {
f676886a 3267 refreshicon (f);
dc6f92b8
JB
3268 break;
3269 }
3270 /* If window already needs full redraw, ignore this rectangle. */
f676886a 3271 if (expose_all_windows && f->display.x->needs_exposure)
dc6f92b8
JB
3272 break;
3273 /* Put the event on the queue of rectangles to redraw. */
3274 if (enqueue_event (&event, &x_expose_queue))
3275 /* If it is full, we can't record the rectangle,
3276 so redraw this entire window. */
3277 {
3278 /* Say must check all windows' needs_exposure flags. */
3279 expose_all_windows = 1;
f676886a 3280 f->display.x->needs_exposure = 1;
dc6f92b8
JB
3281 }
3282 break;
3283
3284 case ExposeCopy:
3285 return;
3286 }
3287 }
3288}
3289#endif /* HAVE_X11 */
3290
dc6f92b8 3291\f
f451eb13
JB
3292/* Drawing the cursor. */
3293
3294
dc6f92b8
JB
3295/* Draw a hollow box cursor. Don't change the inside of the box. */
3296
3297static void
f676886a
JB
3298x_draw_box (f)
3299 struct frame *f;
dc6f92b8 3300{
12ba150f
JB
3301 int left = CHAR_TO_PIXEL_COL (f, f->cursor_x);
3302 int top = CHAR_TO_PIXEL_ROW (f, f->cursor_y);
f676886a
JB
3303 int width = FONT_WIDTH (f->display.x->font);
3304 int height = FONT_HEIGHT (f->display.x->font);
dc6f92b8
JB
3305
3306#ifdef HAVE_X11
c118dd06 3307 XDrawRectangle (x_current_display, FRAME_X_WINDOW (f),
f676886a 3308 f->display.x->cursor_gc,
dc6f92b8 3309 left, top, width - 1, height - 1);
c118dd06
JB
3310#else /* ! defined (HAVE_X11) */
3311 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3312 left, top, width, 1,
f676886a 3313 f->display.x->cursor_pixel);
dc6f92b8 3314
c118dd06 3315 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3316 left, top, 1, height,
f676886a 3317 f->display.x->cursor_pixel);
dc6f92b8 3318
c118dd06 3319 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3320 left+width-1, top, 1, height,
f676886a 3321 f->display.x->cursor_pixel);
dc6f92b8 3322
c118dd06 3323 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3324 left, top+height-1, width, 1,
f676886a 3325 f->display.x->cursor_pixel);
c118dd06 3326#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3327}
3328
f676886a 3329/* Clear the cursor of frame F to background color,
dc6f92b8
JB
3330 and mark the cursor as not shown.
3331 This is used when the text where the cursor is
3332 is about to be rewritten. */
3333
3334static void
f676886a
JB
3335clear_cursor (f)
3336 struct frame *f;
dc6f92b8
JB
3337{
3338 int mask;
3339
f451eb13 3340 if (! FRAME_VISIBLE_P (f)
f676886a 3341 || f->phys_cursor_x < 0)
dc6f92b8
JB
3342 return;
3343
3344#ifdef HAVE_X11
f676886a 3345 x_display_cursor (f, 0);
c118dd06
JB
3346#else /* ! defined (HAVE_X11) */
3347 XPixSet (FRAME_X_WINDOW (f),
12ba150f
JB
3348 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
3349 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
f676886a
JB
3350 FONT_WIDTH (f->display.x->font), FONT_HEIGHT (f->display.x->font),
3351 f->display.x->background_pixel);
c118dd06 3352#endif /* ! defined (HAVE_X11) */
f676886a 3353 f->phys_cursor_x = -1;
dc6f92b8
JB
3354}
3355
f676886a 3356/* Redraw the glyph at ROW, COLUMN on frame F, in the style
90e65f07
JB
3357 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
3358 glyph drawn. */
dc6f92b8
JB
3359
3360static void
f676886a
JB
3361x_draw_single_glyph (f, row, column, glyph, highlight)
3362 struct frame *f;
dc6f92b8 3363 int row, column;
90e65f07 3364 GLYPH glyph;
dc6f92b8
JB
3365 int highlight;
3366{
f676886a 3367 dumpglyphs (f,
12ba150f
JB
3368 CHAR_TO_PIXEL_COL (f, column),
3369 CHAR_TO_PIXEL_ROW (f, row),
07e34cb0 3370 &glyph, 1, highlight);
dc6f92b8
JB
3371}
3372
dc6f92b8 3373static void
dbc4e1c1 3374x_display_bar_cursor (f, on)
f676886a 3375 struct frame *f;
dc6f92b8
JB
3376 int on;
3377{
f676886a 3378 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
90e65f07 3379
49d838ea
JB
3380 /* This is pointless on invisible frames, and dangerous on garbaged
3381 frames; in the latter case, the frame may be in the midst of
3382 changing its size, and curs_x and curs_y may be off the frame. */
3383 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dbc4e1c1
JB
3384 return;
3385
3386 if (! on && f->phys_cursor_x < 0)
3387 return;
3388
f676886a 3389 /* If we're not updating, then we want to use the current frame's
1113d9db 3390 cursor position, not our local idea of where the cursor ought to be. */
f676886a 3391 if (f != updating_frame)
1113d9db 3392 {
f676886a
JB
3393 curs_x = FRAME_CURSOR_X (f);
3394 curs_y = FRAME_CURSOR_Y (f);
1113d9db
JB
3395 }
3396
dbc4e1c1
JB
3397 /* If there is anything wrong with the current cursor state, remove it. */
3398 if (f->phys_cursor_x >= 0
3399 && (!on
3400 || f->phys_cursor_x != curs_x
3401 || f->phys_cursor_y != curs_y
3402 || f->display.x->current_cursor != bar_cursor))
3403 {
3404 /* Erase the cursor by redrawing the character underneath it. */
3405 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
3406 f->phys_cursor_glyph,
3407 current_glyphs->highlight[f->phys_cursor_y]);
3408 f->phys_cursor_x = -1;
3409 }
3410
3411 /* If we now need a cursor in the new place or in the new form, do it so. */
3412 if (on
3413 && (f->phys_cursor_x < 0
3414 || (f->display.x->current_cursor != bar_cursor)))
3415 {
3416 f->phys_cursor_glyph
3417 = ((current_glyphs->enable[curs_y]
3418 && curs_x < current_glyphs->used[curs_y])
3419 ? current_glyphs->glyphs[curs_y][curs_x]
3420 : SPACEGLYPH);
3421 XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
3422 f->display.x->cursor_gc,
3423 CHAR_TO_PIXEL_COL (f, curs_x),
3424 CHAR_TO_PIXEL_ROW (f, curs_y),
3425 1, FONT_HEIGHT (f->display.x->font));
3426
3427 f->phys_cursor_x = curs_x;
3428 f->phys_cursor_y = curs_y;
3429
3430 f->display.x->current_cursor = bar_cursor;
3431 }
3432
3433 if (updating_frame != f)
3434 XFlushQueue ();
3435}
3436
3437
3438/* Turn the displayed cursor of frame F on or off according to ON.
3439 If ON is nonzero, where to put the cursor is specified
3440 by F->cursor_x and F->cursor_y. */
3441
3442static void
3443x_display_box_cursor (f, on)
3444 struct frame *f;
3445 int on;
3446{
3447 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
3448
49d838ea
JB
3449 /* This is pointless on invisible frames, and dangerous on garbaged
3450 frames; in the latter case, the frame may be in the midst of
3451 changing its size, and curs_x and curs_y may be off the frame. */
3452 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dc6f92b8
JB
3453 return;
3454
3455 /* If cursor is off and we want it off, return quickly. */
f676886a 3456 if (!on && f->phys_cursor_x < 0)
dc6f92b8
JB
3457 return;
3458
dbc4e1c1
JB
3459 /* If we're not updating, then we want to use the current frame's
3460 cursor position, not our local idea of where the cursor ought to be. */
3461 if (f != updating_frame)
3462 {
3463 curs_x = FRAME_CURSOR_X (f);
3464 curs_y = FRAME_CURSOR_Y (f);
3465 }
3466
dc6f92b8
JB
3467 /* If cursor is currently being shown and we don't want it to be
3468 or it is in the wrong place,
3469 or we want a hollow box and it's not so, (pout!)
3470 erase it. */
f676886a 3471 if (f->phys_cursor_x >= 0
dc6f92b8 3472 && (!on
f676886a
JB
3473 || f->phys_cursor_x != curs_x
3474 || f->phys_cursor_y != curs_y
dbc4e1c1 3475 || (f->display.x->current_cursor != hollow_box_cursor
f676886a 3476 && (f != x_highlight_frame))))
dc6f92b8
JB
3477 {
3478 /* Erase the cursor by redrawing the character underneath it. */
f676886a
JB
3479 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
3480 f->phys_cursor_glyph,
3481 current_glyphs->highlight[f->phys_cursor_y]);
3482 f->phys_cursor_x = -1;
dc6f92b8
JB
3483 }
3484
3485 /* If we want to show a cursor,
3486 or we want a box cursor and it's not so,
3487 write it in the right place. */
3488 if (on
f676886a 3489 && (f->phys_cursor_x < 0
dbc4e1c1 3490 || (f->display.x->current_cursor != filled_box_cursor
f676886a 3491 && f == x_highlight_frame)))
dc6f92b8 3492 {
f676886a 3493 f->phys_cursor_glyph
1113d9db
JB
3494 = ((current_glyphs->enable[curs_y]
3495 && curs_x < current_glyphs->used[curs_y])
3496 ? current_glyphs->glyphs[curs_y][curs_x]
90e65f07 3497 : SPACEGLYPH);
f676886a 3498 if (f != x_highlight_frame)
dc6f92b8 3499 {
f676886a 3500 x_draw_box (f);
dbc4e1c1 3501 f->display.x->current_cursor = hollow_box_cursor;
dc6f92b8
JB
3502 }
3503 else
3504 {
f676886a
JB
3505 x_draw_single_glyph (f, curs_y, curs_x,
3506 f->phys_cursor_glyph, 2);
dbc4e1c1 3507 f->display.x->current_cursor = filled_box_cursor;
dc6f92b8
JB
3508 }
3509
f676886a
JB
3510 f->phys_cursor_x = curs_x;
3511 f->phys_cursor_y = curs_y;
dc6f92b8
JB
3512 }
3513
f676886a 3514 if (updating_frame != f)
dc6f92b8
JB
3515 XFlushQueue ();
3516}
3517
f676886a
JB
3518x_display_cursor (f, on)
3519 struct frame *f;
dc6f92b8
JB
3520 int on;
3521{
dbc4e1c1 3522 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
f676886a 3523 x_display_box_cursor (f, on);
dbc4e1c1 3524 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
f676886a 3525 x_display_bar_cursor (f, on);
dbc4e1c1
JB
3526 else
3527 /* Those are the only two we have implemented! */
3528 abort ();
dc6f92b8
JB
3529}
3530\f
3531/* Icons. */
3532
f676886a 3533/* Refresh bitmap kitchen sink icon for frame F
dc6f92b8
JB
3534 when we get an expose event for it. */
3535
f676886a
JB
3536refreshicon (f)
3537 struct frame *f;
dc6f92b8
JB
3538{
3539#ifdef HAVE_X11
3540 /* Normally, the window manager handles this function. */
c118dd06 3541#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3542 int mask;
3543
f676886a
JB
3544 if (f->display.x->icon_bitmap_flag)
3545 XBitmapBitsPut (f->display.x->icon_desc, 0, 0, sink_width, sink_height,
dc6f92b8
JB
3546 sink_bits, BlackPixel, WHITE_PIX_DEFAULT,
3547 icon_bitmap, GXcopy, AllPlanes);
3548 else
3549 {
f676886a 3550 extern struct frame *selected_frame;
dc6f92b8
JB
3551 struct Lisp_String *str;
3552 unsigned char *string;
3553
3554 string
f676886a 3555 = XSTRING (XBUFFER (XWINDOW (f->selected_window)->buffer)->name)->data;
dc6f92b8 3556
f676886a 3557 if (f->display.x->icon_label != string)
dc6f92b8 3558 {
f676886a
JB
3559 f->display.x->icon_label = string;
3560 XChangeWindow (f->display.x->icon_desc,
dc6f92b8
JB
3561 XQueryWidth (string, icon_font_info->id) + 10,
3562 icon_font_info->height + 10);
3563 }
3564
f676886a 3565 XText (f->display.x->icon_desc, 5, 5, string,
dc6f92b8
JB
3566 str->size, icon_font_info->id,
3567 BLACK_PIX_DEFAULT, WHITE_PIX_DEFAULT);
3568 }
3569 XFlushQueue ();
c118dd06 3570#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3571}
3572
dbc4e1c1 3573/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
3574
3575int
f676886a
JB
3576x_bitmap_icon (f)
3577 struct frame *f;
dc6f92b8
JB
3578{
3579 int mask;
3580 Window icon_window;
3581
c118dd06 3582 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
3583 return 1;
3584
3585#ifdef HAVE_X11
3586 if (icon_bitmap)
3587 XFreePixmap (x_current_display, icon_bitmap);
3588
3589 icon_bitmap =
c118dd06 3590 XCreateBitmapFromData (x_current_display, FRAME_X_WINDOW (f),
dc6f92b8 3591 gnu_bits, gnu_width, gnu_height);
f676886a
JB
3592 x_wm_set_icon_pixmap (f, icon_bitmap);
3593 f->display.x->icon_bitmap_flag = 1;
c118dd06 3594#else /* ! defined (HAVE_X11) */
f676886a 3595 if (f->display.x->icon_desc)
dc6f92b8 3596 {
c118dd06 3597 XClearIconWindow (FRAME_X_WINDOW (f));
f676886a 3598 XDestroyWindow (f->display.x->icon_desc);
dc6f92b8
JB
3599 }
3600
f676886a 3601 icon_window = XCreateWindow (f->display.x->parent_desc,
dc6f92b8
JB
3602 0, 0, sink_width, sink_height,
3603 2, WhitePixmap, (Pixmap) NULL);
3604
3605 if (icon_window == 0)
3606 return 1;
3607
c118dd06 3608 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
dc6f92b8
JB
3609 XSelectInput (icon_window, ExposeWindow | UnmapWindow);
3610
f676886a
JB
3611 f->display.x->icon_desc = icon_window;
3612 f->display.x->icon_bitmap_flag = 1;
dc6f92b8
JB
3613
3614 if (icon_bitmap == 0)
3615 icon_bitmap
3616 = XStoreBitmap (sink_mask_width, sink_mask_height, sink_mask_bits);
c118dd06 3617#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3618
3619 return 0;
3620}
3621
3622
f676886a 3623/* Make the x-window of frame F use a rectangle with text. */
dc6f92b8
JB
3624
3625int
f676886a
JB
3626x_text_icon (f, icon_name)
3627 struct frame *f;
dc6f92b8
JB
3628 char *icon_name;
3629{
3630#ifndef HAVE_X11
3631 int mask;
3632 int width;
3633 Window icon_window;
3634 char *X_DefaultValue;
3635 Bitmap b1;
3636
dc6f92b8
JB
3637#ifndef WhitePixel
3638#define WhitePixel 1
c118dd06 3639#endif /* WhitePixel */
dc6f92b8
JB
3640
3641#ifndef BlackPixel
3642#define BlackPixel 0
c118dd06
JB
3643#endif /* BlackPixel */
3644#endif /* HAVE_X11 */
dc6f92b8 3645
c118dd06 3646 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
3647 return 1;
3648
dc6f92b8
JB
3649#ifdef HAVE_X11
3650 if (icon_name)
f676886a 3651 f->display.x->icon_label = icon_name;
dc6f92b8 3652 else
f676886a
JB
3653 if (! f->display.x->icon_label)
3654 f->display.x->icon_label = " *emacs* ";
dc6f92b8 3655
dfeccd2d 3656#if 0
c118dd06 3657 XSetIconName (x_current_display, FRAME_X_WINDOW (f),
f676886a 3658 (char *) f->display.x->icon_label);
dfeccd2d 3659#endif
dc6f92b8 3660
f676886a 3661 f->display.x->icon_bitmap_flag = 0;
b1c884c3 3662 x_wm_set_icon_pixmap (f, 0);
c118dd06 3663#else /* ! defined (HAVE_X11) */
dbc4e1c1
JB
3664 if (icon_font_info == 0)
3665 icon_font_info
3666 = XGetFont (XGetDefault (XDISPLAY
59653951 3667 (char *) XSTRING (Vinvocation_name)->data,
dbc4e1c1
JB
3668 "BodyFont"));
3669
f676886a 3670 if (f->display.x->icon_desc)
dc6f92b8 3671 {
c118dd06 3672 XClearIconWindow (XDISPLAY FRAME_X_WINDOW (f));
f676886a 3673 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
dc6f92b8
JB
3674 }
3675
3676 if (icon_name)
f676886a 3677 f->display.x->icon_label = (unsigned char *) icon_name;
dc6f92b8 3678 else
f676886a
JB
3679 if (! f->display.x->icon_label)
3680 f->display.x->icon_label = XSTRING (f->name)->data;
dc6f92b8 3681
f676886a
JB
3682 width = XStringWidth (f->display.x->icon_label, icon_font_info, 0, 0);
3683 icon_window = XCreateWindow (f->display.x->parent_desc,
3684 f->display.x->left_pos,
3685 f->display.x->top_pos,
dc6f92b8
JB
3686 width + 10, icon_font_info->height + 10,
3687 2, BlackPixmap, WhitePixmap);
3688
3689 if (icon_window == 0)
3690 return 1;
3691
c118dd06 3692 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
dc6f92b8
JB
3693 XSelectInput (icon_window, ExposeWindow | ExposeRegion | UnmapWindow | ButtonPressed);
3694
f676886a
JB
3695 f->display.x->icon_desc = icon_window;
3696 f->display.x->icon_bitmap_flag = 0;
3697 f->display.x->icon_label = 0;
c118dd06 3698#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3699
3700 return 0;
3701}
3702\f
4746118a
JB
3703/* Handling X errors. */
3704
12ba150f
JB
3705/* Shut down Emacs in an orderly fashion, because of a SIGPIPE on the
3706 X server's connection, or an error reported via the X protocol. */
16bd92ea 3707
4746118a 3708static SIGTYPE
c118dd06 3709x_connection_closed ()
4746118a
JB
3710{
3711 if (_Xdebug)
3712 abort ();
12ba150f
JB
3713
3714 shut_down_emacs (0);
3715
3716 exit (70);
4746118a
JB
3717}
3718
8922af5f
JB
3719/* An X error handler which prints an error message and then kills
3720 Emacs. This is what's normally installed as Xlib's handler for
3721 protocol errors. */
c118dd06
JB
3722static int
3723x_error_quitter (display, error)
3724 Display *display;
3725 XErrorEvent *error;
3726{
3727 char buf[256];
dc6f92b8 3728
c118dd06
JB
3729 /* Note that there is no real way portable across R3/R4 to get the
3730 original error handler. */
dc6f92b8 3731
c118dd06
JB
3732 XGetErrorText (display, error->error_code, buf, sizeof (buf));
3733 fprintf (stderr, "X protocol error: %s on protocol request %d\n",
3734 buf, error->request_code);
dc6f92b8 3735
12ba150f
JB
3736 /* While we're testing Emacs 19, we'll just dump core whenever we
3737 get an X error, so we can figure out why it happened. */
3738 abort ();
3739
c118dd06 3740 x_connection_closed ();
dc6f92b8
JB
3741}
3742
8922af5f
JB
3743/* A handler for X IO errors which prints an error message and then
3744 kills Emacs. This is what is always installed as Xlib's handler
3745 for I/O errors. */
3746static int
3747x_io_error_quitter (display)
3748 Display *display;
3749{
3750 fprintf (stderr, "Connection to X server %s lost.\n",
3751 XDisplayName (DisplayString (display)));
3752
3753 /* While we're testing Emacs 19, we'll just dump core whenever we
3754 get an X error, so we can figure out why it happened. */
3755 abort ();
3756
3757 x_connection_closed ();
3758}
3759
c118dd06
JB
3760/* A buffer for storing X error messages. */
3761static char (*x_caught_error_message)[200];
3762
3763/* An X error handler which stores the error message in
3764 x_caught_error_message. This is what's installed when
3765 x_catch_errors is in effect. */
3766static int
3767x_error_catcher (display, error)
3768 Display *display;
3769 XErrorEvent *error;
3770{
3771 XGetErrorText (display, error->error_code,
3772 *x_caught_error_message, sizeof (*x_caught_error_message));
3773}
3774
3775
3776/* Begin trapping X errors.
dc6f92b8 3777
c118dd06
JB
3778 After calling this function, X protocol errors no longer cause
3779 Emacs to exit; instead, they are recorded in x_cfc_error_message.
dc6f92b8 3780
c118dd06
JB
3781 Calling x_check_errors signals an Emacs error if an X error has
3782 occurred since the last call to x_catch_errors or x_check_errors.
3783
3784 Calling x_uncatch_errors resumes the normal error handling. */
3785
3786void x_catch_errors(), x_check_errors (), x_uncatch_errors ();
3787
3788void
3789x_catch_errors ()
dc6f92b8 3790{
c118dd06
JB
3791 /* Make sure any errors from previous requests have been dealt with. */
3792 XSync (x_current_display, False);
dc6f92b8 3793
c118dd06
JB
3794 /* Set up the error buffer. */
3795 x_caught_error_message =
3796 (char (*)[]) xmalloc (sizeof (*x_caught_error_message));
d872b748 3797 (*x_caught_error_message)[0] = '\0';
16bd92ea 3798
c118dd06
JB
3799 /* Install our little error handler. */
3800 XHandleError (x_error_catcher);
3801}
16bd92ea 3802
c118dd06
JB
3803/* If any X protocol errors have arrived since the last call to
3804 x_catch_errors or x_check_errors, signal an Emacs error using
3805 sprintf (a buffer, FORMAT, the x error message text) as the text. */
3806void
3807x_check_errors (format)
3808 char *format;
3809{
3810 /* Make sure to catch any errors incurred so far. */
3811 XSync (x_current_display, False);
16bd92ea 3812
c118dd06
JB
3813 if ((*x_caught_error_message)[0])
3814 {
3815 char buf[256];
3816
3817 sprintf (buf, format, *x_caught_error_message);
9ac0d9e0 3818 xfree (x_caught_error_message);
dc6f92b8 3819
c118dd06
JB
3820 x_uncatch_errors ();
3821 error (buf);
3822 }
3823}
3824
3825void
3826x_uncatch_errors ()
3827{
9ac0d9e0 3828 xfree (x_caught_error_message);
c118dd06 3829 XHandleError (x_error_quitter);
dc6f92b8
JB
3830}
3831
dc6f92b8
JB
3832#if 0
3833static unsigned int x_wire_count;
3834x_trace_wire ()
3835{
3836 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
3837}
c118dd06 3838#endif /* ! 0 */
dc6f92b8
JB
3839
3840\f
f451eb13
JB
3841/* Changing the font of the frame. */
3842
f676886a 3843/* Set the font of the x-window specified by frame F
dc6f92b8 3844 to the font named NEWNAME. This is safe to use
f676886a 3845 even before F has an actual x-window. */
dc6f92b8
JB
3846
3847#ifdef HAVE_X11
3848
3849/* A table of all the fonts we have already loaded. */
3850static XFontStruct **x_font_table;
3851
3852/* The current capacity of x_font_table. */
3853static int x_font_table_size;
3854
3855/* The number of fonts actually stored in x_font_table.
3856 x_font_table[n] is used and valid iff 0 <= n < n_fonts.
3857 0 <= n_fonts <= x_font_table_size. */
3858static int n_fonts;
3859
f676886a
JB
3860x_new_font (f, fontname)
3861 struct frame *f;
dc6f92b8
JB
3862 register char *fontname;
3863{
3864 XFontStruct *temp;
3865 int already_loaded;
3866 int n_matching_fonts;
3867 XFontStruct *font_info;
3868 char **font_names;
3869
3870 /* Get a list of all the fonts that match this name. Once we
3871 have a list of matching fonts, we compare them against the fonts
3872 we already have by comparing font ids. */
3873 font_names = (char **) XListFontsWithInfo (x_current_display, fontname,
3874 1024, &n_matching_fonts,
3875 &font_info);
3876 /* If the server couldn't find any fonts whose named matched fontname,
3877 return an error code. */
3878 if (n_matching_fonts == 0)
3879 return 1;
3880
90e65f07 3881 /* See if we've already loaded a matching font. */
dc6f92b8
JB
3882 {
3883 int i, j;
3884
3885 already_loaded = 0;
3886 for (i = 0; i < n_fonts; i++)
3887 for (j = 0; j < n_matching_fonts; j++)
3888 if (x_font_table[i]->fid == font_info[j].fid)
3889 {
3890 already_loaded = i;
3891 goto found_font;
3892 }
3893 }
3894 found_font:
3895
3896 /* If we have, just return it from the table. */
3897 if (already_loaded)
f676886a 3898 f->display.x->font = x_font_table[already_loaded];
90e65f07 3899
dc6f92b8
JB
3900 /* Otherwise, load the font and add it to the table. */
3901 else
3902 {
3903 XFontStruct *font;
3904
3905 font = (XFontStruct *) XLoadQueryFont (x_current_display, fontname);
3906 if (! font)
3907 return 1;
3908
3909 /* Do we need to create the table? */
3910 if (x_font_table_size == 0)
3911 {
3912 x_font_table_size = 16;
3913 x_font_table
3914 = (XFontStruct **) xmalloc (x_font_table_size
3915 * sizeof (x_font_table[0]));
3916 }
3917 /* Do we need to grow the table? */
3918 else if (n_fonts >= x_font_table_size)
3919 {
90e65f07 3920 x_font_table_size *= 2;
dc6f92b8
JB
3921 x_font_table
3922 = (XFontStruct **) xrealloc (x_font_table,
3923 (x_font_table_size
3924 * sizeof (x_font_table[0])));
3925 }
3926
f676886a 3927 f->display.x->font = x_font_table[n_fonts++] = font;
dc6f92b8
JB
3928 }
3929
3930 /* Free the information from XListFontsWithInfo. The data
3931 we actually retain comes from XLoadQueryFont. */
3932 XFreeFontInfo (font_names, font_info, n_matching_fonts);
3933
f676886a 3934 /* Now make the frame display the given font. */
c118dd06 3935 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 3936 {
f676886a
JB
3937 XSetFont (x_current_display, f->display.x->normal_gc,
3938 f->display.x->font->fid);
3939 XSetFont (x_current_display, f->display.x->reverse_gc,
3940 f->display.x->font->fid);
3941 XSetFont (x_current_display, f->display.x->cursor_gc,
3942 f->display.x->font->fid);
decb54c6 3943 init_frame_faces (f);
f676886a
JB
3944
3945 x_set_window_size (f, f->width, f->height);
dc6f92b8
JB
3946 }
3947
3948 return 0;
3949}
c118dd06 3950#else /* ! defined (HAVE_X11) */
f676886a
JB
3951x_new_font (f, newname)
3952 struct frame *f;
dc6f92b8
JB
3953 register char *newname;
3954{
3955 FONT_TYPE *temp;
3956 int mask;
3957
3958 temp = XGetFont (newname);
3959 if (temp == (FONT_TYPE *) 0)
3960 return 1;
3961
f676886a
JB
3962 if (f->display.x->font)
3963 XLoseFont (f->display.x->font);
dc6f92b8 3964
f676886a 3965 f->display.x->font = temp;
dc6f92b8 3966
c118dd06 3967 if (FRAME_X_WINDOW (f) != 0)
f676886a 3968 x_set_window_size (f, f->width, f->height);
dc6f92b8
JB
3969
3970 return 0;
3971}
c118dd06 3972#endif /* ! defined (HAVE_X11) */
dc6f92b8 3973\f
f451eb13
JB
3974/* X Window sizes and positions. */
3975
f676886a
JB
3976x_calc_absolute_position (f)
3977 struct frame *f;
dc6f92b8
JB
3978{
3979#ifdef HAVE_X11
f676886a
JB
3980 if (f->display.x->left_pos < 0)
3981 f->display.x->left_pos
7c5283e4 3982 = x_screen_width - PIXEL_WIDTH (f) + f->display.x->left_pos;
dc6f92b8 3983
f676886a
JB
3984 if (f->display.x->top_pos < 0)
3985 f->display.x->top_pos
7c5283e4 3986 = x_screen_height - PIXEL_HEIGHT (f) + f->display.x->top_pos;
c118dd06 3987#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3988 WINDOWINFO_TYPE parentinfo;
3989
c118dd06 3990 XGetWindowInfo (FRAME_X_WINDOW (f), &parentinfo);
dc6f92b8 3991
f676886a
JB
3992 if (f->display.x->left_pos < 0)
3993 f->display.x->left_pos = parentinfo.width + (f->display.x->left_pos + 1)
3994 - PIXEL_WIDTH (f) - 2 * f->display.x->internal_border_width;
dc6f92b8 3995
f676886a
JB
3996 if (f->display.x->top_pos < 0)
3997 f->display.x->top_pos = parentinfo.height + (f->display.x->top_pos + 1)
3998 - PIXEL_HEIGHT (f) - 2 * f->display.x->internal_border_width;
c118dd06 3999#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4000}
4001
f676886a
JB
4002x_set_offset (f, xoff, yoff)
4003 struct frame *f;
dc6f92b8
JB
4004 register int xoff, yoff;
4005{
f676886a
JB
4006 f->display.x->top_pos = yoff;
4007 f->display.x->left_pos = xoff;
4008 x_calc_absolute_position (f);
dc6f92b8
JB
4009
4010 BLOCK_INPUT;
c118dd06 4011 XMoveWindow (XDISPLAY FRAME_X_WINDOW (f),
f676886a 4012 f->display.x->left_pos, f->display.x->top_pos);
dc6f92b8 4013#ifdef HAVE_X11
f676886a 4014 x_wm_set_size_hint (f, 0);
c118dd06 4015#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4016 UNBLOCK_INPUT;
4017}
4018
f676886a 4019/* Call this to change the size of frame F's x-window. */
dc6f92b8 4020
f676886a
JB
4021x_set_window_size (f, cols, rows)
4022 struct frame *f;
b1c884c3 4023 int cols, rows;
dc6f92b8
JB
4024{
4025 int pixelwidth, pixelheight;
4026 int mask;
dc6f92b8
JB
4027
4028 BLOCK_INPUT;
4029
b1c884c3 4030 check_frame_size (f, &rows, &cols);
ab648270
JB
4031 f->display.x->vertical_scroll_bar_extra =
4032 (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4033 ? VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f)
f451eb13
JB
4034 : 0);
4035 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
4036 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8
JB
4037
4038#ifdef HAVE_X11
f676886a 4039 x_wm_set_size_hint (f, 0);
c118dd06
JB
4040#endif /* ! defined (HAVE_X11) */
4041 XChangeWindowSize (FRAME_X_WINDOW (f), pixelwidth, pixelheight);
b1c884c3
JB
4042
4043 /* Now, strictly speaking, we can't be sure that this is accurate,
4044 but the window manager will get around to dealing with the size
4045 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
4046 ConfigureNotify event gets here.
4047
4048 We could just not bother storing any of this information here,
4049 and let the ConfigureNotify event set everything up, but that
4050 might be kind of confusing to the lisp code, since size changes
4051 wouldn't be reported in the frame parameters until some random
4052 point in the future when the ConfigureNotify event arrives. */
8922af5f 4053 change_frame_size (f, rows, cols, 0, 0);
b1c884c3
JB
4054 PIXEL_WIDTH (f) = pixelwidth;
4055 PIXEL_HEIGHT (f) = pixelheight;
4056
dbc4e1c1
JB
4057 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
4058 receive in the ConfigureNotify event; if we get what we asked
4059 for, then the event won't cause the screen to become garbaged, so
4060 we have to make sure to do it here. */
4061 SET_FRAME_GARBAGED (f);
4062
dc6f92b8
JB
4063 XFlushQueue ();
4064 UNBLOCK_INPUT;
4065}
4066
4067#ifndef HAVE_X11
f676886a
JB
4068x_set_resize_hint (f)
4069 struct frame *f;
dc6f92b8 4070{
12ba150f
JB
4071 XSetResizeHint (FRAME_X_WINDOW (f),
4072 2 * f->display.x->internal_border_width,
f676886a 4073 2 * f->display.x->internal_border_width,
12ba150f
JB
4074 FONT_WIDTH (f->display.x->font),
4075 FONT_HEIGHT (f->display.x->font));
dc6f92b8 4076}
c118dd06 4077#endif /* HAVE_X11 */
dc6f92b8 4078\f
f451eb13 4079/* Mouse warping, focus shifting, raising and lowering. */
dc6f92b8 4080
f676886a
JB
4081x_set_mouse_position (f, x, y)
4082 struct frame *f;
dc6f92b8
JB
4083 int x, y;
4084{
4085 int pix_x, pix_y;
4086
f676886a 4087 x_raise_frame (f);
dc6f92b8 4088
12ba150f
JB
4089 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2;
4090 pix_y = CHAR_TO_PIXEL_ROW (f, y) + FONT_HEIGHT (f->display.x->font) / 2;
f451eb13
JB
4091
4092 if (pix_x < 0) pix_x = 0;
4093 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
4094
4095 if (pix_y < 0) pix_y = 0;
4096 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
4097
4098 BLOCK_INPUT;
dc6f92b8 4099
c118dd06 4100 XWarpMousePointer (FRAME_X_WINDOW (f), pix_x, pix_y);
dc6f92b8
JB
4101 UNBLOCK_INPUT;
4102}
4103
4104#ifdef HAVE_X11
f676886a
JB
4105x_focus_on_frame (f)
4106 struct frame *f;
dc6f92b8 4107{
f676886a 4108 x_raise_frame (f);
6d4238f3
JB
4109#if 0
4110 /* I don't think that the ICCCM allows programs to do things like this
4111 without the interaction of the window manager. Whatever you end up
f676886a 4112 doing with this code, do it to x_unfocus_frame too. */
c118dd06 4113 XSetInputFocus (x_current_display, FRAME_X_WINDOW (f),
dc6f92b8 4114 RevertToPointerRoot, CurrentTime);
c118dd06 4115#endif /* ! 0 */
dc6f92b8
JB
4116}
4117
f676886a
JB
4118x_unfocus_frame (f)
4119 struct frame *f;
dc6f92b8 4120{
6d4238f3 4121#if 0
f676886a
JB
4122 /* Look at the remarks in x_focus_on_frame. */
4123 if (x_focus_frame == f)
dc6f92b8
JB
4124 XSetInputFocus (x_current_display, PointerRoot,
4125 RevertToPointerRoot, CurrentTime);
c118dd06 4126#endif /* ! 0 */
dc6f92b8
JB
4127}
4128
c118dd06 4129#endif /* ! defined (HAVE_X11) */
dc6f92b8 4130
f676886a 4131/* Raise frame F. */
dc6f92b8 4132
f676886a
JB
4133x_raise_frame (f)
4134 struct frame *f;
dc6f92b8 4135{
3a88c238 4136 if (f->async_visible)
dc6f92b8
JB
4137 {
4138 BLOCK_INPUT;
c118dd06 4139 XRaiseWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8
JB
4140 XFlushQueue ();
4141 UNBLOCK_INPUT;
4142 }
4143}
4144
f676886a 4145/* Lower frame F. */
dc6f92b8 4146
f676886a
JB
4147x_lower_frame (f)
4148 struct frame *f;
dc6f92b8 4149{
3a88c238 4150 if (f->async_visible)
dc6f92b8
JB
4151 {
4152 BLOCK_INPUT;
c118dd06 4153 XLowerWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8
JB
4154 XFlushQueue ();
4155 UNBLOCK_INPUT;
4156 }
4157}
4158
dbc4e1c1
JB
4159static void
4160XTframe_raise_lower (f, raise)
4161 FRAME_PTR f;
4162 int raise;
4163{
4164 if (raise)
4165 x_raise_frame (f);
4166 else
4167 x_lower_frame (f);
4168}
4169
4170
dc6f92b8
JB
4171/* Change from withdrawn state to mapped state. */
4172
f676886a
JB
4173x_make_frame_visible (f)
4174 struct frame *f;
dc6f92b8
JB
4175{
4176 int mask;
4177
dc6f92b8 4178 BLOCK_INPUT;
dc6f92b8 4179
f676886a 4180 if (! FRAME_VISIBLE_P (f))
90e65f07
JB
4181 {
4182#ifdef HAVE_X11
4183 if (! EQ (Vx_no_window_manager, Qt))
f676886a 4184 x_wm_set_window_state (f, NormalState);
dc6f92b8 4185
c118dd06 4186 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
ab648270 4187 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
c118dd06
JB
4188 XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
4189#else /* ! defined (HAVE_X11) */
4190 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
f676886a
JB
4191 if (f->display.x->icon_desc != 0)
4192 XUnmapWindow (f->display.x->icon_desc);
dc6f92b8 4193
90e65f07 4194 /* Handled by the MapNotify event for X11 */
3a88c238
JB
4195 f->async_visible = 1;
4196 f->async_iconified = 0;
dc6f92b8 4197
f676886a 4198 /* NOTE: this may cause problems for the first frame. */
90e65f07 4199 XTcursor_to (0, 0);
c118dd06 4200#endif /* ! defined (HAVE_X11) */
90e65f07 4201 }
dc6f92b8 4202
dc6f92b8 4203 XFlushQueue ();
90e65f07 4204
dc6f92b8
JB
4205 UNBLOCK_INPUT;
4206}
4207
4208/* Change from mapped state to withdrawn state. */
4209
f676886a
JB
4210x_make_frame_invisible (f)
4211 struct frame *f;
dc6f92b8
JB
4212{
4213 int mask;
4214
3a88c238 4215 if (! f->async_visible)
dc6f92b8
JB
4216 return;
4217
4218 BLOCK_INPUT;
c118dd06
JB
4219
4220#ifdef HAVE_X11R4
4221
4222 if (! XWithdrawWindow (x_current_display, FRAME_X_WINDOW (f),
4223 DefaultScreen (x_current_display)))
4224 {
4225 UNBLOCK_INPUT_RESIGNAL;
4226 error ("can't notify window manager of window withdrawl");
4227 }
4228
4229#else /* ! defined (HAVE_X11R4) */
dc6f92b8 4230#ifdef HAVE_X11
16bd92ea 4231
c118dd06 4232 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
4233 if (! EQ (Vx_no_window_manager, Qt))
4234 {
16bd92ea 4235 XEvent unmap;
dc6f92b8 4236
16bd92ea 4237 unmap.xunmap.type = UnmapNotify;
c118dd06 4238 unmap.xunmap.window = FRAME_X_WINDOW (f);
16bd92ea
JB
4239 unmap.xunmap.event = DefaultRootWindow (x_current_display);
4240 unmap.xunmap.from_configure = False;
4241 if (! XSendEvent (x_current_display,
4242 DefaultRootWindow (x_current_display),
4243 False,
4244 SubstructureRedirectMask|SubstructureNotifyMask,
4245 &unmap))
4246 {
4247 UNBLOCK_INPUT_RESIGNAL;
4248 error ("can't notify window manager of withdrawal");
4249 }
dc6f92b8
JB
4250 }
4251
16bd92ea 4252 /* Unmap the window ourselves. Cheeky! */
c118dd06
JB
4253 XUnmapWindow (x_current_display, FRAME_X_WINDOW (f));
4254
4255#else /* ! defined (HAVE_X11) */
dc6f92b8 4256
c118dd06 4257 XUnmapWindow (FRAME_X_WINDOW (f));
3a88c238 4258 f->async_visible = 0; /* Handled by the UnMap event for X11 */
f676886a 4259 if (f->display.x->icon_desc != 0)
c118dd06
JB
4260 XUnmapWindow (f->display.x->icon_desc);
4261
4262#endif /* ! defined (HAVE_X11) */
4263#endif /* ! defined (HAVE_X11R4) */
dc6f92b8
JB
4264
4265 XFlushQueue ();
4266 UNBLOCK_INPUT;
4267}
4268
dc6f92b8
JB
4269/* Change window state from mapped to iconified. */
4270
f676886a
JB
4271x_iconify_frame (f)
4272 struct frame *f;
dc6f92b8
JB
4273{
4274 int mask;
4275
3a88c238 4276 if (f->async_iconified)
dc6f92b8
JB
4277 return;
4278
4279 BLOCK_INPUT;
4280
4281#ifdef HAVE_X11
16bd92ea
JB
4282 /* Since we don't know which revision of X we're running, we'll use both
4283 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
4284
4285 /* X11R4: send a ClientMessage to the window manager using the
4286 WM_CHANGE_STATE type. */
4287 {
4288 XEvent message;
4289
c118dd06 4290 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea
JB
4291 message.xclient.type = ClientMessage;
4292 message.xclient.message_type = Xatom_wm_change_state;
4293 message.xclient.format = 32;
4294 message.xclient.data.l[0] = IconicState;
4295
4296 if (! XSendEvent (x_current_display,
4297 DefaultRootWindow (x_current_display),
4298 False,
4299 SubstructureRedirectMask | SubstructureNotifyMask,
4300 &message))
dc6f92b8
JB
4301 {
4302 UNBLOCK_INPUT_RESIGNAL;
4303 error ("Can't notify window manager of iconification.");
4304 }
16bd92ea 4305 }
dc6f92b8 4306
16bd92ea
JB
4307 /* X11R3: set the initial_state field of the window manager hints to
4308 IconicState. */
4309 x_wm_set_window_state (f, IconicState);
dc6f92b8 4310
3a88c238 4311 f->async_iconified = 1;
c118dd06
JB
4312#else /* ! defined (HAVE_X11) */
4313 XUnmapWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8 4314
3a88c238 4315 f->async_visible = 0; /* Handled in the UnMap event for X11. */
f676886a 4316 if (f->display.x->icon_desc != 0)
dc6f92b8 4317 {
f676886a
JB
4318 XMapWindow (XDISPLAY f->display.x->icon_desc);
4319 refreshicon (f);
dc6f92b8 4320 }
c118dd06 4321#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4322
4323 XFlushQueue ();
4324 UNBLOCK_INPUT;
4325}
4326
c0ff3fab 4327/* Destroy the X window of frame F. */
dc6f92b8 4328
c0ff3fab 4329x_destroy_window (f)
f676886a 4330 struct frame *f;
dc6f92b8 4331{
dc6f92b8 4332 BLOCK_INPUT;
c0ff3fab
JB
4333
4334 if (f->display.x->icon_desc != 0)
4335 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
4336 XDestroyWindow (XDISPLAY f->display.x->window_desc);
07e34cb0 4337 free_frame_faces (f);
dc6f92b8 4338 XFlushQueue ();
dc6f92b8 4339
9ac0d9e0 4340 xfree (f->display.x);
c0ff3fab 4341 f->display.x = 0;
f676886a
JB
4342 if (f == x_focus_frame)
4343 x_focus_frame = 0;
4344 if (f == x_highlight_frame)
4345 x_highlight_frame = 0;
c0ff3fab
JB
4346
4347 UNBLOCK_INPUT;
dc6f92b8
JB
4348}
4349\f
f451eb13
JB
4350/* Manage event queues for X10. */
4351
dc6f92b8
JB
4352#ifndef HAVE_X11
4353
4354/* Manage event queues.
4355
4356 This code is only used by the X10 support.
4357
4358 We cannot leave events in the X queue and get them when we are ready
4359 because X does not provide a subroutine to get only a certain kind
4360 of event but not block if there are no queued events of that kind.
4361
4362 Therefore, we must examine events as they come in and copy events
4363 of certain kinds into our private queues.
4364
4365 All ExposeRegion events are put in x_expose_queue.
4366 All ButtonPressed and ButtonReleased events are put in x_mouse_queue. */
4367
4368
4369/* Write the event *P_XREP into the event queue *QUEUE.
4370 If the queue is full, do nothing, but return nonzero. */
4371
4372int
4373enqueue_event (p_xrep, queue)
4374 register XEvent *p_xrep;
4375 register struct event_queue *queue;
4376{
4377 int newindex = queue->windex + 1;
4378 if (newindex == EVENT_BUFFER_SIZE)
4379 newindex = 0;
4380 if (newindex == queue->rindex)
4381 return -1;
4382 queue->xrep[queue->windex] = *p_xrep;
4383 queue->windex = newindex;
4384 return 0;
4385}
4386
4387/* Fetch the next event from queue *QUEUE and store it in *P_XREP.
4388 If *QUEUE is empty, do nothing and return 0. */
4389
4390int
4391dequeue_event (p_xrep, queue)
4392 register XEvent *p_xrep;
4393 register struct event_queue *queue;
4394{
4395 if (queue->windex == queue->rindex)
4396 return 0;
4397 *p_xrep = queue->xrep[queue->rindex++];
4398 if (queue->rindex == EVENT_BUFFER_SIZE)
4399 queue->rindex = 0;
4400 return 1;
4401}
4402
4403/* Return the number of events buffered in *QUEUE. */
4404
4405int
4406queue_event_count (queue)
4407 register struct event_queue *queue;
4408{
4409 int tem = queue->windex - queue->rindex;
4410 if (tem >= 0)
4411 return tem;
4412 return EVENT_BUFFER_SIZE + tem;
4413}
4414
4415/* Return nonzero if mouse input is pending. */
4416
4417int
4418mouse_event_pending_p ()
4419{
4420 return queue_event_count (&x_mouse_queue);
4421}
c118dd06 4422#endif /* HAVE_X11 */
dc6f92b8 4423\f
f451eb13
JB
4424/* Setting window manager hints. */
4425
dc6f92b8
JB
4426#ifdef HAVE_X11
4427
f676886a
JB
4428x_wm_set_size_hint (f, prompting)
4429 struct frame *f;
dc6f92b8
JB
4430 long prompting;
4431{
4432 XSizeHints size_hints;
c118dd06 4433 Window window = FRAME_X_WINDOW (f);
dc6f92b8
JB
4434
4435 size_hints.flags = PResizeInc | PMinSize | PMaxSize;
4436
f676886a
JB
4437 flexlines = f->height;
4438
4439 size_hints.x = f->display.x->left_pos;
4440 size_hints.y = f->display.x->top_pos;
4441 size_hints.height = PIXEL_HEIGHT (f);
4442 size_hints.width = PIXEL_WIDTH (f);
4443 size_hints.width_inc = FONT_WIDTH (f->display.x->font);
4444 size_hints.height_inc = FONT_HEIGHT (f->display.x->font);
12ba150f
JB
4445 size_hints.max_width = x_screen_width - CHAR_TO_PIXEL_WIDTH (f, 0);
4446 size_hints.max_height = x_screen_height - CHAR_TO_PIXEL_HEIGHT (f, 0);
f451eb13 4447
b1c884c3 4448 {
b0342f17
JB
4449 int base_width, base_height;
4450
f451eb13
JB
4451 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
4452 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17
JB
4453
4454 {
4455 int min_rows = 0, min_cols = 0;
4456 check_frame_size (f, &min_rows, &min_cols);
4457
4458 /* The window manager uses the base width hints to calculate the
4459 current number of rows and columns in the frame while
4460 resizing; min_width and min_height aren't useful for this
4461 purpose, since they might not give the dimensions for a
4462 zero-row, zero-column frame.
4463
4464 We use the base_width and base_height members if we have
4465 them; otherwise, we set the min_width and min_height members
4466 to the size for a zero x zero frame. */
4467
4468#ifdef HAVE_X11R4
4469 size_hints.flags |= PBaseSize;
4470 size_hints.base_width = base_width;
4471 size_hints.base_height = base_height;
4472 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
4473 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
4474#else
4475 size_hints.min_width = base_width;
4476 size_hints.min_height = base_height;
4477#endif
4478 }
b1c884c3 4479
b1c884c3 4480 }
dc6f92b8
JB
4481
4482 if (prompting)
4483 size_hints.flags |= prompting;
4484 else
4485 {
4486 XSizeHints hints; /* Sometimes I hate X Windows... */
4487
4488 XGetNormalHints (x_current_display, window, &hints);
4489 if (hints.flags & PSize)
4490 size_hints.flags |= PSize;
4491 if (hints.flags & PPosition)
4492 size_hints.flags |= PPosition;
4493 if (hints.flags & USPosition)
4494 size_hints.flags |= USPosition;
4495 if (hints.flags & USSize)
4496 size_hints.flags |= USSize;
4497 }
16bd92ea 4498
b0342f17
JB
4499#ifdef HAVE_X11R4
4500 XSetWMNormalHints (x_current_display, window, &size_hints);
4501#else
dc6f92b8 4502 XSetNormalHints (x_current_display, window, &size_hints);
b0342f17 4503#endif
dc6f92b8
JB
4504}
4505
4506/* Used for IconicState or NormalState */
f676886a
JB
4507x_wm_set_window_state (f, state)
4508 struct frame *f;
dc6f92b8
JB
4509 int state;
4510{
c118dd06 4511 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4512
16bd92ea
JB
4513 f->display.x->wm_hints.flags |= StateHint;
4514 f->display.x->wm_hints.initial_state = state;
b1c884c3 4515
16bd92ea 4516 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4517}
4518
f676886a
JB
4519x_wm_set_icon_pixmap (f, icon_pixmap)
4520 struct frame *f;
dc6f92b8
JB
4521 Pixmap icon_pixmap;
4522{
c118dd06 4523 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4524
dbc4e1c1
JB
4525 if (icon_pixmap)
4526 {
4527 f->display.x->wm_hints.icon_pixmap = icon_pixmap;
4528 f->display.x->wm_hints.flags |= IconPixmapHint;
4529 }
4530 else
4531 f->display.x->wm_hints.flags &= ~IconPixmapHint;
b1c884c3 4532
16bd92ea 4533 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4534}
4535
f676886a
JB
4536x_wm_set_icon_position (f, icon_x, icon_y)
4537 struct frame *f;
dc6f92b8
JB
4538 int icon_x, icon_y;
4539{
c118dd06 4540 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4541
16bd92ea
JB
4542 f->display.x->wm_hints.flags |= IconPositionHint;
4543 f->display.x->wm_hints.icon_x = icon_x;
4544 f->display.x->wm_hints.icon_y = icon_y;
b1c884c3 4545
16bd92ea 4546 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4547}
4548
4549\f
f451eb13
JB
4550/* Initialization. */
4551
dc6f92b8
JB
4552void
4553x_term_init (display_name)
4554 char *display_name;
4555{
f676886a 4556 Lisp_Object frame;
dc6f92b8
JB
4557 char *defaultvalue;
4558#ifdef F_SETOWN
4559 extern int old_fcntl_owner;
c118dd06 4560#endif /* ! defined (F_SETOWN) */
6d4238f3 4561
f676886a 4562 x_focus_frame = x_highlight_frame = 0;
dc6f92b8
JB
4563
4564 x_current_display = XOpenDisplay (display_name);
4565 if (x_current_display == 0)
4566 fatal ("X server %s not responding; check the DISPLAY environment variable or use \"-d\"\n",
4567 display_name);
4568
4569#ifdef HAVE_X11
4570 {
16bd92ea 4571 int hostname_size = 256;
60fb3ee1
JB
4572
4573 hostname = (char *) xmalloc (hostname_size);
4574
dc6f92b8
JB
4575#if 0
4576 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 4577#endif /* ! 0 */
dc6f92b8 4578
60fb3ee1
JB
4579 /* Try to get the host name; if the buffer is too short, try
4580 again. Apparently, the only indication gethostname gives of
4581 whether the buffer was large enough is the presence or absence
4582 of a '\0' in the string. Eech. */
4583 for (;;)
4584 {
4585 gethostname (hostname, hostname_size - 1);
4586 hostname[hostname_size - 1] = '\0';
4587
4588 /* Was the buffer large enough for gethostname to store the '\0'? */
4589 if (strlen (hostname) < hostname_size - 1)
4590 break;
4591
4592 hostname_size <<= 1;
4593 hostname = (char *) xrealloc (hostname, hostname_size);
4594 }
59653951 4595 x_id_name = (char *) xmalloc (XSTRING (Vinvocation_name)->size
60fb3ee1
JB
4596 + strlen (hostname)
4597 + 2);
59653951 4598 sprintf (x_id_name, "%s@%s", XSTRING (Vinvocation_name)->data, hostname);
dc6f92b8 4599 }
28430d3c
JB
4600
4601 /* Figure out which modifier bits mean what. */
4602 x_find_modifier_meanings ();
f451eb13 4603
ab648270 4604 /* Get the scroll bar cursor. */
d56a553a
RS
4605 x_vertical_scroll_bar_cursor
4606 = XCreateFontCursor (x_current_display, XC_sb_v_double_arrow);
f451eb13 4607
d56a553a 4608#if 0
28430d3c
JB
4609 /* Watch for PropertyNotify events on the root window; we use them
4610 to figure out when to invalidate our cache of the cut buffers. */
4611 x_watch_cut_buffer_cache ();
d56a553a 4612#endif
28430d3c 4613
a4fc7360
JB
4614 if (ConnectionNumber (x_current_display) != 0)
4615 {
4616 dup2 (ConnectionNumber (x_current_display), 0);
6d4238f3
JB
4617
4618#ifndef SYSV_STREAMS
a4fc7360
JB
4619 /* Streams somehow keeps track of which descriptor number
4620 is being used to talk to X. So it is not safe to substitute
4621 descriptor 0. But it is safe to make descriptor 0 a copy of it. */
4622 close (ConnectionNumber (x_current_display));
4623 ConnectionNumber (x_current_display) = 0; /* Looks a little strange?
6d4238f3
JB
4624 * check the def of the macro;
4625 * it is a genuine lvalue */
c118dd06 4626#endif /* SYSV_STREAMS */
a4fc7360 4627 }
6d4238f3 4628
c118dd06 4629#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4630
4631#ifdef F_SETOWN
4632 old_fcntl_owner = fcntl (0, F_GETOWN, 0);
4633#ifdef F_SETOWN_SOCK_NEG
4634 fcntl (0, F_SETOWN, -getpid ()); /* stdin is a socket here */
c118dd06 4635#else /* ! defined (F_SETOWN_SOCK_NEG) */
dc6f92b8 4636 fcntl (0, F_SETOWN, getpid ());
c118dd06
JB
4637#endif /* ! defined (F_SETOWN_SOCK_NEG) */
4638#endif /* ! defined (F_SETOWN) */
dc6f92b8
JB
4639
4640#ifdef SIGIO
4641 init_sigio ();
c118dd06 4642#endif /* ! defined (SIGIO) */
dc6f92b8
JB
4643
4644 /* Must use interrupt input because we cannot otherwise
4645 arrange for C-g to be noticed immediately.
4646 We cannot connect it to SIGINT. */
4647 Fset_input_mode (Qt, Qnil, Qt, Qnil);
4648
4649 expose_all_windows = 0;
4650
f676886a 4651 clear_frame_hook = XTclear_frame;
dc6f92b8
JB
4652 clear_end_of_line_hook = XTclear_end_of_line;
4653 ins_del_lines_hook = XTins_del_lines;
4654 change_line_highlight_hook = XTchange_line_highlight;
4655 insert_glyphs_hook = XTinsert_glyphs;
4656 write_glyphs_hook = XTwrite_glyphs;
4657 delete_glyphs_hook = XTdelete_glyphs;
4658 ring_bell_hook = XTring_bell;
4659 reset_terminal_modes_hook = XTreset_terminal_modes;
4660 set_terminal_modes_hook = XTset_terminal_modes;
4661 update_begin_hook = XTupdate_begin;
4662 update_end_hook = XTupdate_end;
4663 set_terminal_window_hook = XTset_terminal_window;
4664 read_socket_hook = XTread_socket;
4665 cursor_to_hook = XTcursor_to;
4666 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 4667 mouse_position_hook = XTmouse_position;
f451eb13 4668 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 4669 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
4670 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
4671 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
4672 redeem_scroll_bar_hook = XTredeem_scroll_bar;
4673 judge_scroll_bars_hook = XTjudge_scroll_bars;
dc6f92b8 4674
f676886a 4675 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
4676 char_ins_del_ok = 0; /* just as fast to write the line */
4677 line_ins_del_ok = 1; /* we'll just blt 'em */
4678 fast_clear_end_of_line = 1; /* X does this well */
f676886a 4679 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
4680 off the bottom */
4681 baud_rate = 19200;
4682
c118dd06
JB
4683 /* Note that there is no real way portable across R3/R4 to get the
4684 original error handler. */
4685 XHandleError (x_error_quitter);
8922af5f 4686 XHandleIOError (x_io_error_quitter);
dc6f92b8
JB
4687
4688 /* Disable Window Change signals; they are handled by X events. */
4689#ifdef SIGWINCH
4690 signal (SIGWINCH, SIG_DFL);
c118dd06 4691#endif /* ! defined (SIGWINCH) */
dc6f92b8 4692
c118dd06 4693 signal (SIGPIPE, x_connection_closed);
dc6f92b8 4694}
55123275
JB
4695
4696void
4697syms_of_xterm ()
4698{
ab648270 4699 staticpro (&last_mouse_scroll_bar);
55123275 4700}
c118dd06
JB
4701#endif /* ! defined (HAVE_X11) */
4702#endif /* ! defined (HAVE_X_WINDOWS) */