*** empty log message ***
[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
af395ec1
RS
3093 if (! event.xconfigure.send_event
3094 /* Sometimes we get root-relative coordinates
3095 even tho send_event is 0.
3096 This is not a perfectly reliable way of distinguishing,
3097 but it does the right thing except in a case
3098 where it doesn't hurt much to be wrong. */
3099 && event.xconfigure.x < 20)
3100 {
3101 Window win, child;
3102 int win_x, win_y;
3103
3104 XTranslateCoordinates (x_current_display,
3105
3106 /* From-window, to-window. */
3107 event.xconfigure.window, ROOT_WINDOW,
3108
3109 /* From-position, to-position. */
3110 event.xconfigure.x,
3111 event.xconfigure.y,
3112 &win_x, &win_y,
3113
3114 /* Child of win. */
3115 &child);
3116 event.xconfigure.x = win_x;
3117 event.xconfigure.y = win_y;
3118 }
3119
dbc4e1c1
JB
3120 f->display.x->pixel_width = event.xconfigure.width;
3121 f->display.x->pixel_height = event.xconfigure.height;
3122 f->display.x->left_pos = event.xconfigure.x;
3123 f->display.x->top_pos = event.xconfigure.y;
3124 }
3125 break;
dc6f92b8
JB
3126
3127 case ButtonPress:
3128 case ButtonRelease:
3129 {
3130 /* If we decide we want to generate an event to be seen
3131 by the rest of Emacs, we put it here. */
3132 struct input_event emacs_event;
3133 emacs_event.kind = no_event;
3134
f676886a
JB
3135 f = x_window_to_frame (event.xbutton.window);
3136 if (f)
f451eb13
JB
3137 {
3138 if (!x_focus_frame || (f == x_focus_frame))
3139 construct_mouse_click (&emacs_event,
b10fd412 3140 &event, f);
f451eb13 3141 }
dc6f92b8 3142 else
f451eb13 3143 {
ab648270
JB
3144 struct scroll_bar *bar =
3145 x_window_to_scroll_bar (event.xbutton.window);
f451eb13
JB
3146
3147 if (bar)
ab648270 3148 x_scroll_bar_handle_click (bar, &event, &emacs_event);
f451eb13 3149 }
dc6f92b8
JB
3150
3151 if (numchars >= 1 && emacs_event.kind != no_event)
3152 {
3153 bcopy (&emacs_event, bufp, sizeof (struct input_event));
3154 bufp++;
3155 count++;
3156 numchars--;
3157 }
3158 }
3159 break;
3160
c118dd06 3161#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3162 case ButtonPressed:
3163 case ButtonReleased:
f676886a
JB
3164 f = x_window_to_frame (event.window);
3165 if (f)
dc6f92b8 3166 {
f676886a 3167 if (event.window == f->display.x->icon_desc)
dc6f92b8 3168 {
f676886a 3169 x_make_frame_visible (f);
dc6f92b8
JB
3170
3171 if (warp_mouse_on_deiconify)
c118dd06 3172 XWarpMouse (FRAME_X_WINDOW (f), 10, 10);
dc6f92b8
JB
3173 break;
3174 }
c118dd06 3175 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8 3176 {
f676886a
JB
3177 if (f->auto_raise)
3178 x_raise_frame (f);
dc6f92b8
JB
3179 }
3180 }
3181 enqueue_event (&event, &x_mouse_queue);
3182 if (numchars >= 2)
3183 {
3184 bufp->kind = ascii_keystroke;
3185 bufp->code = (char) 'X' & 037; /* C-x */
12ba150f 3186 XSET (bufp->frame_or_window, Lisp_Frame, f);
90e65f07 3187 XSET (bufp->time, Lisp_Int, event.xkey.time);
dc6f92b8
JB
3188 bufp++;
3189
3190 bufp->kind = ascii_keystroke;
3191 bufp->code = (char) 0; /* C-@ */
12ba150f 3192 XSET (bufp->frame_or_window, Lisp_Frame, f);
90e65f07 3193 XSET (bufp->time, Lisp_Int, event.xkey.time);
dc6f92b8
JB
3194 bufp++;
3195
3196 count += 2;
3197 numchars -= 2;
3198 }
3199 break;
c118dd06 3200#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3201
3202#ifdef HAVE_X11
3203
3204 case CirculateNotify:
3205 break;
3206 case CirculateRequest:
3207 break;
3208
c118dd06 3209#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3210
3211 case MappingNotify:
11edeb03
JB
3212 /* Someone has changed the keyboard mapping - update the
3213 local cache. */
3214 switch (event.xmapping.request)
3215 {
3216 case MappingModifier:
3217 x_find_modifier_meanings ();
3218 /* This is meant to fall through. */
3219 case MappingKeyboard:
3220 XRefreshKeyboardMapping (&event.xmapping);
3221 }
dc6f92b8
JB
3222 break;
3223
3224 default:
3225 break;
3226 }
3227 }
3228
3229#if 0
3230#ifdef HAVE_SELECT
3231 if (expected && ! event_found)
3232 {
3233 /* AOJ 880406: if select returns true but XPending doesn't, it means that
3234 there is an EOF condition; in other words, that X has died.
3235 Act as if there had been a hangup. */
3236
3237 int fd = ConnectionNumber (x_current_display);
3238 int mask = 1 << fd;
3239
3240 if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0,
3a2712f9 3241 (EMACS_TIME) 0)
dc6f92b8
JB
3242 && !XStuffPending ())
3243 kill (getpid (), SIGHUP);
3244 }
c118dd06
JB
3245#endif /* ! defined (HAVE_SELECT) */
3246#endif /* ! 0 */
dc6f92b8 3247
f451eb13 3248#ifndef HAVE_X11
f676886a 3249 if (updating_frame == 0)
dc6f92b8 3250 x_do_pending_expose ();
f451eb13 3251#endif
dc6f92b8
JB
3252
3253 UNBLOCK_INPUT;
3254 return count;
3255}
3256
3257#ifndef HAVE_X11
3258/* Read and process only Expose events
3259 until we get an ExposeCopy event; then return.
3260 This is used in insert/delete line.
3261 We assume input is already blocked. */
3262
3263static void
3264x_read_exposes ()
3265{
f676886a 3266 struct frame *f;
dc6f92b8
JB
3267 XKeyPressedEvent event;
3268
3269 while (1)
3270 {
3271 /* while there are more events*/
3272 XMaskEvent (ExposeWindow | ExposeRegion | ExposeCopy, &event);
3273 switch (event.type)
3274 {
3275 case ExposeWindow:
3276 if (event.subwindow != 0)
3277 break; /* duplicate event */
f676886a
JB
3278 f = x_window_to_frame (event.window);
3279 if (event.window == f->display.x->icon_desc)
dc6f92b8 3280 {
f676886a 3281 refreshicon (f);
dc6f92b8
JB
3282 break;
3283 }
c118dd06 3284 if (event.window == FRAME_X_WINDOW (f))
dc6f92b8
JB
3285 {
3286 expose_all_windows = 1;
f676886a 3287 f->display.x->needs_exposure = 1;
dc6f92b8
JB
3288 break;
3289 }
3290 break;
3291
3292 case ExposeRegion:
3293 if (event.subwindow != 0)
3294 break; /* duplicate event */
f676886a
JB
3295 f = x_window_to_frame (event.window);
3296 if (event.window == f->display.x->icon_desc)
dc6f92b8 3297 {
f676886a 3298 refreshicon (f);
dc6f92b8
JB
3299 break;
3300 }
3301 /* If window already needs full redraw, ignore this rectangle. */
f676886a 3302 if (expose_all_windows && f->display.x->needs_exposure)
dc6f92b8
JB
3303 break;
3304 /* Put the event on the queue of rectangles to redraw. */
3305 if (enqueue_event (&event, &x_expose_queue))
3306 /* If it is full, we can't record the rectangle,
3307 so redraw this entire window. */
3308 {
3309 /* Say must check all windows' needs_exposure flags. */
3310 expose_all_windows = 1;
f676886a 3311 f->display.x->needs_exposure = 1;
dc6f92b8
JB
3312 }
3313 break;
3314
3315 case ExposeCopy:
3316 return;
3317 }
3318 }
3319}
3320#endif /* HAVE_X11 */
3321
dc6f92b8 3322\f
f451eb13
JB
3323/* Drawing the cursor. */
3324
3325
dc6f92b8
JB
3326/* Draw a hollow box cursor. Don't change the inside of the box. */
3327
3328static void
f676886a
JB
3329x_draw_box (f)
3330 struct frame *f;
dc6f92b8 3331{
12ba150f
JB
3332 int left = CHAR_TO_PIXEL_COL (f, f->cursor_x);
3333 int top = CHAR_TO_PIXEL_ROW (f, f->cursor_y);
f676886a
JB
3334 int width = FONT_WIDTH (f->display.x->font);
3335 int height = FONT_HEIGHT (f->display.x->font);
dc6f92b8
JB
3336
3337#ifdef HAVE_X11
c118dd06 3338 XDrawRectangle (x_current_display, FRAME_X_WINDOW (f),
f676886a 3339 f->display.x->cursor_gc,
dc6f92b8 3340 left, top, width - 1, height - 1);
c118dd06
JB
3341#else /* ! defined (HAVE_X11) */
3342 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3343 left, top, width, 1,
f676886a 3344 f->display.x->cursor_pixel);
dc6f92b8 3345
c118dd06 3346 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3347 left, top, 1, height,
f676886a 3348 f->display.x->cursor_pixel);
dc6f92b8 3349
c118dd06 3350 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3351 left+width-1, top, 1, height,
f676886a 3352 f->display.x->cursor_pixel);
dc6f92b8 3353
c118dd06 3354 XPixSet (FRAME_X_WINDOW (f),
dc6f92b8 3355 left, top+height-1, width, 1,
f676886a 3356 f->display.x->cursor_pixel);
c118dd06 3357#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3358}
3359
f676886a 3360/* Clear the cursor of frame F to background color,
dc6f92b8
JB
3361 and mark the cursor as not shown.
3362 This is used when the text where the cursor is
3363 is about to be rewritten. */
3364
3365static void
f676886a
JB
3366clear_cursor (f)
3367 struct frame *f;
dc6f92b8
JB
3368{
3369 int mask;
3370
f451eb13 3371 if (! FRAME_VISIBLE_P (f)
f676886a 3372 || f->phys_cursor_x < 0)
dc6f92b8
JB
3373 return;
3374
3375#ifdef HAVE_X11
f676886a 3376 x_display_cursor (f, 0);
c118dd06
JB
3377#else /* ! defined (HAVE_X11) */
3378 XPixSet (FRAME_X_WINDOW (f),
12ba150f
JB
3379 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
3380 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
f676886a
JB
3381 FONT_WIDTH (f->display.x->font), FONT_HEIGHT (f->display.x->font),
3382 f->display.x->background_pixel);
c118dd06 3383#endif /* ! defined (HAVE_X11) */
f676886a 3384 f->phys_cursor_x = -1;
dc6f92b8
JB
3385}
3386
f676886a 3387/* Redraw the glyph at ROW, COLUMN on frame F, in the style
90e65f07
JB
3388 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
3389 glyph drawn. */
dc6f92b8
JB
3390
3391static void
f676886a
JB
3392x_draw_single_glyph (f, row, column, glyph, highlight)
3393 struct frame *f;
dc6f92b8 3394 int row, column;
90e65f07 3395 GLYPH glyph;
dc6f92b8
JB
3396 int highlight;
3397{
f676886a 3398 dumpglyphs (f,
12ba150f
JB
3399 CHAR_TO_PIXEL_COL (f, column),
3400 CHAR_TO_PIXEL_ROW (f, row),
07e34cb0 3401 &glyph, 1, highlight);
dc6f92b8
JB
3402}
3403
dc6f92b8 3404static void
dbc4e1c1 3405x_display_bar_cursor (f, on)
f676886a 3406 struct frame *f;
dc6f92b8
JB
3407 int on;
3408{
f676886a 3409 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
90e65f07 3410
49d838ea
JB
3411 /* This is pointless on invisible frames, and dangerous on garbaged
3412 frames; in the latter case, the frame may be in the midst of
3413 changing its size, and curs_x and curs_y may be off the frame. */
3414 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dbc4e1c1
JB
3415 return;
3416
3417 if (! on && f->phys_cursor_x < 0)
3418 return;
3419
f676886a 3420 /* If we're not updating, then we want to use the current frame's
1113d9db 3421 cursor position, not our local idea of where the cursor ought to be. */
f676886a 3422 if (f != updating_frame)
1113d9db 3423 {
f676886a
JB
3424 curs_x = FRAME_CURSOR_X (f);
3425 curs_y = FRAME_CURSOR_Y (f);
1113d9db
JB
3426 }
3427
dbc4e1c1
JB
3428 /* If there is anything wrong with the current cursor state, remove it. */
3429 if (f->phys_cursor_x >= 0
3430 && (!on
3431 || f->phys_cursor_x != curs_x
3432 || f->phys_cursor_y != curs_y
3433 || f->display.x->current_cursor != bar_cursor))
3434 {
3435 /* Erase the cursor by redrawing the character underneath it. */
3436 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
3437 f->phys_cursor_glyph,
3438 current_glyphs->highlight[f->phys_cursor_y]);
3439 f->phys_cursor_x = -1;
3440 }
3441
3442 /* If we now need a cursor in the new place or in the new form, do it so. */
3443 if (on
3444 && (f->phys_cursor_x < 0
3445 || (f->display.x->current_cursor != bar_cursor)))
3446 {
3447 f->phys_cursor_glyph
3448 = ((current_glyphs->enable[curs_y]
3449 && curs_x < current_glyphs->used[curs_y])
3450 ? current_glyphs->glyphs[curs_y][curs_x]
3451 : SPACEGLYPH);
3452 XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
3453 f->display.x->cursor_gc,
3454 CHAR_TO_PIXEL_COL (f, curs_x),
3455 CHAR_TO_PIXEL_ROW (f, curs_y),
3456 1, FONT_HEIGHT (f->display.x->font));
3457
3458 f->phys_cursor_x = curs_x;
3459 f->phys_cursor_y = curs_y;
3460
3461 f->display.x->current_cursor = bar_cursor;
3462 }
3463
3464 if (updating_frame != f)
3465 XFlushQueue ();
3466}
3467
3468
3469/* Turn the displayed cursor of frame F on or off according to ON.
3470 If ON is nonzero, where to put the cursor is specified
3471 by F->cursor_x and F->cursor_y. */
3472
3473static void
3474x_display_box_cursor (f, on)
3475 struct frame *f;
3476 int on;
3477{
3478 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
3479
49d838ea
JB
3480 /* This is pointless on invisible frames, and dangerous on garbaged
3481 frames; in the latter case, the frame may be in the midst of
3482 changing its size, and curs_x and curs_y may be off the frame. */
3483 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dc6f92b8
JB
3484 return;
3485
3486 /* If cursor is off and we want it off, return quickly. */
f676886a 3487 if (!on && f->phys_cursor_x < 0)
dc6f92b8
JB
3488 return;
3489
dbc4e1c1
JB
3490 /* If we're not updating, then we want to use the current frame's
3491 cursor position, not our local idea of where the cursor ought to be. */
3492 if (f != updating_frame)
3493 {
3494 curs_x = FRAME_CURSOR_X (f);
3495 curs_y = FRAME_CURSOR_Y (f);
3496 }
3497
dc6f92b8
JB
3498 /* If cursor is currently being shown and we don't want it to be
3499 or it is in the wrong place,
3500 or we want a hollow box and it's not so, (pout!)
3501 erase it. */
f676886a 3502 if (f->phys_cursor_x >= 0
dc6f92b8 3503 && (!on
f676886a
JB
3504 || f->phys_cursor_x != curs_x
3505 || f->phys_cursor_y != curs_y
dbc4e1c1 3506 || (f->display.x->current_cursor != hollow_box_cursor
f676886a 3507 && (f != x_highlight_frame))))
dc6f92b8
JB
3508 {
3509 /* Erase the cursor by redrawing the character underneath it. */
f676886a
JB
3510 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
3511 f->phys_cursor_glyph,
3512 current_glyphs->highlight[f->phys_cursor_y]);
3513 f->phys_cursor_x = -1;
dc6f92b8
JB
3514 }
3515
3516 /* If we want to show a cursor,
3517 or we want a box cursor and it's not so,
3518 write it in the right place. */
3519 if (on
f676886a 3520 && (f->phys_cursor_x < 0
dbc4e1c1 3521 || (f->display.x->current_cursor != filled_box_cursor
f676886a 3522 && f == x_highlight_frame)))
dc6f92b8 3523 {
f676886a 3524 f->phys_cursor_glyph
1113d9db
JB
3525 = ((current_glyphs->enable[curs_y]
3526 && curs_x < current_glyphs->used[curs_y])
3527 ? current_glyphs->glyphs[curs_y][curs_x]
90e65f07 3528 : SPACEGLYPH);
f676886a 3529 if (f != x_highlight_frame)
dc6f92b8 3530 {
f676886a 3531 x_draw_box (f);
dbc4e1c1 3532 f->display.x->current_cursor = hollow_box_cursor;
dc6f92b8
JB
3533 }
3534 else
3535 {
f676886a
JB
3536 x_draw_single_glyph (f, curs_y, curs_x,
3537 f->phys_cursor_glyph, 2);
dbc4e1c1 3538 f->display.x->current_cursor = filled_box_cursor;
dc6f92b8
JB
3539 }
3540
f676886a
JB
3541 f->phys_cursor_x = curs_x;
3542 f->phys_cursor_y = curs_y;
dc6f92b8
JB
3543 }
3544
f676886a 3545 if (updating_frame != f)
dc6f92b8
JB
3546 XFlushQueue ();
3547}
3548
f676886a
JB
3549x_display_cursor (f, on)
3550 struct frame *f;
dc6f92b8
JB
3551 int on;
3552{
dbc4e1c1 3553 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
f676886a 3554 x_display_box_cursor (f, on);
dbc4e1c1 3555 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
f676886a 3556 x_display_bar_cursor (f, on);
dbc4e1c1
JB
3557 else
3558 /* Those are the only two we have implemented! */
3559 abort ();
dc6f92b8
JB
3560}
3561\f
3562/* Icons. */
3563
f676886a 3564/* Refresh bitmap kitchen sink icon for frame F
dc6f92b8
JB
3565 when we get an expose event for it. */
3566
f676886a
JB
3567refreshicon (f)
3568 struct frame *f;
dc6f92b8
JB
3569{
3570#ifdef HAVE_X11
3571 /* Normally, the window manager handles this function. */
c118dd06 3572#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
3573 int mask;
3574
f676886a
JB
3575 if (f->display.x->icon_bitmap_flag)
3576 XBitmapBitsPut (f->display.x->icon_desc, 0, 0, sink_width, sink_height,
dc6f92b8
JB
3577 sink_bits, BlackPixel, WHITE_PIX_DEFAULT,
3578 icon_bitmap, GXcopy, AllPlanes);
3579 else
3580 {
f676886a 3581 extern struct frame *selected_frame;
dc6f92b8
JB
3582 struct Lisp_String *str;
3583 unsigned char *string;
3584
3585 string
f676886a 3586 = XSTRING (XBUFFER (XWINDOW (f->selected_window)->buffer)->name)->data;
dc6f92b8 3587
f676886a 3588 if (f->display.x->icon_label != string)
dc6f92b8 3589 {
f676886a
JB
3590 f->display.x->icon_label = string;
3591 XChangeWindow (f->display.x->icon_desc,
dc6f92b8
JB
3592 XQueryWidth (string, icon_font_info->id) + 10,
3593 icon_font_info->height + 10);
3594 }
3595
f676886a 3596 XText (f->display.x->icon_desc, 5, 5, string,
dc6f92b8
JB
3597 str->size, icon_font_info->id,
3598 BLACK_PIX_DEFAULT, WHITE_PIX_DEFAULT);
3599 }
3600 XFlushQueue ();
c118dd06 3601#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3602}
3603
dbc4e1c1 3604/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
3605
3606int
f676886a
JB
3607x_bitmap_icon (f)
3608 struct frame *f;
dc6f92b8
JB
3609{
3610 int mask;
3611 Window icon_window;
3612
c118dd06 3613 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
3614 return 1;
3615
3616#ifdef HAVE_X11
3617 if (icon_bitmap)
3618 XFreePixmap (x_current_display, icon_bitmap);
3619
3620 icon_bitmap =
c118dd06 3621 XCreateBitmapFromData (x_current_display, FRAME_X_WINDOW (f),
dc6f92b8 3622 gnu_bits, gnu_width, gnu_height);
f676886a
JB
3623 x_wm_set_icon_pixmap (f, icon_bitmap);
3624 f->display.x->icon_bitmap_flag = 1;
c118dd06 3625#else /* ! defined (HAVE_X11) */
f676886a 3626 if (f->display.x->icon_desc)
dc6f92b8 3627 {
c118dd06 3628 XClearIconWindow (FRAME_X_WINDOW (f));
f676886a 3629 XDestroyWindow (f->display.x->icon_desc);
dc6f92b8
JB
3630 }
3631
f676886a 3632 icon_window = XCreateWindow (f->display.x->parent_desc,
dc6f92b8
JB
3633 0, 0, sink_width, sink_height,
3634 2, WhitePixmap, (Pixmap) NULL);
3635
3636 if (icon_window == 0)
3637 return 1;
3638
c118dd06 3639 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
dc6f92b8
JB
3640 XSelectInput (icon_window, ExposeWindow | UnmapWindow);
3641
f676886a
JB
3642 f->display.x->icon_desc = icon_window;
3643 f->display.x->icon_bitmap_flag = 1;
dc6f92b8
JB
3644
3645 if (icon_bitmap == 0)
3646 icon_bitmap
3647 = XStoreBitmap (sink_mask_width, sink_mask_height, sink_mask_bits);
c118dd06 3648#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3649
3650 return 0;
3651}
3652
3653
f676886a 3654/* Make the x-window of frame F use a rectangle with text. */
dc6f92b8
JB
3655
3656int
f676886a
JB
3657x_text_icon (f, icon_name)
3658 struct frame *f;
dc6f92b8
JB
3659 char *icon_name;
3660{
3661#ifndef HAVE_X11
3662 int mask;
3663 int width;
3664 Window icon_window;
3665 char *X_DefaultValue;
3666 Bitmap b1;
3667
dc6f92b8
JB
3668#ifndef WhitePixel
3669#define WhitePixel 1
c118dd06 3670#endif /* WhitePixel */
dc6f92b8
JB
3671
3672#ifndef BlackPixel
3673#define BlackPixel 0
c118dd06
JB
3674#endif /* BlackPixel */
3675#endif /* HAVE_X11 */
dc6f92b8 3676
c118dd06 3677 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
3678 return 1;
3679
dc6f92b8
JB
3680#ifdef HAVE_X11
3681 if (icon_name)
f676886a 3682 f->display.x->icon_label = icon_name;
dc6f92b8 3683 else
f676886a
JB
3684 if (! f->display.x->icon_label)
3685 f->display.x->icon_label = " *emacs* ";
dc6f92b8 3686
dfeccd2d 3687#if 0
c118dd06 3688 XSetIconName (x_current_display, FRAME_X_WINDOW (f),
f676886a 3689 (char *) f->display.x->icon_label);
dfeccd2d 3690#endif
dc6f92b8 3691
f676886a 3692 f->display.x->icon_bitmap_flag = 0;
b1c884c3 3693 x_wm_set_icon_pixmap (f, 0);
c118dd06 3694#else /* ! defined (HAVE_X11) */
dbc4e1c1
JB
3695 if (icon_font_info == 0)
3696 icon_font_info
3697 = XGetFont (XGetDefault (XDISPLAY
59653951 3698 (char *) XSTRING (Vinvocation_name)->data,
dbc4e1c1
JB
3699 "BodyFont"));
3700
f676886a 3701 if (f->display.x->icon_desc)
dc6f92b8 3702 {
c118dd06 3703 XClearIconWindow (XDISPLAY FRAME_X_WINDOW (f));
f676886a 3704 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
dc6f92b8
JB
3705 }
3706
3707 if (icon_name)
f676886a 3708 f->display.x->icon_label = (unsigned char *) icon_name;
dc6f92b8 3709 else
f676886a
JB
3710 if (! f->display.x->icon_label)
3711 f->display.x->icon_label = XSTRING (f->name)->data;
dc6f92b8 3712
f676886a
JB
3713 width = XStringWidth (f->display.x->icon_label, icon_font_info, 0, 0);
3714 icon_window = XCreateWindow (f->display.x->parent_desc,
3715 f->display.x->left_pos,
3716 f->display.x->top_pos,
dc6f92b8
JB
3717 width + 10, icon_font_info->height + 10,
3718 2, BlackPixmap, WhitePixmap);
3719
3720 if (icon_window == 0)
3721 return 1;
3722
c118dd06 3723 XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
dc6f92b8
JB
3724 XSelectInput (icon_window, ExposeWindow | ExposeRegion | UnmapWindow | ButtonPressed);
3725
f676886a
JB
3726 f->display.x->icon_desc = icon_window;
3727 f->display.x->icon_bitmap_flag = 0;
3728 f->display.x->icon_label = 0;
c118dd06 3729#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
3730
3731 return 0;
3732}
3733\f
4746118a
JB
3734/* Handling X errors. */
3735
12ba150f
JB
3736/* Shut down Emacs in an orderly fashion, because of a SIGPIPE on the
3737 X server's connection, or an error reported via the X protocol. */
16bd92ea 3738
4746118a 3739static SIGTYPE
c118dd06 3740x_connection_closed ()
4746118a
JB
3741{
3742 if (_Xdebug)
3743 abort ();
12ba150f
JB
3744
3745 shut_down_emacs (0);
3746
3747 exit (70);
4746118a
JB
3748}
3749
8922af5f
JB
3750/* An X error handler which prints an error message and then kills
3751 Emacs. This is what's normally installed as Xlib's handler for
3752 protocol errors. */
c118dd06
JB
3753static int
3754x_error_quitter (display, error)
3755 Display *display;
3756 XErrorEvent *error;
3757{
3758 char buf[256];
dc6f92b8 3759
c118dd06
JB
3760 /* Note that there is no real way portable across R3/R4 to get the
3761 original error handler. */
dc6f92b8 3762
c118dd06
JB
3763 XGetErrorText (display, error->error_code, buf, sizeof (buf));
3764 fprintf (stderr, "X protocol error: %s on protocol request %d\n",
3765 buf, error->request_code);
dc6f92b8 3766
12ba150f
JB
3767 /* While we're testing Emacs 19, we'll just dump core whenever we
3768 get an X error, so we can figure out why it happened. */
3769 abort ();
3770
c118dd06 3771 x_connection_closed ();
dc6f92b8
JB
3772}
3773
8922af5f
JB
3774/* A handler for X IO errors which prints an error message and then
3775 kills Emacs. This is what is always installed as Xlib's handler
3776 for I/O errors. */
3777static int
3778x_io_error_quitter (display)
3779 Display *display;
3780{
3781 fprintf (stderr, "Connection to X server %s lost.\n",
3782 XDisplayName (DisplayString (display)));
3783
3784 /* While we're testing Emacs 19, we'll just dump core whenever we
3785 get an X error, so we can figure out why it happened. */
3786 abort ();
3787
3788 x_connection_closed ();
3789}
3790
c118dd06
JB
3791/* A buffer for storing X error messages. */
3792static char (*x_caught_error_message)[200];
3793
3794/* An X error handler which stores the error message in
3795 x_caught_error_message. This is what's installed when
3796 x_catch_errors is in effect. */
3797static int
3798x_error_catcher (display, error)
3799 Display *display;
3800 XErrorEvent *error;
3801{
3802 XGetErrorText (display, error->error_code,
3803 *x_caught_error_message, sizeof (*x_caught_error_message));
3804}
3805
3806
3807/* Begin trapping X errors.
dc6f92b8 3808
c118dd06
JB
3809 After calling this function, X protocol errors no longer cause
3810 Emacs to exit; instead, they are recorded in x_cfc_error_message.
dc6f92b8 3811
c118dd06
JB
3812 Calling x_check_errors signals an Emacs error if an X error has
3813 occurred since the last call to x_catch_errors or x_check_errors.
3814
3815 Calling x_uncatch_errors resumes the normal error handling. */
3816
3817void x_catch_errors(), x_check_errors (), x_uncatch_errors ();
3818
3819void
3820x_catch_errors ()
dc6f92b8 3821{
c118dd06
JB
3822 /* Make sure any errors from previous requests have been dealt with. */
3823 XSync (x_current_display, False);
dc6f92b8 3824
c118dd06
JB
3825 /* Set up the error buffer. */
3826 x_caught_error_message =
3827 (char (*)[]) xmalloc (sizeof (*x_caught_error_message));
d872b748 3828 (*x_caught_error_message)[0] = '\0';
16bd92ea 3829
c118dd06
JB
3830 /* Install our little error handler. */
3831 XHandleError (x_error_catcher);
3832}
16bd92ea 3833
c118dd06
JB
3834/* If any X protocol errors have arrived since the last call to
3835 x_catch_errors or x_check_errors, signal an Emacs error using
3836 sprintf (a buffer, FORMAT, the x error message text) as the text. */
3837void
3838x_check_errors (format)
3839 char *format;
3840{
3841 /* Make sure to catch any errors incurred so far. */
3842 XSync (x_current_display, False);
16bd92ea 3843
c118dd06
JB
3844 if ((*x_caught_error_message)[0])
3845 {
3846 char buf[256];
3847
3848 sprintf (buf, format, *x_caught_error_message);
9ac0d9e0 3849 xfree (x_caught_error_message);
dc6f92b8 3850
c118dd06
JB
3851 x_uncatch_errors ();
3852 error (buf);
3853 }
3854}
3855
3856void
3857x_uncatch_errors ()
3858{
9ac0d9e0 3859 xfree (x_caught_error_message);
c118dd06 3860 XHandleError (x_error_quitter);
dc6f92b8
JB
3861}
3862
dc6f92b8
JB
3863#if 0
3864static unsigned int x_wire_count;
3865x_trace_wire ()
3866{
3867 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
3868}
c118dd06 3869#endif /* ! 0 */
dc6f92b8
JB
3870
3871\f
f451eb13
JB
3872/* Changing the font of the frame. */
3873
f676886a 3874/* Set the font of the x-window specified by frame F
dc6f92b8 3875 to the font named NEWNAME. This is safe to use
f676886a 3876 even before F has an actual x-window. */
dc6f92b8
JB
3877
3878#ifdef HAVE_X11
3879
3880/* A table of all the fonts we have already loaded. */
3881static XFontStruct **x_font_table;
3882
3883/* The current capacity of x_font_table. */
3884static int x_font_table_size;
3885
3886/* The number of fonts actually stored in x_font_table.
3887 x_font_table[n] is used and valid iff 0 <= n < n_fonts.
3888 0 <= n_fonts <= x_font_table_size. */
3889static int n_fonts;
3890
f676886a
JB
3891x_new_font (f, fontname)
3892 struct frame *f;
dc6f92b8
JB
3893 register char *fontname;
3894{
3895 XFontStruct *temp;
3896 int already_loaded;
3897 int n_matching_fonts;
3898 XFontStruct *font_info;
3899 char **font_names;
3900
3901 /* Get a list of all the fonts that match this name. Once we
3902 have a list of matching fonts, we compare them against the fonts
3903 we already have by comparing font ids. */
3904 font_names = (char **) XListFontsWithInfo (x_current_display, fontname,
3905 1024, &n_matching_fonts,
3906 &font_info);
9696f58b 3907
dc6f92b8
JB
3908 /* If the server couldn't find any fonts whose named matched fontname,
3909 return an error code. */
3910 if (n_matching_fonts == 0)
3911 return 1;
3912
90e65f07 3913 /* See if we've already loaded a matching font. */
dc6f92b8
JB
3914 {
3915 int i, j;
3916
3917 already_loaded = 0;
3918 for (i = 0; i < n_fonts; i++)
3919 for (j = 0; j < n_matching_fonts; j++)
3920 if (x_font_table[i]->fid == font_info[j].fid)
3921 {
3922 already_loaded = i;
3923 goto found_font;
3924 }
3925 }
3926 found_font:
3927
3928 /* If we have, just return it from the table. */
3929 if (already_loaded)
f676886a 3930 f->display.x->font = x_font_table[already_loaded];
90e65f07 3931
dc6f92b8
JB
3932 /* Otherwise, load the font and add it to the table. */
3933 else
3934 {
9696f58b 3935 int i;
dc6f92b8
JB
3936 XFontStruct *font;
3937
9696f58b
JB
3938 /* Try to find a character-cell font in the list. */
3939 for (i = 0; i < n_matching_fonts; i++)
3940 if (! font_info[i].per_char)
3941 break;
3942
3943 if (i >= n_matching_fonts)
3944 return 2;
3945 else
3946 fontname = font_names[i];
3947
dc6f92b8
JB
3948 font = (XFontStruct *) XLoadQueryFont (x_current_display, fontname);
3949 if (! font)
3950 return 1;
3951
3952 /* Do we need to create the table? */
3953 if (x_font_table_size == 0)
3954 {
3955 x_font_table_size = 16;
3956 x_font_table
3957 = (XFontStruct **) xmalloc (x_font_table_size
3958 * sizeof (x_font_table[0]));
3959 }
3960 /* Do we need to grow the table? */
3961 else if (n_fonts >= x_font_table_size)
3962 {
90e65f07 3963 x_font_table_size *= 2;
dc6f92b8
JB
3964 x_font_table
3965 = (XFontStruct **) xrealloc (x_font_table,
3966 (x_font_table_size
3967 * sizeof (x_font_table[0])));
3968 }
3969
f676886a 3970 f->display.x->font = x_font_table[n_fonts++] = font;
dc6f92b8
JB
3971 }
3972
3973 /* Free the information from XListFontsWithInfo. The data
3974 we actually retain comes from XLoadQueryFont. */
3975 XFreeFontInfo (font_names, font_info, n_matching_fonts);
3976
f676886a 3977 /* Now make the frame display the given font. */
c118dd06 3978 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 3979 {
f676886a
JB
3980 XSetFont (x_current_display, f->display.x->normal_gc,
3981 f->display.x->font->fid);
3982 XSetFont (x_current_display, f->display.x->reverse_gc,
3983 f->display.x->font->fid);
3984 XSetFont (x_current_display, f->display.x->cursor_gc,
3985 f->display.x->font->fid);
decb54c6 3986 init_frame_faces (f);
f676886a
JB
3987
3988 x_set_window_size (f, f->width, f->height);
dc6f92b8
JB
3989 }
3990
3991 return 0;
3992}
c118dd06 3993#else /* ! defined (HAVE_X11) */
f676886a
JB
3994x_new_font (f, newname)
3995 struct frame *f;
dc6f92b8
JB
3996 register char *newname;
3997{
3998 FONT_TYPE *temp;
3999 int mask;
4000
4001 temp = XGetFont (newname);
4002 if (temp == (FONT_TYPE *) 0)
4003 return 1;
4004
f676886a
JB
4005 if (f->display.x->font)
4006 XLoseFont (f->display.x->font);
dc6f92b8 4007
f676886a 4008 f->display.x->font = temp;
dc6f92b8 4009
c118dd06 4010 if (FRAME_X_WINDOW (f) != 0)
f676886a 4011 x_set_window_size (f, f->width, f->height);
dc6f92b8
JB
4012
4013 return 0;
4014}
c118dd06 4015#endif /* ! defined (HAVE_X11) */
dc6f92b8 4016\f
f451eb13
JB
4017/* X Window sizes and positions. */
4018
f676886a
JB
4019x_calc_absolute_position (f)
4020 struct frame *f;
dc6f92b8
JB
4021{
4022#ifdef HAVE_X11
f676886a
JB
4023 if (f->display.x->left_pos < 0)
4024 f->display.x->left_pos
7c5283e4 4025 = x_screen_width - PIXEL_WIDTH (f) + f->display.x->left_pos;
dc6f92b8 4026
f676886a
JB
4027 if (f->display.x->top_pos < 0)
4028 f->display.x->top_pos
7c5283e4 4029 = x_screen_height - PIXEL_HEIGHT (f) + f->display.x->top_pos;
c118dd06 4030#else /* ! defined (HAVE_X11) */
dc6f92b8
JB
4031 WINDOWINFO_TYPE parentinfo;
4032
c118dd06 4033 XGetWindowInfo (FRAME_X_WINDOW (f), &parentinfo);
dc6f92b8 4034
f676886a
JB
4035 if (f->display.x->left_pos < 0)
4036 f->display.x->left_pos = parentinfo.width + (f->display.x->left_pos + 1)
4037 - PIXEL_WIDTH (f) - 2 * f->display.x->internal_border_width;
dc6f92b8 4038
f676886a
JB
4039 if (f->display.x->top_pos < 0)
4040 f->display.x->top_pos = parentinfo.height + (f->display.x->top_pos + 1)
4041 - PIXEL_HEIGHT (f) - 2 * f->display.x->internal_border_width;
c118dd06 4042#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4043}
4044
f676886a
JB
4045x_set_offset (f, xoff, yoff)
4046 struct frame *f;
dc6f92b8
JB
4047 register int xoff, yoff;
4048{
f676886a
JB
4049 f->display.x->top_pos = yoff;
4050 f->display.x->left_pos = xoff;
4051 x_calc_absolute_position (f);
dc6f92b8
JB
4052
4053 BLOCK_INPUT;
c118dd06 4054 XMoveWindow (XDISPLAY FRAME_X_WINDOW (f),
f676886a 4055 f->display.x->left_pos, f->display.x->top_pos);
dc6f92b8 4056#ifdef HAVE_X11
f676886a 4057 x_wm_set_size_hint (f, 0);
c118dd06 4058#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4059 UNBLOCK_INPUT;
4060}
4061
f676886a 4062/* Call this to change the size of frame F's x-window. */
dc6f92b8 4063
f676886a
JB
4064x_set_window_size (f, cols, rows)
4065 struct frame *f;
b1c884c3 4066 int cols, rows;
dc6f92b8
JB
4067{
4068 int pixelwidth, pixelheight;
4069 int mask;
dc6f92b8
JB
4070
4071 BLOCK_INPUT;
4072
b1c884c3 4073 check_frame_size (f, &rows, &cols);
ab648270
JB
4074 f->display.x->vertical_scroll_bar_extra =
4075 (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4076 ? VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f)
f451eb13
JB
4077 : 0);
4078 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
4079 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8
JB
4080
4081#ifdef HAVE_X11
f676886a 4082 x_wm_set_size_hint (f, 0);
c118dd06
JB
4083#endif /* ! defined (HAVE_X11) */
4084 XChangeWindowSize (FRAME_X_WINDOW (f), pixelwidth, pixelheight);
b1c884c3
JB
4085
4086 /* Now, strictly speaking, we can't be sure that this is accurate,
4087 but the window manager will get around to dealing with the size
4088 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
4089 ConfigureNotify event gets here.
4090
4091 We could just not bother storing any of this information here,
4092 and let the ConfigureNotify event set everything up, but that
4093 might be kind of confusing to the lisp code, since size changes
4094 wouldn't be reported in the frame parameters until some random
4095 point in the future when the ConfigureNotify event arrives. */
8922af5f 4096 change_frame_size (f, rows, cols, 0, 0);
b1c884c3
JB
4097 PIXEL_WIDTH (f) = pixelwidth;
4098 PIXEL_HEIGHT (f) = pixelheight;
4099
dbc4e1c1
JB
4100 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
4101 receive in the ConfigureNotify event; if we get what we asked
4102 for, then the event won't cause the screen to become garbaged, so
4103 we have to make sure to do it here. */
4104 SET_FRAME_GARBAGED (f);
4105
dc6f92b8
JB
4106 XFlushQueue ();
4107 UNBLOCK_INPUT;
4108}
4109
4110#ifndef HAVE_X11
f676886a
JB
4111x_set_resize_hint (f)
4112 struct frame *f;
dc6f92b8 4113{
12ba150f
JB
4114 XSetResizeHint (FRAME_X_WINDOW (f),
4115 2 * f->display.x->internal_border_width,
f676886a 4116 2 * f->display.x->internal_border_width,
12ba150f
JB
4117 FONT_WIDTH (f->display.x->font),
4118 FONT_HEIGHT (f->display.x->font));
dc6f92b8 4119}
c118dd06 4120#endif /* HAVE_X11 */
dc6f92b8 4121\f
f451eb13 4122/* Mouse warping, focus shifting, raising and lowering. */
dc6f92b8 4123
f676886a
JB
4124x_set_mouse_position (f, x, y)
4125 struct frame *f;
dc6f92b8
JB
4126 int x, y;
4127{
4128 int pix_x, pix_y;
4129
f676886a 4130 x_raise_frame (f);
dc6f92b8 4131
12ba150f
JB
4132 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2;
4133 pix_y = CHAR_TO_PIXEL_ROW (f, y) + FONT_HEIGHT (f->display.x->font) / 2;
f451eb13
JB
4134
4135 if (pix_x < 0) pix_x = 0;
4136 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
4137
4138 if (pix_y < 0) pix_y = 0;
4139 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
4140
4141 BLOCK_INPUT;
dc6f92b8 4142
c118dd06 4143 XWarpMousePointer (FRAME_X_WINDOW (f), pix_x, pix_y);
dc6f92b8
JB
4144 UNBLOCK_INPUT;
4145}
4146
4147#ifdef HAVE_X11
f676886a
JB
4148x_focus_on_frame (f)
4149 struct frame *f;
dc6f92b8 4150{
f676886a 4151 x_raise_frame (f);
6d4238f3
JB
4152#if 0
4153 /* I don't think that the ICCCM allows programs to do things like this
4154 without the interaction of the window manager. Whatever you end up
f676886a 4155 doing with this code, do it to x_unfocus_frame too. */
c118dd06 4156 XSetInputFocus (x_current_display, FRAME_X_WINDOW (f),
dc6f92b8 4157 RevertToPointerRoot, CurrentTime);
c118dd06 4158#endif /* ! 0 */
dc6f92b8
JB
4159}
4160
f676886a
JB
4161x_unfocus_frame (f)
4162 struct frame *f;
dc6f92b8 4163{
6d4238f3 4164#if 0
f676886a
JB
4165 /* Look at the remarks in x_focus_on_frame. */
4166 if (x_focus_frame == f)
dc6f92b8
JB
4167 XSetInputFocus (x_current_display, PointerRoot,
4168 RevertToPointerRoot, CurrentTime);
c118dd06 4169#endif /* ! 0 */
dc6f92b8
JB
4170}
4171
c118dd06 4172#endif /* ! defined (HAVE_X11) */
dc6f92b8 4173
f676886a 4174/* Raise frame F. */
dc6f92b8 4175
f676886a
JB
4176x_raise_frame (f)
4177 struct frame *f;
dc6f92b8 4178{
3a88c238 4179 if (f->async_visible)
dc6f92b8
JB
4180 {
4181 BLOCK_INPUT;
c118dd06 4182 XRaiseWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8
JB
4183 XFlushQueue ();
4184 UNBLOCK_INPUT;
4185 }
4186}
4187
f676886a 4188/* Lower frame F. */
dc6f92b8 4189
f676886a
JB
4190x_lower_frame (f)
4191 struct frame *f;
dc6f92b8 4192{
3a88c238 4193 if (f->async_visible)
dc6f92b8
JB
4194 {
4195 BLOCK_INPUT;
c118dd06 4196 XLowerWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8
JB
4197 XFlushQueue ();
4198 UNBLOCK_INPUT;
4199 }
4200}
4201
dbc4e1c1
JB
4202static void
4203XTframe_raise_lower (f, raise)
4204 FRAME_PTR f;
4205 int raise;
4206{
4207 if (raise)
4208 x_raise_frame (f);
4209 else
4210 x_lower_frame (f);
4211}
4212
4213
dc6f92b8
JB
4214/* Change from withdrawn state to mapped state. */
4215
f676886a
JB
4216x_make_frame_visible (f)
4217 struct frame *f;
dc6f92b8
JB
4218{
4219 int mask;
4220
dc6f92b8 4221 BLOCK_INPUT;
dc6f92b8 4222
f676886a 4223 if (! FRAME_VISIBLE_P (f))
90e65f07
JB
4224 {
4225#ifdef HAVE_X11
4226 if (! EQ (Vx_no_window_manager, Qt))
f676886a 4227 x_wm_set_window_state (f, NormalState);
dc6f92b8 4228
c118dd06 4229 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
ab648270 4230 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
c118dd06
JB
4231 XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
4232#else /* ! defined (HAVE_X11) */
4233 XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
f676886a
JB
4234 if (f->display.x->icon_desc != 0)
4235 XUnmapWindow (f->display.x->icon_desc);
dc6f92b8 4236
90e65f07 4237 /* Handled by the MapNotify event for X11 */
3a88c238
JB
4238 f->async_visible = 1;
4239 f->async_iconified = 0;
dc6f92b8 4240
f676886a 4241 /* NOTE: this may cause problems for the first frame. */
90e65f07 4242 XTcursor_to (0, 0);
c118dd06 4243#endif /* ! defined (HAVE_X11) */
90e65f07 4244 }
dc6f92b8 4245
dc6f92b8 4246 XFlushQueue ();
90e65f07 4247
dc6f92b8
JB
4248 UNBLOCK_INPUT;
4249}
4250
4251/* Change from mapped state to withdrawn state. */
4252
f676886a
JB
4253x_make_frame_invisible (f)
4254 struct frame *f;
dc6f92b8
JB
4255{
4256 int mask;
4257
3a88c238 4258 if (! f->async_visible)
dc6f92b8
JB
4259 return;
4260
4261 BLOCK_INPUT;
c118dd06
JB
4262
4263#ifdef HAVE_X11R4
4264
4265 if (! XWithdrawWindow (x_current_display, FRAME_X_WINDOW (f),
4266 DefaultScreen (x_current_display)))
4267 {
4268 UNBLOCK_INPUT_RESIGNAL;
4269 error ("can't notify window manager of window withdrawl");
4270 }
4271
4272#else /* ! defined (HAVE_X11R4) */
dc6f92b8 4273#ifdef HAVE_X11
16bd92ea 4274
c118dd06 4275 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
4276 if (! EQ (Vx_no_window_manager, Qt))
4277 {
16bd92ea 4278 XEvent unmap;
dc6f92b8 4279
16bd92ea 4280 unmap.xunmap.type = UnmapNotify;
c118dd06 4281 unmap.xunmap.window = FRAME_X_WINDOW (f);
16bd92ea
JB
4282 unmap.xunmap.event = DefaultRootWindow (x_current_display);
4283 unmap.xunmap.from_configure = False;
4284 if (! XSendEvent (x_current_display,
4285 DefaultRootWindow (x_current_display),
4286 False,
4287 SubstructureRedirectMask|SubstructureNotifyMask,
4288 &unmap))
4289 {
4290 UNBLOCK_INPUT_RESIGNAL;
4291 error ("can't notify window manager of withdrawal");
4292 }
dc6f92b8
JB
4293 }
4294
16bd92ea 4295 /* Unmap the window ourselves. Cheeky! */
c118dd06
JB
4296 XUnmapWindow (x_current_display, FRAME_X_WINDOW (f));
4297
4298#else /* ! defined (HAVE_X11) */
dc6f92b8 4299
c118dd06 4300 XUnmapWindow (FRAME_X_WINDOW (f));
3a88c238 4301 f->async_visible = 0; /* Handled by the UnMap event for X11 */
f676886a 4302 if (f->display.x->icon_desc != 0)
c118dd06
JB
4303 XUnmapWindow (f->display.x->icon_desc);
4304
4305#endif /* ! defined (HAVE_X11) */
4306#endif /* ! defined (HAVE_X11R4) */
dc6f92b8
JB
4307
4308 XFlushQueue ();
4309 UNBLOCK_INPUT;
4310}
4311
dc6f92b8
JB
4312/* Change window state from mapped to iconified. */
4313
f676886a
JB
4314x_iconify_frame (f)
4315 struct frame *f;
dc6f92b8
JB
4316{
4317 int mask;
4318
3a88c238 4319 if (f->async_iconified)
dc6f92b8
JB
4320 return;
4321
4322 BLOCK_INPUT;
4323
4324#ifdef HAVE_X11
16bd92ea
JB
4325 /* Since we don't know which revision of X we're running, we'll use both
4326 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
4327
4328 /* X11R4: send a ClientMessage to the window manager using the
4329 WM_CHANGE_STATE type. */
4330 {
4331 XEvent message;
4332
c118dd06 4333 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea
JB
4334 message.xclient.type = ClientMessage;
4335 message.xclient.message_type = Xatom_wm_change_state;
4336 message.xclient.format = 32;
4337 message.xclient.data.l[0] = IconicState;
4338
4339 if (! XSendEvent (x_current_display,
4340 DefaultRootWindow (x_current_display),
4341 False,
4342 SubstructureRedirectMask | SubstructureNotifyMask,
4343 &message))
dc6f92b8
JB
4344 {
4345 UNBLOCK_INPUT_RESIGNAL;
4346 error ("Can't notify window manager of iconification.");
4347 }
16bd92ea 4348 }
dc6f92b8 4349
16bd92ea
JB
4350 /* X11R3: set the initial_state field of the window manager hints to
4351 IconicState. */
4352 x_wm_set_window_state (f, IconicState);
dc6f92b8 4353
3a88c238 4354 f->async_iconified = 1;
c118dd06
JB
4355#else /* ! defined (HAVE_X11) */
4356 XUnmapWindow (XDISPLAY FRAME_X_WINDOW (f));
dc6f92b8 4357
3a88c238 4358 f->async_visible = 0; /* Handled in the UnMap event for X11. */
f676886a 4359 if (f->display.x->icon_desc != 0)
dc6f92b8 4360 {
f676886a
JB
4361 XMapWindow (XDISPLAY f->display.x->icon_desc);
4362 refreshicon (f);
dc6f92b8 4363 }
c118dd06 4364#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4365
4366 XFlushQueue ();
4367 UNBLOCK_INPUT;
4368}
4369
c0ff3fab 4370/* Destroy the X window of frame F. */
dc6f92b8 4371
c0ff3fab 4372x_destroy_window (f)
f676886a 4373 struct frame *f;
dc6f92b8 4374{
dc6f92b8 4375 BLOCK_INPUT;
c0ff3fab
JB
4376
4377 if (f->display.x->icon_desc != 0)
4378 XDestroyWindow (XDISPLAY f->display.x->icon_desc);
4379 XDestroyWindow (XDISPLAY f->display.x->window_desc);
07e34cb0 4380 free_frame_faces (f);
dc6f92b8 4381 XFlushQueue ();
dc6f92b8 4382
9ac0d9e0 4383 xfree (f->display.x);
c0ff3fab 4384 f->display.x = 0;
f676886a
JB
4385 if (f == x_focus_frame)
4386 x_focus_frame = 0;
4387 if (f == x_highlight_frame)
4388 x_highlight_frame = 0;
c0ff3fab
JB
4389
4390 UNBLOCK_INPUT;
dc6f92b8
JB
4391}
4392\f
f451eb13
JB
4393/* Manage event queues for X10. */
4394
dc6f92b8
JB
4395#ifndef HAVE_X11
4396
4397/* Manage event queues.
4398
4399 This code is only used by the X10 support.
4400
4401 We cannot leave events in the X queue and get them when we are ready
4402 because X does not provide a subroutine to get only a certain kind
4403 of event but not block if there are no queued events of that kind.
4404
4405 Therefore, we must examine events as they come in and copy events
4406 of certain kinds into our private queues.
4407
4408 All ExposeRegion events are put in x_expose_queue.
4409 All ButtonPressed and ButtonReleased events are put in x_mouse_queue. */
4410
4411
4412/* Write the event *P_XREP into the event queue *QUEUE.
4413 If the queue is full, do nothing, but return nonzero. */
4414
4415int
4416enqueue_event (p_xrep, queue)
4417 register XEvent *p_xrep;
4418 register struct event_queue *queue;
4419{
4420 int newindex = queue->windex + 1;
4421 if (newindex == EVENT_BUFFER_SIZE)
4422 newindex = 0;
4423 if (newindex == queue->rindex)
4424 return -1;
4425 queue->xrep[queue->windex] = *p_xrep;
4426 queue->windex = newindex;
4427 return 0;
4428}
4429
4430/* Fetch the next event from queue *QUEUE and store it in *P_XREP.
4431 If *QUEUE is empty, do nothing and return 0. */
4432
4433int
4434dequeue_event (p_xrep, queue)
4435 register XEvent *p_xrep;
4436 register struct event_queue *queue;
4437{
4438 if (queue->windex == queue->rindex)
4439 return 0;
4440 *p_xrep = queue->xrep[queue->rindex++];
4441 if (queue->rindex == EVENT_BUFFER_SIZE)
4442 queue->rindex = 0;
4443 return 1;
4444}
4445
4446/* Return the number of events buffered in *QUEUE. */
4447
4448int
4449queue_event_count (queue)
4450 register struct event_queue *queue;
4451{
4452 int tem = queue->windex - queue->rindex;
4453 if (tem >= 0)
4454 return tem;
4455 return EVENT_BUFFER_SIZE + tem;
4456}
4457
4458/* Return nonzero if mouse input is pending. */
4459
4460int
4461mouse_event_pending_p ()
4462{
4463 return queue_event_count (&x_mouse_queue);
4464}
c118dd06 4465#endif /* HAVE_X11 */
dc6f92b8 4466\f
f451eb13
JB
4467/* Setting window manager hints. */
4468
dc6f92b8
JB
4469#ifdef HAVE_X11
4470
f676886a
JB
4471x_wm_set_size_hint (f, prompting)
4472 struct frame *f;
dc6f92b8
JB
4473 long prompting;
4474{
4475 XSizeHints size_hints;
c118dd06 4476 Window window = FRAME_X_WINDOW (f);
dc6f92b8
JB
4477
4478 size_hints.flags = PResizeInc | PMinSize | PMaxSize;
4479
f676886a
JB
4480 flexlines = f->height;
4481
4482 size_hints.x = f->display.x->left_pos;
4483 size_hints.y = f->display.x->top_pos;
4484 size_hints.height = PIXEL_HEIGHT (f);
4485 size_hints.width = PIXEL_WIDTH (f);
4486 size_hints.width_inc = FONT_WIDTH (f->display.x->font);
4487 size_hints.height_inc = FONT_HEIGHT (f->display.x->font);
12ba150f
JB
4488 size_hints.max_width = x_screen_width - CHAR_TO_PIXEL_WIDTH (f, 0);
4489 size_hints.max_height = x_screen_height - CHAR_TO_PIXEL_HEIGHT (f, 0);
f451eb13 4490
b1c884c3 4491 {
b0342f17
JB
4492 int base_width, base_height;
4493
f451eb13
JB
4494 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
4495 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17
JB
4496
4497 {
4498 int min_rows = 0, min_cols = 0;
4499 check_frame_size (f, &min_rows, &min_cols);
4500
4501 /* The window manager uses the base width hints to calculate the
4502 current number of rows and columns in the frame while
4503 resizing; min_width and min_height aren't useful for this
4504 purpose, since they might not give the dimensions for a
4505 zero-row, zero-column frame.
4506
4507 We use the base_width and base_height members if we have
4508 them; otherwise, we set the min_width and min_height members
4509 to the size for a zero x zero frame. */
4510
4511#ifdef HAVE_X11R4
4512 size_hints.flags |= PBaseSize;
4513 size_hints.base_width = base_width;
4514 size_hints.base_height = base_height;
4515 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
4516 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
4517#else
4518 size_hints.min_width = base_width;
4519 size_hints.min_height = base_height;
4520#endif
4521 }
b1c884c3 4522
b1c884c3 4523 }
dc6f92b8
JB
4524
4525 if (prompting)
4526 size_hints.flags |= prompting;
4527 else
4528 {
4529 XSizeHints hints; /* Sometimes I hate X Windows... */
4530
4531 XGetNormalHints (x_current_display, window, &hints);
4532 if (hints.flags & PSize)
4533 size_hints.flags |= PSize;
4534 if (hints.flags & PPosition)
4535 size_hints.flags |= PPosition;
4536 if (hints.flags & USPosition)
4537 size_hints.flags |= USPosition;
4538 if (hints.flags & USSize)
4539 size_hints.flags |= USSize;
4540 }
16bd92ea 4541
b0342f17
JB
4542#ifdef HAVE_X11R4
4543 XSetWMNormalHints (x_current_display, window, &size_hints);
4544#else
dc6f92b8 4545 XSetNormalHints (x_current_display, window, &size_hints);
b0342f17 4546#endif
dc6f92b8
JB
4547}
4548
4549/* Used for IconicState or NormalState */
f676886a
JB
4550x_wm_set_window_state (f, state)
4551 struct frame *f;
dc6f92b8
JB
4552 int state;
4553{
c118dd06 4554 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4555
16bd92ea
JB
4556 f->display.x->wm_hints.flags |= StateHint;
4557 f->display.x->wm_hints.initial_state = state;
b1c884c3 4558
16bd92ea 4559 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4560}
4561
f676886a
JB
4562x_wm_set_icon_pixmap (f, icon_pixmap)
4563 struct frame *f;
dc6f92b8
JB
4564 Pixmap icon_pixmap;
4565{
c118dd06 4566 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4567
dbc4e1c1
JB
4568 if (icon_pixmap)
4569 {
4570 f->display.x->wm_hints.icon_pixmap = icon_pixmap;
4571 f->display.x->wm_hints.flags |= IconPixmapHint;
4572 }
4573 else
4574 f->display.x->wm_hints.flags &= ~IconPixmapHint;
b1c884c3 4575
16bd92ea 4576 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4577}
4578
f676886a
JB
4579x_wm_set_icon_position (f, icon_x, icon_y)
4580 struct frame *f;
dc6f92b8
JB
4581 int icon_x, icon_y;
4582{
c118dd06 4583 Window window = FRAME_X_WINDOW (f);
dc6f92b8 4584
16bd92ea
JB
4585 f->display.x->wm_hints.flags |= IconPositionHint;
4586 f->display.x->wm_hints.icon_x = icon_x;
4587 f->display.x->wm_hints.icon_y = icon_y;
b1c884c3 4588
16bd92ea 4589 XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
dc6f92b8
JB
4590}
4591
4592\f
f451eb13
JB
4593/* Initialization. */
4594
dc6f92b8
JB
4595void
4596x_term_init (display_name)
4597 char *display_name;
4598{
f676886a 4599 Lisp_Object frame;
dc6f92b8
JB
4600 char *defaultvalue;
4601#ifdef F_SETOWN
4602 extern int old_fcntl_owner;
c118dd06 4603#endif /* ! defined (F_SETOWN) */
6d4238f3 4604
f676886a 4605 x_focus_frame = x_highlight_frame = 0;
dc6f92b8
JB
4606
4607 x_current_display = XOpenDisplay (display_name);
4608 if (x_current_display == 0)
4609 fatal ("X server %s not responding; check the DISPLAY environment variable or use \"-d\"\n",
4610 display_name);
4611
4612#ifdef HAVE_X11
4613 {
16bd92ea 4614 int hostname_size = 256;
60fb3ee1
JB
4615
4616 hostname = (char *) xmalloc (hostname_size);
4617
dc6f92b8
JB
4618#if 0
4619 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 4620#endif /* ! 0 */
dc6f92b8 4621
60fb3ee1
JB
4622 /* Try to get the host name; if the buffer is too short, try
4623 again. Apparently, the only indication gethostname gives of
4624 whether the buffer was large enough is the presence or absence
4625 of a '\0' in the string. Eech. */
4626 for (;;)
4627 {
4628 gethostname (hostname, hostname_size - 1);
4629 hostname[hostname_size - 1] = '\0';
4630
4631 /* Was the buffer large enough for gethostname to store the '\0'? */
4632 if (strlen (hostname) < hostname_size - 1)
4633 break;
4634
4635 hostname_size <<= 1;
4636 hostname = (char *) xrealloc (hostname, hostname_size);
4637 }
59653951 4638 x_id_name = (char *) xmalloc (XSTRING (Vinvocation_name)->size
60fb3ee1
JB
4639 + strlen (hostname)
4640 + 2);
59653951 4641 sprintf (x_id_name, "%s@%s", XSTRING (Vinvocation_name)->data, hostname);
dc6f92b8 4642 }
28430d3c
JB
4643
4644 /* Figure out which modifier bits mean what. */
4645 x_find_modifier_meanings ();
f451eb13 4646
ab648270 4647 /* Get the scroll bar cursor. */
d56a553a
RS
4648 x_vertical_scroll_bar_cursor
4649 = XCreateFontCursor (x_current_display, XC_sb_v_double_arrow);
f451eb13 4650
d56a553a 4651#if 0
28430d3c
JB
4652 /* Watch for PropertyNotify events on the root window; we use them
4653 to figure out when to invalidate our cache of the cut buffers. */
4654 x_watch_cut_buffer_cache ();
d56a553a 4655#endif
28430d3c 4656
a4fc7360
JB
4657 if (ConnectionNumber (x_current_display) != 0)
4658 {
4659 dup2 (ConnectionNumber (x_current_display), 0);
6d4238f3
JB
4660
4661#ifndef SYSV_STREAMS
a4fc7360
JB
4662 /* Streams somehow keeps track of which descriptor number
4663 is being used to talk to X. So it is not safe to substitute
4664 descriptor 0. But it is safe to make descriptor 0 a copy of it. */
4665 close (ConnectionNumber (x_current_display));
4666 ConnectionNumber (x_current_display) = 0; /* Looks a little strange?
6d4238f3
JB
4667 * check the def of the macro;
4668 * it is a genuine lvalue */
c118dd06 4669#endif /* SYSV_STREAMS */
a4fc7360 4670 }
6d4238f3 4671
c118dd06 4672#endif /* ! defined (HAVE_X11) */
dc6f92b8
JB
4673
4674#ifdef F_SETOWN
4675 old_fcntl_owner = fcntl (0, F_GETOWN, 0);
4676#ifdef F_SETOWN_SOCK_NEG
4677 fcntl (0, F_SETOWN, -getpid ()); /* stdin is a socket here */
c118dd06 4678#else /* ! defined (F_SETOWN_SOCK_NEG) */
dc6f92b8 4679 fcntl (0, F_SETOWN, getpid ());
c118dd06
JB
4680#endif /* ! defined (F_SETOWN_SOCK_NEG) */
4681#endif /* ! defined (F_SETOWN) */
dc6f92b8
JB
4682
4683#ifdef SIGIO
4684 init_sigio ();
c118dd06 4685#endif /* ! defined (SIGIO) */
dc6f92b8
JB
4686
4687 /* Must use interrupt input because we cannot otherwise
4688 arrange for C-g to be noticed immediately.
4689 We cannot connect it to SIGINT. */
4690 Fset_input_mode (Qt, Qnil, Qt, Qnil);
4691
4692 expose_all_windows = 0;
4693
f676886a 4694 clear_frame_hook = XTclear_frame;
dc6f92b8
JB
4695 clear_end_of_line_hook = XTclear_end_of_line;
4696 ins_del_lines_hook = XTins_del_lines;
4697 change_line_highlight_hook = XTchange_line_highlight;
4698 insert_glyphs_hook = XTinsert_glyphs;
4699 write_glyphs_hook = XTwrite_glyphs;
4700 delete_glyphs_hook = XTdelete_glyphs;
4701 ring_bell_hook = XTring_bell;
4702 reset_terminal_modes_hook = XTreset_terminal_modes;
4703 set_terminal_modes_hook = XTset_terminal_modes;
4704 update_begin_hook = XTupdate_begin;
4705 update_end_hook = XTupdate_end;
4706 set_terminal_window_hook = XTset_terminal_window;
4707 read_socket_hook = XTread_socket;
4708 cursor_to_hook = XTcursor_to;
4709 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 4710 mouse_position_hook = XTmouse_position;
f451eb13 4711 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 4712 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
4713 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
4714 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
4715 redeem_scroll_bar_hook = XTredeem_scroll_bar;
4716 judge_scroll_bars_hook = XTjudge_scroll_bars;
dc6f92b8 4717
f676886a 4718 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
4719 char_ins_del_ok = 0; /* just as fast to write the line */
4720 line_ins_del_ok = 1; /* we'll just blt 'em */
4721 fast_clear_end_of_line = 1; /* X does this well */
f676886a 4722 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
4723 off the bottom */
4724 baud_rate = 19200;
4725
c118dd06
JB
4726 /* Note that there is no real way portable across R3/R4 to get the
4727 original error handler. */
4728 XHandleError (x_error_quitter);
8922af5f 4729 XHandleIOError (x_io_error_quitter);
dc6f92b8
JB
4730
4731 /* Disable Window Change signals; they are handled by X events. */
4732#ifdef SIGWINCH
4733 signal (SIGWINCH, SIG_DFL);
c118dd06 4734#endif /* ! defined (SIGWINCH) */
dc6f92b8 4735
c118dd06 4736 signal (SIGPIPE, x_connection_closed);
dc6f92b8 4737}
55123275
JB
4738
4739void
4740syms_of_xterm ()
4741{
ab648270 4742 staticpro (&last_mouse_scroll_bar);
55123275 4743}
c118dd06
JB
4744#endif /* ! defined (HAVE_X11) */
4745#endif /* ! defined (HAVE_X_WINDOWS) */