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