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