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