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