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