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