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