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