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