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