JimB's changes from January 18 to present
[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 1760 a.cursor = x_vertical_scrollbar_cursor;
c0ff3fab 1761 a.win_gravity = EastGravity;
f451eb13 1762
c0ff3fab 1763 mask = (CWBackPixel | CWEventMask | CWCursor | CWWinGravity);
f451eb13 1764
12ba150f
JB
1765 SET_SCROLLBAR_X_WINDOW
1766 (bar,
1767 XCreateWindow (x_current_display, FRAME_X_WINDOW (frame),
f451eb13 1768
12ba150f
JB
1769 /* Position and size of scrollbar. */
1770 left, top, width, height,
f451eb13 1771
12ba150f
JB
1772 /* Border width, depth, class, and visual. */
1773 0, CopyFromParent, CopyFromParent, CopyFromParent,
f451eb13 1774
12ba150f
JB
1775 /* Attributes. */
1776 mask, &a));
f451eb13
JB
1777 }
1778
12ba150f
JB
1779 XSET (bar->window, Lisp_Window, window);
1780 XSET (bar->top, Lisp_Int, top);
1781 XSET (bar->left, Lisp_Int, left);
1782 XSET (bar->width, Lisp_Int, width);
1783 XSET (bar->height, Lisp_Int, height);
1784 XSET (bar->start, Lisp_Int, 0);
1785 XSET (bar->end, Lisp_Int, 0);
1786 bar->dragging = Qnil;
f451eb13
JB
1787
1788 /* Add bar to its frame's list of scroll bars. */
12ba150f
JB
1789 bar->next = FRAME_SCROLLBARS (frame);
1790 bar->prev = Qnil;
1791 XSET (FRAME_SCROLLBARS (frame), Lisp_Vector, bar);
1792 if (! NILP (bar->next))
1793 XSET (XSCROLLBAR (bar->next)->prev, Lisp_Vector, bar);
f451eb13 1794
12ba150f 1795 XMapWindow (x_current_display, SCROLLBAR_X_WINDOW (bar));
f451eb13
JB
1796
1797 UNBLOCK_INPUT;
12ba150f
JB
1798
1799 return bar;
f451eb13
JB
1800}
1801
12ba150f
JB
1802/* Draw BAR's handle in the proper position.
1803 If the handle is already drawn from START to END, don't bother
1804 redrawing it, unless REBUILD is non-zero; in that case, always
1805 redraw it. (REBUILD is handy for drawing the handle after expose
1806 events.)
1807
1808 Normally, we want to constrain the start and end of the handle to
1809 fit inside its rectangle, but if the user is dragging the scrollbar
1810 handle, we want to let them drag it down all the way, so that the
1811 bar's top is as far down as it goes; otherwise, there's no way to
1812 move to the very end of the buffer. */
f451eb13 1813static void
12ba150f 1814x_scrollbar_set_handle (bar, start, end, rebuild)
f451eb13
JB
1815 struct scrollbar *bar;
1816 int start, end;
12ba150f 1817 int rebuild;
f451eb13 1818{
12ba150f
JB
1819 int dragging = ! NILP (bar->dragging);
1820 Window w = SCROLLBAR_X_WINDOW (bar);
1821 GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
1822
1823 /* If the display is already accurate, do nothing. */
1824 if (! rebuild
1825 && start == XINT (bar->start)
1826 && end == XINT (bar->end))
1827 return;
1828
f451eb13
JB
1829 BLOCK_INPUT;
1830
1831 {
12ba150f
JB
1832 int inside_width = VERTICAL_SCROLLBAR_INSIDE_WIDTH (XINT (bar->width));
1833 int inside_height = VERTICAL_SCROLLBAR_INSIDE_HEIGHT (XINT (bar->height));
1834 int top_range = VERTICAL_SCROLLBAR_TOP_RANGE (XINT (bar->height));
f451eb13
JB
1835
1836 /* Make sure the values are reasonable, and try to preserve
1837 the distance between start and end. */
12ba150f
JB
1838 {
1839 int length = end - start;
1840
1841 if (start < 0)
1842 start = 0;
1843 else if (start > top_range)
1844 start = top_range;
1845 end = start + length;
1846
1847 if (end < start)
1848 end = start;
1849 else if (end > top_range && ! dragging)
1850 end = top_range;
1851 }
f451eb13 1852
12ba150f
JB
1853 /* Store the adjusted setting in the scrollbar. */
1854 XSET (bar->start, Lisp_Int, start);
1855 XSET (bar->end, Lisp_Int, end);
f451eb13 1856
12ba150f
JB
1857 /* Clip the end position, just for display. */
1858 if (end > top_range)
1859 end = top_range;
f451eb13 1860
12ba150f
JB
1861 /* Draw bottom positions VERTICAL_SCROLLBAR_MIN_HANDLE pixels
1862 below top positions, to make sure the handle is always at least
1863 that many pixels tall. */
1864 end += VERTICAL_SCROLLBAR_MIN_HANDLE;
f451eb13 1865
12ba150f
JB
1866 /* Draw the empty space above the handle. Note that we can't clear
1867 zero-height areas; that means "clear to end of window." */
1868 if (0 < start)
1869 XClearArea (x_current_display, w,
f451eb13 1870
12ba150f
JB
1871 /* x, y, width, height, and exposures. */
1872 VERTICAL_SCROLLBAR_LEFT_BORDER,
1873 VERTICAL_SCROLLBAR_TOP_BORDER,
1874 inside_width, start,
1875 False);
f451eb13 1876
12ba150f
JB
1877 /* Draw the handle itself. */
1878 XFillRectangle (x_current_display, w, gc,
f451eb13 1879
12ba150f
JB
1880 /* x, y, width, height */
1881 VERTICAL_SCROLLBAR_LEFT_BORDER,
1882 VERTICAL_SCROLLBAR_TOP_BORDER + start,
1883 inside_width, end - start);
f451eb13 1884
f451eb13 1885
12ba150f
JB
1886 /* Draw the empty space below the handle. Note that we can't
1887 clear zero-height areas; that means "clear to end of window." */
1888 if (end < inside_height)
1889 XClearArea (x_current_display, w,
f451eb13 1890
12ba150f
JB
1891 /* x, y, width, height, and exposures. */
1892 VERTICAL_SCROLLBAR_LEFT_BORDER,
1893 VERTICAL_SCROLLBAR_TOP_BORDER + end,
1894 inside_width, inside_height - end,
1895 False);
f451eb13 1896
f451eb13
JB
1897 }
1898
f451eb13
JB
1899 UNBLOCK_INPUT;
1900}
1901
12ba150f
JB
1902/* Move a scrollbar around on the screen, to accomodate changing
1903 window configurations. */
f451eb13
JB
1904static void
1905x_scrollbar_move (bar, top, left, width, height)
1906 struct scrollbar *bar;
1907 int top, left, width, height;
1908{
1909 BLOCK_INPUT;
1910
1911 {
1912 XWindowChanges wc;
1913 unsigned int mask = 0;
1914
1915 wc.x = left;
1916 wc.y = top;
1917 wc.width = width;
1918 wc.height = height;
1919
12ba150f
JB
1920 if (left != XINT (bar->left)) mask |= CWX;
1921 if (top != XINT (bar->top)) mask |= CWY;
1922 if (width != XINT (bar->width)) mask |= CWWidth;
1923 if (height != XINT (bar->height)) mask |= CWHeight;
1924
1925 if (mask)
1926 XConfigureWindow (x_current_display, SCROLLBAR_X_WINDOW (bar),
1927 mask, &wc);
f451eb13
JB
1928 }
1929
12ba150f
JB
1930 XSET (bar->left, Lisp_Int, left);
1931 XSET (bar->top, Lisp_Int, top);
1932 XSET (bar->width, Lisp_Int, width);
1933 XSET (bar->height, Lisp_Int, height);
1934
f451eb13
JB
1935 UNBLOCK_INPUT;
1936}
1937
12ba150f
JB
1938/* Destroy the X window for BAR, and set its Emacs window's scrollbar
1939 to nil. */
1940static void
1941x_scrollbar_remove (bar)
f451eb13 1942 struct scrollbar *bar;
12ba150f
JB
1943{
1944 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
1945
1946 BLOCK_INPUT;
1947
1948 /* Destroy the window. */
1949 XDestroyWindow (x_current_display, SCROLLBAR_X_WINDOW (bar));
1950
1951 /* Disassociate this scrollbar from its window. */
1952 XWINDOW (bar->window)->vertical_scrollbar = Qnil;
1953
1954 UNBLOCK_INPUT;
1955}
1956
1957/* Set the handle of the vertical scroll bar for WINDOW to indicate
1958 that we are displaying PORTION characters out of a total of WHOLE
1959 characters, starting at POSITION. If WINDOW has no scrollbar,
1960 create one. */
1961static void
1962XTset_vertical_scrollbar (window, portion, whole, position)
f451eb13
JB
1963 struct window *window;
1964 int portion, whole, position;
1965{
1966 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
f451eb13
JB
1967 int top = XINT (window->top);
1968 int left = WINDOW_VERTICAL_SCROLLBAR_COLUMN (window);
1969 int height = WINDOW_VERTICAL_SCROLLBAR_HEIGHT (window);
1970
1971 /* Where should this scrollbar be, pixelwise? */
12ba150f
JB
1972 int pixel_top = CHAR_TO_PIXEL_ROW (f, top);
1973 int pixel_left = CHAR_TO_PIXEL_COL (f, left);
f451eb13
JB
1974 int pixel_width = VERTICAL_SCROLLBAR_PIXEL_WIDTH (f);
1975 int pixel_height = VERTICAL_SCROLLBAR_PIXEL_HEIGHT (f, height);
1976
12ba150f
JB
1977 struct scrollbar *bar;
1978
f451eb13 1979 /* Does the scrollbar exist yet? */
12ba150f
JB
1980 if (NILP (window->vertical_scrollbar))
1981 bar = x_scrollbar_create (window,
f451eb13
JB
1982 pixel_top, pixel_left,
1983 pixel_width, pixel_height);
1984 else
12ba150f
JB
1985 {
1986 /* It may just need to be moved and resized. */
1987 bar = XSCROLLBAR (window->vertical_scrollbar);
1988 x_scrollbar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
1989 }
f451eb13
JB
1990
1991 /* Set the scrollbar's current state, unless we're currently being
1992 dragged. */
12ba150f 1993 if (NILP (bar->dragging))
f451eb13 1994 {
12ba150f
JB
1995 int top_range =
1996 VERTICAL_SCROLLBAR_TOP_RANGE (pixel_height);
f451eb13 1997
12ba150f
JB
1998 if (whole == 0)
1999 x_scrollbar_set_handle (bar, 0, top_range, 0);
2000 else
2001 {
2002 int start = (position * top_range) / whole;
2003 int end = ((position + portion) * top_range) / whole;
2004
2005 x_scrollbar_set_handle (bar, start, end, 0);
2006 }
f451eb13
JB
2007 }
2008
12ba150f 2009 XSET (window->vertical_scrollbar, Lisp_Vector, bar);
f451eb13
JB
2010}
2011
12ba150f 2012
f451eb13
JB
2013/* The following three hooks are used when we're doing a thorough
2014 redisplay of the frame. We don't explicitly know which scrollbars
2015 are going to be deleted, because keeping track of when windows go
12ba150f
JB
2016 away is a real pain - "Can you say set-window-configuration, boys
2017 and girls?" Instead, we just assert at the beginning of redisplay
2018 that *all* scrollbars are to be removed, and then save a scrollbar
2019 from the fiery pit when we actually redisplay its window. */
f451eb13
JB
2020
2021/* Arrange for all scrollbars on FRAME to be removed at the next call
2022 to `*judge_scrollbars_hook'. A scrollbar may be spared if
12ba150f 2023 `*redeem_scrollbar_hook' is applied to its window before the judgement. */
f451eb13
JB
2024static void
2025XTcondemn_scrollbars (frame)
2026 FRAME_PTR frame;
2027{
12ba150f
JB
2028 /* The condemned list should be empty at this point; if it's not,
2029 then the rest of Emacs isn't using the condemn/redeem/judge
2030 protocol correctly. */
2031 if (! NILP (FRAME_CONDEMNED_SCROLLBARS (frame)))
2032 abort ();
2033
2034 /* Move them all to the "condemned" list. */
2035 FRAME_CONDEMNED_SCROLLBARS (frame) = FRAME_SCROLLBARS (frame);
2036 FRAME_SCROLLBARS (frame) = Qnil;
f451eb13
JB
2037}
2038
12ba150f
JB
2039/* Unmark WINDOW's scrollbar for deletion in this judgement cycle.
2040 Note that WINDOW isn't necessarily condemned at all. */
f451eb13 2041static void
12ba150f
JB
2042XTredeem_scrollbar (window)
2043 struct window *window;
f451eb13 2044{
12ba150f
JB
2045 struct scrollbar *bar;
2046
2047 /* We can't redeem this window's scrollbar if it doesn't have one. */
2048 if (NILP (window->vertical_scrollbar))
2049 abort ();
2050
2051 bar = XSCROLLBAR (window->vertical_scrollbar);
2052
2053 /* Unlink it from the condemned list. */
2054 {
2055 FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
2056
2057 if (NILP (bar->prev))
2058 {
2059 /* If the prev pointer is nil, it must be the first in one of
2060 the lists. */
2061 if (EQ (FRAME_SCROLLBARS (f), window->vertical_scrollbar))
2062 /* It's not condemned. Everything's fine. */
2063 return;
2064 else if (EQ (FRAME_CONDEMNED_SCROLLBARS (f),
2065 window->vertical_scrollbar))
2066 FRAME_CONDEMNED_SCROLLBARS (f) = bar->next;
2067 else
2068 /* If its prev pointer is nil, it must be at the front of
2069 one or the other! */
2070 abort ();
2071 }
2072 else
2073 XSCROLLBAR (bar->prev)->next = bar->next;
2074
2075 if (! NILP (bar->next))
2076 XSCROLLBAR (bar->next)->prev = bar->prev;
2077
2078 bar->next = FRAME_SCROLLBARS (f);
2079 bar->prev = Qnil;
2080 XSET (FRAME_SCROLLBARS (f), Lisp_Vector, bar);
2081 if (! NILP (bar->next))
2082 XSET (XSCROLLBAR (bar->next)->prev, Lisp_Vector, bar);
2083 }
f451eb13
JB
2084}
2085
2086/* Remove all scrollbars on FRAME that haven't been saved since the
2087 last call to `*condemn_scrollbars_hook'. */
2088static void
12ba150f
JB
2089XTjudge_scrollbars (f)
2090 FRAME_PTR f;
f451eb13 2091{
12ba150f 2092 Lisp_Object bar, next;
f451eb13 2093
cf7cb199
JB
2094 bar = FRAME_CONDEMNED_SCROLLBARS (f);
2095
2096 /* Clear out the condemned list now so we won't try to process any
2097 more events on the hapless scrollbars. */
2098 FRAME_CONDEMNED_SCROLLBARS (f) = Qnil;
2099
2100 for (; ! NILP (bar); bar = next)
f451eb13 2101 {
12ba150f
JB
2102 struct scrollbar *b = XSCROLLBAR (bar);
2103
2104 x_scrollbar_remove (b);
2105
2106 next = b->next;
2107 b->next = b->prev = Qnil;
f451eb13 2108 }
12ba150f 2109
12ba150f
JB
2110 /* Now there should be no references to the condemned scrollbars,
2111 and they should get garbage-collected. */
f451eb13
JB
2112}
2113
2114
2115/* Handle an Expose or GraphicsExpose event on a scrollbar. */
2116static void
2117x_scrollbar_expose (bar, event)
2118 struct scrollbar *bar;
2119 XEvent *event;
2120{
12ba150f
JB
2121 Window w = SCROLLBAR_X_WINDOW (bar);
2122 GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
2123
f451eb13
JB
2124 BLOCK_INPUT;
2125
12ba150f 2126 x_scrollbar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 2127
12ba150f
JB
2128 /* Draw a one-pixel border just inside the edges of the scrollbar. */
2129 XDrawRectangle (x_current_display, w, gc,
f451eb13
JB
2130
2131 /* x, y, width, height */
12ba150f 2132 0, 0, XINT (bar->width) - 1, XINT (bar->height) - 1);
f451eb13 2133
12ba150f
JB
2134 /* Draw another line to make the extra-thick border on the right. */
2135 XFillRectangle (x_current_display, w, gc,
f451eb13 2136
12ba150f
JB
2137 /* x, y, width, height */
2138 XINT (bar->width) - 2, 1, 1, XINT (bar->height) - 2);
f451eb13
JB
2139
2140 UNBLOCK_INPUT;
2141}
2142
2143/* Handle a mouse click on the scrollbar BAR. If *EMACS_EVENT's kind
2144 is set to something other than no_event, it is enqueued. */
2145static void
2146x_scrollbar_handle_click (bar, event, emacs_event)
2147 struct scrollbar *bar;
2148 XEvent *event;
2149 struct input_event *emacs_event;
2150{
12ba150f
JB
2151 if (XTYPE (bar->window) != Lisp_Window)
2152 abort ();
2153
f451eb13 2154 emacs_event->kind = scrollbar_click;
12ba150f 2155 XSET (emacs_event->code, Lisp_Int, event->xbutton.button - Button1);
f451eb13
JB
2156 emacs_event->modifiers =
2157 (x_convert_modifiers (event->xbutton.state)
2158 | (event->type == ButtonRelease
2159 ? up_modifier
2160 : down_modifier));
12ba150f 2161 emacs_event->frame_or_window = bar->window;
f451eb13 2162 emacs_event->timestamp = event->xbutton.time;
12ba150f
JB
2163 {
2164 int internal_height =
2165 VERTICAL_SCROLLBAR_INSIDE_HEIGHT (XINT (bar->height));
2166 int top_range =
2167 VERTICAL_SCROLLBAR_TOP_RANGE (XINT (bar->height));
2168 int y = event->xbutton.y - VERTICAL_SCROLLBAR_TOP_BORDER;
2169
2170 if (y < 0) y = 0;
2171 if (y > top_range) y = top_range;
2172
2173 if (y < XINT (bar->start))
2174 emacs_event->part = scrollbar_above_handle;
2175 else if (y < XINT (bar->end) + VERTICAL_SCROLLBAR_MIN_HANDLE)
2176 emacs_event->part = scrollbar_handle;
2177 else
2178 emacs_event->part = scrollbar_below_handle;
2179
2180 /* If the user has just clicked on the handle, record where they're
2181 holding it. */
2182 if (event->type == ButtonPress
2183 && emacs_event->part == scrollbar_handle)
2184 XSET (bar->dragging, Lisp_Int, y - XINT (bar->start));
2185
2186 /* If the user has released the handle, set it to its final position. */
2187 if (event->type == ButtonRelease
2188 && ! NILP (bar->dragging))
2189 {
2190 int new_start = y - XINT (bar->dragging);
2191 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 2192
12ba150f
JB
2193 x_scrollbar_set_handle (bar, new_start, new_end, 0);
2194 bar->dragging = Qnil;
2195 }
f451eb13 2196
12ba150f
JB
2197 /* Clicks on the handle are always reported as occuring at the top of
2198 the handle. */
2199 if (emacs_event->part == scrollbar_handle)
2200 emacs_event->x = bar->start;
2201 else
2202 XSET (emacs_event->x, Lisp_Int, y);
f451eb13 2203
12ba150f
JB
2204 XSET (emacs_event->y, Lisp_Int, top_range);
2205 }
2206}
f451eb13
JB
2207
2208/* Handle some mouse motion while someone is dragging the scrollbar. */
2209static void
12ba150f 2210x_scrollbar_note_movement (bar, event)
f451eb13
JB
2211 struct scrollbar *bar;
2212 XEvent *event;
2213{
2214 last_mouse_movement_time = event->xmotion.time;
2215
2216 mouse_moved = 1;
12ba150f 2217 XSET (last_mouse_scrollbar, Lisp_Vector, bar);
f451eb13
JB
2218
2219 /* If we're dragging the bar, display it. */
12ba150f 2220 if (! NILP (bar->dragging))
f451eb13
JB
2221 {
2222 /* Where should the handle be now? */
12ba150f 2223 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 2224
12ba150f 2225 if (new_start != XINT (bar->start))
f451eb13 2226 {
12ba150f 2227 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 2228
12ba150f 2229 x_scrollbar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
2230 }
2231 }
2232
2233 /* Call XQueryPointer so we'll get an event the next time the mouse
2234 moves and we can see *still* on the same position. */
2235 {
2236 int dummy;
2237
2238 XQueryPointer (event->xmotion.display, event->xmotion.window,
2239 (Window *) &dummy, (Window *) &dummy,
2240 &dummy, &dummy, &dummy, &dummy,
2241 (unsigned int *) &dummy);
2242 }
2243}
2244
12ba150f
JB
2245/* Return information to the user about the current position of the mouse
2246 on the scrollbar. */
2247static void
2248x_scrollbar_report_motion (f, bar_window, part, x, y, time)
2249 FRAME_PTR *f;
2250 Lisp_Object *bar_window;
2251 enum scrollbar_part *part;
2252 Lisp_Object *x, *y;
2253 unsigned long *time;
2254{
2255 struct scrollbar *bar = XSCROLLBAR (last_mouse_scrollbar);
2256 int win_x, win_y;
2257
cf7cb199
JB
2258 BLOCK_INPUT;
2259
12ba150f
JB
2260 /* Get the mouse's position relative to the scrollbar window, and
2261 report that. */
2262 {
2263 Window dummy_window;
2264 int dummy_coord;
2265 unsigned int dummy_mask;
2266
2267 if (! XQueryPointer (x_current_display,
2268 SCROLLBAR_X_WINDOW (bar),
2269
2270 /* Root, child, root x and root y. */
2271 &dummy_window, &dummy_window,
2272 &dummy_coord, &dummy_coord,
2273
2274 /* Position relative to scrollbar. */
2275 &win_x, &win_y,
2276
2277 /* Mouse buttons and modifier keys. */
2278 &dummy_mask))
2279 {
2280 *f = 0;
cf7cb199 2281 goto done;
12ba150f
JB
2282 }
2283 }
2284
2285 {
2286 int inside_height = VERTICAL_SCROLLBAR_INSIDE_HEIGHT (XINT (bar->height));
2287 int top_range = VERTICAL_SCROLLBAR_TOP_RANGE (XINT (bar->height));
2288
2289 win_y -= VERTICAL_SCROLLBAR_TOP_BORDER;
2290
2291 if (! NILP (bar->dragging))
2292 win_y -= XINT (bar->dragging);
2293
2294 if (win_y < 0)
2295 win_y = 0;
2296 if (win_y > top_range)
2297 win_y = top_range;
2298
2299 *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2300 *bar_window = bar->window;
2301
2302 if (! NILP (bar->dragging))
2303 *part = scrollbar_handle;
2304 else if (win_y < XINT (bar->start))
2305 *part = scrollbar_above_handle;
2306 else if (win_y < XINT (bar->end) + VERTICAL_SCROLLBAR_MIN_HANDLE)
2307 *part = scrollbar_handle;
2308 else
2309 *part = scrollbar_below_handle;
2310
2311 XSET (*x, Lisp_Int, win_y);
2312 XSET (*y, Lisp_Int, top_range);
2313 *time = last_mouse_movement_time;
2314 }
2315
2316 mouse_moved = 0;
2317 last_mouse_scrollbar = Qnil;
cf7cb199
JB
2318
2319 done:
2320 UNBLOCK_INPUT;
12ba150f
JB
2321}
2322
f451eb13
JB
2323
2324\f
2325/* The main X event-reading loop - XTread_socket. */
dc6f92b8 2326
dc6f92b8
JB
2327/* Timestamp of enter window event. This is only used by XTread_socket,
2328 but we have to put it out here, since static variables within functions
2329 sometimes don't work. */
2330static Time enter_timestamp;
2331
11edeb03
JB
2332/* This holds the state XLookupString needs to implement dead keys
2333 and other tricks known as "compose processing". _X Window System_
2334 says that a portable program can't use this, but Stephen Gildea assures
2335 me that letting the compiler initialize it to zeros will work okay.
2336
2337 This must be defined outside of XTread_socket, for the same reasons
2338 given for enter_timestamp, above. */
2339static XComposeStatus compose_status;
2340
c047688c
JA
2341/* Communication with window managers. */
2342Atom Xatom_wm_protocols;
2343
2344/* Kinds of protocol things we may receive. */
2345Atom Xatom_wm_take_focus;
2346Atom Xatom_wm_save_yourself;
2347Atom Xatom_wm_delete_window;
2348
2349/* Other WM communication */
2350Atom Xatom_wm_configure_denied; /* When our config request is denied */
2351Atom Xatom_wm_window_moved; /* When the WM moves us. */
2352
dc6f92b8
JB
2353/* Read events coming from the X server.
2354 This routine is called by the SIGIO handler.
2355 We return as soon as there are no more events to be read.
2356
2357 Events representing keys are stored in buffer BUFP,
2358 which can hold up to NUMCHARS characters.
2359 We return the number of characters stored into the buffer,
2360 thus pretending to be `read'.
2361
2362 WAITP is nonzero if we should block until input arrives.
2363 EXPECTED is nonzero if the caller knows input is available. */
2364
7c5283e4 2365int
dc6f92b8
JB
2366XTread_socket (sd, bufp, numchars, waitp, expected)
2367 register int sd;
2368 register struct input_event *bufp;
2369 register int numchars;
2370 int waitp;
2371 int expected;
2372{
2373 int count = 0;
2374 int nbytes = 0;
2375 int mask;
2376 int items_pending; /* How many items are in the X queue. */
2377 XEvent event;
f676886a 2378 struct frame *f;
dc6f92b8
JB
2379 int event_found;
2380 int prefix;
2381 Lisp_Object part;
2382
2383 if (x_input_blocked)
2384 {
2385 x_pending_input = 1;
2386 return -1;
2387 }
2388
2389 x_pending_input = 0;
2390 BLOCK_INPUT;
2391
2392 if (numchars <= 0)
2393 abort (); /* Don't think this happens. */
2394
2395#ifdef FIOSNBIO
2396 /* If available, Xlib uses FIOSNBIO to make the socket
2397 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
2398 FIOSNBIO is ignored, and instead of signalling EWOULDBLOCK,
2399 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
2400 fcntl (fileno (stdin), F_SETFL, 0);
c118dd06 2401#endif /* ! defined (FIOSNBIO) */
dc6f92b8
JB
2402
2403#ifndef SIGIO
2404#ifndef HAVE_SELECT
2405 if (! (fcntl (fileno (stdin), F_GETFL, 0) & O_NDELAY))
2406 {
2407 extern int read_alarm_should_throw;
2408 read_alarm_should_throw = 1;
2409 XPeekEvent (XDISPLAY &event);
2410 read_alarm_should_throw = 0;
2411 }
c118dd06
JB
2412#endif /* HAVE_SELECT */
2413#endif /* SIGIO */
dc6f92b8
JB
2414
2415 while (XStuffPending () != 0)
2416 {
2417 XNextEvent (XDISPLAY &event);
2418 event_found = 1;
2419
2420 switch (event.type)
2421 {
2422#ifdef HAVE_X11
c047688c
JA
2423 case ClientMessage:
2424 {
2425 if (event.xclient.message_type == Xatom_wm_protocols
2426 && event.xclient.format == 32)
2427 {
2428 if (event.xclient.data.l[0] == Xatom_wm_take_focus)
2429 {
f676886a
JB
2430 f = x_window_to_frame (event.xclient.window);
2431 if (f)
2432 x_focus_on_frame (f);
c047688c
JA
2433 /* Not certain about handling scrollbars here */
2434 }
2435 else if (event.xclient.data.l[0] == Xatom_wm_save_yourself)
2436 {
2437 /* Save state modify the WM_COMMAND property to
2438 something which can reinstate us. This notifies
2439 the session manager, who's looking for such a
2440 PropertyNotify. Can restart processing when
2441 a keyboard or mouse event arrives. */
2442 if (numchars > 0)
2443 {
2444 }
2445 }
2446 else if (event.xclient.data.l[0] == Xatom_wm_delete_window)
2447 {
f676886a 2448 struct frame *f = x_window_to_frame (event.xclient.window);
c047688c 2449
f676886a 2450 if (f)
c047688c
JA
2451 if (numchars > 0)
2452 {
2453 }
2454 }
2455 }
2456 else if (event.xclient.message_type == Xatom_wm_configure_denied)
2457 {
2458 }
2459 else if (event.xclient.message_type == Xatom_wm_window_moved)
2460 {
2461 int new_x, new_y;
2462
4357eba7
JB
2463 new_x = event.xclient.data.s[0];
2464 new_y = event.xclient.data.s[1];
c047688c
JA
2465 }
2466 }
2467 break;
dc6f92b8
JB
2468
2469 case SelectionClear: /* Someone has grabbed ownership. */
2470 x_disown_selection (event.xselectionclear.window,
2471 event.xselectionclear.selection,
2472 event.xselectionclear.time);
2473 break;
2474
2475 case SelectionRequest: /* Someone wants our selection. */
2476 x_answer_selection_request (event);
2477 break;
2478
2479 case PropertyNotify:
28430d3c
JB
2480
2481 /* If we're being told about a root window property, then it's
2482 a cut buffer change. */
2483 if (event.xproperty.window == ROOT_WINDOW)
2484 x_invalidate_cut_buffer_cache (&event.xproperty);
2485
2486 /* Otherwise, we're probably handling an incremental
2487 selection transmission. */
2488 else
2489 {
2490 /* If we were to do this synchronously, there'd be no worry
2491 about re-selecting. */
2492 x_send_incremental (event);
2493 }
dc6f92b8
JB
2494 break;
2495
2496 case Expose:
f676886a
JB
2497 f = x_window_to_frame (event.xexpose.window);
2498 if (f)
dc6f92b8 2499 {
3a88c238 2500 if (f->async_visible == 0)
dc6f92b8 2501 {
3a88c238
JB
2502 f->async_visible = 1;
2503 f->async_iconified = 0;
f676886a 2504 SET_FRAME_GARBAGED (f);
dc6f92b8
JB
2505 }
2506 else
f451eb13
JB
2507 {
2508 dumprectangle (x_window_to_frame (event.xexpose.window),
2509 event.xexpose.x, event.xexpose.y,
2510 event.xexpose.width, event.xexpose.height);
f451eb13
JB
2511 }
2512 }
2513 else
2514 {
2515 struct scrollbar *bar
2516 = x_window_to_scrollbar (event.xexpose.window);
2517
2518 if (bar)
2519 x_scrollbar_expose (bar, &event);
dc6f92b8
JB
2520 }
2521 break;
2522
2523 case GraphicsExpose: /* This occurs when an XCopyArea's
2524 source area was obscured or not
2525 available.*/
f451eb13
JB
2526 f = x_window_to_frame (event.xgraphicsexpose.drawable);
2527 if (f)
2528 {
2529 dumprectangle (f,
2530 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
2531 event.xgraphicsexpose.width,
2532 event.xgraphicsexpose.height);
f451eb13 2533 }
dc6f92b8
JB
2534 break;
2535
2536 case NoExpose: /* This occurs when an XCopyArea's
2537 source area was completely
2538 available */
2539 break;
c118dd06 2540#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
2541 case ExposeWindow:
2542 if (event.subwindow != 0)
2543 break; /* duplicate event */
f676886a
JB
2544 f = x_window_to_frame (event.window);
2545 if (event.window == f->display.x->icon_desc)
dc6f92b8 2546 {
f676886a 2547 refreshicon (f);
3a88c238 2548 f->async_iconified = 1;
dc6f92b8 2549 }
c118dd06 2550 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8
JB
2551 {
2552 /* Say must check all windows' needs_exposure flags. */
2553 expose_all_windows = 1;
f676886a 2554 f->display.x->needs_exposure = 1;
3a88c238 2555 f->async_visible = 1;
dc6f92b8
JB
2556 }
2557 break;
2558
2559 case ExposeRegion:
2560 if (event.subwindow != 0)
2561 break; /* duplicate event */
f676886a
JB
2562 f = x_window_to_frame (event.window);
2563 if (event.window == f->display.x->icon_desc)
dc6f92b8 2564 {
f676886a 2565 refreshicon (f);
dc6f92b8
JB
2566 break;
2567 }
2568 /* If window already needs full redraw, ignore this rectangle. */
f676886a 2569 if (expose_all_windows && f->display.x->needs_exposure)
dc6f92b8
JB
2570 break;
2571 /* Put the event on the queue of rectangles to redraw. */
2572 if (enqueue_event (&event, &x_expose_queue))
2573 /* If it is full, we can't record the rectangle,
2574 so redraw this entire window. */
2575 {
2576 /* Say must check all windows' needs_exposure flags. */
2577 expose_all_windows = 1;
f676886a 2578 f->display.x->needs_exposure = 1;
dc6f92b8
JB
2579 }
2580 break;
2581
2582 case ExposeCopy:
2583 /* This should happen only when we are expecting it,
2584 in x_read_exposes. */
2585 abort ();
c118dd06 2586#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
2587
2588#ifdef HAVE_X11
2589 case UnmapNotify:
f451eb13
JB
2590 f = x_window_to_frame (event.xunmap.window);
2591 if (f) /* F may no longer exist if
f676886a 2592 the frame was deleted. */
f451eb13
JB
2593 {
2594 /* While a frame is unmapped, display generation is
2595 disabled; you don't want to spend time updating a
2596 display that won't ever be seen. */
2597 f->async_visible = 0;
2598 }
dc6f92b8
JB
2599 break;
2600
2601 case MapNotify:
f676886a
JB
2602 f = x_window_to_frame (event.xmap.window);
2603 if (f)
dc6f92b8 2604 {
3a88c238
JB
2605 f->async_visible = 1;
2606 f->async_iconified = 0;
dc6f92b8
JB
2607
2608 /* wait_reading_process_input will notice this and update
f676886a
JB
2609 the frame's display structures. */
2610 SET_FRAME_GARBAGED (f);
dc6f92b8
JB
2611 }
2612 break;
2613
2614 /* Turn off processing if we become fully obscured. */
2615 case VisibilityNotify:
2616 break;
2617
c118dd06 2618#else /* ! defined (HAVE_X11) */
dc6f92b8 2619 case UnmapWindow:
f676886a
JB
2620 f = x_window_to_frame (event.window);
2621 if (event.window == f->display.x->icon_desc)
3a88c238 2622 f->async_iconified = 0;
c118dd06 2623 if (event.window == FRAME_X_WINDOW (f))
3a88c238 2624 f->async_visible = 0;
dc6f92b8 2625 break;
c118dd06 2626#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
2627
2628#ifdef HAVE_X11
2629 case KeyPress:
f676886a 2630 f = x_window_to_frame (event.xkey.window);
f451eb13 2631
f676886a 2632 if (f != 0)
dc6f92b8
JB
2633 {
2634 KeySym keysym;
dc6f92b8 2635 char copy_buffer[80];
3a2712f9
JB
2636 int modifiers = event.xkey.state;
2637
2638 /* Some keyboards generate different characters
2639 depending on the state of the meta key, in an attempt
2640 to support non-English typists. It would be nice to
2641 keep this functionality somehow, but for now, we will
2642 just clear the meta-key flag to get the 'pure' character. */
2643 event.xkey.state &= ~Mod1Mask;
dc6f92b8 2644
11edeb03
JB
2645 /* This will have to go some day... */
2646 nbytes =
2647 XLookupString (&event.xkey, copy_buffer, 80, &keysym,
2648 &compose_status);
dc6f92b8 2649
55123275
JB
2650 /* Strip off the vendor-specific keysym bit, and take a shot
2651 at recognizing the codes. HP servers have extra keysyms
2652 that fit into the MiscFunctionKey category. */
2653 keysym &= ~(1<<28);
2654
dc6f92b8
JB
2655 if (numchars > 1)
2656 {
55123275
JB
2657 if (IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
2658 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < 0xff80 */
2659 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
2660 || IsFunctionKey (keysym)) /* 0xffbe <= x < 0xffe1 */
dc6f92b8
JB
2661 {
2662 bufp->kind = non_ascii_keystroke;
90e65f07 2663 XSET (bufp->code, Lisp_Int, (unsigned) keysym - 0xff50);
12ba150f 2664 XSET (bufp->frame_or_window, Lisp_Frame, f);
3a2712f9 2665 bufp->modifiers = x_convert_modifiers (modifiers);
1113d9db 2666 bufp->timestamp = event.xkey.time;
dc6f92b8
JB
2667 bufp++;
2668 count++;
2669 numchars--;
2670 }
2671 else if (numchars > nbytes)
2672 {
2673 register int i;
2674
2675 if (nbytes == 1)
2676 {
f689eb05 2677 if (modifiers & x_meta_mod_mask)
dc6f92b8
JB
2678 *copy_buffer |= METABIT;
2679 bufp->kind = ascii_keystroke;
2680 XSET (bufp->code, Lisp_Int, *copy_buffer);
12ba150f 2681 XSET (bufp->frame_or_window, Lisp_Frame, f);
1113d9db 2682 bufp->timestamp = event.xkey.time;
dc6f92b8
JB
2683 bufp++;
2684 }
2685 else
2686 for (i = nbytes - 1; i > 1; i--)
2687 {
2688 bufp->kind = ascii_keystroke;
2689 XSET (bufp->code, Lisp_Int, copy_buffer[i]);
12ba150f 2690 XSET (bufp->frame_or_window, Lisp_Frame, f);
1113d9db 2691 bufp->timestamp = event.xkey.time;
dc6f92b8
JB
2692 bufp++;
2693 }
2694
2695 count += nbytes;
2696 numchars -= nbytes;
2697 }
2698 }
2699 }
2700 break;
c118dd06 2701#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
2702 case KeyPressed:
2703 {
2704 register char *where_mapping;
2705
f676886a 2706 f = x_window_to_frame (event.window);
dc6f92b8 2707 /* Ignore keys typed on icon windows. */
f676886a 2708 if (f != 0 && event.window == f->display.x->icon_desc)
dc6f92b8
JB
2709 break;
2710 where_mapping = XLookupMapping (&event, &nbytes);
2711 /* Nasty fix for arrow keys */
2712 if (!nbytes && IsCursorKey (event.detail & 0xff))
2713 {
2714 switch (event.detail & 0xff)
2715 {
2716 case KC_CURSOR_LEFT:
2717 where_mapping = "\002";
2718 break;
2719 case KC_CURSOR_RIGHT:
2720 where_mapping = "\006";
2721 break;
2722 case KC_CURSOR_UP:
2723 where_mapping = "\020";
2724 break;
2725 case KC_CURSOR_DOWN:
2726 where_mapping = "\016";
2727 break;
2728 }
2729 nbytes = 1;
2730 }
2731 if (numchars - nbytes > 0)
2732 {
2733 register int i;
2734
2735 for (i = 0; i < nbytes; i++)
2736 {
2737 bufp->kind = ascii_keystroke;
2738 XSET (bufp->code, Lisp_Int, where_mapping[i]);
90e65f07 2739 XSET (bufp->time, Lisp_Int, event.xkey.time);
12ba150f 2740 XSET (bufp->frame_or_window, Lisp_Frame, f);
dc6f92b8
JB
2741 bufp++;
2742 }
2743 count += nbytes;
2744 numchars -= nbytes;
2745 }
2746 }
2747 break;
c118dd06 2748#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
2749
2750#ifdef HAVE_X11
f451eb13
JB
2751
2752 /* Here's a possible interpretation of the whole
2753 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If you get a
2754 FocusIn event, you have to get a FocusOut event before you
2755 relinquish the focus. If you haven't received a FocusIn event,
2756 then a mere LeaveNotify is enough to free you. */
2757
dc6f92b8 2758 case EnterNotify:
f676886a 2759 f = x_window_to_frame (event.xcrossing.window);
6d4238f3 2760
f451eb13 2761 if (event.xcrossing.focus) /* Entered Window */
dc6f92b8 2762 {
dc6f92b8 2763 /* Avoid nasty pop/raise loops. */
f676886a
JB
2764 if (f && (!(f->auto_raise)
2765 || !(f->auto_lower)
dc6f92b8
JB
2766 || (event.xcrossing.time - enter_timestamp) > 500))
2767 {
f676886a 2768 x_new_focus_frame (f);
dc6f92b8
JB
2769 enter_timestamp = event.xcrossing.time;
2770 }
dc6f92b8 2771 }
f676886a
JB
2772 else if (f == x_focus_frame)
2773 x_new_focus_frame (0);
dc6f92b8
JB
2774
2775 break;
2776
2777 case FocusIn:
f676886a 2778 f = x_window_to_frame (event.xfocus.window);
f451eb13
JB
2779 if (event.xfocus.detail != NotifyPointer)
2780 x_focus_event_frame = f;
f676886a
JB
2781 if (f)
2782 x_new_focus_frame (f);
dc6f92b8
JB
2783 break;
2784
f451eb13 2785
dc6f92b8 2786 case LeaveNotify:
f451eb13 2787 f = x_window_to_frame (event.xcrossing.window);
b1c884c3 2788
f451eb13
JB
2789 if (event.xcrossing.focus)
2790 {
2791 if (! x_focus_event_frame)
2792 x_new_focus_frame (0);
2793 else
f676886a 2794 x_new_focus_frame (f);
f451eb13
JB
2795 }
2796 else
2797 {
2798 if (f == x_focus_event_frame)
2799 x_focus_event_frame = 0;
2800 if (f == x_focus_frame)
f676886a 2801 x_new_focus_frame (0);
dc6f92b8
JB
2802 }
2803 break;
2804
2805 case FocusOut:
f676886a 2806 f = x_window_to_frame (event.xfocus.window);
f451eb13
JB
2807 if (event.xfocus.detail != NotifyPointer
2808 && f == x_focus_event_frame)
2809 x_focus_event_frame = 0;
f676886a
JB
2810 if (f && f == x_focus_frame)
2811 x_new_focus_frame (0);
dc6f92b8
JB
2812 break;
2813
c118dd06 2814#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
2815
2816 case EnterWindow:
2817 if ((event.detail & 0xFF) == 1)
2818 break; /* Coming from our own subwindow */
2819 if (event.subwindow != 0)
2820 break; /* Entering our own subwindow. */
2821
2822 {
f676886a
JB
2823 f = x_window_to_frame (event.window);
2824 x_mouse_frame = f;
dc6f92b8 2825
f676886a 2826 x_new_focus_frame (f);
dc6f92b8
JB
2827 }
2828 break;
2829
2830 case LeaveWindow:
2831 if ((event.detail & 0xFF) == 1)
2832 break; /* Entering our own subwindow */
2833 if (event.subwindow != 0)
2834 break; /* Leaving our own subwindow. */
2835
f676886a
JB
2836 x_mouse_frame = 0;
2837 if (x_focus_frame == 0
2838 && x_input_frame != 0
2839 && x_input_frame == x_window_to_frame (event.window)
c118dd06 2840 && event.window == FRAME_X_WINDOW (x_input_frame))
dc6f92b8 2841 {
f676886a
JB
2842 f = x_input_frame;
2843 x_input_frame = 0;
2844 if (f)
2845 frame_unhighlight (f);
dc6f92b8
JB
2846 }
2847 break;
c118dd06 2848#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
2849
2850#ifdef HAVE_X11
2851 case MotionNotify:
2852 {
f676886a
JB
2853 f = x_window_to_frame (event.xmotion.window);
2854 if (f)
12ba150f 2855 note_mouse_movement (f, &event.xmotion);
f451eb13 2856 else
dc6f92b8 2857 {
f451eb13
JB
2858 struct scrollbar *bar =
2859 x_window_to_scrollbar (event.xmotion.window);
2860
2861 if (bar)
12ba150f 2862 x_scrollbar_note_movement (bar, &event);
dc6f92b8 2863 }
dc6f92b8
JB
2864 }
2865 break;
2866
2867 case ConfigureNotify:
2868 {
2869 int rows, columns;
f676886a
JB
2870 f = x_window_to_frame (event.xconfigure.window);
2871 if (!f)
dc6f92b8
JB
2872 break;
2873
f451eb13
JB
2874 columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
2875 rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
dc6f92b8 2876
90e65f07
JB
2877 /* Even if the number of character rows and columns has
2878 not changed, the font size may have changed, so we need
2879 to check the pixel dimensions as well. */
f676886a
JB
2880 if (columns != f->width
2881 || rows != f->height
2882 || event.xconfigure.width != f->display.x->pixel_width
2883 || event.xconfigure.height != f->display.x->pixel_height)
dc6f92b8 2884 {
b1c884c3 2885 change_frame_size (f, rows, columns, 0, 1);
f676886a 2886 SET_FRAME_GARBAGED (f);
dc6f92b8
JB
2887 }
2888
f676886a
JB
2889 f->display.x->pixel_width = event.xconfigure.width;
2890 f->display.x->pixel_height = event.xconfigure.height;
2891 f->display.x->left_pos = event.xconfigure.x;
2892 f->display.x->top_pos = event.xconfigure.y;
dc6f92b8
JB
2893 break;
2894 }
2895
2896 case ButtonPress:
2897 case ButtonRelease:
2898 {
2899 /* If we decide we want to generate an event to be seen
2900 by the rest of Emacs, we put it here. */
2901 struct input_event emacs_event;
2902 emacs_event.kind = no_event;
2903
f676886a
JB
2904 f = x_window_to_frame (event.xbutton.window);
2905 if (f)
f451eb13
JB
2906 {
2907 if (!x_focus_frame || (f == x_focus_frame))
2908 construct_mouse_click (&emacs_event,
2909 &event, f, Qnil, 0);
2910 }
dc6f92b8 2911 else
f451eb13
JB
2912 {
2913 struct scrollbar *bar =
2914 x_window_to_scrollbar (event.xbutton.window);
2915
2916 if (bar)
2917 x_scrollbar_handle_click (bar, &event, &emacs_event);
2918 }
dc6f92b8
JB
2919
2920 if (numchars >= 1 && emacs_event.kind != no_event)
2921 {
2922 bcopy (&emacs_event, bufp, sizeof (struct input_event));
2923 bufp++;
2924 count++;
2925 numchars--;
2926 }
2927 }
2928 break;
2929
c118dd06 2930#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
2931 case ButtonPressed:
2932 case ButtonReleased:
f676886a
JB
2933 f = x_window_to_frame (event.window);
2934 if (f)
dc6f92b8 2935 {
f676886a 2936 if (event.window == f->display.x->icon_desc)
dc6f92b8 2937 {
f676886a 2938 x_make_frame_visible (f);
dc6f92b8
JB
2939
2940 if (warp_mouse_on_deiconify)
c118dd06 2941 XWarpMouse (FRAME_X_WINDOW (f), 10, 10);
dc6f92b8
JB
2942 break;
2943 }
c118dd06 2944 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8 2945 {
f676886a
JB
2946 if (f->auto_raise)
2947 x_raise_frame (f);
dc6f92b8
JB
2948 }
2949 }
2950 enqueue_event (&event, &x_mouse_queue);
2951 if (numchars >= 2)
2952 {
2953 bufp->kind = ascii_keystroke;
2954 bufp->code = (char) 'X' & 037; /* C-x */
12ba150f 2955 XSET (bufp->frame_or_window, Lisp_Frame, f);
90e65f07 2956 XSET (bufp->time, Lisp_Int, event.xkey.time);
dc6f92b8
JB
2957 bufp++;
2958
2959 bufp->kind = ascii_keystroke;
2960 bufp->code = (char) 0; /* C-@ */
12ba150f 2961 XSET (bufp->frame_or_window, Lisp_Frame, f);
90e65f07 2962 XSET (bufp->time, Lisp_Int, event.xkey.time);
dc6f92b8
JB
2963 bufp++;
2964
2965 count += 2;
2966 numchars -= 2;
2967 }
2968 break;
c118dd06 2969#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
2970
2971#ifdef HAVE_X11
2972
2973 case CirculateNotify:
2974 break;
2975 case CirculateRequest:
2976 break;
2977
c118dd06 2978#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
2979
2980 case MappingNotify:
11edeb03
JB
2981 /* Someone has changed the keyboard mapping - update the
2982 local cache. */
2983 switch (event.xmapping.request)
2984 {
2985 case MappingModifier:
2986 x_find_modifier_meanings ();
2987 /* This is meant to fall through. */
2988 case MappingKeyboard:
2989 XRefreshKeyboardMapping (&event.xmapping);
2990 }
dc6f92b8
JB
2991 break;
2992
2993 default:
2994 break;
2995 }
2996 }
2997
2998#if 0
2999#ifdef HAVE_SELECT
3000 if (expected && ! event_found)
3001 {
3002 /* AOJ 880406: if select returns true but XPending doesn't, it means that
3003 there is an EOF condition; in other words, that X has died.
3004 Act as if there had been a hangup. */
3005
3006 int fd = ConnectionNumber (x_current_display);
3007 int mask = 1 << fd;
3008
3009 if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0,
3a2712f9 3010 (EMACS_TIME) 0)
dc6f92b8
JB
3011 && !XStuffPending ())
3012 kill (getpid (), SIGHUP);
3013 }
c118dd06
JB
3014#endif /* ! defined (HAVE_SELECT) */
3015#endif /* ! 0 */
dc6f92b8 3016
f451eb13 3017#ifndef HAVE_X11
f676886a 3018 if (updating_frame == 0)
dc6f92b8 3019 x_do_pending_expose ();
f451eb13 3020#endif
dc6f92b8
JB
3021
3022 UNBLOCK_INPUT;
3023 return count;
3024}
3025
3026#ifndef HAVE_X11
3027/* Read and process only Expose events
3028 until we get an ExposeCopy event; then return.
3029 This is used in insert/delete line.
3030 We assume input is already blocked. */
3031
3032static void
3033x_read_exposes ()
3034{
f676886a 3035 struct frame *f;
dc6f92b8
JB
3036 XKeyPressedEvent event;
3037
3038 while (1)
3039 {
3040 /* while there are more events*/
3041 XMaskEvent (ExposeWindow | ExposeRegion | ExposeCopy, &event);
3042 switch (event.type)
3043 {
3044 case ExposeWindow:
3045 if (event.subwindow != 0)
3046 break; /* duplicate event */
f676886a
JB
3047 f = x_window_to_frame (event.window);
3048 if (event.window == f->display.x->icon_desc)
dc6f92b8 3049 {
f676886a 3050 refreshicon (f);
dc6f92b8
JB
3051 break;
3052 }
c118dd06 3053 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8
JB
3054 {
3055 expose_all_windows = 1;
f676886a 3056 f->display.x->needs_exposure = 1;
dc6f92b8
JB
3057 break;
3058 }
3059 break;
3060
3061 case ExposeRegion:
3062 if (event.subwindow != 0)
3063 break; /* duplicate event */
f676886a
JB
3064 f = x_window_to_frame (event.window);
3065 if (event.window == f->display.x->icon_desc)
dc6f92b8 3066 {
f676886a 3067 refreshicon (f);
dc6f92b8
JB
3068 break;
3069 }
3070 /* If window already needs full redraw, ignore this rectangle. */
f676886a 3071 if (expose_all_windows && f->display.x->needs_exposure)
dc6f92b8
JB
3072 break;
3073 /* Put the event on the queue of rectangles to redraw. */
3074 if (enqueue_event (&event, &x_expose_queue))
3075 /* If it is full, we can't record the rectangle,
3076 so redraw this entire window. */
3077 {
3078 /* Say must check all windows' needs_exposure flags. */
3079 expose_all_windows = 1;
f676886a 3080 f->display.x->needs_exposure = 1;
dc6f92b8
JB
3081 }
3082 break;
3083
3084 case ExposeCopy:
3085 return;
3086 }
3087 }
3088}
3089#endif /* HAVE_X11 */
3090
dc6f92b8 3091\f
f451eb13
JB
3092/* Drawing the cursor. */
3093
3094
dc6f92b8
JB
3095/* Draw a hollow box cursor. Don't change the inside of the box. */
3096
3097static void
f676886a
JB
3098x_draw_box (f)
3099 struct frame *f;
dc6f92b8 3100{
12ba150f
JB
3101 int left = CHAR_TO_PIXEL_COL (f, f->cursor_x);
3102 int top = CHAR_TO_PIXEL_ROW (f, f->cursor_y);
f676886a
JB
3103 int width = FONT_WIDTH (f->display.x->font);
3104 int height = FONT_HEIGHT (f->display.x->font);
dc6f92b8
JB
3105
3106#ifdef HAVE_X11
c118dd06 3107 XDrawRectangle (x_current_display, FRAME_X_WINDOW (f),
f676886a 3108 f->display.x->cursor_gc,
dc6f92b8 3109 left, top, width - 1, height - 1);
c118dd06
JB
3110#else /* ! defined (HAVE_X11) */
3111 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3112 left, top, width, 1,
f676886a 3113 f->display.x->cursor_pixel);
dc6f92b8 3114
c118dd06 3115 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3116 left, top, 1, height,
f676886a 3117 f->display.x->cursor_pixel);
dc6f92b8 3118
c118dd06 3119 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3120 left+width-1, top, 1, height,
f676886a 3121 f->display.x->cursor_pixel);
dc6f92b8 3122
c118dd06 3123 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3124 left, top+height-1, width, 1,
f676886a 3125 f->display.x->cursor_pixel);
c118dd06 3126#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3127}
3128
f676886a 3129/* Clear the cursor of frame F to background color,
dc6f92b8
JB
3130 and mark the cursor as not shown.
3131 This is used when the text where the cursor is
3132 is about to be rewritten. */
3133
3134static void
f676886a
JB
3135clear_cursor (f)
3136 struct frame *f;
dc6f92b8
JB
3137{
3138 int mask;
3139
f451eb13 3140 if (! FRAME_VISIBLE_P (f)
f676886a 3141 || f->phys_cursor_x < 0)
dc6f92b8
JB
3142 return;
3143
3144#ifdef HAVE_X11
f676886a 3145 x_display_cursor (f, 0);
c118dd06
JB
3146#else /* ! defined (HAVE_X11) */
3147 XPixSet (FRAME_X_WINDOW (f),
12ba150f
JB
3148 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
3149 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
f676886a
JB
3150 FONT_WIDTH (f->display.x->font), FONT_HEIGHT (f->display.x->font),
3151 f->display.x->background_pixel);
c118dd06 3152#endif /* ! defined (HAVE_X11) */
f676886a 3153 f->phys_cursor_x = -1;
dc6f92b8
JB
3154}
3155
90e65f07 3156static void
f676886a
JB
3157x_display_bar_cursor (f, on)
3158 struct frame *f;
dc6f92b8
JB
3159 int on;
3160{
f676886a
JB
3161 register int phys_x = f->phys_cursor_x;
3162 register int phys_y = f->phys_cursor_y;
dc6f92b8
JB
3163 register int x1;
3164 register int y1;
3165 register int y2;
3166
f451eb13 3167 if (! FRAME_VISIBLE_P (f) || (! on && f->phys_cursor_x < 0))
dc6f92b8
JB
3168 return;
3169
3170#ifdef HAVE_X11
3171 if (phys_x >= 0 &&
f676886a 3172 (!on || phys_x != f->cursor_x || phys_y != f->cursor_y))
dc6f92b8 3173 {
12ba150f
JB
3174 x1 = CHAR_TO_PIXEL_COL (f, phys_x);
3175 y1 = CHAR_TO_PIXEL_ROW (f, phys_y) - 1;
f676886a 3176 y2 = y1 + FONT_HEIGHT (f->display.x->font) + 1;
dc6f92b8 3177
c118dd06 3178 XDrawLine (x_current_display, FRAME_X_WINDOW (f),
f676886a 3179 f->display.x->reverse_gc, x1, y1, x1, y2);
dc6f92b8 3180
f676886a 3181 f->phys_cursor_x = phys_x = -1;
dc6f92b8
JB
3182 }
3183
f676886a 3184 if (on && f == x_highlight_frame)
dc6f92b8 3185 {
12ba150f
JB
3186 x1 = CHAR_TO_PIXEL_COL (f, f->cursor_x);
3187 y1 = CHAR_TO_PIXEL_ROW (f, f->cursor_y) - 1;
f676886a 3188 y2 = y1 + FONT_HEIGHT (f->display.x->font) + 1;
dc6f92b8 3189
c118dd06 3190 XDrawLine (x_current_display, FRAME_X_WINDOW (f),
f676886a 3191 f->display.x->cursor_gc, x1, y1, x1, y2);
dc6f92b8 3192
f676886a
JB
3193 f->phys_cursor_x = f->cursor_x;
3194 f->phys_cursor_y = f->cursor_y;
dc6f92b8 3195 }
c118dd06 3196#else /* ! defined (HAVE_X11) */
dc6f92b8 3197 Give it up, dude.
c118dd06 3198#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3199}
3200
3201
f676886a 3202/* Redraw the glyph at ROW, COLUMN on frame F, in the style
90e65f07
JB
3203 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
3204 glyph drawn. */
dc6f92b8
JB
3205
3206static void
f676886a
JB
3207x_draw_single_glyph (f, row, column, glyph, highlight)
3208 struct frame *f;
dc6f92b8 3209 int row, column;
90e65f07 3210 GLYPH glyph;
dc6f92b8
JB
3211 int highlight;
3212{
f676886a 3213 dumpglyphs (f,
12ba150f
JB
3214 CHAR_TO_PIXEL_COL (f, column),
3215 CHAR_TO_PIXEL_ROW (f, row),
f676886a 3216 &glyph, 1, highlight, f->display.x->font);
dc6f92b8
JB
3217}
3218
f676886a 3219/* Turn the displayed cursor of frame F on or off according to ON.
dc6f92b8 3220 If ON is nonzero, where to put the cursor is specified
f676886a 3221 by F->cursor_x and F->cursor_y. */
dc6f92b8
JB
3222
3223static void
f676886a
JB
3224x_display_box_cursor (f, on)
3225 struct frame *f;
dc6f92b8
JB
3226 int on;
3227{
f676886a 3228 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
90e65f07 3229
f676886a 3230 /* If we're not updating, then we want to use the current frame's
1113d9db 3231 cursor position, not our local idea of where the cursor ought to be. */
f676886a 3232 if (f != updating_frame)
1113d9db 3233 {
f676886a
JB
3234 curs_x = FRAME_CURSOR_X (f);
3235 curs_y = FRAME_CURSOR_Y (f);
1113d9db
JB
3236 }
3237
f451eb13 3238 if (! FRAME_VISIBLE_P (f))
dc6f92b8
JB
3239 return;
3240
3241 /* If cursor is off and we want it off, return quickly. */
f676886a 3242 if (!on && f->phys_cursor_x < 0)
dc6f92b8
JB
3243 return;
3244
3245 /* If cursor is currently being shown and we don't want it to be
3246 or it is in the wrong place,
3247 or we want a hollow box and it's not so, (pout!)
3248 erase it. */
f676886a 3249 if (f->phys_cursor_x >= 0
dc6f92b8 3250 && (!on
f676886a
JB
3251 || f->phys_cursor_x != curs_x
3252 || f->phys_cursor_y != curs_y
3253 || (f->display.x->text_cursor_kind != hollow_box_cursor
3254 && (f != x_highlight_frame))))
dc6f92b8
JB
3255 {
3256 /* Erase the cursor by redrawing the character underneath it. */
f676886a
JB
3257 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
3258 f->phys_cursor_glyph,
3259 current_glyphs->highlight[f->phys_cursor_y]);
3260 f->phys_cursor_x = -1;
dc6f92b8
JB
3261 }
3262
3263 /* If we want to show a cursor,
3264 or we want a box cursor and it's not so,
3265 write it in the right place. */
3266 if (on
f676886a
JB
3267 && (f->phys_cursor_x < 0
3268 || (f->display.x->text_cursor_kind != filled_box_cursor
3269 && f == x_highlight_frame)))
dc6f92b8 3270 {
f676886a 3271 f->phys_cursor_glyph
1113d9db
JB
3272 = ((current_glyphs->enable[curs_y]
3273 && curs_x < current_glyphs->used[curs_y])
3274 ? current_glyphs->glyphs[curs_y][curs_x]
90e65f07 3275 : SPACEGLYPH);
f676886a 3276 if (f != x_highlight_frame)
dc6f92b8 3277 {
f676886a
JB
3278 x_draw_box (f);
3279 f->display.x->text_cursor_kind = hollow_box_cursor;
dc6f92b8
JB
3280 }
3281 else
3282 {
f676886a
JB
3283 x_draw_single_glyph (f, curs_y, curs_x,
3284 f->phys_cursor_glyph, 2);
3285 f->display.x->text_cursor_kind = filled_box_cursor;
dc6f92b8
JB
3286 }
3287
f676886a
JB
3288 f->phys_cursor_x = curs_x;
3289 f->phys_cursor_y = curs_y;
dc6f92b8
JB
3290 }
3291
f676886a 3292 if (updating_frame != f)
dc6f92b8
JB
3293 XFlushQueue ();
3294}
3295
dc6f92b8
JB
3296extern Lisp_Object Vbar_cursor;
3297
f676886a
JB
3298x_display_cursor (f, on)
3299 struct frame *f;
dc6f92b8
JB
3300 int on;
3301{
3302 if (EQ (Vbar_cursor, Qnil))
f676886a 3303 x_display_box_cursor (f, on);
dc6f92b8 3304 else
f676886a 3305 x_display_bar_cursor (f, on);
dc6f92b8
JB
3306}
3307\f
3308/* Icons. */
3309
f676886a 3310/* Refresh bitmap kitchen sink icon for frame F
dc6f92b8
JB
3311 when we get an expose event for it. */
3312
f676886a
JB
3313refreshicon (f)
3314 struct frame *f;
dc6f92b8
JB
3315{
3316#ifdef HAVE_X11
3317 /* Normally, the window manager handles this function. */
c118dd06 3318#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3319 int mask;
3320
f676886a
JB
3321 if (f->display.x->icon_bitmap_flag)
3322 XBitmapBitsPut (f->display.x->icon_desc, 0, 0, sink_width, sink_height,
dc6f92b8
JB
3323 sink_bits, BlackPixel, WHITE_PIX_DEFAULT,
3324 icon_bitmap, GXcopy, AllPlanes);
3325 else
3326 {
f676886a 3327 extern struct frame *selected_frame;
dc6f92b8
JB
3328 struct Lisp_String *str;
3329 unsigned char *string;
3330
3331 string
f676886a 3332 = XSTRING (XBUFFER (XWINDOW (f->selected_window)->buffer)->name)->data;
dc6f92b8 3333
f676886a 3334 if (f->display.x->icon_label != string)
dc6f92b8 3335 {
f676886a
JB
3336 f->display.x->icon_label = string;
3337 XChangeWindow (f->display.x->icon_desc,
dc6f92b8
JB
3338 XQueryWidth (string, icon_font_info->id) + 10,
3339 icon_font_info->height + 10);
3340 }
3341
f676886a 3342 XText (f->display.x->icon_desc, 5, 5, string,
dc6f92b8
JB
3343 str->size, icon_font_info->id,
3344 BLACK_PIX_DEFAULT, WHITE_PIX_DEFAULT);
3345 }
3346 XFlushQueue ();
c118dd06 3347#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3348}
3349
f676886a 3350/* Make the x-window of frame F use the kitchen-sink icon
dc6f92b8
JB
3351 that's a window generated by Emacs. */
3352
3353int
f676886a
JB
3354x_bitmap_icon (f)
3355 struct frame *f;
dc6f92b8
JB
3356{
3357 int mask;
3358 Window icon_window;
3359
c118dd06 3360 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
3361 return 1;
3362
3363#ifdef HAVE_X11
3364 if (icon_bitmap)
3365 XFreePixmap (x_current_display, icon_bitmap);
3366
3367 icon_bitmap =
c118dd06 3368 XCreateBitmapFromData (x_current_display, FRAME_X_WINDOW (f),
dc6f92b8 3369 gnu_bits, gnu_width, gnu_height);
f676886a
JB
3370 x_wm_set_icon_pixmap (f, icon_bitmap);
3371 f->display.x->icon_bitmap_flag = 1;
c118dd06 3372#else /* ! defined (HAVE_X11) */
f676886a 3373 if (f->display.x->icon_desc)
dc6f92b8 3374 {
c118dd06 3375 XClearIconWindow (FRAME_X_WINDOW (f));
f676886a 3376 XDestroyWindow (f->display.x->icon_desc);
dc6f92b8
JB
3377 }
3378
f676886a 3379 icon_window = XCreateWindow (f->display.x->parent_desc,
dc6f92b8
JB
3380 0, 0, sink_width, sink_height,
3381 2, WhitePixmap, (Pixmap) NULL);
3382
3383 if (icon_window == 0)
3384 return 1;
3385
c118dd06 3386 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
dc6f92b8
JB
3387 XSelectInput (icon_window, ExposeWindow | UnmapWindow);
3388
f676886a
JB
3389 f->display.x->icon_desc = icon_window;
3390 f->display.x->icon_bitmap_flag = 1;
dc6f92b8
JB
3391
3392 if (icon_bitmap == 0)
3393 icon_bitmap
3394 = XStoreBitmap (sink_mask_width, sink_mask_height, sink_mask_bits);
c118dd06 3395#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3396
3397 return 0;
3398}
3399
3400
f676886a 3401/* Make the x-window of frame F use a rectangle with text. */
dc6f92b8
JB
3402
3403int
f676886a
JB
3404x_text_icon (f, icon_name)
3405 struct frame *f;
dc6f92b8
JB
3406 char *icon_name;
3407{
3408#ifndef HAVE_X11
3409 int mask;
3410 int width;
3411 Window icon_window;
3412 char *X_DefaultValue;
3413 Bitmap b1;
3414
dc6f92b8
JB
3415#ifndef WhitePixel
3416#define WhitePixel 1
c118dd06 3417#endif /* WhitePixel */
dc6f92b8
JB
3418
3419#ifndef BlackPixel
3420#define BlackPixel 0
c118dd06
JB
3421#endif /* BlackPixel */
3422#endif /* HAVE_X11 */
dc6f92b8 3423
c118dd06 3424 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
3425 return 1;
3426
3427 if (icon_font_info == 0)
3428 icon_font_info
55123275
JB
3429 = XGetFont (XGetDefault (XDISPLAY
3430 (char *) XSTRING (invocation_name)->data,
3431 "BodyFont"));
dc6f92b8
JB
3432
3433#ifdef HAVE_X11
3434 if (icon_name)
f676886a 3435 f->display.x->icon_label = icon_name;
dc6f92b8 3436 else
f676886a
JB
3437 if (! f->display.x->icon_label)
3438 f->display.x->icon_label = " *emacs* ";
dc6f92b8 3439
c118dd06 3440 XSetIconName (x_current_display, FRAME_X_WINDOW (f),
f676886a 3441 (char *) f->display.x->icon_label);
dc6f92b8 3442
f676886a 3443 f->display.x->icon_bitmap_flag = 0;
b1c884c3 3444 x_wm_set_icon_pixmap (f, 0);
c118dd06 3445#else /* ! defined (HAVE_X11) */
f676886a 3446 if (f->display.x->icon_desc)
dc6f92b8 3447 {
c118dd06 3448 XClearIconWindow (XDISPLAY FRAME_X_WINDOW (f));
f676886a 3449 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
dc6f92b8
JB
3450 }
3451
3452 if (icon_name)
f676886a 3453 f->display.x->icon_label = (unsigned char *) icon_name;
dc6f92b8 3454 else
f676886a
JB
3455 if (! f->display.x->icon_label)
3456 f->display.x->icon_label = XSTRING (f->name)->data;
dc6f92b8 3457
f676886a
JB
3458 width = XStringWidth (f->display.x->icon_label, icon_font_info, 0, 0);
3459 icon_window = XCreateWindow (f->display.x->parent_desc,
3460 f->display.x->left_pos,
3461 f->display.x->top_pos,
dc6f92b8
JB
3462 width + 10, icon_font_info->height + 10,
3463 2, BlackPixmap, WhitePixmap);
3464
3465 if (icon_window == 0)
3466 return 1;
3467
c118dd06 3468 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
dc6f92b8
JB
3469 XSelectInput (icon_window, ExposeWindow | ExposeRegion | UnmapWindow | ButtonPressed);
3470
f676886a
JB
3471 f->display.x->icon_desc = icon_window;
3472 f->display.x->icon_bitmap_flag = 0;
3473 f->display.x->icon_label = 0;
c118dd06 3474#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3475
3476 return 0;
3477}
3478\f
4746118a
JB
3479/* Handling X errors. */
3480
12ba150f
JB
3481/* Shut down Emacs in an orderly fashion, because of a SIGPIPE on the
3482 X server's connection, or an error reported via the X protocol. */
16bd92ea 3483
4746118a 3484static SIGTYPE
c118dd06 3485x_connection_closed ()
4746118a
JB
3486{
3487 if (_Xdebug)
3488 abort ();
12ba150f
JB
3489
3490 shut_down_emacs (0);
3491
3492 exit (70);
4746118a
JB
3493}
3494
c118dd06
JB
3495/* An X error handler which prints an error message and then kills Emacs.
3496 This is what's normally installed as Xlib's handler for protocol and
3497 I/O errors. */
3498static int
3499x_error_quitter (display, error)
3500 Display *display;
3501 XErrorEvent *error;
3502{
3503 char buf[256];
dc6f92b8 3504
c118dd06
JB
3505 /* Note that there is no real way portable across R3/R4 to get the
3506 original error handler. */
dc6f92b8 3507
c118dd06
JB
3508 XGetErrorText (display, error->error_code, buf, sizeof (buf));
3509 fprintf (stderr, "X protocol error: %s on protocol request %d\n",
3510 buf, error->request_code);
dc6f92b8 3511
12ba150f
JB
3512 /* While we're testing Emacs 19, we'll just dump core whenever we
3513 get an X error, so we can figure out why it happened. */
3514 abort ();
3515
c118dd06 3516 x_connection_closed ();
dc6f92b8
JB
3517}
3518
c118dd06
JB
3519/* A buffer for storing X error messages. */
3520static char (*x_caught_error_message)[200];
3521
3522/* An X error handler which stores the error message in
3523 x_caught_error_message. This is what's installed when
3524 x_catch_errors is in effect. */
3525static int
3526x_error_catcher (display, error)
3527 Display *display;
3528 XErrorEvent *error;
3529{
3530 XGetErrorText (display, error->error_code,
3531 *x_caught_error_message, sizeof (*x_caught_error_message));
3532}
3533
3534
3535/* Begin trapping X errors.
dc6f92b8 3536
c118dd06
JB
3537 After calling this function, X protocol errors no longer cause
3538 Emacs to exit; instead, they are recorded in x_cfc_error_message.
dc6f92b8 3539
c118dd06
JB
3540 Calling x_check_errors signals an Emacs error if an X error has
3541 occurred since the last call to x_catch_errors or x_check_errors.
3542
3543 Calling x_uncatch_errors resumes the normal error handling. */
3544
3545void x_catch_errors(), x_check_errors (), x_uncatch_errors ();
3546
3547void
3548x_catch_errors ()
dc6f92b8 3549{
c118dd06
JB
3550 /* Make sure any errors from previous requests have been dealt with. */
3551 XSync (x_current_display, False);
dc6f92b8 3552
c118dd06
JB
3553 /* Set up the error buffer. */
3554 x_caught_error_message =
3555 (char (*)[]) xmalloc (sizeof (*x_caught_error_message));
d872b748 3556 (*x_caught_error_message)[0] = '\0';
16bd92ea 3557
c118dd06
JB
3558 /* Install our little error handler. */
3559 XHandleError (x_error_catcher);
3560}
16bd92ea 3561
c118dd06
JB
3562/* If any X protocol errors have arrived since the last call to
3563 x_catch_errors or x_check_errors, signal an Emacs error using
3564 sprintf (a buffer, FORMAT, the x error message text) as the text. */
3565void
3566x_check_errors (format)
3567 char *format;
3568{
3569 /* Make sure to catch any errors incurred so far. */
3570 XSync (x_current_display, False);
16bd92ea 3571
c118dd06
JB
3572 if ((*x_caught_error_message)[0])
3573 {
3574 char buf[256];
3575
3576 sprintf (buf, format, *x_caught_error_message);
3577 free (x_caught_error_message);
dc6f92b8 3578
c118dd06
JB
3579 x_uncatch_errors ();
3580 error (buf);
3581 }
3582}
3583
3584void
3585x_uncatch_errors ()
3586{
3587 free (x_caught_error_message);
3588 XHandleError (x_error_quitter);
dc6f92b8
JB
3589}
3590
dc6f92b8
JB
3591#if 0
3592static unsigned int x_wire_count;
3593x_trace_wire ()
3594{
3595 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
3596}
c118dd06 3597#endif /* ! 0 */
dc6f92b8
JB
3598
3599\f
f451eb13
JB
3600/* Changing the font of the frame. */
3601
f676886a 3602/* Set the font of the x-window specified by frame F
dc6f92b8 3603 to the font named NEWNAME. This is safe to use
f676886a 3604 even before F has an actual x-window. */
dc6f92b8
JB
3605
3606#ifdef HAVE_X11
3607
3608/* A table of all the fonts we have already loaded. */
3609static XFontStruct **x_font_table;
3610
3611/* The current capacity of x_font_table. */
3612static int x_font_table_size;
3613
3614/* The number of fonts actually stored in x_font_table.
3615 x_font_table[n] is used and valid iff 0 <= n < n_fonts.
3616 0 <= n_fonts <= x_font_table_size. */
3617static int n_fonts;
3618
f676886a
JB
3619x_new_font (f, fontname)
3620 struct frame *f;
dc6f92b8
JB
3621 register char *fontname;
3622{
3623 XFontStruct *temp;
3624 int already_loaded;
3625 int n_matching_fonts;
3626 XFontStruct *font_info;
3627 char **font_names;
3628
3629 /* Get a list of all the fonts that match this name. Once we
3630 have a list of matching fonts, we compare them against the fonts
3631 we already have by comparing font ids. */
3632 font_names = (char **) XListFontsWithInfo (x_current_display, fontname,
3633 1024, &n_matching_fonts,
3634 &font_info);
3635 /* If the server couldn't find any fonts whose named matched fontname,
3636 return an error code. */
3637 if (n_matching_fonts == 0)
3638 return 1;
3639
90e65f07 3640 /* See if we've already loaded a matching font. */
dc6f92b8
JB
3641 {
3642 int i, j;
3643
3644 already_loaded = 0;
3645 for (i = 0; i < n_fonts; i++)
3646 for (j = 0; j < n_matching_fonts; j++)
3647 if (x_font_table[i]->fid == font_info[j].fid)
3648 {
3649 already_loaded = i;
3650 goto found_font;
3651 }
3652 }
3653 found_font:
3654
3655 /* If we have, just return it from the table. */
3656 if (already_loaded)
f676886a 3657 f->display.x->font = x_font_table[already_loaded];
90e65f07 3658
dc6f92b8
JB
3659 /* Otherwise, load the font and add it to the table. */
3660 else
3661 {
3662 XFontStruct *font;
3663
3664 font = (XFontStruct *) XLoadQueryFont (x_current_display, fontname);
3665 if (! font)
3666 return 1;
3667
3668 /* Do we need to create the table? */
3669 if (x_font_table_size == 0)
3670 {
3671 x_font_table_size = 16;
3672 x_font_table
3673 = (XFontStruct **) xmalloc (x_font_table_size
3674 * sizeof (x_font_table[0]));
3675 }
3676 /* Do we need to grow the table? */
3677 else if (n_fonts >= x_font_table_size)
3678 {
90e65f07 3679 x_font_table_size *= 2;
dc6f92b8
JB
3680 x_font_table
3681 = (XFontStruct **) xrealloc (x_font_table,
3682 (x_font_table_size
3683 * sizeof (x_font_table[0])));
3684 }
3685
f676886a 3686 f->display.x->font = x_font_table[n_fonts++] = font;
dc6f92b8
JB
3687 }
3688
3689 /* Free the information from XListFontsWithInfo. The data
3690 we actually retain comes from XLoadQueryFont. */
3691 XFreeFontInfo (font_names, font_info, n_matching_fonts);
3692
f676886a 3693 /* Now make the frame display the given font. */
c118dd06 3694 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 3695 {
f676886a
JB
3696 XSetFont (x_current_display, f->display.x->normal_gc,
3697 f->display.x->font->fid);
3698 XSetFont (x_current_display, f->display.x->reverse_gc,
3699 f->display.x->font->fid);
3700 XSetFont (x_current_display, f->display.x->cursor_gc,
3701 f->display.x->font->fid);
3702
3703 x_set_window_size (f, f->width, f->height);
dc6f92b8
JB
3704 }
3705
3706 return 0;
3707}
c118dd06 3708#else /* ! defined (HAVE_X11) */
f676886a
JB
3709x_new_font (f, newname)
3710 struct frame *f;
dc6f92b8
JB
3711 register char *newname;
3712{
3713 FONT_TYPE *temp;
3714 int mask;
3715
3716 temp = XGetFont (newname);
3717 if (temp == (FONT_TYPE *) 0)
3718 return 1;
3719
f676886a
JB
3720 if (f->display.x->font)
3721 XLoseFont (f->display.x->font);
dc6f92b8 3722
f676886a 3723 f->display.x->font = temp;
dc6f92b8 3724
c118dd06 3725 if (FRAME_X_WINDOW (f) != 0)
f676886a 3726 x_set_window_size (f, f->width, f->height);
dc6f92b8
JB
3727
3728 return 0;
3729}
c118dd06 3730#endif /* ! defined (HAVE_X11) */
dc6f92b8 3731\f
f451eb13
JB
3732/* X Window sizes and positions. */
3733
f676886a
JB
3734x_calc_absolute_position (f)
3735 struct frame *f;
dc6f92b8
JB
3736{
3737#ifdef HAVE_X11
f676886a
JB
3738 if (f->display.x->left_pos < 0)
3739 f->display.x->left_pos
7c5283e4 3740 = x_screen_width - PIXEL_WIDTH (f) + f->display.x->left_pos;
dc6f92b8 3741
f676886a
JB
3742 if (f->display.x->top_pos < 0)
3743 f->display.x->top_pos
7c5283e4 3744 = x_screen_height - PIXEL_HEIGHT (f) + f->display.x->top_pos;
c118dd06 3745#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3746 WINDOWINFO_TYPE parentinfo;
3747
c118dd06 3748 XGetWindowInfo (FRAME_X_WINDOW (f), &parentinfo);
dc6f92b8 3749
f676886a
JB
3750 if (f->display.x->left_pos < 0)
3751 f->display.x->left_pos = parentinfo.width + (f->display.x->left_pos + 1)
3752 - PIXEL_WIDTH (f) - 2 * f->display.x->internal_border_width;
dc6f92b8 3753
f676886a
JB
3754 if (f->display.x->top_pos < 0)
3755 f->display.x->top_pos = parentinfo.height + (f->display.x->top_pos + 1)
3756 - PIXEL_HEIGHT (f) - 2 * f->display.x->internal_border_width;
c118dd06 3757#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3758}
3759
f676886a
JB
3760x_set_offset (f, xoff, yoff)
3761 struct frame *f;
dc6f92b8
JB
3762 register int xoff, yoff;
3763{
f676886a
JB
3764 f->display.x->top_pos = yoff;
3765 f->display.x->left_pos = xoff;
3766 x_calc_absolute_position (f);
dc6f92b8
JB
3767
3768 BLOCK_INPUT;
c118dd06 3769 XMoveWindow (XDISPLAY FRAME_X_WINDOW (f),
f676886a 3770 f->display.x->left_pos, f->display.x->top_pos);
dc6f92b8 3771#ifdef HAVE_X11
f676886a 3772 x_wm_set_size_hint (f, 0);
c118dd06 3773#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3774 UNBLOCK_INPUT;
3775}
3776
f676886a 3777/* Call this to change the size of frame F's x-window. */
dc6f92b8 3778
f676886a
JB
3779x_set_window_size (f, cols, rows)
3780 struct frame *f;
b1c884c3 3781 int cols, rows;
dc6f92b8
JB
3782{
3783 int pixelwidth, pixelheight;
3784 int mask;
dc6f92b8
JB
3785
3786 BLOCK_INPUT;
3787
b1c884c3 3788 check_frame_size (f, &rows, &cols);
f451eb13
JB
3789 f->display.x->vertical_scrollbar_extra =
3790 (FRAME_HAS_VERTICAL_SCROLLBARS (f)
3791 ? VERTICAL_SCROLLBAR_PIXEL_WIDTH (f)
3792 : 0);
3793 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
3794 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8
JB
3795
3796#ifdef HAVE_X11
f676886a 3797 x_wm_set_size_hint (f, 0);
c118dd06
JB
3798#endif /* ! defined (HAVE_X11) */
3799 XChangeWindowSize (FRAME_X_WINDOW (f), pixelwidth, pixelheight);
b1c884c3
JB
3800
3801 /* Now, strictly speaking, we can't be sure that this is accurate,
3802 but the window manager will get around to dealing with the size
3803 change request eventually, and we'll hear how it went when the
3804 ConfigureNotify event gets here. */
3805 FRAME_WIDTH (f) = cols;
12ba150f 3806 FRAME_HEIGHT (f) = rows;
b1c884c3
JB
3807 PIXEL_WIDTH (f) = pixelwidth;
3808 PIXEL_HEIGHT (f) = pixelheight;
3809
dc6f92b8
JB
3810 XFlushQueue ();
3811 UNBLOCK_INPUT;
3812}
3813
3814#ifndef HAVE_X11
f676886a
JB
3815x_set_resize_hint (f)
3816 struct frame *f;
dc6f92b8 3817{
12ba150f
JB
3818 XSetResizeHint (FRAME_X_WINDOW (f),
3819 2 * f->display.x->internal_border_width,
f676886a 3820 2 * f->display.x->internal_border_width,
12ba150f
JB
3821 FONT_WIDTH (f->display.x->font),
3822 FONT_HEIGHT (f->display.x->font));
dc6f92b8 3823}
c118dd06 3824#endif /* HAVE_X11 */
dc6f92b8 3825\f
f451eb13 3826/* Mouse warping, focus shifting, raising and lowering. */
dc6f92b8 3827
f676886a
JB
3828x_set_mouse_position (f, x, y)
3829 struct frame *f;
dc6f92b8
JB
3830 int x, y;
3831{
3832 int pix_x, pix_y;
3833
f676886a 3834 x_raise_frame (f);
dc6f92b8 3835
12ba150f
JB
3836 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2;
3837 pix_y = CHAR_TO_PIXEL_ROW (f, y) + FONT_HEIGHT (f->display.x->font) / 2;
f451eb13
JB
3838
3839 if (pix_x < 0) pix_x = 0;
3840 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
3841
3842 if (pix_y < 0) pix_y = 0;
3843 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
3844
3845 BLOCK_INPUT;
dc6f92b8 3846
c118dd06 3847 XWarpMousePointer (FRAME_X_WINDOW (f), pix_x, pix_y);
dc6f92b8
JB
3848 UNBLOCK_INPUT;
3849}
3850
3851#ifdef HAVE_X11
f676886a
JB
3852x_focus_on_frame (f)
3853 struct frame *f;
dc6f92b8 3854{
f676886a 3855 x_raise_frame (f);
6d4238f3
JB
3856#if 0
3857 /* I don't think that the ICCCM allows programs to do things like this
3858 without the interaction of the window manager. Whatever you end up
f676886a 3859 doing with this code, do it to x_unfocus_frame too. */
c118dd06 3860 XSetInputFocus (x_current_display, FRAME_X_WINDOW (f),
dc6f92b8 3861 RevertToPointerRoot, CurrentTime);
c118dd06 3862#endif /* ! 0 */
dc6f92b8
JB
3863}
3864
f676886a
JB
3865x_unfocus_frame (f)
3866 struct frame *f;
dc6f92b8 3867{
6d4238f3 3868#if 0
f676886a
JB
3869 /* Look at the remarks in x_focus_on_frame. */
3870 if (x_focus_frame == f)
dc6f92b8
JB
3871 XSetInputFocus (x_current_display, PointerRoot,
3872 RevertToPointerRoot, CurrentTime);
c118dd06 3873#endif /* ! 0 */
dc6f92b8
JB
3874}
3875
c118dd06 3876#endif /* ! defined (HAVE_X11) */
dc6f92b8 3877
f676886a 3878/* Raise frame F. */
dc6f92b8 3879
f676886a
JB
3880x_raise_frame (f)
3881 struct frame *f;
dc6f92b8 3882{
3a88c238 3883 if (f->async_visible)
dc6f92b8
JB
3884 {
3885 BLOCK_INPUT;
c118dd06 3886 XRaiseWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8
JB
3887 XFlushQueue ();
3888 UNBLOCK_INPUT;
3889 }
3890}
3891
f676886a 3892/* Lower frame F. */
dc6f92b8 3893
f676886a
JB
3894x_lower_frame (f)
3895 struct frame *f;
dc6f92b8 3896{
3a88c238 3897 if (f->async_visible)
dc6f92b8
JB
3898 {
3899 BLOCK_INPUT;
c118dd06 3900 XLowerWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8
JB
3901 XFlushQueue ();
3902 UNBLOCK_INPUT;
3903 }
3904}
3905
3906/* Change from withdrawn state to mapped state. */
3907
f676886a
JB
3908x_make_frame_visible (f)
3909 struct frame *f;
dc6f92b8
JB
3910{
3911 int mask;
3912
dc6f92b8 3913 BLOCK_INPUT;
dc6f92b8 3914
f676886a 3915 if (! FRAME_VISIBLE_P (f))
90e65f07
JB
3916 {
3917#ifdef HAVE_X11
3918 if (! EQ (Vx_no_window_manager, Qt))
f676886a 3919 x_wm_set_window_state (f, NormalState);
dc6f92b8 3920
c118dd06 3921 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
f451eb13 3922 if (FRAME_HAS_VERTICAL_SCROLLBARS (f))
c118dd06
JB
3923 XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
3924#else /* ! defined (HAVE_X11) */
3925 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
f676886a
JB
3926 if (f->display.x->icon_desc != 0)
3927 XUnmapWindow (f->display.x->icon_desc);
dc6f92b8 3928
90e65f07 3929 /* Handled by the MapNotify event for X11 */
3a88c238
JB
3930 f->async_visible = 1;
3931 f->async_iconified = 0;
dc6f92b8 3932
f676886a 3933 /* NOTE: this may cause problems for the first frame. */
90e65f07 3934 XTcursor_to (0, 0);
c118dd06 3935#endif /* ! defined (HAVE_X11) */
90e65f07 3936 }
dc6f92b8 3937
dc6f92b8 3938 XFlushQueue ();
90e65f07 3939
dc6f92b8
JB
3940 UNBLOCK_INPUT;
3941}
3942
3943/* Change from mapped state to withdrawn state. */
3944
f676886a
JB
3945x_make_frame_invisible (f)
3946 struct frame *f;
dc6f92b8
JB
3947{
3948 int mask;
3949
3a88c238 3950 if (! f->async_visible)
dc6f92b8
JB
3951 return;
3952
3953 BLOCK_INPUT;
c118dd06
JB
3954
3955#ifdef HAVE_X11R4
3956
3957 if (! XWithdrawWindow (x_current_display, FRAME_X_WINDOW (f),
3958 DefaultScreen (x_current_display)))
3959 {
3960 UNBLOCK_INPUT_RESIGNAL;
3961 error ("can't notify window manager of window withdrawl");
3962 }
3963
3964#else /* ! defined (HAVE_X11R4) */
dc6f92b8 3965#ifdef HAVE_X11
16bd92ea 3966
c118dd06 3967 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
3968 if (! EQ (Vx_no_window_manager, Qt))
3969 {
16bd92ea 3970 XEvent unmap;
dc6f92b8 3971
16bd92ea 3972 unmap.xunmap.type = UnmapNotify;
c118dd06 3973 unmap.xunmap.window = FRAME_X_WINDOW (f);
16bd92ea
JB
3974 unmap.xunmap.event = DefaultRootWindow (x_current_display);
3975 unmap.xunmap.from_configure = False;
3976 if (! XSendEvent (x_current_display,
3977 DefaultRootWindow (x_current_display),
3978 False,
3979 SubstructureRedirectMask|SubstructureNotifyMask,
3980 &unmap))
3981 {
3982 UNBLOCK_INPUT_RESIGNAL;
3983 error ("can't notify window manager of withdrawal");
3984 }
dc6f92b8
JB
3985 }
3986
16bd92ea 3987 /* Unmap the window ourselves. Cheeky! */
c118dd06
JB
3988 XUnmapWindow (x_current_display, FRAME_X_WINDOW (f));
3989
3990#else /* ! defined (HAVE_X11) */
dc6f92b8 3991
c118dd06 3992 XUnmapWindow (FRAME_X_WINDOW (f));
3a88c238 3993 f->async_visible = 0; /* Handled by the UnMap event for X11 */
f676886a 3994 if (f->display.x->icon_desc != 0)
c118dd06
JB
3995 XUnmapWindow (f->display.x->icon_desc);
3996
3997#endif /* ! defined (HAVE_X11) */
3998#endif /* ! defined (HAVE_X11R4) */
dc6f92b8
JB
3999
4000 XFlushQueue ();
4001 UNBLOCK_INPUT;
4002}
4003
16bd92ea 4004/* Window manager communication. Created in Fx_open_connection. */
dc6f92b8
JB
4005extern Atom Xatom_wm_change_state;
4006
4007/* Change window state from mapped to iconified. */
4008
f676886a
JB
4009x_iconify_frame (f)
4010 struct frame *f;
dc6f92b8
JB
4011{
4012 int mask;
4013
3a88c238 4014 if (f->async_iconified)
dc6f92b8
JB
4015 return;
4016
4017 BLOCK_INPUT;
4018
4019#ifdef HAVE_X11
16bd92ea
JB
4020 /* Since we don't know which revision of X we're running, we'll use both
4021 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
4022
4023 /* X11R4: send a ClientMessage to the window manager using the
4024 WM_CHANGE_STATE type. */
4025 {
4026 XEvent message;
4027
c118dd06 4028 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea
JB
4029 message.xclient.type = ClientMessage;
4030 message.xclient.message_type = Xatom_wm_change_state;
4031 message.xclient.format = 32;
4032 message.xclient.data.l[0] = IconicState;
4033
4034 if (! XSendEvent (x_current_display,
4035 DefaultRootWindow (x_current_display),
4036 False,
4037 SubstructureRedirectMask | SubstructureNotifyMask,
4038 &message))
dc6f92b8
JB
4039 {
4040 UNBLOCK_INPUT_RESIGNAL;
4041 error ("Can't notify window manager of iconification.");
4042 }
16bd92ea 4043 }
dc6f92b8 4044
16bd92ea
JB
4045 /* X11R3: set the initial_state field of the window manager hints to
4046 IconicState. */
4047 x_wm_set_window_state (f, IconicState);
dc6f92b8 4048
3a88c238 4049 f->async_iconified = 1;
c118dd06
JB
4050#else /* ! defined (HAVE_X11) */
4051 XUnmapWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8 4052
3a88c238 4053 f->async_visible = 0; /* Handled in the UnMap event for X11. */
f676886a 4054 if (f->display.x->icon_desc != 0)
dc6f92b8 4055 {
f676886a
JB
4056 XMapWindow (XDISPLAY f->display.x->icon_desc);
4057 refreshicon (f);
dc6f92b8 4058 }
c118dd06 4059#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4060
4061 XFlushQueue ();
4062 UNBLOCK_INPUT;
4063}
4064
c0ff3fab 4065/* Destroy the X window of frame F. */
dc6f92b8 4066
c0ff3fab 4067x_destroy_window (f)
f676886a 4068 struct frame *f;
dc6f92b8 4069{
dc6f92b8 4070 BLOCK_INPUT;
c0ff3fab
JB
4071
4072 if (f->display.x->icon_desc != 0)
4073 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
4074 XDestroyWindow (XDISPLAY f->display.x->window_desc);
dc6f92b8 4075 XFlushQueue ();
dc6f92b8 4076
c0ff3fab
JB
4077 free (f->display.x);
4078 f->display.x = 0;
f676886a
JB
4079 if (f == x_focus_frame)
4080 x_focus_frame = 0;
4081 if (f == x_highlight_frame)
4082 x_highlight_frame = 0;
c0ff3fab
JB
4083
4084 UNBLOCK_INPUT;
dc6f92b8
JB
4085}
4086\f
f451eb13
JB
4087/* Manage event queues for X10. */
4088
dc6f92b8
JB
4089#ifndef HAVE_X11
4090
4091/* Manage event queues.
4092
4093 This code is only used by the X10 support.
4094
4095 We cannot leave events in the X queue and get them when we are ready
4096 because X does not provide a subroutine to get only a certain kind
4097 of event but not block if there are no queued events of that kind.
4098
4099 Therefore, we must examine events as they come in and copy events
4100 of certain kinds into our private queues.
4101
4102 All ExposeRegion events are put in x_expose_queue.
4103 All ButtonPressed and ButtonReleased events are put in x_mouse_queue. */
4104
4105
4106/* Write the event *P_XREP into the event queue *QUEUE.
4107 If the queue is full, do nothing, but return nonzero. */
4108
4109int
4110enqueue_event (p_xrep, queue)
4111 register XEvent *p_xrep;
4112 register struct event_queue *queue;
4113{
4114 int newindex = queue->windex + 1;
4115 if (newindex == EVENT_BUFFER_SIZE)
4116 newindex = 0;
4117 if (newindex == queue->rindex)
4118 return -1;
4119 queue->xrep[queue->windex] = *p_xrep;
4120 queue->windex = newindex;
4121 return 0;
4122}
4123
4124/* Fetch the next event from queue *QUEUE and store it in *P_XREP.
4125 If *QUEUE is empty, do nothing and return 0. */
4126
4127int
4128dequeue_event (p_xrep, queue)
4129 register XEvent *p_xrep;
4130 register struct event_queue *queue;
4131{
4132 if (queue->windex == queue->rindex)
4133 return 0;
4134 *p_xrep = queue->xrep[queue->rindex++];
4135 if (queue->rindex == EVENT_BUFFER_SIZE)
4136 queue->rindex = 0;
4137 return 1;
4138}
4139
4140/* Return the number of events buffered in *QUEUE. */
4141
4142int
4143queue_event_count (queue)
4144 register struct event_queue *queue;
4145{
4146 int tem = queue->windex - queue->rindex;
4147 if (tem >= 0)
4148 return tem;
4149 return EVENT_BUFFER_SIZE + tem;
4150}
4151
4152/* Return nonzero if mouse input is pending. */
4153
4154int
4155mouse_event_pending_p ()
4156{
4157 return queue_event_count (&x_mouse_queue);
4158}
c118dd06 4159#endif /* HAVE_X11 */
dc6f92b8 4160\f
f451eb13
JB
4161/* Setting window manager hints. */
4162
dc6f92b8
JB
4163#ifdef HAVE_X11
4164
f676886a
JB
4165x_wm_set_size_hint (f, prompting)
4166 struct frame *f;
dc6f92b8
JB
4167 long prompting;
4168{
4169 XSizeHints size_hints;
c118dd06 4170 Window window = FRAME_X_WINDOW (f);
dc6f92b8
JB
4171
4172 size_hints.flags = PResizeInc | PMinSize | PMaxSize;
4173
f676886a
JB
4174 flexlines = f->height;
4175
4176 size_hints.x = f->display.x->left_pos;
4177 size_hints.y = f->display.x->top_pos;
4178 size_hints.height = PIXEL_HEIGHT (f);
4179 size_hints.width = PIXEL_WIDTH (f);
4180 size_hints.width_inc = FONT_WIDTH (f->display.x->font);
4181 size_hints.height_inc = FONT_HEIGHT (f->display.x->font);
12ba150f
JB
4182 size_hints.max_width = x_screen_width - CHAR_TO_PIXEL_WIDTH (f, 0);
4183 size_hints.max_height = x_screen_height - CHAR_TO_PIXEL_HEIGHT (f, 0);
f451eb13 4184
b1c884c3 4185 {
b0342f17
JB
4186 int base_width, base_height;
4187
f451eb13
JB
4188 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
4189 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17
JB
4190
4191 {
4192 int min_rows = 0, min_cols = 0;
4193 check_frame_size (f, &min_rows, &min_cols);
4194
4195 /* The window manager uses the base width hints to calculate the
4196 current number of rows and columns in the frame while
4197 resizing; min_width and min_height aren't useful for this
4198 purpose, since they might not give the dimensions for a
4199 zero-row, zero-column frame.
4200
4201 We use the base_width and base_height members if we have
4202 them; otherwise, we set the min_width and min_height members
4203 to the size for a zero x zero frame. */
4204
4205#ifdef HAVE_X11R4
4206 size_hints.flags |= PBaseSize;
4207 size_hints.base_width = base_width;
4208 size_hints.base_height = base_height;
4209 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
4210 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
4211#else
4212 size_hints.min_width = base_width;
4213 size_hints.min_height = base_height;
4214#endif
4215 }
b1c884c3 4216
b1c884c3 4217 }
dc6f92b8
JB
4218
4219 if (prompting)
4220 size_hints.flags |= prompting;
4221 else
4222 {
4223 XSizeHints hints; /* Sometimes I hate X Windows... */
4224
4225 XGetNormalHints (x_current_display, window, &hints);
4226 if (hints.flags & PSize)
4227 size_hints.flags |= PSize;
4228 if (hints.flags & PPosition)
4229 size_hints.flags |= PPosition;
4230 if (hints.flags & USPosition)
4231 size_hints.flags |= USPosition;
4232 if (hints.flags & USSize)
4233 size_hints.flags |= USSize;
4234 }
16bd92ea 4235
b0342f17
JB
4236#ifdef HAVE_X11R4
4237 XSetWMNormalHints (x_current_display, window, &size_hints);
4238#else
dc6f92b8 4239 XSetNormalHints (x_current_display, window, &size_hints);
b0342f17 4240#endif
dc6f92b8
JB
4241}
4242
4243/* Used for IconicState or NormalState */
f676886a
JB
4244x_wm_set_window_state (f, state)
4245 struct frame *f;
dc6f92b8
JB
4246 int state;
4247{
c118dd06 4248 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4249
16bd92ea
JB
4250 f->display.x->wm_hints.flags |= StateHint;
4251 f->display.x->wm_hints.initial_state = state;
b1c884c3 4252
16bd92ea 4253 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4254}
4255
f676886a
JB
4256x_wm_set_icon_pixmap (f, icon_pixmap)
4257 struct frame *f;
dc6f92b8
JB
4258 Pixmap icon_pixmap;
4259{
c118dd06 4260 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4261
16bd92ea
JB
4262 f->display.x->wm_hints.flags |= IconPixmapHint;
4263 f->display.x->wm_hints.icon_pixmap = icon_pixmap ? icon_pixmap : None;
b1c884c3 4264
16bd92ea 4265 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4266}
4267
f676886a
JB
4268x_wm_set_icon_position (f, icon_x, icon_y)
4269 struct frame *f;
dc6f92b8
JB
4270 int icon_x, icon_y;
4271{
c118dd06 4272 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4273
16bd92ea
JB
4274 f->display.x->wm_hints.flags |= IconPositionHint;
4275 f->display.x->wm_hints.icon_x = icon_x;
4276 f->display.x->wm_hints.icon_y = icon_y;
b1c884c3 4277
16bd92ea 4278 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4279}
4280
4281\f
f451eb13
JB
4282/* Initialization. */
4283
dc6f92b8
JB
4284void
4285x_term_init (display_name)
4286 char *display_name;
4287{
f676886a 4288 Lisp_Object frame;
dc6f92b8
JB
4289 char *defaultvalue;
4290#ifdef F_SETOWN
4291 extern int old_fcntl_owner;
c118dd06 4292#endif /* ! defined (F_SETOWN) */
6d4238f3 4293
f676886a 4294 x_focus_frame = x_highlight_frame = 0;
dc6f92b8
JB
4295
4296 x_current_display = XOpenDisplay (display_name);
4297 if (x_current_display == 0)
4298 fatal ("X server %s not responding; check the DISPLAY environment variable or use \"-d\"\n",
4299 display_name);
4300
4301#ifdef HAVE_X11
4302 {
16bd92ea 4303 int hostname_size = 256;
60fb3ee1
JB
4304
4305 hostname = (char *) xmalloc (hostname_size);
4306
dc6f92b8
JB
4307#if 0
4308 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 4309#endif /* ! 0 */
dc6f92b8 4310
55123275 4311 invocation_name = Ffile_name_nondirectory (Fcar (Vcommand_line_args));
60fb3ee1
JB
4312
4313 /* Try to get the host name; if the buffer is too short, try
4314 again. Apparently, the only indication gethostname gives of
4315 whether the buffer was large enough is the presence or absence
4316 of a '\0' in the string. Eech. */
4317 for (;;)
4318 {
4319 gethostname (hostname, hostname_size - 1);
4320 hostname[hostname_size - 1] = '\0';
4321
4322 /* Was the buffer large enough for gethostname to store the '\0'? */
4323 if (strlen (hostname) < hostname_size - 1)
4324 break;
4325
4326 hostname_size <<= 1;
4327 hostname = (char *) xrealloc (hostname, hostname_size);
4328 }
4329 x_id_name = (char *) xmalloc (XSTRING (invocation_name)->size
4330 + strlen (hostname)
4331 + 2);
4332 sprintf (x_id_name, "%s@%s", XSTRING (invocation_name)->data, hostname);
dc6f92b8 4333 }
28430d3c
JB
4334
4335 /* Figure out which modifier bits mean what. */
4336 x_find_modifier_meanings ();
f451eb13
JB
4337
4338 /* Get the scrollbar cursor. */
4339 x_vertical_scrollbar_cursor =
4340 XCreateFontCursor (x_current_display, XC_sb_v_double_arrow);
4341
28430d3c
JB
4342 /* Watch for PropertyNotify events on the root window; we use them
4343 to figure out when to invalidate our cache of the cut buffers. */
4344 x_watch_cut_buffer_cache ();
4345
dc6f92b8 4346 dup2 (ConnectionNumber (x_current_display), 0);
6d4238f3
JB
4347
4348#ifndef SYSV_STREAMS
4349 /* Streams somehow keeps track of which descriptor number
4350 is being used to talk to X. So it is not safe to substitute
4351 descriptor 0. But it is safe to make descriptor 0 a copy of it. */
dc6f92b8 4352 close (ConnectionNumber (x_current_display));
6d4238f3
JB
4353 ConnectionNumber (x_current_display) = 0; /* Looks a little strange?
4354 * check the def of the macro;
4355 * it is a genuine lvalue */
c118dd06 4356#endif /* SYSV_STREAMS */
6d4238f3 4357
c118dd06 4358#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4359
4360#ifdef F_SETOWN
4361 old_fcntl_owner = fcntl (0, F_GETOWN, 0);
4362#ifdef F_SETOWN_SOCK_NEG
4363 fcntl (0, F_SETOWN, -getpid ()); /* stdin is a socket here */
c118dd06 4364#else /* ! defined (F_SETOWN_SOCK_NEG) */
dc6f92b8 4365 fcntl (0, F_SETOWN, getpid ());
c118dd06
JB
4366#endif /* ! defined (F_SETOWN_SOCK_NEG) */
4367#endif /* ! defined (F_SETOWN) */
dc6f92b8
JB
4368
4369#ifdef SIGIO
4370 init_sigio ();
c118dd06 4371#endif /* ! defined (SIGIO) */
dc6f92b8
JB
4372
4373 /* Must use interrupt input because we cannot otherwise
4374 arrange for C-g to be noticed immediately.
4375 We cannot connect it to SIGINT. */
4376 Fset_input_mode (Qt, Qnil, Qt, Qnil);
4377
4378 expose_all_windows = 0;
4379
f676886a 4380 clear_frame_hook = XTclear_frame;
dc6f92b8
JB
4381 clear_end_of_line_hook = XTclear_end_of_line;
4382 ins_del_lines_hook = XTins_del_lines;
4383 change_line_highlight_hook = XTchange_line_highlight;
4384 insert_glyphs_hook = XTinsert_glyphs;
4385 write_glyphs_hook = XTwrite_glyphs;
4386 delete_glyphs_hook = XTdelete_glyphs;
4387 ring_bell_hook = XTring_bell;
4388 reset_terminal_modes_hook = XTreset_terminal_modes;
4389 set_terminal_modes_hook = XTset_terminal_modes;
4390 update_begin_hook = XTupdate_begin;
4391 update_end_hook = XTupdate_end;
4392 set_terminal_window_hook = XTset_terminal_window;
4393 read_socket_hook = XTread_socket;
4394 cursor_to_hook = XTcursor_to;
4395 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 4396 mouse_position_hook = XTmouse_position;
f451eb13 4397 frame_rehighlight_hook = XTframe_rehighlight;
12ba150f 4398 set_vertical_scrollbar_hook = XTset_vertical_scrollbar;
f451eb13
JB
4399 condemn_scrollbars_hook = XTcondemn_scrollbars;
4400 redeem_scrollbar_hook = XTredeem_scrollbar;
4401 judge_scrollbars_hook = XTjudge_scrollbars;
dc6f92b8 4402
f676886a 4403 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
4404 char_ins_del_ok = 0; /* just as fast to write the line */
4405 line_ins_del_ok = 1; /* we'll just blt 'em */
4406 fast_clear_end_of_line = 1; /* X does this well */
f676886a 4407 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
4408 off the bottom */
4409 baud_rate = 19200;
4410
c118dd06
JB
4411 /* Note that there is no real way portable across R3/R4 to get the
4412 original error handler. */
4413 XHandleError (x_error_quitter);
4414 XHandleIOError (x_error_quitter);
dc6f92b8
JB
4415
4416 /* Disable Window Change signals; they are handled by X events. */
4417#ifdef SIGWINCH
4418 signal (SIGWINCH, SIG_DFL);
c118dd06 4419#endif /* ! defined (SIGWINCH) */
dc6f92b8 4420
c118dd06 4421 signal (SIGPIPE, x_connection_closed);
dc6f92b8 4422}
55123275
JB
4423
4424void
4425syms_of_xterm ()
4426{
4427 staticpro (&invocation_name);
4428 invocation_name = Qnil;
12ba150f
JB
4429
4430 staticpro (&last_mouse_scrollbar);
55123275 4431}
c118dd06
JB
4432#endif /* ! defined (HAVE_X11) */
4433#endif /* ! defined (HAVE_X_WINDOWS) */