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