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