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