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