* xfns.c (x_make_gc): After building the GC's for the frame, call
[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"
9ac0d9e0 35#include "blockinput.h"
dc6f92b8 36
54c908b5
JB
37/* On 4.3 these lose if they come after xterm.h. */
38#include <stdio.h>
dc6f92b8
JB
39#include <signal.h>
40
41/* This may include sys/types.h, and that somehow loses
42 if this is not done before the other system files. */
43#include "xterm.h"
f451eb13 44#include <X11/cursorfont.h>
dc6f92b8 45
16bd92ea 46#ifndef USG
dc6f92b8
JB
47/* Load sys/types.h if not already loaded.
48 In some systems loading it twice is suicidal. */
49#ifndef makedev
50#include <sys/types.h>
c118dd06
JB
51#endif /* makedev */
52#endif /* USG */
dc6f92b8
JB
53
54#ifdef BSD
55#include <sys/ioctl.h>
56#include <strings.h>
c118dd06 57#else /* ! defined (BSD) */
febf25d5 58#ifndef VMS
dc6f92b8
JB
59#include <sys/termio.h>
60#include <string.h>
febf25d5 61#endif
c118dd06 62#endif /* ! defined (BSD) */
dc6f92b8
JB
63
64/* Allow m- file to inhibit use of FIONREAD. */
65#ifdef BROKEN_FIONREAD
66#undef FIONREAD
c118dd06 67#endif /* ! defined (BROKEN_FIONREAD) */
dc6f92b8
JB
68
69/* We are unable to use interrupts if FIONREAD is not available,
70 so flush SIGIO so we won't try. */
71#ifndef FIONREAD
72#ifdef SIGIO
73#undef SIGIO
c118dd06
JB
74#endif /* ! defined (SIGIO) */
75#endif /* FIONREAD */
dc6f92b8 76
3a2712f9 77#include "systime.h"
dc6f92b8
JB
78
79#include <fcntl.h>
dc6f92b8
JB
80#include <ctype.h>
81#include <errno.h>
82#include <setjmp.h>
83#include <sys/stat.h>
84#include <sys/param.h>
85
86#include "dispextern.h"
87#include "termhooks.h"
88#include "termopts.h"
89#include "termchar.h"
90#if 0
91#include "sink.h"
92#include "sinkmask.h"
c118dd06 93#endif /* ! 0 */
dc6f92b8 94#include "gnu.h"
f676886a 95#include "frame.h"
dc6f92b8 96#include "disptab.h"
dc6f92b8 97#include "buffer.h"
f451eb13 98#include "window.h"
dc6f92b8
JB
99
100#ifdef HAVE_X11
101#define XMapWindow XMapRaised /* Raise them when mapping. */
c118dd06 102#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
103#include <X/Xkeyboard.h>
104/*#include <X/Xproto.h> */
c118dd06 105#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
106
107/* For sending Meta-characters. Do we need this? */
108#define METABIT 0200
109
110#define min(a,b) ((a)<(b) ? (a) : (b))
111#define max(a,b) ((a)>(b) ? (a) : (b))
112
113/* Nonzero means we must reprint all windows
114 because 1) we received an ExposeWindow event
f451eb13 115 or 2) we received too many ExposeRegion events to record.
dc6f92b8 116
f451eb13 117 This is never needed under X11. */
dc6f92b8
JB
118static int expose_all_windows;
119
120/* Nonzero means we must reprint all icon windows. */
121
122static int expose_all_icons;
123
124#ifndef HAVE_X11
125/* ExposeRegion events, when received, are copied into this queue
126 for later processing. */
127
128static struct event_queue x_expose_queue;
129
130/* ButtonPressed and ButtonReleased events, when received,
131 are copied into this queue for later processing. */
132
133struct event_queue x_mouse_queue;
c118dd06 134#endif /* HAVE_X11 */
dc6f92b8 135
dc6f92b8
JB
136#if defined (SIGIO) && defined (FIONREAD)
137int BLOCK_INPUT_mask;
c118dd06 138#endif /* ! defined (SIGIO) && defined (FIONREAD) */
dc6f92b8 139
dc6f92b8
JB
140/* The id of a bitmap used for icon windows.
141 One such map is shared by all Emacs icon windows.
142 This is zero if we have not yet had a need to create the bitmap. */
143
144static Bitmap icon_bitmap;
145
146/* Font used for text icons. */
147
148static FONT_TYPE *icon_font_info;
149
150/* Stuff for dealing with the main icon title. */
151
152extern Lisp_Object Vcommand_line_args;
60fb3ee1 153char *hostname, *x_id_name;
dc6f92b8
JB
154
155/* This is the X connection that we are using. */
156
157Display *x_current_display;
158
ab648270
JB
159/* The cursor to use for vertical scroll bars on x_current_display. */
160static Cursor x_vertical_scroll_bar_cursor;
f451eb13 161
987d2ad1 162/* Frame being updated by update_frame. This is declared in term.c.
d0386f2a 163 This is set by update_begin and looked at by all the
dc6f92b8 164 XT functions. It is zero while not inside an update.
f676886a
JB
165 In that case, the XT functions assume that `selected_frame'
166 is the frame to apply to. */
d0386f2a 167extern struct frame *updating_frame;
dc6f92b8 168
f676886a 169/* The frame (if any) which has the X window that has keyboard focus.
f451eb13
JB
170 Zero if none. This is examined by Ffocus_frame in frame.c. Note
171 that a mere EnterNotify event can set this; if you need to know the
172 last frame specified in a FocusIn or FocusOut event, use
173 x_focus_event_frame. */
f676886a 174struct frame *x_focus_frame;
dc6f92b8 175
f451eb13
JB
176/* The last frame mentioned in a FocusIn or FocusOut event. This is
177 separate from x_focus_frame, because whether or not LeaveNotify
178 events cause us to lose focus depends on whether or not we have
179 received a FocusIn event for it. */
180struct frame *x_focus_event_frame;
181
f676886a
JB
182/* The frame which currently has the visual highlight, and should get
183 keyboard input (other sorts of input have the frame encoded in the
184 event). It points to the X focus frame's selected window's
185 frame. It differs from x_focus_frame when we're using a global
6d4238f3 186 minibuffer. */
f676886a 187static struct frame *x_highlight_frame;
6d4238f3 188
dc6f92b8 189/* From .Xdefaults, the value of "emacs.WarpMouse". If non-zero,
f676886a 190 mouse is moved to inside of frame when frame is de-iconified. */
dc6f92b8
JB
191
192static int warp_mouse_on_deiconify;
193
194/* During an update, maximum vpos for ins/del line operations to affect. */
195
196static int flexlines;
197
198/* During an update, nonzero if chars output now should be highlighted. */
199
200static int highlight;
201
202/* Nominal cursor position -- where to draw output.
203 During an update, these are different from the cursor-box position. */
204
205static int curs_x;
206static int curs_y;
207
208#ifdef HAVE_X11
209/* `t' if a mouse button is depressed. */
210
211extern Lisp_Object Vmouse_depressed;
212
213/* Tells if a window manager is present or not. */
214
215extern Lisp_Object Vx_no_window_manager;
216
217/* Timestamp that we requested selection data was made. */
218extern Time requestor_time;
219
220/* ID of the window requesting selection data. */
221extern Window requestor_window;
222
223/* Nonzero enables some debugging for the X interface code. */
224extern int _Xdebug;
225
c118dd06 226#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
227
228/* Bit patterns for the mouse cursor. */
229
230short MouseCursor[] = {
231 0x0000, 0x0008, 0x0018, 0x0038,
232 0x0078, 0x00f8, 0x01f8, 0x03f8,
233 0x07f8, 0x00f8, 0x00d8, 0x0188,
234 0x0180, 0x0300, 0x0300, 0x0000};
235
236short MouseMask[] = {
237 0x000c, 0x001c, 0x003c, 0x007c,
238 0x00fc, 0x01fc, 0x03fc, 0x07fc,
239 0x0ffc, 0x0ffc, 0x01fc, 0x03dc,
240 0x03cc, 0x0780, 0x0780, 0x0300};
241
242static short grey_bits[] = {
243 0x0005, 0x000a, 0x0005, 0x000a};
244
245static Pixmap GreyPixmap = 0;
c118dd06 246#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
247
248/* From time to time we get info on an Emacs window, here. */
249
250static WINDOWINFO_TYPE windowinfo;
251
252extern int errno;
253
dfeccd2d 254/* A mask of extra modifier bits to put into every keyboard char. */
64bb1782
RS
255extern int extra_keyboard_modifiers;
256
dc6f92b8
JB
257extern Display *XOpenDisplay ();
258extern Window XCreateWindow ();
259
260extern Cursor XCreateCursor ();
261extern FONT_TYPE *XOpenFont ();
262
263static void flashback ();
264
265#ifndef HAVE_X11
266static void dumpqueue ();
c118dd06 267#endif /* HAVE_X11 */
dc6f92b8
JB
268
269void dumpborder ();
4746118a
JB
270static int XTcursor_to ();
271static int XTclear_end_of_line ();
16bd92ea
JB
272
273\f
f451eb13
JB
274/* Starting and ending updates.
275
276 These hooks are called by update_frame at the beginning and end
f676886a
JB
277 of a frame update. We record in `updating_frame' the identity
278 of the frame being updated, so that the XT... functions do not
279 need to take a frame as argument. Most of the XT... functions
dc6f92b8
JB
280 should never be called except during an update, the only exceptions
281 being XTcursor_to, XTwrite_char and XTreassert_line_highlight. */
282
283extern int mouse_track_top, mouse_track_left, mouse_track_width;
284
285static
f676886a
JB
286XTupdate_begin (f)
287 struct frame *f;
dc6f92b8
JB
288{
289 int mask;
290
f676886a 291 if (f == 0)
dc6f92b8
JB
292 abort ();
293
f676886a 294 flexlines = f->height;
dc6f92b8
JB
295 highlight = 0;
296
dc6f92b8
JB
297 BLOCK_INPUT;
298#ifndef HAVE_X11
299 dumpqueue ();
c118dd06 300#endif /* HAVE_X11 */
dc6f92b8
JB
301 UNBLOCK_INPUT;
302}
303
f451eb13 304#ifndef HAVE_X11
dc6f92b8 305static void x_do_pending_expose ();
f451eb13 306#endif
dc6f92b8
JB
307
308static
f676886a
JB
309XTupdate_end (f)
310 struct frame *f;
dc6f92b8
JB
311{
312 int mask;
313
f676886a
JB
314 if (updating_frame == 0
315 || updating_frame != f)
dc6f92b8
JB
316 abort ();
317
318 BLOCK_INPUT;
319#ifndef HAVE_X11
320 dumpqueue ();
dc6f92b8 321 x_do_pending_expose ();
f451eb13 322#endif /* HAVE_X11 */
dc6f92b8 323
f676886a 324 x_display_cursor (f, 1);
dc6f92b8 325
dc6f92b8
JB
326 XFlushQueue ();
327 UNBLOCK_INPUT;
328}
329\f
330/* External interface to control of standout mode.
331 Call this when about to modify line at position VPOS
332 and not change whether it is highlighted. */
333
334XTreassert_line_highlight (new, vpos)
335 int new, vpos;
336{
337 highlight = new;
338}
339
340/* Call this when about to modify line at position VPOS
341 and change whether it is highlighted. */
342
343static
344XTchange_line_highlight (new_highlight, vpos, first_unused_hpos)
345 int new_highlight, vpos, first_unused_hpos;
346{
347 highlight = new_highlight;
348 XTcursor_to (vpos, 0);
f676886a 349 XTclear_end_of_line (updating_frame->width);
dc6f92b8
JB
350}
351
352/* This is used when starting Emacs and when restarting after suspend.
353 When starting Emacs, no X window is mapped. And nothing must be done
354 to Emacs's own window if it is suspended (though that rarely happens). */
355
356static
357XTset_terminal_modes ()
358{
359}
360
361/* This is called when exiting or suspending Emacs.
362 Exiting will make the X-windows go away, and suspending
363 requires no action. */
364
365static
366XTreset_terminal_modes ()
367{
f676886a 368/* XTclear_frame (); */
dc6f92b8
JB
369}
370\f
f451eb13
JB
371/* Set the nominal cursor position of the frame.
372 This is where display update commands will take effect.
dc6f92b8
JB
373 This does not affect the place where the cursor-box is displayed. */
374
4746118a 375static int
dc6f92b8
JB
376XTcursor_to (row, col)
377 register int row, col;
378{
379 int mask;
380 int orow = row;
381
382 curs_x = col;
383 curs_y = row;
384
f676886a 385 if (updating_frame == 0)
dc6f92b8
JB
386 {
387 BLOCK_INPUT;
f676886a 388 x_display_cursor (selected_frame, 1);
dc6f92b8
JB
389 XFlushQueue ();
390 UNBLOCK_INPUT;
391 }
392}
393\f
394/* Display a sequence of N glyphs found at GP.
395 WINDOW is the x-window to output to. LEFT and TOP are starting coords.
396 HL is 1 if this text is highlighted, 2 if the cursor is on it.
397
398 FONT is the default font to use (for glyphs whose font-code is 0). */
399
400static void
f676886a
JB
401dumpglyphs (f, left, top, gp, n, hl, font)
402 struct frame *f;
dc6f92b8
JB
403 int left, top;
404 register GLYPH *gp; /* Points to first GLYPH. */
405 register int n; /* Number of glyphs to display. */
406 int hl;
407 FONT_TYPE *font;
408{
dc6f92b8 409 register int len;
c118dd06 410 Window window = FRAME_X_WINDOW (f);
f676886a
JB
411 GC drawing_gc = (hl == 2 ? f->display.x->cursor_gc
412 : (hl ? f->display.x->reverse_gc
413 : f->display.x->normal_gc));
dc6f92b8 414
c7004826
JB
415 if (sizeof (GLYPH) == sizeof (XChar2b))
416 XDrawImageString16 (x_current_display, window, drawing_gc,
417 left, top + FONT_BASE (font), (XChar2b *) gp, n);
418 else if (sizeof (GLYPH) == sizeof (unsigned char))
419 XDrawImageString (x_current_display, window, drawing_gc,
420 left, top + FONT_BASE (font), (char *) gp, n);
421 else
422 /* What size of glyph ARE you using? And does X have a function to
423 draw them? */
424 abort ();
dc6f92b8
JB
425}
426
427#if 0
428static void
f676886a
JB
429dumpglyphs (f, left, top, gp, n, hl, font)
430 struct frame *f;
dc6f92b8
JB
431 int left, top;
432 register GLYPH *gp; /* Points to first GLYPH. */
433 register int n; /* Number of glyphs to display. */
434 int hl;
435 FONT_TYPE *font;
436{
f676886a 437 char buf[f->width]; /* Holds characters to be displayed. */
dc6f92b8
JB
438 register char *cp; /* Steps through buf[]. */
439 register int tlen = GLYPH_TABLE_LENGTH;
440 register Lisp_Object *tbase = GLYPH_TABLE_BASE;
c118dd06 441 Window window = FRAME_X_WINDOW (f);
f676886a
JB
442 int cursor_pixel = f->display.x->cursor_pixel;
443 int fg_pixel = f->display.x->foreground_pixel;
444 int bg_pixel = f->display.x->background_pixel;
445 int intborder = f->display.x->internal_border_width;
dc6f92b8
JB
446
447 while (n)
448 {
449 /* Get the face-code of the next GLYPH. */
450 int cf, len;
451 int g = *gp;
452
453 while (GLYPH_ALIAS_P (tbase, tlen, g))
454 g = GLYPH_ALIAS (tbase, g);
455
456 cf = g >> 8;
457
458 /* Find the run of consecutive glyphs with the same face-code.
459 Extract their character codes into BUF. */
460 cp = buf;
461 while (n > 0)
462 {
463 g = *gp;
464 while (GLYPH_ALIAS_P (tbase, tlen, g))
465 g = GLYPH_ALIAS (tbase, g);
466 if ((g >> 8) != cf)
467 break;
468
469 *cp++ = 0377 & g;
470 --n;
471 ++gp;
472 }
473
474 /* LEN gets the length of the run. */
475 len = cp - buf;
476
477 /* Now output this run of chars, with the font and pixel values
478 determined by the face code CF. */
479 if (cf == 0)
480 {
481#ifdef HAVE_X11
f676886a
JB
482 GC GC_cursor = f->display.x->cursor_gc;
483 GC GC_reverse = f->display.x->reverse_gc;
484 GC GC_normal = f->display.x->normal_gc;
dc6f92b8
JB
485
486 XDrawImageString (x_current_display, window,
487 (hl == 2
488 ? GC_cursor
489 : (hl ? GC_reverse : GC_normal)),
490 left, top + FONT_BASE (font), buf, len);
c118dd06 491#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
492 XText (window, left, top,
493 buf,
494 len,
495 font->id,
496 (hl == 2
497 ? (cursor_pixel == fg_pixel ? bg_pixel : fg_pixel)
498 : hl ? bg_pixel : fg_pixel),
499 (hl == 2 ? cursor_pixel
500 : hl ? fg_pixel : bg_pixel));
c118dd06 501#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
502 }
503 else
504 {
505#ifdef HAVE_X11
506 if (FACE_IS_FONT (cf))
c118dd06 507 XDrawImageString (x_current_display, FRAME_X_WINDOW (f),
dc6f92b8
JB
508 FACE_GC (cf),
509 left, top + FONT_BASE (FACE_FONT (cf)),
510 buf, len);
511 else if (FACE_IS_IMAGE (cf))
512 XCopyPlane (x_current_display, FACE_IMAGE (cf),
c118dd06 513 FRAME_X_WINDOW (f),
f676886a 514 f->display.x->normal_gc,
dc6f92b8
JB
515 0, 0,
516 FACE_IMAGE_WIDTH (cf),
517 FACE_IMAGE_HEIGHT (cf), left, top);
518 else
519 abort ();
c118dd06 520#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
521 register struct face *fp = x_face_table[cf];
522
523 XText (window, left, top,
524 buf,
525 len,
526 fp->font->id,
527 (hl == 2
528 ? (cursor_pixel == fp->fg ? fp->bg : fp->fg)
529 : hl ? fp->bg : fp->fg),
530 (hl == 2 ? cursor_pixel
531 : hl ? fp->fg : fp->bg));
c118dd06 532#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
533 }
534 left += len * FONT_WIDTH (font);
535 }
536}
c118dd06 537#endif /* ! 0 */
dc6f92b8 538\f
f451eb13
JB
539/* Output some text at the nominal frame cursor position.
540 Advance the cursor over the text.
dc6f92b8
JB
541 Output LEN glyphs at START.
542
543 `highlight', set up by XTreassert_line_highlight or XTchange_line_highlight,
544 controls the pixel values used for foreground and background. */
545
546static
547XTwrite_glyphs (start, len)
548 register GLYPH *start;
549 int len;
550{
551 register int temp_length;
552 int mask;
f676886a 553 struct frame *f;
dc6f92b8
JB
554
555 BLOCK_INPUT;
556
f676886a
JB
557 f = updating_frame;
558 if (f == 0)
dc6f92b8 559 {
f676886a 560 f = selected_frame;
dc6f92b8 561 /* If not within an update,
f676886a
JB
562 output at the frame's visible cursor. */
563 curs_x = f->cursor_x;
564 curs_y = f->cursor_y;
dc6f92b8
JB
565 }
566
f676886a 567 dumpglyphs (f,
12ba150f
JB
568 CHAR_TO_PIXEL_COL (f, curs_x),
569 CHAR_TO_PIXEL_ROW (f, curs_y),
570 start, len, highlight, f->display.x->font);
90e65f07
JB
571
572 /* If we drew on top of the cursor, note that it is turned off. */
f676886a
JB
573 if (curs_y == f->phys_cursor_y
574 && curs_x <= f->phys_cursor_x
575 && curs_x + len > f->phys_cursor_x)
576 f->phys_cursor_x = -1;
dc6f92b8 577
f676886a 578 if (updating_frame == 0)
dc6f92b8 579 {
f676886a
JB
580 f->cursor_x += len;
581 x_display_cursor (f, 1);
582 f->cursor_x -= len;
dc6f92b8
JB
583 }
584 else
585 curs_x += len;
586
587 UNBLOCK_INPUT;
588}
589\f
f451eb13
JB
590/* Clear to the end of the line.
591 Erase the current text line from the nominal cursor position (inclusive)
dc6f92b8
JB
592 to column FIRST_UNUSED (exclusive). The idea is that everything
593 from FIRST_UNUSED onward is already erased. */
594
4746118a 595static int
dc6f92b8
JB
596XTclear_end_of_line (first_unused)
597 register int first_unused;
598{
f676886a 599 struct frame *f = updating_frame;
dc6f92b8
JB
600 int mask;
601
f676886a 602 if (f == 0)
dc6f92b8
JB
603 abort ();
604
f676886a 605 if (curs_y < 0 || curs_y >= f->height)
dc6f92b8
JB
606 return;
607 if (first_unused <= 0)
608 return;
609
f676886a
JB
610 if (first_unused >= f->width)
611 first_unused = f->width;
dc6f92b8
JB
612
613 BLOCK_INPUT;
614
90e65f07 615 /* Notice if the cursor will be cleared by this operation. */
f676886a
JB
616 if (curs_y == f->phys_cursor_y
617 && curs_x <= f->phys_cursor_x
618 && f->phys_cursor_x < first_unused)
619 f->phys_cursor_x = -1;
dc6f92b8
JB
620
621#ifdef HAVE_X11
c118dd06 622 XClearArea (x_current_display, FRAME_X_WINDOW (f),
12ba150f
JB
623 CHAR_TO_PIXEL_COL (f, curs_x),
624 CHAR_TO_PIXEL_ROW (f, curs_y),
f676886a
JB
625 FONT_WIDTH (f->display.x->font) * (first_unused - curs_x),
626 FONT_HEIGHT (f->display.x->font), False);
dc6f92b8 627
c118dd06
JB
628#else /* ! defined (HAVE_X11) */
629 XPixSet (FRAME_X_WINDOW (f),
12ba150f
JB
630 CHAR_TO_PIXEL_COL (f, curs_x),
631 CHAR_TO_PIXEL_ROW (f, curs_y),
f676886a
JB
632 FONT_WIDTH (f->display.x->font) * (first_unused - curs_x),
633 FONT_HEIGHT (f->display.x->font),
634 f->display.x->background_pixel);
c118dd06 635#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
636
637 UNBLOCK_INPUT;
638}
639
640static
f676886a 641XTclear_frame ()
dc6f92b8
JB
642{
643 int mask;
f676886a 644 struct frame *f = updating_frame;
dc6f92b8 645
f676886a
JB
646 if (f == 0)
647 f = selected_frame;
dc6f92b8 648
f676886a 649 f->phys_cursor_x = -1; /* Cursor not visible. */
dc6f92b8
JB
650 curs_x = 0; /* Nominal cursor position is top left. */
651 curs_y = 0;
652
653 BLOCK_INPUT;
dbc4e1c1 654
c118dd06 655 XClear (FRAME_X_WINDOW (f));
dbc4e1c1 656
ab648270 657 /* We have to clear the scroll bars, too. If we have changed
dbc4e1c1 658 colors or something like that, then they should be notified. */
ab648270 659 x_scroll_bar_clear (f);
dbc4e1c1 660
dc6f92b8 661#ifndef HAVE_X11
f676886a 662 dumpborder (f, 0);
c118dd06 663#endif /* HAVE_X11 */
dbc4e1c1 664
dc6f92b8
JB
665 XFlushQueue ();
666 UNBLOCK_INPUT;
667}
668\f
dbc4e1c1
JB
669/* Invert the middle quarter of the frame for .15 sec. */
670
671/* We use the select system call to do the waiting, so we have to make sure
672 it's avaliable. If it isn't, we just won't do visual bells. */
673#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
674
675/* Subtract the `struct timeval' values X and Y,
676 storing the result in RESULT.
677 Return 1 if the difference is negative, otherwise 0. */
678
679static int
680timeval_subtract (result, x, y)
681 struct timeval *result, x, y;
682{
683 /* Perform the carry for the later subtraction by updating y.
684 This is safer because on some systems
685 the tv_sec member is unsigned. */
686 if (x.tv_usec < y.tv_usec)
687 {
688 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
689 y.tv_usec -= 1000000 * nsec;
690 y.tv_sec += nsec;
691 }
692 if (x.tv_usec - y.tv_usec > 1000000)
693 {
694 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
695 y.tv_usec += 1000000 * nsec;
696 y.tv_sec -= nsec;
697 }
698
699 /* Compute the time remaining to wait. tv_usec is certainly positive. */
700 result->tv_sec = x.tv_sec - y.tv_sec;
701 result->tv_usec = x.tv_usec - y.tv_usec;
702
703 /* Return indication of whether the result should be considered negative. */
704 return x.tv_sec < y.tv_sec;
705}
dc6f92b8 706
f676886a
JB
707XTflash (f)
708 struct frame *f;
dc6f92b8 709{
dbc4e1c1 710 BLOCK_INPUT;
dc6f92b8 711
dbc4e1c1
JB
712 {
713 GC gc;
dc6f92b8 714
dbc4e1c1
JB
715 /* Create a GC that will use the GXxor function to flip foreground pixels
716 into background pixels. */
717 {
718 XGCValues values;
dc6f92b8 719
dbc4e1c1
JB
720 values.function = GXxor;
721 values.foreground = (f->display.x->foreground_pixel
722 ^ f->display.x->background_pixel);
723
724 gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f),
725 GCFunction | GCForeground, &values);
726 }
dc6f92b8 727
dbc4e1c1
JB
728 {
729 int width = PIXEL_WIDTH (f);
730 int height = PIXEL_HEIGHT (f);
dc6f92b8 731
dbc4e1c1
JB
732 XFillRectangle (x_current_display, FRAME_X_WINDOW (f), gc,
733 width/4, height/4, width/2, height/2);
734 XFlush (x_current_display);
dc6f92b8 735
dbc4e1c1
JB
736 {
737 struct timeval wakeup, now;
dc6f92b8 738
dbc4e1c1 739 gettimeofday (&wakeup, (struct timezone *) 0);
dc6f92b8 740
dbc4e1c1
JB
741 /* Compute time to wait until, propagating carry from usecs. */
742 wakeup.tv_usec += 150000;
743 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
744 wakeup.tv_usec %= 1000000;
745
746 /* Keep waiting until past the time wakeup. */
747 while (1)
748 {
749 struct timeval timeout;
750
751 gettimeofday (&timeout, (struct timezone *)0);
752
753 /* In effect, timeout = wakeup - timeout.
754 Break if result would be negative. */
755 if (timeval_subtract (&timeout, wakeup, timeout))
756 break;
757
758 /* Try to wait that long--but we might wake up sooner. */
759 select (0, 0, 0, 0, &timeout);
760 }
761 }
762
763 XFillRectangle (x_current_display, FRAME_X_WINDOW (f), gc,
764 width/4, height/4, width/2, height/2);
765 XFreeGC (x_current_display, gc);
766 XFlush (x_current_display);
dc6f92b8 767 }
dbc4e1c1
JB
768 }
769
770 UNBLOCK_INPUT;
dc6f92b8
JB
771}
772
dbc4e1c1
JB
773#endif
774
775
dc6f92b8
JB
776/* Make audible bell. */
777
778#ifdef HAVE_X11
779#define XRINGBELL XBell(x_current_display, 0)
c118dd06 780#else /* ! defined (HAVE_X11) */
dc6f92b8 781#define XRINGBELL XFeep(0);
c118dd06 782#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
783
784XTring_bell ()
785{
dbc4e1c1 786#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
dc6f92b8 787 if (visible_bell)
f676886a 788 XTflash (selected_frame);
dc6f92b8 789 else
dbc4e1c1 790#endif
dc6f92b8
JB
791 {
792 BLOCK_INPUT;
793 XRINGBELL;
794 XFlushQueue ();
795 UNBLOCK_INPUT;
796 }
797}
798\f
f451eb13
JB
799/* Insert and delete character.
800 These are not supposed to be used because we are supposed to turn
801 off the feature of using them. */
dc6f92b8
JB
802
803static
804XTinsert_glyphs (start, len)
805 register char *start;
806 register int len;
807{
808 abort ();
809}
810
811static
812XTdelete_glyphs (n)
813 register int n;
814{
815 abort ();
816}
817\f
818/* Specify how many text lines, from the top of the window,
819 should be affected by insert-lines and delete-lines operations.
820 This, and those operations, are used only within an update
821 that is bounded by calls to XTupdate_begin and XTupdate_end. */
822
823static
824XTset_terminal_window (n)
825 register int n;
826{
f676886a 827 if (updating_frame == 0)
dc6f92b8
JB
828 abort ();
829
f676886a
JB
830 if ((n <= 0) || (n > updating_frame->height))
831 flexlines = updating_frame->height;
dc6f92b8
JB
832 else
833 flexlines = n;
834}
835\f
f451eb13
JB
836/* Perform an insert-lines operation.
837 Insert N lines at a vertical position curs_y. */
dc6f92b8
JB
838
839static void
840stufflines (n)
841 register int n;
842{
843 register int topregion, bottomregion;
844 register int length, newtop, mask;
f676886a
JB
845 register struct frame *f = updating_frame;
846 int intborder = f->display.x->internal_border_width;
dc6f92b8
JB
847
848 if (curs_y >= flexlines)
849 return;
850
851 topregion = curs_y;
852 bottomregion = flexlines - (n + 1);
853 newtop = topregion + n;
854 length = (bottomregion - topregion) + 1;
855
856#ifndef HAVE_X11
857 dumpqueue ();
c118dd06 858#endif /* HAVE_X11 */
dc6f92b8
JB
859
860 if ((length > 0) && (newtop <= flexlines))
861 {
862#ifdef HAVE_X11
c118dd06
JB
863 XCopyArea (x_current_display, FRAME_X_WINDOW (f),
864 FRAME_X_WINDOW (f), f->display.x->normal_gc,
12ba150f 865 intborder, CHAR_TO_PIXEL_ROW (f, topregion),
f676886a
JB
866 f->width * FONT_WIDTH (f->display.x->font),
867 length * FONT_HEIGHT (f->display.x->font), intborder,
12ba150f 868 CHAR_TO_PIXEL_ROW (f, newtop));
c118dd06
JB
869#else /* ! defined (HAVE_X11) */
870 XMoveArea (FRAME_X_WINDOW (f),
12ba150f
JB
871 intborder, CHAR_TO_PIXEL_ROW (f, topregion),
872 intborder, CHAR_TO_PIXEL_ROW (f, newtop),
f676886a
JB
873 f->width * FONT_WIDTH (f->display.x->font),
874 length * FONT_HEIGHT (f->display.x->font));
dc6f92b8
JB
875 /* Now we must process any ExposeRegion events that occur
876 if the area being copied from is obscured.
877 We can't let it wait because further i/d operations
878 may want to copy this area to another area. */
879 x_read_exposes ();
c118dd06 880#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
881 }
882
883 newtop = min (newtop, (flexlines - 1));
884 length = newtop - topregion;
885 if (length > 0)
886 {
887#ifdef HAVE_X11
c118dd06 888 XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder,
12ba150f 889 CHAR_TO_PIXEL_ROW (f, topregion),
f676886a
JB
890 f->width * FONT_WIDTH (f->display.x->font),
891 n * FONT_HEIGHT (f->display.x->font), False);
c118dd06
JB
892#else /* ! defined (HAVE_X11) */
893 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 894 intborder,
12ba150f 895 CHAR_TO_PIXEL_ROW (f, topregion),
f676886a
JB
896 f->width * FONT_WIDTH (f->display.x->font),
897 n * FONT_HEIGHT (f->display.x->font),
898 f->display.x->background_pixel);
c118dd06 899#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
900 }
901}
902
903/* Perform a delete-lines operation, deleting N lines
904 at a vertical position curs_y. */
905
906static void
907scraplines (n)
908 register int n;
909{
910 int mask;
f676886a
JB
911 register struct frame *f = updating_frame;
912 int intborder = f->display.x->internal_border_width;
dc6f92b8
JB
913
914 if (curs_y >= flexlines)
915 return;
916
917#ifndef HAVE_X11
918 dumpqueue ();
c118dd06 919#endif /* HAVE_X11 */
dc6f92b8
JB
920
921 if ((curs_y + n) >= flexlines)
922 {
923 if (flexlines >= (curs_y + 1))
924 {
925#ifdef HAVE_X11
c118dd06 926 XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder,
12ba150f 927 CHAR_TO_PIXEL_ROW (f, curs_y),
f676886a
JB
928 f->width * FONT_WIDTH (f->display.x->font),
929 (flexlines - curs_y) * FONT_HEIGHT (f->display.x->font), False);
c118dd06
JB
930#else /* ! defined (HAVE_X11) */
931 XPixSet (FRAME_X_WINDOW (f),
12ba150f 932 intborder, CHAR_TO_PIXEL_ROW (f, curs_y),
f676886a
JB
933 f->width * FONT_WIDTH (f->display.x->font),
934 (flexlines - curs_y) * FONT_HEIGHT (f->display.x->font),
935 f->display.x->background_pixel);
c118dd06 936#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
937 }
938 }
939 else
940 {
941#ifdef HAVE_X11
c118dd06
JB
942 XCopyArea (x_current_display, FRAME_X_WINDOW (f),
943 FRAME_X_WINDOW (f), f->display.x->normal_gc,
dc6f92b8 944 intborder,
12ba150f 945 CHAR_TO_PIXEL_ROW (f, curs_y + n),
f676886a
JB
946 f->width * FONT_WIDTH (f->display.x->font),
947 (flexlines - (curs_y + n)) * FONT_HEIGHT (f->display.x->font),
12ba150f 948 intborder, CHAR_TO_PIXEL_ROW (f, curs_y));
c118dd06 949 XClearArea (x_current_display, FRAME_X_WINDOW (f),
dc6f92b8 950 intborder,
12ba150f 951 CHAR_TO_PIXEL_ROW (f, flexlines - n),
f676886a
JB
952 f->width * FONT_WIDTH (f->display.x->font),
953 n * FONT_HEIGHT (f->display.x->font), False);
c118dd06
JB
954#else /* ! defined (HAVE_X11) */
955 XMoveArea (FRAME_X_WINDOW (f),
dc6f92b8 956 intborder,
12ba150f
JB
957 CHAR_TO_PIXEL_ROW (f, curs_y + n),
958 intborder, CHAR_TO_PIXEL_ROW (f, curs_y),
f676886a
JB
959 f->width * FONT_WIDTH (f->display.x->font),
960 (flexlines - (curs_y + n)) * FONT_HEIGHT (f->display.x->font));
dc6f92b8
JB
961 /* Now we must process any ExposeRegion events that occur
962 if the area being copied from is obscured.
963 We can't let it wait because further i/d operations
964 may want to copy this area to another area. */
965 x_read_exposes ();
c118dd06 966 XPixSet (FRAME_X_WINDOW (f), intborder,
12ba150f 967 CHAR_TO_PIXEL_ROW (f, flexlines - n),
f676886a
JB
968 f->width * FONT_WIDTH (f->display.x->font),
969 n * FONT_HEIGHT (f->display.x->font), f->display.x->background_pixel);
c118dd06 970#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
971 }
972}
973
974/* Perform an insert-lines or delete-lines operation,
975 inserting N lines or deleting -N lines at vertical position VPOS. */
976
977XTins_del_lines (vpos, n)
978 int vpos, n;
979{
f676886a 980 if (updating_frame == 0)
dc6f92b8
JB
981 abort ();
982
90e65f07 983 /* Hide the cursor. */
f676886a 984 x_display_cursor (updating_frame, 0);
dc6f92b8
JB
985
986 XTcursor_to (vpos, 0);
987
988 BLOCK_INPUT;
989 if (n >= 0)
990 stufflines (n);
991 else
992 scraplines (-n);
993 XFlushQueue ();
994 UNBLOCK_INPUT;
995}
996\f
f451eb13 997/* Support routines for exposure events. */
dc6f92b8
JB
998static void clear_cursor ();
999
f676886a
JB
1000/* Output into a rectangle of an X-window (for frame F)
1001 the characters in f->phys_lines that overlap that rectangle.
dc6f92b8
JB
1002 TOP and LEFT are the position of the upper left corner of the rectangle.
1003 ROWS and COLS are the size of the rectangle. */
1004
1005static void
f676886a
JB
1006dumprectangle (f, left, top, cols, rows)
1007 struct frame *f;
dc6f92b8
JB
1008 register int left, top, cols, rows;
1009{
f676886a 1010 register struct frame_glyphs *active_frame = FRAME_CURRENT_GLYPHS (f);
dc6f92b8
JB
1011 int cursor_cleared = 0;
1012 int bottom, right;
1013 register int y;
1014
f676886a 1015 if (FRAME_GARBAGED_P (f))
dc6f92b8
JB
1016 return;
1017
dc6f92b8
JB
1018 /* Express rectangle as four edges, instead of position-and-size. */
1019 bottom = top + rows;
1020 right = left + cols;
1021
1022#ifndef HAVE_X11 /* Window manger does this for X11. */
12ba150f
JB
1023 {
1024 int intborder = f->display.x->internal_border_width;
1025
1026 /* If the rectangle includes any of the internal border area,
1027 redisplay the border emphasis. */
1028 if (top < intborder || left < intborder
1029 || bottom > intborder + f->height * FONT_HEIGHT (f->display.x->font)
1030 || right > intborder + f->width * FONT_WIDTH (f->display.x->font))
1031 dumpborder (f, 0);
1032 }
c118dd06 1033#endif /* HAVE_X11 /* Window manger does this for X11. */ */
dc6f92b8
JB
1034
1035 /* Convert rectangle edges in pixels to edges in chars.
1036 Round down for left and top, up for right and bottom. */
12ba150f
JB
1037 top = PIXEL_TO_CHAR_ROW (f, top);
1038 left = PIXEL_TO_CHAR_COL (f, left);
f676886a
JB
1039 bottom += (FONT_HEIGHT (f->display.x->font) - 1);
1040 right += (FONT_WIDTH (f->display.x->font) - 1);
12ba150f
JB
1041 bottom = PIXEL_TO_CHAR_ROW (f, bottom);
1042 right = PIXEL_TO_CHAR_COL (f, right);
dc6f92b8
JB
1043
1044 /* Clip the rectangle to what can be visible. */
1045 if (left < 0)
1046 left = 0;
1047 if (top < 0)
1048 top = 0;
f676886a
JB
1049 if (right > f->width)
1050 right = f->width;
1051 if (bottom > f->height)
1052 bottom = f->height;
dc6f92b8
JB
1053
1054 /* Get size in chars of the rectangle. */
1055 cols = right - left;
1056 rows = bottom - top;
1057
1058 /* If rectangle has zero area, return. */
1059 if (rows <= 0) return;
1060 if (cols <= 0) return;
1061
1062 /* Turn off the cursor if it is in the rectangle.
1063 We will turn it back on afterward. */
f676886a
JB
1064 if ((f->phys_cursor_x >= left) && (f->phys_cursor_x < right)
1065 && (f->phys_cursor_y >= top) && (f->phys_cursor_y < bottom))
dc6f92b8 1066 {
f676886a 1067 clear_cursor (f);
dc6f92b8
JB
1068 cursor_cleared = 1;
1069 }
1070
1071 /* Display the text in the rectangle, one text line at a time. */
1072
1073 for (y = top; y < bottom; y++)
1074 {
f676886a 1075 GLYPH *line = &active_frame->glyphs[y][left];
dc6f92b8 1076
f676886a 1077 if (! active_frame->enable[y] || left > active_frame->used[y])
dc6f92b8
JB
1078 continue;
1079
f676886a 1080 dumpglyphs (f,
12ba150f
JB
1081 CHAR_TO_PIXEL_COL (f, left),
1082 CHAR_TO_PIXEL_ROW (f, y),
1083 line, min (cols, active_frame->used[y] - left),
1084 active_frame->highlight[y], f->display.x->font);
dc6f92b8
JB
1085 }
1086
1087 /* Turn the cursor on if we turned it off. */
1088
1089 if (cursor_cleared)
f676886a 1090 x_display_cursor (f, 1);
dc6f92b8
JB
1091}
1092
1093#ifndef HAVE_X11
1094/* Process all queued ExposeRegion events. */
1095
1096static void
1097dumpqueue ()
1098{
1099 register int i;
1100 XExposeRegionEvent r;
1101
1102 while (dequeue_event (&r, &x_expose_queue))
1103 {
f676886a
JB
1104 struct frame *f = x_window_to_frame (r.window);
1105 if (f->display.x->icon_desc == r.window)
1106 refreshicon (f);
dc6f92b8 1107 else
f676886a 1108 dumprectangle (f, r.x, r.y, r.width, r.height);
dc6f92b8
JB
1109 }
1110 XFlushQueue ();
1111}
c118dd06 1112#endif /* HAVE_X11 */
dc6f92b8 1113\f
f451eb13 1114/* Process all expose events that are pending, for X10.
f676886a
JB
1115 Redraws the cursor if necessary on any frame that
1116 is not in the process of being updated with update_frame. */
dc6f92b8 1117
f451eb13 1118#ifndef HAVE_X11
dc6f92b8
JB
1119static void
1120x_do_pending_expose ()
1121{
1122 int mask;
f676886a
JB
1123 struct frame *f;
1124 Lisp_Object tail, frame;
dc6f92b8
JB
1125
1126 if (expose_all_windows)
1127 {
1128 expose_all_windows = 0;
f676886a 1129 for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
dc6f92b8
JB
1130 {
1131 register int temp_width, temp_height;
1132 int intborder;
1133
f676886a 1134 frame = XCONS (tail)->car;
ab648270 1135 if (XGCTYPE (frame) != Lisp_Frame)
dc6f92b8 1136 continue;
f676886a 1137 f = XFRAME (frame);
b1c884c3 1138 if (! FRAME_X_P (f))
dc6f92b8 1139 continue;
3a88c238 1140 if (!f->async_visible)
dc6f92b8 1141 continue;
f676886a 1142 if (!f->display.x->needs_exposure)
dc6f92b8
JB
1143 continue;
1144
f676886a 1145 intborder = f->display.x->internal_border_width;
dc6f92b8 1146
f676886a 1147 clear_cursor (f);
c118dd06 1148 XGetWindowInfo (FRAME_X_WINDOW (f), &windowinfo);
dc6f92b8 1149 temp_width = ((windowinfo.width - 2 * intborder
ab648270 1150 - f->display.x->v_scroll_bar_width)
f676886a 1151 / FONT_WIDTH (f->display.x->font));
dc6f92b8 1152 temp_height = ((windowinfo.height- 2 * intborder
ab648270 1153 - f->display.x->h_scroll_bar_height)
f676886a
JB
1154 / FONT_HEIGHT (f->display.x->font));
1155 if (temp_width != f->width || temp_height != f->height)
dc6f92b8 1156 {
f676886a 1157 change_frame_size (f, max (1, temp_height),
b1c884c3 1158 max (1, temp_width), 0, 1);
ab648270 1159 x_resize_scroll_bars (f);
dc6f92b8 1160 }
f676886a
JB
1161 f->display.x->left_pos = windowinfo.x;
1162 f->display.x->top_pos = windowinfo.y;
1163 dumprectangle (f, 0, 0, PIXEL_WIDTH (f), PIXEL_HEIGHT (f));
dc6f92b8 1164#if 0
f676886a 1165 dumpborder (f, 0);
c118dd06 1166#endif /* ! 0 */
f676886a
JB
1167 f->display.x->needs_exposure = 0;
1168 if (updating_frame != f)
1169 x_display_cursor (f, 1);
dc6f92b8
JB
1170 XFlushQueue ();
1171 }
1172 }
1173 else
1174 /* Handle any individual-rectangle expose events queued
1175 for various windows. */
1176#ifdef HAVE_X11
1177 ;
c118dd06 1178#else /* ! defined (HAVE_X11) */
dc6f92b8 1179 dumpqueue ();
c118dd06 1180#endif /* ! defined (HAVE_X11) */
dc6f92b8 1181}
f451eb13 1182#endif
dc6f92b8
JB
1183
1184#ifdef HAVE_X11
1185static void
f676886a
JB
1186frame_highlight (frame)
1187 struct frame *frame;
dc6f92b8
JB
1188{
1189 if (! EQ (Vx_no_window_manager, Qnil))
c118dd06 1190 XSetWindowBorder (x_current_display, FRAME_X_WINDOW (frame),
f676886a
JB
1191 frame->display.x->border_pixel);
1192 x_display_cursor (frame, 1);
dc6f92b8
JB
1193}
1194
1195static void
f676886a
JB
1196frame_unhighlight (frame)
1197 struct frame *frame;
dc6f92b8
JB
1198{
1199 if (! EQ (Vx_no_window_manager, Qnil))
c118dd06 1200 XSetWindowBorderPixmap (x_current_display, FRAME_X_WINDOW (frame),
f676886a
JB
1201 frame->display.x->border_tile);
1202 x_display_cursor (frame, 1);
dc6f92b8 1203}
c118dd06 1204#else /* ! defined (HAVE_X11) */
f676886a
JB
1205/* Dump the border-emphasis of frame F.
1206 If F is selected, this is a lining of the same color as the border,
dc6f92b8 1207 just within the border, occupying a portion of the internal border.
f676886a 1208 If F is not selected, it is background in the same place.
dc6f92b8
JB
1209 If ALWAYS is 0, don't bother explicitly drawing if it's background.
1210
f676886a 1211 ALWAYS = 1 is used when a frame becomes selected or deselected.
dc6f92b8
JB
1212 In that case, we also turn the cursor off and on again
1213 so it will appear in the proper shape (solid if selected; else hollow.) */
1214
1215static void
f676886a
JB
1216dumpborder (f, always)
1217 struct frame *f;
dc6f92b8
JB
1218 int always;
1219{
f676886a
JB
1220 int thickness = f->display.x->internal_border_width / 2;
1221 int width = PIXEL_WIDTH (f);
1222 int height = PIXEL_HEIGHT (f);
dc6f92b8
JB
1223 int pixel;
1224
f676886a 1225 if (f != selected_frame)
dc6f92b8
JB
1226 {
1227 if (!always)
1228 return;
1229
f676886a 1230 pixel = f->display.x->background_pixel;
dc6f92b8
JB
1231 }
1232 else
1233 {
f676886a 1234 pixel = f->display.x->border_pixel;
dc6f92b8
JB
1235 }
1236
c118dd06
JB
1237 XPixSet (FRAME_X_WINDOW (f), 0, 0, width, thickness, pixel);
1238 XPixSet (FRAME_X_WINDOW (f), 0, 0, thickness, height, pixel);
1239 XPixSet (FRAME_X_WINDOW (f), 0, height - thickness, width,
dc6f92b8 1240 thickness, pixel);
c118dd06 1241 XPixSet (FRAME_X_WINDOW (f), width - thickness, 0, thickness,
dc6f92b8
JB
1242 height, pixel);
1243
1244 if (always)
f676886a 1245 x_display_cursor (f, 1);
dc6f92b8 1246}
c118dd06 1247#endif /* ! defined (HAVE_X11) */
dc6f92b8 1248
f676886a 1249static void XTframe_rehighlight ();
6d4238f3 1250
f676886a
JB
1251/* The focus has changed. Update the frames as necessary to reflect
1252 the new situation. Note that we can't change the selected frame
dc6f92b8 1253 here, because the lisp code we are interrupting might become confused.
f676886a 1254 Each event gets marked with the frame in which it occured, so the
6d4238f3 1255 lisp code can tell when the switch took place by examining the events. */
dc6f92b8 1256
6d4238f3 1257static void
f676886a
JB
1258x_new_focus_frame (frame)
1259 struct frame *frame;
dc6f92b8 1260{
f676886a 1261 struct frame *old_focus = x_focus_frame;
dc6f92b8
JB
1262 int events_enqueued = 0;
1263
f676886a 1264 if (frame != x_focus_frame)
dc6f92b8 1265 {
6d4238f3 1266 /* Set this before calling other routines, so that they see
f676886a
JB
1267 the correct value of x_focus_frame. */
1268 x_focus_frame = frame;
6d4238f3
JB
1269
1270 if (old_focus && old_focus->auto_lower)
f676886a 1271 x_lower_frame (old_focus);
dc6f92b8
JB
1272
1273#if 0
f676886a
JB
1274 selected_frame = frame;
1275 XSET (XWINDOW (selected_frame->selected_window)->frame,
1276 Lisp_Frame, selected_frame);
1277 Fselect_window (selected_frame->selected_window);
1278 choose_minibuf_frame ();
c118dd06 1279#endif /* ! 0 */
dc6f92b8 1280
f676886a
JB
1281 if (x_focus_frame && x_focus_frame->auto_raise)
1282 x_raise_frame (x_focus_frame);
6d4238f3 1283 }
dc6f92b8 1284
f676886a 1285 XTframe_rehighlight ();
6d4238f3
JB
1286}
1287
1288
f451eb13
JB
1289/* The focus has changed, or we have redirected a frame's focus to
1290 another frame (this happens when a frame uses a surrogate
1291 minibuffer frame). Shift the highlight as appropriate. */
6d4238f3 1292static void
f676886a 1293XTframe_rehighlight ()
6d4238f3 1294{
f676886a 1295 struct frame *old_highlight = x_highlight_frame;
6d4238f3 1296
f676886a 1297 if (x_focus_frame)
6d4238f3 1298 {
f451eb13 1299 x_highlight_frame =
ab648270 1300 ((XGCTYPE (FRAME_FOCUS_FRAME (x_focus_frame)) == Lisp_Frame)
f451eb13
JB
1301 ? XFRAME (FRAME_FOCUS_FRAME (x_focus_frame))
1302 : x_focus_frame);
1303 if (! FRAME_LIVE_P (x_highlight_frame))
1304 {
1305 FRAME_FOCUS_FRAME (x_focus_frame) = Qnil;
1306 x_highlight_frame = x_focus_frame;
1307 }
dc6f92b8 1308 }
6d4238f3 1309 else
f676886a 1310 x_highlight_frame = 0;
dc6f92b8 1311
f676886a 1312 if (x_highlight_frame != old_highlight)
6d4238f3
JB
1313 {
1314 if (old_highlight)
f676886a
JB
1315 frame_unhighlight (old_highlight);
1316 if (x_highlight_frame)
1317 frame_highlight (x_highlight_frame);
6d4238f3 1318 }
dc6f92b8
JB
1319}
1320\f
90e65f07
JB
1321/* Mouse clicks and mouse movement. Rah. */
1322#ifdef HAVE_X11
1323
f676886a 1324/* Given a pixel position (PIX_X, PIX_Y) on the frame F, return
90e65f07
JB
1325 glyph co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle
1326 that the glyph at X, Y occupies, if BOUNDS != 0. */
1327static void
f676886a
JB
1328pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds)
1329 FRAME_PTR f;
dc6f92b8
JB
1330 register unsigned int pix_x, pix_y;
1331 register int *x, *y;
90e65f07 1332 XRectangle *bounds;
dc6f92b8 1333{
12ba150f
JB
1334 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
1335 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
90e65f07
JB
1336
1337 if (bounds)
1338 {
12ba150f
JB
1339 bounds->width = FONT_WIDTH (f->display.x->font);
1340 bounds->height = FONT_HEIGHT (f->display.x->font);
1341 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
1342 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
90e65f07 1343 }
12ba150f
JB
1344
1345 if (pix_x < 0) pix_x = 0;
1346 else if (pix_x > f->width) pix_x = f->width;
1347
1348 if (pix_y < 0) pix_y = 0;
1349 else if (pix_y > f->height) pix_y = f->height;
1350
1351 *x = pix_x;
1352 *y = pix_y;
dc6f92b8 1353}
dc6f92b8
JB
1354
1355/* Any buttons grabbed. */
1356unsigned int x_mouse_grabbed;
1357
28430d3c
JB
1358/* Which modifier keys are on which modifier bits?
1359
1360 With each keystroke, X returns eight bits indicating which modifier
11edeb03
JB
1361 keys were held down when the key was pressed. The interpretation
1362 of the top five modifier bits depends on what keys are attached
28430d3c
JB
1363 to them. If the Meta_L and Meta_R keysyms are on mod5, then mod5
1364 is the meta bit.
1365
1366 x_meta_mod_mask is a mask containing the bits used for the meta key.
1367 It may have more than one bit set, if more than one modifier bit
1368 has meta keys on it. Basically, if EVENT is a KeyPress event,
11edeb03
JB
1369 the meta key is pressed if (EVENT.state & x_meta_mod_mask) != 0.
1370
1371 x_shift_lock_mask is LockMask if the XK_Shift_Lock keysym is on the
1372 lock modifier bit, or zero otherwise. Non-alphabetic keys should
1373 only be affected by the lock modifier bit if XK_Shift_Lock is in
1374 use; XK_Caps_Lock should only affect alphabetic keys. With this
1375 arrangement, the lock modifier should shift the character if
1376 (EVENT.state & x_shift_lock_mask) != 0. */
1377static int x_meta_mod_mask, x_shift_lock_mask;
28430d3c 1378
a3c44b14
RS
1379/* These are like x_meta_mod_mask, but for different modifiers. */
1380static int x_alt_mod_mask, x_super_mod_mask, x_hyper_mod_mask;
1381
28430d3c
JB
1382/* Initialize mode_switch_bit and modifier_meaning. */
1383static void
1384x_find_modifier_meanings ()
1385{
f689eb05 1386 int min_code, max_code;
28430d3c
JB
1387 KeySym *syms;
1388 int syms_per_code;
1389 XModifierKeymap *mods;
1390
1391 x_meta_mod_mask = 0;
11edeb03 1392 x_shift_lock_mask = 0;
a3c44b14
RS
1393 x_alt_mod_mask = 0;
1394 x_super_mod_mask = 0;
1395 x_hyper_mod_mask = 0;
28430d3c 1396
9658a521 1397#ifdef HAVE_X11R4
28430d3c 1398 XDisplayKeycodes (x_current_display, &min_code, &max_code);
9658a521
JB
1399#else
1400 min_code = x_current_display->min_keycode;
1401 max_code = x_current_display->max_keycode;
1402#endif
1403
28430d3c
JB
1404 syms = XGetKeyboardMapping (x_current_display,
1405 min_code, max_code - min_code + 1,
1406 &syms_per_code);
1407 mods = XGetModifierMapping (x_current_display);
1408
11edeb03
JB
1409 /* Scan the modifier table to see which modifier bits the Meta and
1410 Alt keysyms are on. */
28430d3c
JB
1411 {
1412 int row, col; /* The row and column in the modifier table. */
1413
1414 for (row = 3; row < 8; row++)
1415 for (col = 0; col < mods->max_keypermod; col++)
1416 {
1417 KeyCode code =
1418 mods->modifiermap[(row * mods->max_keypermod) + col];
1419
1420 /* Are any of this keycode's keysyms a meta key? */
1421 {
1422 int code_col;
1423
1424 for (code_col = 0; code_col < syms_per_code; code_col++)
1425 {
f689eb05 1426 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 1427
f689eb05 1428 switch (sym)
28430d3c 1429 {
f689eb05
JB
1430 case XK_Meta_L:
1431 case XK_Meta_R:
28430d3c
JB
1432 x_meta_mod_mask |= (1 << row);
1433 break;
f689eb05
JB
1434
1435 case XK_Alt_L:
1436 case XK_Alt_R:
a3c44b14
RS
1437 x_alt_mod_mask |= (1 << row);
1438 break;
1439
1440 case XK_Hyper_L:
1441 case XK_Hyper_R:
1442 x_hyper_mod_mask |= (1 << row);
1443 break;
1444
1445 case XK_Super_L:
1446 case XK_Super_R:
1447 x_super_mod_mask |= (1 << row);
f689eb05 1448 break;
11edeb03
JB
1449
1450 case XK_Shift_Lock:
1451 /* Ignore this if it's not on the lock modifier. */
1452 if ((1 << row) == LockMask)
1453 x_shift_lock_mask = LockMask;
1454 break;
28430d3c
JB
1455 }
1456 }
1457 }
1458 }
1459 }
1460
f689eb05
JB
1461 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
1462 if (! x_meta_mod_mask)
a3c44b14
RS
1463 {
1464 x_meta_mod_mask = x_alt_mod_mask;
1465 x_alt_mod_mask = 0;
1466 }
f689eb05 1467
28430d3c 1468 XFree ((char *) syms);
f689eb05 1469 XFreeModifiermap (mods);
28430d3c
JB
1470}
1471
1472
dfeccd2d
JB
1473/* Convert between the modifier bits X uses and the modifier bits
1474 Emacs uses. */
7c5283e4 1475static unsigned int
dfeccd2d 1476x_x_to_emacs_modifiers (state)
dc6f92b8
JB
1477 unsigned int state;
1478{
11edeb03
JB
1479 return ( ((state & (ShiftMask | x_shift_lock_mask)) ? shift_modifier : 0)
1480 | ((state & ControlMask) ? ctrl_modifier : 0)
a3c44b14
RS
1481 | ((state & x_meta_mod_mask) ? meta_modifier : 0)
1482 | ((state & x_alt_mod_mask) ? alt_modifier : 0)
1483 | ((state & x_super_mod_mask) ? super_modifier : 0)
1484 | ((state & x_hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
1485}
1486
dfeccd2d
JB
1487static unsigned int
1488x_emacs_to_x_modifiers (state)
1489 unsigned int state;
1490{
1491 return ( ((state & alt_modifier) ? x_alt_mod_mask : 0)
1492 | ((state & super_modifier) ? x_super_mod_mask : 0)
1493 | ((state & hyper_modifier) ? x_hyper_mod_mask : 0)
1494 | ((state & shift_modifier) ? ShiftMask : 0)
1495 | ((state & ctrl_modifier) ? ControlMask : 0)
1496 | ((state & meta_modifier) ? x_meta_mod_mask : 0));
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;
dfeccd2d 1515 result->modifiers = (x_x_to_emacs_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 2228 emacs_event->modifiers =
dfeccd2d 2229 (x_x_to_emacs_modifiers (event->xbutton.state)
f451eb13
JB
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
9ac0d9e0 2484 if (interrupt_input_blocked)
dc6f92b8 2485 {
9ac0d9e0 2486 interrupt_input_pending = 1;
dc6f92b8
JB
2487 return -1;
2488 }
2489
9ac0d9e0 2490 interrupt_input_pending = 0;
dc6f92b8
JB
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
dfeccd2d
JB
2787 event.xkey.state
2788 |= x_emacs_to_x_modifiers (extra_keyboard_modifiers);
64bb1782 2789 modifiers = event.xkey.state;
3a2712f9 2790
11edeb03
JB
2791 /* This will have to go some day... */
2792 nbytes =
2793 XLookupString (&event.xkey, copy_buffer, 80, &keysym,
2794 &compose_status);
dc6f92b8 2795
55123275
JB
2796 /* Strip off the vendor-specific keysym bit, and take a shot
2797 at recognizing the codes. HP servers have extra keysyms
2798 that fit into the MiscFunctionKey category. */
2799 keysym &= ~(1<<28);
2800
dc6f92b8
JB
2801 if (numchars > 1)
2802 {
a3c44b14
RS
2803 if ((keysym >= XK_BackSpace && keysym <= XK_Escape)
2804 || keysym == XK_Delete
2805 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
55123275
JB
2806 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < 0xff80 */
2807 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
2808 || IsFunctionKey (keysym)) /* 0xffbe <= x < 0xffe1 */
dc6f92b8 2809 {
10e6549c
RS
2810 if (temp_index == sizeof temp_buffer / sizeof (short))
2811 temp_index = 0;
2812 temp_buffer[temp_index++] = keysym;
dc6f92b8 2813 bufp->kind = non_ascii_keystroke;
a3c44b14 2814 XSET (bufp->code, Lisp_Int, (unsigned) keysym - 0xff00);
12ba150f 2815 XSET (bufp->frame_or_window, Lisp_Frame, f);
dfeccd2d 2816 bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
1113d9db 2817 bufp->timestamp = event.xkey.time;
dc6f92b8
JB
2818 bufp++;
2819 count++;
2820 numchars--;
2821 }
2822 else if (numchars > nbytes)
2823 {
2824 register int i;
2825
10e6549c 2826 for (i = 0; i < nbytes; i++)
dc6f92b8 2827 {
10e6549c
RS
2828 if (temp_index == sizeof temp_buffer / sizeof (short))
2829 temp_index = 0;
2830 temp_buffer[temp_index++] = copy_buffer[i];
dc6f92b8 2831 bufp->kind = ascii_keystroke;
10e6549c 2832 XSET (bufp->code, Lisp_Int, copy_buffer[i]);
12ba150f 2833 XSET (bufp->frame_or_window, Lisp_Frame, f);
dfeccd2d 2834 bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
1113d9db 2835 bufp->timestamp = event.xkey.time;
dc6f92b8
JB
2836 bufp++;
2837 }
dc6f92b8
JB
2838
2839 count += nbytes;
2840 numchars -= nbytes;
2841 }
10e6549c
RS
2842 else
2843 abort ();
dc6f92b8 2844 }
10e6549c
RS
2845 else
2846 abort ();
dc6f92b8
JB
2847 }
2848 break;
c118dd06 2849#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
2850 case KeyPressed:
2851 {
2852 register char *where_mapping;
2853
f676886a 2854 f = x_window_to_frame (event.window);
dc6f92b8 2855 /* Ignore keys typed on icon windows. */
f676886a 2856 if (f != 0 && event.window == f->display.x->icon_desc)
dc6f92b8
JB
2857 break;
2858 where_mapping = XLookupMapping (&event, &nbytes);
2859 /* Nasty fix for arrow keys */
2860 if (!nbytes && IsCursorKey (event.detail & 0xff))
2861 {
2862 switch (event.detail & 0xff)
2863 {
2864 case KC_CURSOR_LEFT:
2865 where_mapping = "\002";
2866 break;
2867 case KC_CURSOR_RIGHT:
2868 where_mapping = "\006";
2869 break;
2870 case KC_CURSOR_UP:
2871 where_mapping = "\020";
2872 break;
2873 case KC_CURSOR_DOWN:
2874 where_mapping = "\016";
2875 break;
2876 }
2877 nbytes = 1;
2878 }
2879 if (numchars - nbytes > 0)
2880 {
2881 register int i;
2882
2883 for (i = 0; i < nbytes; i++)
2884 {
2885 bufp->kind = ascii_keystroke;
2886 XSET (bufp->code, Lisp_Int, where_mapping[i]);
90e65f07 2887 XSET (bufp->time, Lisp_Int, event.xkey.time);
12ba150f 2888 XSET (bufp->frame_or_window, Lisp_Frame, f);
dc6f92b8
JB
2889 bufp++;
2890 }
2891 count += nbytes;
2892 numchars -= nbytes;
2893 }
2894 }
2895 break;
c118dd06 2896#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
2897
2898#ifdef HAVE_X11
f451eb13
JB
2899
2900 /* Here's a possible interpretation of the whole
2901 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If you get a
2902 FocusIn event, you have to get a FocusOut event before you
2903 relinquish the focus. If you haven't received a FocusIn event,
2904 then a mere LeaveNotify is enough to free you. */
2905
dc6f92b8 2906 case EnterNotify:
f676886a 2907 f = x_window_to_frame (event.xcrossing.window);
6d4238f3 2908
f451eb13 2909 if (event.xcrossing.focus) /* Entered Window */
dc6f92b8 2910 {
dc6f92b8 2911 /* Avoid nasty pop/raise loops. */
f676886a
JB
2912 if (f && (!(f->auto_raise)
2913 || !(f->auto_lower)
dc6f92b8
JB
2914 || (event.xcrossing.time - enter_timestamp) > 500))
2915 {
f676886a 2916 x_new_focus_frame (f);
dc6f92b8
JB
2917 enter_timestamp = event.xcrossing.time;
2918 }
dc6f92b8 2919 }
f676886a
JB
2920 else if (f == x_focus_frame)
2921 x_new_focus_frame (0);
dc6f92b8
JB
2922
2923 break;
2924
2925 case FocusIn:
f676886a 2926 f = x_window_to_frame (event.xfocus.window);
f451eb13
JB
2927 if (event.xfocus.detail != NotifyPointer)
2928 x_focus_event_frame = f;
f676886a
JB
2929 if (f)
2930 x_new_focus_frame (f);
dc6f92b8
JB
2931 break;
2932
f451eb13 2933
dc6f92b8 2934 case LeaveNotify:
f451eb13 2935 f = x_window_to_frame (event.xcrossing.window);
b1c884c3 2936
f451eb13
JB
2937 if (event.xcrossing.focus)
2938 {
2939 if (! x_focus_event_frame)
2940 x_new_focus_frame (0);
2941 else
f676886a 2942 x_new_focus_frame (f);
f451eb13
JB
2943 }
2944 else
2945 {
2946 if (f == x_focus_event_frame)
2947 x_focus_event_frame = 0;
2948 if (f == x_focus_frame)
f676886a 2949 x_new_focus_frame (0);
dc6f92b8
JB
2950 }
2951 break;
2952
2953 case FocusOut:
f676886a 2954 f = x_window_to_frame (event.xfocus.window);
f451eb13
JB
2955 if (event.xfocus.detail != NotifyPointer
2956 && f == x_focus_event_frame)
2957 x_focus_event_frame = 0;
f676886a
JB
2958 if (f && f == x_focus_frame)
2959 x_new_focus_frame (0);
dc6f92b8
JB
2960 break;
2961
c118dd06 2962#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
2963
2964 case EnterWindow:
2965 if ((event.detail & 0xFF) == 1)
2966 break; /* Coming from our own subwindow */
2967 if (event.subwindow != 0)
2968 break; /* Entering our own subwindow. */
2969
2970 {
f676886a
JB
2971 f = x_window_to_frame (event.window);
2972 x_mouse_frame = f;
dc6f92b8 2973
f676886a 2974 x_new_focus_frame (f);
dc6f92b8
JB
2975 }
2976 break;
2977
2978 case LeaveWindow:
2979 if ((event.detail & 0xFF) == 1)
2980 break; /* Entering our own subwindow */
2981 if (event.subwindow != 0)
2982 break; /* Leaving our own subwindow. */
2983
f676886a
JB
2984 x_mouse_frame = 0;
2985 if (x_focus_frame == 0
2986 && x_input_frame != 0
2987 && x_input_frame == x_window_to_frame (event.window)
c118dd06 2988 && event.window == FRAME_X_WINDOW (x_input_frame))
dc6f92b8 2989 {
f676886a
JB
2990 f = x_input_frame;
2991 x_input_frame = 0;
2992 if (f)
2993 frame_unhighlight (f);
dc6f92b8
JB
2994 }
2995 break;
c118dd06 2996#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
2997
2998#ifdef HAVE_X11
2999 case MotionNotify:
3000 {
f676886a
JB
3001 f = x_window_to_frame (event.xmotion.window);
3002 if (f)
12ba150f 3003 note_mouse_movement (f, &event.xmotion);
f451eb13 3004 else
dc6f92b8 3005 {
ab648270
JB
3006 struct scroll_bar *bar =
3007 x_window_to_scroll_bar (event.xmotion.window);
f451eb13
JB
3008
3009 if (bar)
ab648270 3010 x_scroll_bar_note_movement (bar, &event);
dc6f92b8 3011 }
dc6f92b8
JB
3012 }
3013 break;
3014
3015 case ConfigureNotify:
dbc4e1c1
JB
3016 f = x_window_to_frame (event.xconfigure.window);
3017 if (f)
3018 {
3019 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
3020 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
3021
3022 /* Even if the number of character rows and columns has
3023 not changed, the font size may have changed, so we need
3024 to check the pixel dimensions as well. */
3025 if (columns != f->width
3026 || rows != f->height
3027 || event.xconfigure.width != f->display.x->pixel_width
3028 || event.xconfigure.height != f->display.x->pixel_height)
3029 {
3030 change_frame_size (f, rows, columns, 0, 1);
3031 SET_FRAME_GARBAGED (f);
3032 }
dc6f92b8 3033
dbc4e1c1
JB
3034 f->display.x->pixel_width = event.xconfigure.width;
3035 f->display.x->pixel_height = event.xconfigure.height;
3036 f->display.x->left_pos = event.xconfigure.x;
3037 f->display.x->top_pos = event.xconfigure.y;
3038 }
3039 break;
dc6f92b8
JB
3040
3041 case ButtonPress:
3042 case ButtonRelease:
3043 {
3044 /* If we decide we want to generate an event to be seen
3045 by the rest of Emacs, we put it here. */
3046 struct input_event emacs_event;
3047 emacs_event.kind = no_event;
3048
f676886a
JB
3049 f = x_window_to_frame (event.xbutton.window);
3050 if (f)
f451eb13
JB
3051 {
3052 if (!x_focus_frame || (f == x_focus_frame))
3053 construct_mouse_click (&emacs_event,
b10fd412 3054 &event, f);
f451eb13 3055 }
dc6f92b8 3056 else
f451eb13 3057 {
ab648270
JB
3058 struct scroll_bar *bar =
3059 x_window_to_scroll_bar (event.xbutton.window);
f451eb13
JB
3060
3061 if (bar)
ab648270 3062 x_scroll_bar_handle_click (bar, &event, &emacs_event);
f451eb13 3063 }
dc6f92b8
JB
3064
3065 if (numchars >= 1 && emacs_event.kind != no_event)
3066 {
3067 bcopy (&emacs_event, bufp, sizeof (struct input_event));
3068 bufp++;
3069 count++;
3070 numchars--;
3071 }
3072 }
3073 break;
3074
c118dd06 3075#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3076 case ButtonPressed:
3077 case ButtonReleased:
f676886a
JB
3078 f = x_window_to_frame (event.window);
3079 if (f)
dc6f92b8 3080 {
f676886a 3081 if (event.window == f->display.x->icon_desc)
dc6f92b8 3082 {
f676886a 3083 x_make_frame_visible (f);
dc6f92b8
JB
3084
3085 if (warp_mouse_on_deiconify)
c118dd06 3086 XWarpMouse (FRAME_X_WINDOW (f), 10, 10);
dc6f92b8
JB
3087 break;
3088 }
c118dd06 3089 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8 3090 {
f676886a
JB
3091 if (f->auto_raise)
3092 x_raise_frame (f);
dc6f92b8
JB
3093 }
3094 }
3095 enqueue_event (&event, &x_mouse_queue);
3096 if (numchars >= 2)
3097 {
3098 bufp->kind = ascii_keystroke;
3099 bufp->code = (char) 'X' & 037; /* C-x */
12ba150f 3100 XSET (bufp->frame_or_window, Lisp_Frame, f);
90e65f07 3101 XSET (bufp->time, Lisp_Int, event.xkey.time);
dc6f92b8
JB
3102 bufp++;
3103
3104 bufp->kind = ascii_keystroke;
3105 bufp->code = (char) 0; /* C-@ */
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 count += 2;
3111 numchars -= 2;
3112 }
3113 break;
c118dd06 3114#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3115
3116#ifdef HAVE_X11
3117
3118 case CirculateNotify:
3119 break;
3120 case CirculateRequest:
3121 break;
3122
c118dd06 3123#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3124
3125 case MappingNotify:
11edeb03
JB
3126 /* Someone has changed the keyboard mapping - update the
3127 local cache. */
3128 switch (event.xmapping.request)
3129 {
3130 case MappingModifier:
3131 x_find_modifier_meanings ();
3132 /* This is meant to fall through. */
3133 case MappingKeyboard:
3134 XRefreshKeyboardMapping (&event.xmapping);
3135 }
dc6f92b8
JB
3136 break;
3137
3138 default:
3139 break;
3140 }
3141 }
3142
3143#if 0
3144#ifdef HAVE_SELECT
3145 if (expected && ! event_found)
3146 {
3147 /* AOJ 880406: if select returns true but XPending doesn't, it means that
3148 there is an EOF condition; in other words, that X has died.
3149 Act as if there had been a hangup. */
3150
3151 int fd = ConnectionNumber (x_current_display);
3152 int mask = 1 << fd;
3153
3154 if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0,
3a2712f9 3155 (EMACS_TIME) 0)
dc6f92b8
JB
3156 && !XStuffPending ())
3157 kill (getpid (), SIGHUP);
3158 }
c118dd06
JB
3159#endif /* ! defined (HAVE_SELECT) */
3160#endif /* ! 0 */
dc6f92b8 3161
f451eb13 3162#ifndef HAVE_X11
f676886a 3163 if (updating_frame == 0)
dc6f92b8 3164 x_do_pending_expose ();
f451eb13 3165#endif
dc6f92b8
JB
3166
3167 UNBLOCK_INPUT;
3168 return count;
3169}
3170
3171#ifndef HAVE_X11
3172/* Read and process only Expose events
3173 until we get an ExposeCopy event; then return.
3174 This is used in insert/delete line.
3175 We assume input is already blocked. */
3176
3177static void
3178x_read_exposes ()
3179{
f676886a 3180 struct frame *f;
dc6f92b8
JB
3181 XKeyPressedEvent event;
3182
3183 while (1)
3184 {
3185 /* while there are more events*/
3186 XMaskEvent (ExposeWindow | ExposeRegion | ExposeCopy, &event);
3187 switch (event.type)
3188 {
3189 case ExposeWindow:
3190 if (event.subwindow != 0)
3191 break; /* duplicate event */
f676886a
JB
3192 f = x_window_to_frame (event.window);
3193 if (event.window == f->display.x->icon_desc)
dc6f92b8 3194 {
f676886a 3195 refreshicon (f);
dc6f92b8
JB
3196 break;
3197 }
c118dd06 3198 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8
JB
3199 {
3200 expose_all_windows = 1;
f676886a 3201 f->display.x->needs_exposure = 1;
dc6f92b8
JB
3202 break;
3203 }
3204 break;
3205
3206 case ExposeRegion:
3207 if (event.subwindow != 0)
3208 break; /* duplicate event */
f676886a
JB
3209 f = x_window_to_frame (event.window);
3210 if (event.window == f->display.x->icon_desc)
dc6f92b8 3211 {
f676886a 3212 refreshicon (f);
dc6f92b8
JB
3213 break;
3214 }
3215 /* If window already needs full redraw, ignore this rectangle. */
f676886a 3216 if (expose_all_windows && f->display.x->needs_exposure)
dc6f92b8
JB
3217 break;
3218 /* Put the event on the queue of rectangles to redraw. */
3219 if (enqueue_event (&event, &x_expose_queue))
3220 /* If it is full, we can't record the rectangle,
3221 so redraw this entire window. */
3222 {
3223 /* Say must check all windows' needs_exposure flags. */
3224 expose_all_windows = 1;
f676886a 3225 f->display.x->needs_exposure = 1;
dc6f92b8
JB
3226 }
3227 break;
3228
3229 case ExposeCopy:
3230 return;
3231 }
3232 }
3233}
3234#endif /* HAVE_X11 */
3235
dc6f92b8 3236\f
f451eb13
JB
3237/* Drawing the cursor. */
3238
3239
dc6f92b8
JB
3240/* Draw a hollow box cursor. Don't change the inside of the box. */
3241
3242static void
f676886a
JB
3243x_draw_box (f)
3244 struct frame *f;
dc6f92b8 3245{
12ba150f
JB
3246 int left = CHAR_TO_PIXEL_COL (f, f->cursor_x);
3247 int top = CHAR_TO_PIXEL_ROW (f, f->cursor_y);
f676886a
JB
3248 int width = FONT_WIDTH (f->display.x->font);
3249 int height = FONT_HEIGHT (f->display.x->font);
dc6f92b8
JB
3250
3251#ifdef HAVE_X11
c118dd06 3252 XDrawRectangle (x_current_display, FRAME_X_WINDOW (f),
f676886a 3253 f->display.x->cursor_gc,
dc6f92b8 3254 left, top, width - 1, height - 1);
c118dd06
JB
3255#else /* ! defined (HAVE_X11) */
3256 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3257 left, top, width, 1,
f676886a 3258 f->display.x->cursor_pixel);
dc6f92b8 3259
c118dd06 3260 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3261 left, top, 1, height,
f676886a 3262 f->display.x->cursor_pixel);
dc6f92b8 3263
c118dd06 3264 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3265 left+width-1, top, 1, height,
f676886a 3266 f->display.x->cursor_pixel);
dc6f92b8 3267
c118dd06 3268 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3269 left, top+height-1, width, 1,
f676886a 3270 f->display.x->cursor_pixel);
c118dd06 3271#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3272}
3273
f676886a 3274/* Clear the cursor of frame F to background color,
dc6f92b8
JB
3275 and mark the cursor as not shown.
3276 This is used when the text where the cursor is
3277 is about to be rewritten. */
3278
3279static void
f676886a
JB
3280clear_cursor (f)
3281 struct frame *f;
dc6f92b8
JB
3282{
3283 int mask;
3284
f451eb13 3285 if (! FRAME_VISIBLE_P (f)
f676886a 3286 || f->phys_cursor_x < 0)
dc6f92b8
JB
3287 return;
3288
3289#ifdef HAVE_X11
f676886a 3290 x_display_cursor (f, 0);
c118dd06
JB
3291#else /* ! defined (HAVE_X11) */
3292 XPixSet (FRAME_X_WINDOW (f),
12ba150f
JB
3293 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
3294 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
f676886a
JB
3295 FONT_WIDTH (f->display.x->font), FONT_HEIGHT (f->display.x->font),
3296 f->display.x->background_pixel);
c118dd06 3297#endif /* ! defined (HAVE_X11) */
f676886a 3298 f->phys_cursor_x = -1;
dc6f92b8
JB
3299}
3300
f676886a 3301/* Redraw the glyph at ROW, COLUMN on frame F, in the style
90e65f07
JB
3302 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
3303 glyph drawn. */
dc6f92b8
JB
3304
3305static void
f676886a
JB
3306x_draw_single_glyph (f, row, column, glyph, highlight)
3307 struct frame *f;
dc6f92b8 3308 int row, column;
90e65f07 3309 GLYPH glyph;
dc6f92b8
JB
3310 int highlight;
3311{
f676886a 3312 dumpglyphs (f,
12ba150f
JB
3313 CHAR_TO_PIXEL_COL (f, column),
3314 CHAR_TO_PIXEL_ROW (f, row),
f676886a 3315 &glyph, 1, highlight, f->display.x->font);
dc6f92b8
JB
3316}
3317
dc6f92b8 3318static void
dbc4e1c1 3319x_display_bar_cursor (f, on)
f676886a 3320 struct frame *f;
dc6f92b8
JB
3321 int on;
3322{
f676886a 3323 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
90e65f07 3324
49d838ea
JB
3325 /* This is pointless on invisible frames, and dangerous on garbaged
3326 frames; in the latter case, the frame may be in the midst of
3327 changing its size, and curs_x and curs_y may be off the frame. */
3328 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dbc4e1c1
JB
3329 return;
3330
3331 if (! on && f->phys_cursor_x < 0)
3332 return;
3333
f676886a 3334 /* If we're not updating, then we want to use the current frame's
1113d9db 3335 cursor position, not our local idea of where the cursor ought to be. */
f676886a 3336 if (f != updating_frame)
1113d9db 3337 {
f676886a
JB
3338 curs_x = FRAME_CURSOR_X (f);
3339 curs_y = FRAME_CURSOR_Y (f);
1113d9db
JB
3340 }
3341
dbc4e1c1
JB
3342 /* If there is anything wrong with the current cursor state, remove it. */
3343 if (f->phys_cursor_x >= 0
3344 && (!on
3345 || f->phys_cursor_x != curs_x
3346 || f->phys_cursor_y != curs_y
3347 || f->display.x->current_cursor != bar_cursor))
3348 {
3349 /* Erase the cursor by redrawing the character underneath it. */
3350 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
3351 f->phys_cursor_glyph,
3352 current_glyphs->highlight[f->phys_cursor_y]);
3353 f->phys_cursor_x = -1;
3354 }
3355
3356 /* If we now need a cursor in the new place or in the new form, do it so. */
3357 if (on
3358 && (f->phys_cursor_x < 0
3359 || (f->display.x->current_cursor != bar_cursor)))
3360 {
3361 f->phys_cursor_glyph
3362 = ((current_glyphs->enable[curs_y]
3363 && curs_x < current_glyphs->used[curs_y])
3364 ? current_glyphs->glyphs[curs_y][curs_x]
3365 : SPACEGLYPH);
3366 XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
3367 f->display.x->cursor_gc,
3368 CHAR_TO_PIXEL_COL (f, curs_x),
3369 CHAR_TO_PIXEL_ROW (f, curs_y),
3370 1, FONT_HEIGHT (f->display.x->font));
3371
3372 f->phys_cursor_x = curs_x;
3373 f->phys_cursor_y = curs_y;
3374
3375 f->display.x->current_cursor = bar_cursor;
3376 }
3377
3378 if (updating_frame != f)
3379 XFlushQueue ();
3380}
3381
3382
3383/* Turn the displayed cursor of frame F on or off according to ON.
3384 If ON is nonzero, where to put the cursor is specified
3385 by F->cursor_x and F->cursor_y. */
3386
3387static void
3388x_display_box_cursor (f, on)
3389 struct frame *f;
3390 int on;
3391{
3392 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
3393
49d838ea
JB
3394 /* This is pointless on invisible frames, and dangerous on garbaged
3395 frames; in the latter case, the frame may be in the midst of
3396 changing its size, and curs_x and curs_y may be off the frame. */
3397 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_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
dfeccd2d 3601#if 0
c118dd06 3602 XSetIconName (x_current_display, FRAME_X_WINDOW (f),
f676886a 3603 (char *) f->display.x->icon_label);
dfeccd2d 3604#endif
dc6f92b8 3605
f676886a 3606 f->display.x->icon_bitmap_flag = 0;
b1c884c3 3607 x_wm_set_icon_pixmap (f, 0);
c118dd06 3608#else /* ! defined (HAVE_X11) */
dbc4e1c1
JB
3609 if (icon_font_info == 0)
3610 icon_font_info
3611 = XGetFont (XGetDefault (XDISPLAY
59653951 3612 (char *) XSTRING (Vinvocation_name)->data,
dbc4e1c1
JB
3613 "BodyFont"));
3614
f676886a 3615 if (f->display.x->icon_desc)
dc6f92b8 3616 {
c118dd06 3617 XClearIconWindow (XDISPLAY FRAME_X_WINDOW (f));
f676886a 3618 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
dc6f92b8
JB
3619 }
3620
3621 if (icon_name)
f676886a 3622 f->display.x->icon_label = (unsigned char *) icon_name;
dc6f92b8 3623 else
f676886a
JB
3624 if (! f->display.x->icon_label)
3625 f->display.x->icon_label = XSTRING (f->name)->data;
dc6f92b8 3626
f676886a
JB
3627 width = XStringWidth (f->display.x->icon_label, icon_font_info, 0, 0);
3628 icon_window = XCreateWindow (f->display.x->parent_desc,
3629 f->display.x->left_pos,
3630 f->display.x->top_pos,
dc6f92b8
JB
3631 width + 10, icon_font_info->height + 10,
3632 2, BlackPixmap, WhitePixmap);
3633
3634 if (icon_window == 0)
3635 return 1;
3636
c118dd06 3637 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
dc6f92b8
JB
3638 XSelectInput (icon_window, ExposeWindow | ExposeRegion | UnmapWindow | ButtonPressed);
3639
f676886a
JB
3640 f->display.x->icon_desc = icon_window;
3641 f->display.x->icon_bitmap_flag = 0;
3642 f->display.x->icon_label = 0;
c118dd06 3643#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3644
3645 return 0;
3646}
3647\f
4746118a
JB
3648/* Handling X errors. */
3649
12ba150f
JB
3650/* Shut down Emacs in an orderly fashion, because of a SIGPIPE on the
3651 X server's connection, or an error reported via the X protocol. */
16bd92ea 3652
4746118a 3653static SIGTYPE
c118dd06 3654x_connection_closed ()
4746118a
JB
3655{
3656 if (_Xdebug)
3657 abort ();
12ba150f
JB
3658
3659 shut_down_emacs (0);
3660
3661 exit (70);
4746118a
JB
3662}
3663
8922af5f
JB
3664/* An X error handler which prints an error message and then kills
3665 Emacs. This is what's normally installed as Xlib's handler for
3666 protocol errors. */
c118dd06
JB
3667static int
3668x_error_quitter (display, error)
3669 Display *display;
3670 XErrorEvent *error;
3671{
3672 char buf[256];
dc6f92b8 3673
c118dd06
JB
3674 /* Note that there is no real way portable across R3/R4 to get the
3675 original error handler. */
dc6f92b8 3676
c118dd06
JB
3677 XGetErrorText (display, error->error_code, buf, sizeof (buf));
3678 fprintf (stderr, "X protocol error: %s on protocol request %d\n",
3679 buf, error->request_code);
dc6f92b8 3680
12ba150f
JB
3681 /* While we're testing Emacs 19, we'll just dump core whenever we
3682 get an X error, so we can figure out why it happened. */
3683 abort ();
3684
c118dd06 3685 x_connection_closed ();
dc6f92b8
JB
3686}
3687
8922af5f
JB
3688/* A handler for X IO errors which prints an error message and then
3689 kills Emacs. This is what is always installed as Xlib's handler
3690 for I/O errors. */
3691static int
3692x_io_error_quitter (display)
3693 Display *display;
3694{
3695 fprintf (stderr, "Connection to X server %s lost.\n",
3696 XDisplayName (DisplayString (display)));
3697
3698 /* While we're testing Emacs 19, we'll just dump core whenever we
3699 get an X error, so we can figure out why it happened. */
3700 abort ();
3701
3702 x_connection_closed ();
3703}
3704
c118dd06
JB
3705/* A buffer for storing X error messages. */
3706static char (*x_caught_error_message)[200];
3707
3708/* An X error handler which stores the error message in
3709 x_caught_error_message. This is what's installed when
3710 x_catch_errors is in effect. */
3711static int
3712x_error_catcher (display, error)
3713 Display *display;
3714 XErrorEvent *error;
3715{
3716 XGetErrorText (display, error->error_code,
3717 *x_caught_error_message, sizeof (*x_caught_error_message));
3718}
3719
3720
3721/* Begin trapping X errors.
dc6f92b8 3722
c118dd06
JB
3723 After calling this function, X protocol errors no longer cause
3724 Emacs to exit; instead, they are recorded in x_cfc_error_message.
dc6f92b8 3725
c118dd06
JB
3726 Calling x_check_errors signals an Emacs error if an X error has
3727 occurred since the last call to x_catch_errors or x_check_errors.
3728
3729 Calling x_uncatch_errors resumes the normal error handling. */
3730
3731void x_catch_errors(), x_check_errors (), x_uncatch_errors ();
3732
3733void
3734x_catch_errors ()
dc6f92b8 3735{
c118dd06
JB
3736 /* Make sure any errors from previous requests have been dealt with. */
3737 XSync (x_current_display, False);
dc6f92b8 3738
c118dd06
JB
3739 /* Set up the error buffer. */
3740 x_caught_error_message =
3741 (char (*)[]) xmalloc (sizeof (*x_caught_error_message));
d872b748 3742 (*x_caught_error_message)[0] = '\0';
16bd92ea 3743
c118dd06
JB
3744 /* Install our little error handler. */
3745 XHandleError (x_error_catcher);
3746}
16bd92ea 3747
c118dd06
JB
3748/* If any X protocol errors have arrived since the last call to
3749 x_catch_errors or x_check_errors, signal an Emacs error using
3750 sprintf (a buffer, FORMAT, the x error message text) as the text. */
3751void
3752x_check_errors (format)
3753 char *format;
3754{
3755 /* Make sure to catch any errors incurred so far. */
3756 XSync (x_current_display, False);
16bd92ea 3757
c118dd06
JB
3758 if ((*x_caught_error_message)[0])
3759 {
3760 char buf[256];
3761
3762 sprintf (buf, format, *x_caught_error_message);
9ac0d9e0 3763 xfree (x_caught_error_message);
dc6f92b8 3764
c118dd06
JB
3765 x_uncatch_errors ();
3766 error (buf);
3767 }
3768}
3769
3770void
3771x_uncatch_errors ()
3772{
9ac0d9e0 3773 xfree (x_caught_error_message);
c118dd06 3774 XHandleError (x_error_quitter);
dc6f92b8
JB
3775}
3776
dc6f92b8
JB
3777#if 0
3778static unsigned int x_wire_count;
3779x_trace_wire ()
3780{
3781 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
3782}
c118dd06 3783#endif /* ! 0 */
dc6f92b8
JB
3784
3785\f
f451eb13
JB
3786/* Changing the font of the frame. */
3787
f676886a 3788/* Set the font of the x-window specified by frame F
dc6f92b8 3789 to the font named NEWNAME. This is safe to use
f676886a 3790 even before F has an actual x-window. */
dc6f92b8
JB
3791
3792#ifdef HAVE_X11
3793
3794/* A table of all the fonts we have already loaded. */
3795static XFontStruct **x_font_table;
3796
3797/* The current capacity of x_font_table. */
3798static int x_font_table_size;
3799
3800/* The number of fonts actually stored in x_font_table.
3801 x_font_table[n] is used and valid iff 0 <= n < n_fonts.
3802 0 <= n_fonts <= x_font_table_size. */
3803static int n_fonts;
3804
f676886a
JB
3805x_new_font (f, fontname)
3806 struct frame *f;
dc6f92b8
JB
3807 register char *fontname;
3808{
3809 XFontStruct *temp;
3810 int already_loaded;
3811 int n_matching_fonts;
3812 XFontStruct *font_info;
3813 char **font_names;
3814
3815 /* Get a list of all the fonts that match this name. Once we
3816 have a list of matching fonts, we compare them against the fonts
3817 we already have by comparing font ids. */
3818 font_names = (char **) XListFontsWithInfo (x_current_display, fontname,
3819 1024, &n_matching_fonts,
3820 &font_info);
3821 /* If the server couldn't find any fonts whose named matched fontname,
3822 return an error code. */
3823 if (n_matching_fonts == 0)
3824 return 1;
3825
90e65f07 3826 /* See if we've already loaded a matching font. */
dc6f92b8
JB
3827 {
3828 int i, j;
3829
3830 already_loaded = 0;
3831 for (i = 0; i < n_fonts; i++)
3832 for (j = 0; j < n_matching_fonts; j++)
3833 if (x_font_table[i]->fid == font_info[j].fid)
3834 {
3835 already_loaded = i;
3836 goto found_font;
3837 }
3838 }
3839 found_font:
3840
3841 /* If we have, just return it from the table. */
3842 if (already_loaded)
f676886a 3843 f->display.x->font = x_font_table[already_loaded];
90e65f07 3844
dc6f92b8
JB
3845 /* Otherwise, load the font and add it to the table. */
3846 else
3847 {
3848 XFontStruct *font;
3849
3850 font = (XFontStruct *) XLoadQueryFont (x_current_display, fontname);
3851 if (! font)
3852 return 1;
3853
3854 /* Do we need to create the table? */
3855 if (x_font_table_size == 0)
3856 {
3857 x_font_table_size = 16;
3858 x_font_table
3859 = (XFontStruct **) xmalloc (x_font_table_size
3860 * sizeof (x_font_table[0]));
3861 }
3862 /* Do we need to grow the table? */
3863 else if (n_fonts >= x_font_table_size)
3864 {
90e65f07 3865 x_font_table_size *= 2;
dc6f92b8
JB
3866 x_font_table
3867 = (XFontStruct **) xrealloc (x_font_table,
3868 (x_font_table_size
3869 * sizeof (x_font_table[0])));
3870 }
3871
f676886a 3872 f->display.x->font = x_font_table[n_fonts++] = font;
dc6f92b8
JB
3873 }
3874
3875 /* Free the information from XListFontsWithInfo. The data
3876 we actually retain comes from XLoadQueryFont. */
3877 XFreeFontInfo (font_names, font_info, n_matching_fonts);
3878
f676886a 3879 /* Now make the frame display the given font. */
c118dd06 3880 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 3881 {
f676886a
JB
3882 XSetFont (x_current_display, f->display.x->normal_gc,
3883 f->display.x->font->fid);
3884 XSetFont (x_current_display, f->display.x->reverse_gc,
3885 f->display.x->font->fid);
3886 XSetFont (x_current_display, f->display.x->cursor_gc,
3887 f->display.x->font->fid);
3888
3889 x_set_window_size (f, f->width, f->height);
dc6f92b8
JB
3890 }
3891
3892 return 0;
3893}
c118dd06 3894#else /* ! defined (HAVE_X11) */
f676886a
JB
3895x_new_font (f, newname)
3896 struct frame *f;
dc6f92b8
JB
3897 register char *newname;
3898{
3899 FONT_TYPE *temp;
3900 int mask;
3901
3902 temp = XGetFont (newname);
3903 if (temp == (FONT_TYPE *) 0)
3904 return 1;
3905
f676886a
JB
3906 if (f->display.x->font)
3907 XLoseFont (f->display.x->font);
dc6f92b8 3908
f676886a 3909 f->display.x->font = temp;
dc6f92b8 3910
c118dd06 3911 if (FRAME_X_WINDOW (f) != 0)
f676886a 3912 x_set_window_size (f, f->width, f->height);
dc6f92b8
JB
3913
3914 return 0;
3915}
c118dd06 3916#endif /* ! defined (HAVE_X11) */
dc6f92b8 3917\f
f451eb13
JB
3918/* X Window sizes and positions. */
3919
f676886a
JB
3920x_calc_absolute_position (f)
3921 struct frame *f;
dc6f92b8
JB
3922{
3923#ifdef HAVE_X11
f676886a
JB
3924 if (f->display.x->left_pos < 0)
3925 f->display.x->left_pos
7c5283e4 3926 = x_screen_width - PIXEL_WIDTH (f) + f->display.x->left_pos;
dc6f92b8 3927
f676886a
JB
3928 if (f->display.x->top_pos < 0)
3929 f->display.x->top_pos
7c5283e4 3930 = x_screen_height - PIXEL_HEIGHT (f) + f->display.x->top_pos;
c118dd06 3931#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3932 WINDOWINFO_TYPE parentinfo;
3933
c118dd06 3934 XGetWindowInfo (FRAME_X_WINDOW (f), &parentinfo);
dc6f92b8 3935
f676886a
JB
3936 if (f->display.x->left_pos < 0)
3937 f->display.x->left_pos = parentinfo.width + (f->display.x->left_pos + 1)
3938 - PIXEL_WIDTH (f) - 2 * f->display.x->internal_border_width;
dc6f92b8 3939
f676886a
JB
3940 if (f->display.x->top_pos < 0)
3941 f->display.x->top_pos = parentinfo.height + (f->display.x->top_pos + 1)
3942 - PIXEL_HEIGHT (f) - 2 * f->display.x->internal_border_width;
c118dd06 3943#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3944}
3945
f676886a
JB
3946x_set_offset (f, xoff, yoff)
3947 struct frame *f;
dc6f92b8
JB
3948 register int xoff, yoff;
3949{
f676886a
JB
3950 f->display.x->top_pos = yoff;
3951 f->display.x->left_pos = xoff;
3952 x_calc_absolute_position (f);
dc6f92b8
JB
3953
3954 BLOCK_INPUT;
c118dd06 3955 XMoveWindow (XDISPLAY FRAME_X_WINDOW (f),
f676886a 3956 f->display.x->left_pos, f->display.x->top_pos);
dc6f92b8 3957#ifdef HAVE_X11
f676886a 3958 x_wm_set_size_hint (f, 0);
c118dd06 3959#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3960 UNBLOCK_INPUT;
3961}
3962
f676886a 3963/* Call this to change the size of frame F's x-window. */
dc6f92b8 3964
f676886a
JB
3965x_set_window_size (f, cols, rows)
3966 struct frame *f;
b1c884c3 3967 int cols, rows;
dc6f92b8
JB
3968{
3969 int pixelwidth, pixelheight;
3970 int mask;
dc6f92b8
JB
3971
3972 BLOCK_INPUT;
3973
b1c884c3 3974 check_frame_size (f, &rows, &cols);
ab648270
JB
3975 f->display.x->vertical_scroll_bar_extra =
3976 (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3977 ? VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f)
f451eb13
JB
3978 : 0);
3979 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
3980 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8
JB
3981
3982#ifdef HAVE_X11
f676886a 3983 x_wm_set_size_hint (f, 0);
c118dd06
JB
3984#endif /* ! defined (HAVE_X11) */
3985 XChangeWindowSize (FRAME_X_WINDOW (f), pixelwidth, pixelheight);
b1c884c3
JB
3986
3987 /* Now, strictly speaking, we can't be sure that this is accurate,
3988 but the window manager will get around to dealing with the size
3989 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
3990 ConfigureNotify event gets here.
3991
3992 We could just not bother storing any of this information here,
3993 and let the ConfigureNotify event set everything up, but that
3994 might be kind of confusing to the lisp code, since size changes
3995 wouldn't be reported in the frame parameters until some random
3996 point in the future when the ConfigureNotify event arrives. */
8922af5f 3997 change_frame_size (f, rows, cols, 0, 0);
b1c884c3
JB
3998 PIXEL_WIDTH (f) = pixelwidth;
3999 PIXEL_HEIGHT (f) = pixelheight;
4000
dbc4e1c1
JB
4001 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
4002 receive in the ConfigureNotify event; if we get what we asked
4003 for, then the event won't cause the screen to become garbaged, so
4004 we have to make sure to do it here. */
4005 SET_FRAME_GARBAGED (f);
4006
dc6f92b8
JB
4007 XFlushQueue ();
4008 UNBLOCK_INPUT;
4009}
4010
4011#ifndef HAVE_X11
f676886a
JB
4012x_set_resize_hint (f)
4013 struct frame *f;
dc6f92b8 4014{
12ba150f
JB
4015 XSetResizeHint (FRAME_X_WINDOW (f),
4016 2 * f->display.x->internal_border_width,
f676886a 4017 2 * f->display.x->internal_border_width,
12ba150f
JB
4018 FONT_WIDTH (f->display.x->font),
4019 FONT_HEIGHT (f->display.x->font));
dc6f92b8 4020}
c118dd06 4021#endif /* HAVE_X11 */
dc6f92b8 4022\f
f451eb13 4023/* Mouse warping, focus shifting, raising and lowering. */
dc6f92b8 4024
f676886a
JB
4025x_set_mouse_position (f, x, y)
4026 struct frame *f;
dc6f92b8
JB
4027 int x, y;
4028{
4029 int pix_x, pix_y;
4030
f676886a 4031 x_raise_frame (f);
dc6f92b8 4032
12ba150f
JB
4033 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2;
4034 pix_y = CHAR_TO_PIXEL_ROW (f, y) + FONT_HEIGHT (f->display.x->font) / 2;
f451eb13
JB
4035
4036 if (pix_x < 0) pix_x = 0;
4037 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
4038
4039 if (pix_y < 0) pix_y = 0;
4040 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
4041
4042 BLOCK_INPUT;
dc6f92b8 4043
c118dd06 4044 XWarpMousePointer (FRAME_X_WINDOW (f), pix_x, pix_y);
dc6f92b8
JB
4045 UNBLOCK_INPUT;
4046}
4047
4048#ifdef HAVE_X11
f676886a
JB
4049x_focus_on_frame (f)
4050 struct frame *f;
dc6f92b8 4051{
f676886a 4052 x_raise_frame (f);
6d4238f3
JB
4053#if 0
4054 /* I don't think that the ICCCM allows programs to do things like this
4055 without the interaction of the window manager. Whatever you end up
f676886a 4056 doing with this code, do it to x_unfocus_frame too. */
c118dd06 4057 XSetInputFocus (x_current_display, FRAME_X_WINDOW (f),
dc6f92b8 4058 RevertToPointerRoot, CurrentTime);
c118dd06 4059#endif /* ! 0 */
dc6f92b8
JB
4060}
4061
f676886a
JB
4062x_unfocus_frame (f)
4063 struct frame *f;
dc6f92b8 4064{
6d4238f3 4065#if 0
f676886a
JB
4066 /* Look at the remarks in x_focus_on_frame. */
4067 if (x_focus_frame == f)
dc6f92b8
JB
4068 XSetInputFocus (x_current_display, PointerRoot,
4069 RevertToPointerRoot, CurrentTime);
c118dd06 4070#endif /* ! 0 */
dc6f92b8
JB
4071}
4072
c118dd06 4073#endif /* ! defined (HAVE_X11) */
dc6f92b8 4074
f676886a 4075/* Raise frame F. */
dc6f92b8 4076
f676886a
JB
4077x_raise_frame (f)
4078 struct frame *f;
dc6f92b8 4079{
3a88c238 4080 if (f->async_visible)
dc6f92b8
JB
4081 {
4082 BLOCK_INPUT;
c118dd06 4083 XRaiseWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8
JB
4084 XFlushQueue ();
4085 UNBLOCK_INPUT;
4086 }
4087}
4088
f676886a 4089/* Lower frame F. */
dc6f92b8 4090
f676886a
JB
4091x_lower_frame (f)
4092 struct frame *f;
dc6f92b8 4093{
3a88c238 4094 if (f->async_visible)
dc6f92b8
JB
4095 {
4096 BLOCK_INPUT;
c118dd06 4097 XLowerWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8
JB
4098 XFlushQueue ();
4099 UNBLOCK_INPUT;
4100 }
4101}
4102
dbc4e1c1
JB
4103static void
4104XTframe_raise_lower (f, raise)
4105 FRAME_PTR f;
4106 int raise;
4107{
4108 if (raise)
4109 x_raise_frame (f);
4110 else
4111 x_lower_frame (f);
4112}
4113
4114
dc6f92b8
JB
4115/* Change from withdrawn state to mapped state. */
4116
f676886a
JB
4117x_make_frame_visible (f)
4118 struct frame *f;
dc6f92b8
JB
4119{
4120 int mask;
4121
dc6f92b8 4122 BLOCK_INPUT;
dc6f92b8 4123
f676886a 4124 if (! FRAME_VISIBLE_P (f))
90e65f07
JB
4125 {
4126#ifdef HAVE_X11
4127 if (! EQ (Vx_no_window_manager, Qt))
f676886a 4128 x_wm_set_window_state (f, NormalState);
dc6f92b8 4129
c118dd06 4130 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
ab648270 4131 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
c118dd06
JB
4132 XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
4133#else /* ! defined (HAVE_X11) */
4134 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
f676886a
JB
4135 if (f->display.x->icon_desc != 0)
4136 XUnmapWindow (f->display.x->icon_desc);
dc6f92b8 4137
90e65f07 4138 /* Handled by the MapNotify event for X11 */
3a88c238
JB
4139 f->async_visible = 1;
4140 f->async_iconified = 0;
dc6f92b8 4141
f676886a 4142 /* NOTE: this may cause problems for the first frame. */
90e65f07 4143 XTcursor_to (0, 0);
c118dd06 4144#endif /* ! defined (HAVE_X11) */
90e65f07 4145 }
dc6f92b8 4146
dc6f92b8 4147 XFlushQueue ();
90e65f07 4148
dc6f92b8
JB
4149 UNBLOCK_INPUT;
4150}
4151
4152/* Change from mapped state to withdrawn state. */
4153
f676886a
JB
4154x_make_frame_invisible (f)
4155 struct frame *f;
dc6f92b8
JB
4156{
4157 int mask;
4158
3a88c238 4159 if (! f->async_visible)
dc6f92b8
JB
4160 return;
4161
4162 BLOCK_INPUT;
c118dd06
JB
4163
4164#ifdef HAVE_X11R4
4165
4166 if (! XWithdrawWindow (x_current_display, FRAME_X_WINDOW (f),
4167 DefaultScreen (x_current_display)))
4168 {
4169 UNBLOCK_INPUT_RESIGNAL;
4170 error ("can't notify window manager of window withdrawl");
4171 }
4172
4173#else /* ! defined (HAVE_X11R4) */
dc6f92b8 4174#ifdef HAVE_X11
16bd92ea 4175
c118dd06 4176 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
4177 if (! EQ (Vx_no_window_manager, Qt))
4178 {
16bd92ea 4179 XEvent unmap;
dc6f92b8 4180
16bd92ea 4181 unmap.xunmap.type = UnmapNotify;
c118dd06 4182 unmap.xunmap.window = FRAME_X_WINDOW (f);
16bd92ea
JB
4183 unmap.xunmap.event = DefaultRootWindow (x_current_display);
4184 unmap.xunmap.from_configure = False;
4185 if (! XSendEvent (x_current_display,
4186 DefaultRootWindow (x_current_display),
4187 False,
4188 SubstructureRedirectMask|SubstructureNotifyMask,
4189 &unmap))
4190 {
4191 UNBLOCK_INPUT_RESIGNAL;
4192 error ("can't notify window manager of withdrawal");
4193 }
dc6f92b8
JB
4194 }
4195
16bd92ea 4196 /* Unmap the window ourselves. Cheeky! */
c118dd06
JB
4197 XUnmapWindow (x_current_display, FRAME_X_WINDOW (f));
4198
4199#else /* ! defined (HAVE_X11) */
dc6f92b8 4200
c118dd06 4201 XUnmapWindow (FRAME_X_WINDOW (f));
3a88c238 4202 f->async_visible = 0; /* Handled by the UnMap event for X11 */
f676886a 4203 if (f->display.x->icon_desc != 0)
c118dd06
JB
4204 XUnmapWindow (f->display.x->icon_desc);
4205
4206#endif /* ! defined (HAVE_X11) */
4207#endif /* ! defined (HAVE_X11R4) */
dc6f92b8
JB
4208
4209 XFlushQueue ();
4210 UNBLOCK_INPUT;
4211}
4212
dc6f92b8
JB
4213/* Change window state from mapped to iconified. */
4214
f676886a
JB
4215x_iconify_frame (f)
4216 struct frame *f;
dc6f92b8
JB
4217{
4218 int mask;
4219
3a88c238 4220 if (f->async_iconified)
dc6f92b8
JB
4221 return;
4222
4223 BLOCK_INPUT;
4224
4225#ifdef HAVE_X11
16bd92ea
JB
4226 /* Since we don't know which revision of X we're running, we'll use both
4227 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
4228
4229 /* X11R4: send a ClientMessage to the window manager using the
4230 WM_CHANGE_STATE type. */
4231 {
4232 XEvent message;
4233
c118dd06 4234 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea
JB
4235 message.xclient.type = ClientMessage;
4236 message.xclient.message_type = Xatom_wm_change_state;
4237 message.xclient.format = 32;
4238 message.xclient.data.l[0] = IconicState;
4239
4240 if (! XSendEvent (x_current_display,
4241 DefaultRootWindow (x_current_display),
4242 False,
4243 SubstructureRedirectMask | SubstructureNotifyMask,
4244 &message))
dc6f92b8
JB
4245 {
4246 UNBLOCK_INPUT_RESIGNAL;
4247 error ("Can't notify window manager of iconification.");
4248 }
16bd92ea 4249 }
dc6f92b8 4250
16bd92ea
JB
4251 /* X11R3: set the initial_state field of the window manager hints to
4252 IconicState. */
4253 x_wm_set_window_state (f, IconicState);
dc6f92b8 4254
3a88c238 4255 f->async_iconified = 1;
c118dd06
JB
4256#else /* ! defined (HAVE_X11) */
4257 XUnmapWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8 4258
3a88c238 4259 f->async_visible = 0; /* Handled in the UnMap event for X11. */
f676886a 4260 if (f->display.x->icon_desc != 0)
dc6f92b8 4261 {
f676886a
JB
4262 XMapWindow (XDISPLAY f->display.x->icon_desc);
4263 refreshicon (f);
dc6f92b8 4264 }
c118dd06 4265#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4266
4267 XFlushQueue ();
4268 UNBLOCK_INPUT;
4269}
4270
c0ff3fab 4271/* Destroy the X window of frame F. */
dc6f92b8 4272
c0ff3fab 4273x_destroy_window (f)
f676886a 4274 struct frame *f;
dc6f92b8 4275{
dc6f92b8 4276 BLOCK_INPUT;
c0ff3fab
JB
4277
4278 if (f->display.x->icon_desc != 0)
4279 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
4280 XDestroyWindow (XDISPLAY f->display.x->window_desc);
dc6f92b8 4281 XFlushQueue ();
dc6f92b8 4282
9ac0d9e0 4283 xfree (f->display.x);
c0ff3fab 4284 f->display.x = 0;
f676886a
JB
4285 if (f == x_focus_frame)
4286 x_focus_frame = 0;
4287 if (f == x_highlight_frame)
4288 x_highlight_frame = 0;
c0ff3fab
JB
4289
4290 UNBLOCK_INPUT;
dc6f92b8
JB
4291}
4292\f
f451eb13
JB
4293/* Manage event queues for X10. */
4294
dc6f92b8
JB
4295#ifndef HAVE_X11
4296
4297/* Manage event queues.
4298
4299 This code is only used by the X10 support.
4300
4301 We cannot leave events in the X queue and get them when we are ready
4302 because X does not provide a subroutine to get only a certain kind
4303 of event but not block if there are no queued events of that kind.
4304
4305 Therefore, we must examine events as they come in and copy events
4306 of certain kinds into our private queues.
4307
4308 All ExposeRegion events are put in x_expose_queue.
4309 All ButtonPressed and ButtonReleased events are put in x_mouse_queue. */
4310
4311
4312/* Write the event *P_XREP into the event queue *QUEUE.
4313 If the queue is full, do nothing, but return nonzero. */
4314
4315int
4316enqueue_event (p_xrep, queue)
4317 register XEvent *p_xrep;
4318 register struct event_queue *queue;
4319{
4320 int newindex = queue->windex + 1;
4321 if (newindex == EVENT_BUFFER_SIZE)
4322 newindex = 0;
4323 if (newindex == queue->rindex)
4324 return -1;
4325 queue->xrep[queue->windex] = *p_xrep;
4326 queue->windex = newindex;
4327 return 0;
4328}
4329
4330/* Fetch the next event from queue *QUEUE and store it in *P_XREP.
4331 If *QUEUE is empty, do nothing and return 0. */
4332
4333int
4334dequeue_event (p_xrep, queue)
4335 register XEvent *p_xrep;
4336 register struct event_queue *queue;
4337{
4338 if (queue->windex == queue->rindex)
4339 return 0;
4340 *p_xrep = queue->xrep[queue->rindex++];
4341 if (queue->rindex == EVENT_BUFFER_SIZE)
4342 queue->rindex = 0;
4343 return 1;
4344}
4345
4346/* Return the number of events buffered in *QUEUE. */
4347
4348int
4349queue_event_count (queue)
4350 register struct event_queue *queue;
4351{
4352 int tem = queue->windex - queue->rindex;
4353 if (tem >= 0)
4354 return tem;
4355 return EVENT_BUFFER_SIZE + tem;
4356}
4357
4358/* Return nonzero if mouse input is pending. */
4359
4360int
4361mouse_event_pending_p ()
4362{
4363 return queue_event_count (&x_mouse_queue);
4364}
c118dd06 4365#endif /* HAVE_X11 */
dc6f92b8 4366\f
f451eb13
JB
4367/* Setting window manager hints. */
4368
dc6f92b8
JB
4369#ifdef HAVE_X11
4370
f676886a
JB
4371x_wm_set_size_hint (f, prompting)
4372 struct frame *f;
dc6f92b8
JB
4373 long prompting;
4374{
4375 XSizeHints size_hints;
c118dd06 4376 Window window = FRAME_X_WINDOW (f);
dc6f92b8
JB
4377
4378 size_hints.flags = PResizeInc | PMinSize | PMaxSize;
4379
f676886a
JB
4380 flexlines = f->height;
4381
4382 size_hints.x = f->display.x->left_pos;
4383 size_hints.y = f->display.x->top_pos;
4384 size_hints.height = PIXEL_HEIGHT (f);
4385 size_hints.width = PIXEL_WIDTH (f);
4386 size_hints.width_inc = FONT_WIDTH (f->display.x->font);
4387 size_hints.height_inc = FONT_HEIGHT (f->display.x->font);
12ba150f
JB
4388 size_hints.max_width = x_screen_width - CHAR_TO_PIXEL_WIDTH (f, 0);
4389 size_hints.max_height = x_screen_height - CHAR_TO_PIXEL_HEIGHT (f, 0);
f451eb13 4390
b1c884c3 4391 {
b0342f17
JB
4392 int base_width, base_height;
4393
f451eb13
JB
4394 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
4395 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17
JB
4396
4397 {
4398 int min_rows = 0, min_cols = 0;
4399 check_frame_size (f, &min_rows, &min_cols);
4400
4401 /* The window manager uses the base width hints to calculate the
4402 current number of rows and columns in the frame while
4403 resizing; min_width and min_height aren't useful for this
4404 purpose, since they might not give the dimensions for a
4405 zero-row, zero-column frame.
4406
4407 We use the base_width and base_height members if we have
4408 them; otherwise, we set the min_width and min_height members
4409 to the size for a zero x zero frame. */
4410
4411#ifdef HAVE_X11R4
4412 size_hints.flags |= PBaseSize;
4413 size_hints.base_width = base_width;
4414 size_hints.base_height = base_height;
4415 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
4416 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
4417#else
4418 size_hints.min_width = base_width;
4419 size_hints.min_height = base_height;
4420#endif
4421 }
b1c884c3 4422
b1c884c3 4423 }
dc6f92b8
JB
4424
4425 if (prompting)
4426 size_hints.flags |= prompting;
4427 else
4428 {
4429 XSizeHints hints; /* Sometimes I hate X Windows... */
4430
4431 XGetNormalHints (x_current_display, window, &hints);
4432 if (hints.flags & PSize)
4433 size_hints.flags |= PSize;
4434 if (hints.flags & PPosition)
4435 size_hints.flags |= PPosition;
4436 if (hints.flags & USPosition)
4437 size_hints.flags |= USPosition;
4438 if (hints.flags & USSize)
4439 size_hints.flags |= USSize;
4440 }
16bd92ea 4441
b0342f17
JB
4442#ifdef HAVE_X11R4
4443 XSetWMNormalHints (x_current_display, window, &size_hints);
4444#else
dc6f92b8 4445 XSetNormalHints (x_current_display, window, &size_hints);
b0342f17 4446#endif
dc6f92b8
JB
4447}
4448
4449/* Used for IconicState or NormalState */
f676886a
JB
4450x_wm_set_window_state (f, state)
4451 struct frame *f;
dc6f92b8
JB
4452 int state;
4453{
c118dd06 4454 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4455
16bd92ea
JB
4456 f->display.x->wm_hints.flags |= StateHint;
4457 f->display.x->wm_hints.initial_state = state;
b1c884c3 4458
16bd92ea 4459 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4460}
4461
f676886a
JB
4462x_wm_set_icon_pixmap (f, icon_pixmap)
4463 struct frame *f;
dc6f92b8
JB
4464 Pixmap icon_pixmap;
4465{
c118dd06 4466 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4467
dbc4e1c1
JB
4468 if (icon_pixmap)
4469 {
4470 f->display.x->wm_hints.icon_pixmap = icon_pixmap;
4471 f->display.x->wm_hints.flags |= IconPixmapHint;
4472 }
4473 else
4474 f->display.x->wm_hints.flags &= ~IconPixmapHint;
b1c884c3 4475
16bd92ea 4476 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4477}
4478
f676886a
JB
4479x_wm_set_icon_position (f, icon_x, icon_y)
4480 struct frame *f;
dc6f92b8
JB
4481 int icon_x, icon_y;
4482{
c118dd06 4483 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4484
16bd92ea
JB
4485 f->display.x->wm_hints.flags |= IconPositionHint;
4486 f->display.x->wm_hints.icon_x = icon_x;
4487 f->display.x->wm_hints.icon_y = icon_y;
b1c884c3 4488
16bd92ea 4489 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4490}
4491
4492\f
f451eb13
JB
4493/* Initialization. */
4494
dc6f92b8
JB
4495void
4496x_term_init (display_name)
4497 char *display_name;
4498{
f676886a 4499 Lisp_Object frame;
dc6f92b8
JB
4500 char *defaultvalue;
4501#ifdef F_SETOWN
4502 extern int old_fcntl_owner;
c118dd06 4503#endif /* ! defined (F_SETOWN) */
6d4238f3 4504
f676886a 4505 x_focus_frame = x_highlight_frame = 0;
dc6f92b8
JB
4506
4507 x_current_display = XOpenDisplay (display_name);
4508 if (x_current_display == 0)
4509 fatal ("X server %s not responding; check the DISPLAY environment variable or use \"-d\"\n",
4510 display_name);
4511
4512#ifdef HAVE_X11
4513 {
16bd92ea 4514 int hostname_size = 256;
60fb3ee1
JB
4515
4516 hostname = (char *) xmalloc (hostname_size);
4517
dc6f92b8
JB
4518#if 0
4519 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 4520#endif /* ! 0 */
dc6f92b8 4521
60fb3ee1
JB
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 }
59653951 4538 x_id_name = (char *) xmalloc (XSTRING (Vinvocation_name)->size
60fb3ee1
JB
4539 + strlen (hostname)
4540 + 2);
59653951 4541 sprintf (x_id_name, "%s@%s", XSTRING (Vinvocation_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
a4fc7360
JB
4557 if (ConnectionNumber (x_current_display) != 0)
4558 {
4559 dup2 (ConnectionNumber (x_current_display), 0);
6d4238f3
JB
4560
4561#ifndef SYSV_STREAMS
a4fc7360
JB
4562 /* Streams somehow keeps track of which descriptor number
4563 is being used to talk to X. So it is not safe to substitute
4564 descriptor 0. But it is safe to make descriptor 0 a copy of it. */
4565 close (ConnectionNumber (x_current_display));
4566 ConnectionNumber (x_current_display) = 0; /* Looks a little strange?
6d4238f3
JB
4567 * check the def of the macro;
4568 * it is a genuine lvalue */
c118dd06 4569#endif /* SYSV_STREAMS */
a4fc7360 4570 }
6d4238f3 4571
c118dd06 4572#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4573
4574#ifdef F_SETOWN
4575 old_fcntl_owner = fcntl (0, F_GETOWN, 0);
4576#ifdef F_SETOWN_SOCK_NEG
4577 fcntl (0, F_SETOWN, -getpid ()); /* stdin is a socket here */
c118dd06 4578#else /* ! defined (F_SETOWN_SOCK_NEG) */
dc6f92b8 4579 fcntl (0, F_SETOWN, getpid ());
c118dd06
JB
4580#endif /* ! defined (F_SETOWN_SOCK_NEG) */
4581#endif /* ! defined (F_SETOWN) */
dc6f92b8
JB
4582
4583#ifdef SIGIO
4584 init_sigio ();
c118dd06 4585#endif /* ! defined (SIGIO) */
dc6f92b8
JB
4586
4587 /* Must use interrupt input because we cannot otherwise
4588 arrange for C-g to be noticed immediately.
4589 We cannot connect it to SIGINT. */
4590 Fset_input_mode (Qt, Qnil, Qt, Qnil);
4591
4592 expose_all_windows = 0;
4593
f676886a 4594 clear_frame_hook = XTclear_frame;
dc6f92b8
JB
4595 clear_end_of_line_hook = XTclear_end_of_line;
4596 ins_del_lines_hook = XTins_del_lines;
4597 change_line_highlight_hook = XTchange_line_highlight;
4598 insert_glyphs_hook = XTinsert_glyphs;
4599 write_glyphs_hook = XTwrite_glyphs;
4600 delete_glyphs_hook = XTdelete_glyphs;
4601 ring_bell_hook = XTring_bell;
4602 reset_terminal_modes_hook = XTreset_terminal_modes;
4603 set_terminal_modes_hook = XTset_terminal_modes;
4604 update_begin_hook = XTupdate_begin;
4605 update_end_hook = XTupdate_end;
4606 set_terminal_window_hook = XTset_terminal_window;
4607 read_socket_hook = XTread_socket;
4608 cursor_to_hook = XTcursor_to;
4609 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 4610 mouse_position_hook = XTmouse_position;
f451eb13 4611 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 4612 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
4613 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
4614 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
4615 redeem_scroll_bar_hook = XTredeem_scroll_bar;
4616 judge_scroll_bars_hook = XTjudge_scroll_bars;
dc6f92b8 4617
f676886a 4618 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
4619 char_ins_del_ok = 0; /* just as fast to write the line */
4620 line_ins_del_ok = 1; /* we'll just blt 'em */
4621 fast_clear_end_of_line = 1; /* X does this well */
f676886a 4622 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
4623 off the bottom */
4624 baud_rate = 19200;
4625
c118dd06
JB
4626 /* Note that there is no real way portable across R3/R4 to get the
4627 original error handler. */
4628 XHandleError (x_error_quitter);
8922af5f 4629 XHandleIOError (x_io_error_quitter);
dc6f92b8
JB
4630
4631 /* Disable Window Change signals; they are handled by X events. */
4632#ifdef SIGWINCH
4633 signal (SIGWINCH, SIG_DFL);
c118dd06 4634#endif /* ! defined (SIGWINCH) */
dc6f92b8 4635
c118dd06 4636 signal (SIGPIPE, x_connection_closed);
dc6f92b8 4637}
55123275
JB
4638
4639void
4640syms_of_xterm ()
4641{
ab648270 4642 staticpro (&last_mouse_scroll_bar);
55123275 4643}
c118dd06
JB
4644#endif /* ! defined (HAVE_X11) */
4645#endif /* ! defined (HAVE_X_WINDOWS) */