(x_window_to_frame): New arg DPYINFO. All callers changed.
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
b8009dd1 2 Copyright (C) 1989, 1993, 1994 Free Software Foundation, Inc.
dc6f92b8
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
4746118a 8the Free Software Foundation; either version 2, or (at your option)
dc6f92b8
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
3afe33e7
RS
20/* Xt features made by Fred Pierresteguy. */
21
039440c4
RS
22/* On 4.3 these lose if they come after xterm.h. */
23/* On HP-UX 8.0 signal.h loses if it comes after config.h. */
24/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
25#include <signal.h>
26
18160b98 27#include <config.h>
dc6f92b8 28
4846819e
RS
29#include <stdio.h>
30
3afe33e7 31/* Need syssignal.h for various externs and definitions that may be required
bc20ebbf 32 by some configurations for calls to signal later in this source file. */
3afe33e7
RS
33#include "syssignal.h"
34
dc6f92b8
JB
35#ifdef HAVE_X_WINDOWS
36
37#include "lisp.h"
9ac0d9e0 38#include "blockinput.h"
dc6f92b8 39
dc6f92b8
JB
40/* This may include sys/types.h, and that somehow loses
41 if this is not done before the other system files. */
42#include "xterm.h"
f451eb13 43#include <X11/cursorfont.h>
dc6f92b8 44
16bd92ea 45#ifndef USG
dc6f92b8
JB
46/* Load sys/types.h if not already loaded.
47 In some systems loading it twice is suicidal. */
48#ifndef makedev
49#include <sys/types.h>
c118dd06
JB
50#endif /* makedev */
51#endif /* USG */
dc6f92b8
JB
52
53#ifdef BSD
54#include <sys/ioctl.h>
c118dd06 55#endif /* ! defined (BSD) */
dc6f92b8 56
2d368234 57#include "systty.h"
3a2712f9 58#include "systime.h"
dc6f92b8 59
b8009dd1 60#ifndef INCLUDED_FCNTL
dc6f92b8 61#include <fcntl.h>
b8009dd1 62#endif
dc6f92b8
JB
63#include <ctype.h>
64#include <errno.h>
65#include <setjmp.h>
66#include <sys/stat.h>
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
RS
557 if ((!face->font
558 || (int) face->font == FACE_DEFAULT
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
b5cf7a0e
JB
608 if ((int) font == FACE_DEFAULT)
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? */
2b5c9e71 2309 f1 = x_any_window_to_frame (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
RS
3024/* This processes Expose events from the menubar specific X event
3025 loop in menubar.c. This allows to redisplay the frame if necessary
3026 when handling menubar or popup items. */
3027
3028void
3029process_expose_from_menu (event)
3030 XEvent event;
3031{
3032 FRAME_PTR f;
3033
f94397b5
KH
3034 BLOCK_INPUT;
3035
3afe33e7
RS
3036 f = x_window_to_frame (event.xexpose.window);
3037 if (f)
3038 {
3039 if (f->async_visible == 0)
3040 {
3041 f->async_visible = 1;
3042 f->async_iconified = 0;
3043 SET_FRAME_GARBAGED (f);
3044 }
3045 else
3046 {
3047 dumprectangle (x_window_to_frame (event.xexpose.window),
3048 event.xexpose.x, event.xexpose.y,
3049 event.xexpose.width, event.xexpose.height);
3050 }
3051 }
3052 else
3053 {
3054 struct scroll_bar *bar
3055 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 3056
3afe33e7
RS
3057 if (bar)
3058 x_scroll_bar_expose (bar, &event);
3059 }
f94397b5
KH
3060
3061 UNBLOCK_INPUT;
3afe33e7 3062}
09756a85
RS
3063\f
3064/* Define a queue to save up SelectionRequest events for later handling. */
3065
3066struct selection_event_queue
3067 {
3068 XEvent event;
3069 struct selection_event_queue *next;
3070 };
3071
3072static struct selection_event_queue *queue;
3073
3074/* Nonzero means queue up certain events--don't process them yet. */
3075static int x_queue_selection_requests;
3076
3077/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 3078
09756a85 3079static void
334208b7
RS
3080x_queue_event (f, event)
3081 FRAME_PTR f;
09756a85
RS
3082 XEvent *event;
3083{
3084 struct selection_event_queue *queue_tmp
3085 = (struct selection_event_queue *) malloc (sizeof (struct selection_event_queue));
3086
58769bee 3087 if (queue_tmp != NULL)
09756a85
RS
3088 {
3089 queue_tmp->event = *event;
3090 queue_tmp->next = queue;
3091 queue = queue_tmp;
3092 }
3093}
3094
3095/* Take all the queued events and put them back
3096 so that they get processed afresh. */
3097
3098static void
db3906fd
RS
3099x_unqueue_events (display)
3100 Display *display;
09756a85 3101{
58769bee 3102 while (queue != NULL)
09756a85
RS
3103 {
3104 struct selection_event_queue *queue_tmp = queue;
db3906fd 3105 XPutBackEvent (display, &queue_tmp->event);
09756a85
RS
3106 queue = queue_tmp->next;
3107 free ((char *)queue_tmp);
3108 }
3109}
3110
3111/* Start queuing SelectionRequest events. */
3112
3113void
db3906fd
RS
3114x_start_queuing_selection_requests (display)
3115 Display *display;
09756a85
RS
3116{
3117 x_queue_selection_requests++;
3118}
3119
3120/* Stop queuing SelectionRequest events. */
3121
3122void
db3906fd
RS
3123x_stop_queuing_selection_requests (display)
3124 Display *display;
09756a85
RS
3125{
3126 x_queue_selection_requests--;
db3906fd 3127 x_unqueue_events (display);
09756a85 3128}
f451eb13
JB
3129\f
3130/* The main X event-reading loop - XTread_socket. */
dc6f92b8 3131
dc6f92b8
JB
3132/* Timestamp of enter window event. This is only used by XTread_socket,
3133 but we have to put it out here, since static variables within functions
3134 sometimes don't work. */
3135static Time enter_timestamp;
3136
11edeb03 3137/* This holds the state XLookupString needs to implement dead keys
58769bee 3138 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
3139 says that a portable program can't use this, but Stephen Gildea assures
3140 me that letting the compiler initialize it to zeros will work okay.
3141
3142 This must be defined outside of XTread_socket, for the same reasons
3143 given for enter_timestamp, above. */
3144static XComposeStatus compose_status;
3145
10e6549c
RS
3146/* Record the last 100 characters stored
3147 to help debug the loss-of-chars-during-GC problem. */
3148int temp_index;
3149short temp_buffer[100];
3150
7a13e894
RS
3151/* Set this to nonzero to fake an "X I/O error"
3152 on a particular display. */
3153struct x_display_info *XTread_socket_fake_io_error;
3154
dc6f92b8
JB
3155/* Read events coming from the X server.
3156 This routine is called by the SIGIO handler.
3157 We return as soon as there are no more events to be read.
3158
3159 Events representing keys are stored in buffer BUFP,
3160 which can hold up to NUMCHARS characters.
3161 We return the number of characters stored into the buffer,
3162 thus pretending to be `read'.
3163
3164 WAITP is nonzero if we should block until input arrives.
3165 EXPECTED is nonzero if the caller knows input is available. */
3166
7c5283e4 3167int
dc6f92b8
JB
3168XTread_socket (sd, bufp, numchars, waitp, expected)
3169 register int sd;
3170 register struct input_event *bufp;
3171 register int numchars;
3172 int waitp;
3173 int expected;
3174{
3175 int count = 0;
3176 int nbytes = 0;
3177 int mask;
3178 int items_pending; /* How many items are in the X queue. */
3179 XEvent event;
f676886a 3180 struct frame *f;
66f55a9d 3181 int event_found = 0;
dc6f92b8
JB
3182 int prefix;
3183 Lisp_Object part;
334208b7 3184 struct x_display_info *dpyinfo;
dc6f92b8 3185
9ac0d9e0 3186 if (interrupt_input_blocked)
dc6f92b8 3187 {
9ac0d9e0 3188 interrupt_input_pending = 1;
dc6f92b8
JB
3189 return -1;
3190 }
3191
9ac0d9e0 3192 interrupt_input_pending = 0;
dc6f92b8 3193 BLOCK_INPUT;
c0a04927
RS
3194
3195 /* So people can tell when we have read the available input. */
3196 input_signal_count++;
3197
dc6f92b8
JB
3198 if (numchars <= 0)
3199 abort (); /* Don't think this happens. */
3200
7a13e894
RS
3201 /* Find the display we are supposed to read input for.
3202 It's the one communicating on descriptor SD. */
3203 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
3204 {
3205#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 3206#ifdef FIOSNBIO
7a13e894
RS
3207 /* If available, Xlib uses FIOSNBIO to make the socket
3208 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
3209 FIOSNBIO is ignored, and instead of signalling EWOULDBLOCK,
3210 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
3211 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 3212#endif /* ! defined (FIOSNBIO) */
7a13e894 3213#endif
dc6f92b8 3214
7a13e894
RS
3215#if 0 /* This code can't be made to work, with multiple displays,
3216 and appears not to be used on any system any more.
3217 Also keyboard.c doesn't turn O_NDELAY on and off
3218 for X connections. */
dc6f92b8
JB
3219#ifndef SIGIO
3220#ifndef HAVE_SELECT
7a13e894
RS
3221 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
3222 {
3223 extern int read_alarm_should_throw;
3224 read_alarm_should_throw = 1;
3225 XPeekEvent (dpyinfo->display, &event);
3226 read_alarm_should_throw = 0;
3227 }
c118dd06
JB
3228#endif /* HAVE_SELECT */
3229#endif /* SIGIO */
7a13e894 3230#endif
dc6f92b8 3231
7a13e894
RS
3232 /* For debugging, this gives a way to fake an I/O error. */
3233 if (dpyinfo == XTread_socket_fake_io_error)
3234 {
3235 XTread_socket_fake_io_error = 0;
3236 x_io_error_quitter (dpyinfo->display);
3237 }
dc6f92b8 3238
7a13e894 3239 while (XPending (dpyinfo->display) != 0)
dc6f92b8 3240 {
7a13e894
RS
3241 XNextEvent (dpyinfo->display, &event);
3242 event_found = 1;
3243
3244 switch (event.type)
3245 {
3246 case ClientMessage:
c047688c 3247 {
7a13e894
RS
3248 if (event.xclient.message_type
3249 == dpyinfo->Xatom_wm_protocols
3250 && event.xclient.format == 32)
c047688c 3251 {
7a13e894
RS
3252 if (event.xclient.data.l[0]
3253 == dpyinfo->Xatom_wm_take_focus)
c047688c 3254 {
7a13e894
RS
3255 f = x_window_to_frame (event.xclient.window);
3256 /* Since we set WM_TAKE_FOCUS, we must call
3257 XSetInputFocus explicitly. But not if f is null,
3258 since that might be an event for a deleted frame. */
3259 if (f)
3260 XSetInputFocus (event.xclient.display,
3261 event.xclient.window,
3262 RevertToPointerRoot,
3263 event.xclient.data.l[1]);
3264 /* Not certain about handling scroll bars here */
c047688c 3265 }
7a13e894
RS
3266 else if (event.xclient.data.l[0]
3267 == dpyinfo->Xatom_wm_save_yourself)
3268 {
3269 /* Save state modify the WM_COMMAND property to
3270 something which can reinstate us. This notifies
3271 the session manager, who's looking for such a
3272 PropertyNotify. Can restart processing when
3273 a keyboard or mouse event arrives. */
3274 if (numchars > 0)
3275 {
3276 f = x_top_window_to_frame (event.xclient.window);
3277
3278 /* This is just so we only give real data once
3279 for a single Emacs process. */
3280 if (f == selected_frame)
3281 XSetCommand (FRAME_X_DISPLAY (f),
3282 event.xclient.window,
3283 initial_argv, initial_argc);
3284 else
3285 XSetCommand (FRAME_X_DISPLAY (f),
3286 event.xclient.window,
3287 0, 0);
3288 }
3289 }
3290 else if (event.xclient.data.l[0]
3291 == dpyinfo->Xatom_wm_delete_window)
1fb20991 3292 {
7a13e894 3293 struct frame *f = x_any_window_to_frame (event.xclient.window);
1fb20991 3294
7a13e894
RS
3295 if (f)
3296 {
3297 if (numchars == 0)
3298 abort ();
1fb20991 3299
7a13e894
RS
3300 bufp->kind = delete_window_event;
3301 XSETFRAME (bufp->frame_or_window, f);
3302 bufp++;
3303
3304 count += 1;
3305 numchars -= 1;
3306 }
1fb20991 3307 }
c047688c 3308 }
7a13e894
RS
3309 else if (event.xclient.message_type
3310 == dpyinfo->Xatom_wm_configure_denied)
3311 {
3312 }
3313 else if (event.xclient.message_type
3314 == dpyinfo->Xatom_wm_window_moved)
3315 {
3316 int new_x, new_y;
3317 struct frame *f = x_window_to_frame (event.xclient.window);
58769bee 3318
7a13e894
RS
3319 new_x = event.xclient.data.s[0];
3320 new_y = event.xclient.data.s[1];
1fb20991 3321
7a13e894
RS
3322 if (f)
3323 {
3324 f->display.x->left_pos = new_x;
3325 f->display.x->top_pos = new_y;
3326 }
1fb20991 3327 }
5627c40e 3328#if defined (USE_X_TOOLKIT) && defined (HAVE_X11R5)
7a13e894
RS
3329 else if (event.xclient.message_type
3330 == dpyinfo->Xatom_editres)
3331 {
3332 struct frame *f = x_any_window_to_frame (event.xclient.window);
3333 _XEditResCheckMessages (f->display.x->widget, NULL, &event, NULL);
3334 }
5627c40e 3335#endif /* USE_X_TOOLKIT and HAVE_X11R5 */
7a13e894
RS
3336 }
3337 break;
dc6f92b8 3338
7a13e894 3339 case SelectionNotify:
3afe33e7 3340#ifdef USE_X_TOOLKIT
7a13e894
RS
3341 if (! x_window_to_frame (event.xselection.requestor))
3342 goto OTHER;
3afe33e7 3343#endif /* not USE_X_TOOLKIT */
7a13e894
RS
3344 x_handle_selection_notify (&event);
3345 break;
d56a553a 3346
7a13e894 3347 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 3348#ifdef USE_X_TOOLKIT
7a13e894
RS
3349 if (! x_window_to_frame (event.xselectionclear.window))
3350 goto OTHER;
3afe33e7 3351#endif /* USE_X_TOOLKIT */
7a13e894
RS
3352 {
3353 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 3354
7a13e894
RS
3355 if (numchars == 0)
3356 abort ();
d56a553a 3357
7a13e894
RS
3358 bufp->kind = selection_clear_event;
3359 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3360 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3361 SELECTION_EVENT_TIME (bufp) = eventp->time;
3362 bufp++;
d56a553a 3363
7a13e894
RS
3364 count += 1;
3365 numchars -= 1;
3366 }
3367 break;
dc6f92b8 3368
7a13e894 3369 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 3370#ifdef USE_X_TOOLKIT
7a13e894
RS
3371 if (!x_window_to_frame (event.xselectionrequest.owner))
3372 goto OTHER;
3afe33e7 3373#endif /* USE_X_TOOLKIT */
7a13e894
RS
3374 if (x_queue_selection_requests)
3375 x_queue_event (x_window_to_frame (event.xselectionrequest.owner),
3376 &event);
3377 else
3378 {
3379 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
dc6f92b8 3380
7a13e894
RS
3381 if (numchars == 0)
3382 abort ();
3383
3384 bufp->kind = selection_request_event;
3385 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
3386 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
3387 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
3388 SELECTION_EVENT_TARGET (bufp) = eventp->target;
3389 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
3390 SELECTION_EVENT_TIME (bufp) = eventp->time;
3391 bufp++;
3392
3393 count += 1;
3394 numchars -= 1;
3395 }
3396 break;
3397
3398 case PropertyNotify:
3afe33e7 3399#ifdef USE_X_TOOLKIT
7a13e894
RS
3400 if (!x_any_window_to_frame (event.xproperty.window))
3401 goto OTHER;
3afe33e7 3402#endif /* not USE_X_TOOLKIT */
7a13e894
RS
3403 x_handle_property_notify (&event);
3404 break;
dc6f92b8 3405
7a13e894
RS
3406 case ReparentNotify:
3407 f = x_top_window_to_frame (event.xreparent.window);
3408 if (f)
3409 {
3410 int x, y;
3411 f->display.x->parent_desc = event.xreparent.parent;
3412 x_real_positions (f, &x, &y);
3413 f->display.x->left_pos = x;
3414 f->display.x->top_pos = y;
3415 }
3416 break;
3bd330d4 3417
7a13e894
RS
3418 case Expose:
3419 f = x_window_to_frame (event.xexpose.window);
3420 if (f)
dc6f92b8 3421 {
7a13e894
RS
3422 if (f->async_visible == 0)
3423 {
3424 f->async_visible = 1;
3425 f->async_iconified = 0;
3426 SET_FRAME_GARBAGED (f);
3427 }
3428 else
3429 dumprectangle (x_window_to_frame (event.xexpose.window),
3430 event.xexpose.x, event.xexpose.y,
3431 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
3432 }
3433 else
7a13e894
RS
3434 {
3435 struct scroll_bar *bar
3436 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 3437
7a13e894
RS
3438 if (bar)
3439 x_scroll_bar_expose (bar, &event);
3afe33e7 3440#ifdef USE_X_TOOLKIT
7a13e894
RS
3441 else
3442 goto OTHER;
3afe33e7 3443#endif /* USE_X_TOOLKIT */
7a13e894
RS
3444 }
3445 break;
dc6f92b8 3446
7a13e894
RS
3447 case GraphicsExpose: /* This occurs when an XCopyArea's
3448 source area was obscured or not
3449 available.*/
3450 f = x_window_to_frame (event.xgraphicsexpose.drawable);
3451 if (f)
3452 {
3453 dumprectangle (f,
3454 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
3455 event.xgraphicsexpose.width,
3456 event.xgraphicsexpose.height);
3457 }
3afe33e7 3458#ifdef USE_X_TOOLKIT
7a13e894
RS
3459 else
3460 goto OTHER;
3afe33e7 3461#endif /* USE_X_TOOLKIT */
7a13e894 3462 break;
dc6f92b8 3463
7a13e894
RS
3464 case NoExpose: /* This occurs when an XCopyArea's
3465 source area was completely
3466 available */
3467 break;
dc6f92b8 3468
7a13e894
RS
3469 case UnmapNotify:
3470 f = x_any_window_to_frame (event.xunmap.window);
3471 if (f) /* F may no longer exist if
3472 the frame was deleted. */
3473 {
3474 /* While a frame is unmapped, display generation is
3475 disabled; you don't want to spend time updating a
3476 display that won't ever be seen. */
3477 f->async_visible = 0;
3478 /* We can't distinguish, from the event, whether the window
3479 has become iconified or invisible. So assume, if it
3480 was previously visible, than now it is iconified.
3481 We depend on x_make_frame_invisible to mark it iconified. */
3482 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
3483 f->async_iconified = 1;
bddd097c
KH
3484
3485 bufp->kind = iconify_event;
3486 XSETFRAME (bufp->frame_or_window, f);
3487 bufp++;
3488 count++;
3489 numchars--;
7a13e894 3490 }
3afe33e7 3491#ifdef USE_X_TOOLKIT
7a13e894 3492 goto OTHER;
3afe33e7 3493#endif /* USE_X_TOOLKIT */
7a13e894 3494 break;
dc6f92b8 3495
7a13e894
RS
3496 case MapNotify:
3497 /* We use x_top_window_to_frame because map events can come
3498 for subwindows and they don't mean that the frame is visible. */
3499 f = x_top_window_to_frame (event.xmap.window);
3500 if (f)
3501 {
3502 f->async_visible = 1;
3503 f->async_iconified = 0;
dc6f92b8 3504
7a13e894
RS
3505 /* wait_reading_process_input will notice this and update
3506 the frame's display structures. */
3507 SET_FRAME_GARBAGED (f);
bddd097c
KH
3508
3509 bufp->kind = deiconify_event;
3510 XSETFRAME (bufp->frame_or_window, f);
3511 bufp++;
3512 count++;
3513 numchars--;
7a13e894 3514 }
3afe33e7 3515#ifdef USE_X_TOOLKIT
7a13e894 3516 goto OTHER;
3afe33e7 3517#endif /* USE_X_TOOLKIT */
7a13e894 3518 break;
dc6f92b8 3519
7a13e894
RS
3520 /* Turn off processing if we become fully obscured. */
3521 case VisibilityNotify:
3522 break;
dc6f92b8 3523
7a13e894
RS
3524 case KeyPress:
3525 f = x_any_window_to_frame (event.xkey.window);
f451eb13 3526
7a13e894
RS
3527 if (f != 0)
3528 {
3529 KeySym keysym, orig_keysym;
3530 /* al%imercury@uunet.uu.net says that making this 81 instead of
3531 80 fixed a bug whereby meta chars made his Emacs hang. */
3532 unsigned char copy_buffer[81];
3533 int modifiers;
64bb1782 3534
7a13e894
RS
3535 event.xkey.state
3536 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
3537 extra_keyboard_modifiers);
3538 modifiers = event.xkey.state;
3a2712f9 3539
7a13e894 3540 /* This will have to go some day... */
752a043f 3541
7a13e894
RS
3542 /* make_lispy_event turns chars into control chars.
3543 Don't do it here because XLookupString is too eager. */
3544 event.xkey.state &= ~ControlMask;
0299d313
RS
3545 nbytes = XLookupString (&event.xkey, copy_buffer,
3546 80, &keysym, &compose_status);
dc6f92b8 3547
7a13e894 3548 orig_keysym = keysym;
55123275 3549
7a13e894
RS
3550 if (numchars > 1)
3551 {
3552 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
3553 || keysym == XK_Delete
3554 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
3555 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 3556#ifdef HPUX
7a13e894
RS
3557 /* This recognizes the "extended function keys".
3558 It seems there's no cleaner way.
3559 Test IsModifierKey to avoid handling mode_switch
3560 incorrectly. */
3561 || ((unsigned) (keysym) >= XK_Select
3562 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
3563#endif
3564#ifdef XK_dead_circumflex
7a13e894 3565 || orig_keysym == XK_dead_circumflex
69388238
RS
3566#endif
3567#ifdef XK_dead_grave
7a13e894 3568 || orig_keysym == XK_dead_grave
69388238
RS
3569#endif
3570#ifdef XK_dead_tilde
7a13e894 3571 || orig_keysym == XK_dead_tilde
69388238
RS
3572#endif
3573#ifdef XK_dead_diaeresis
7a13e894 3574 || orig_keysym == XK_dead_diaeresis
69388238
RS
3575#endif
3576#ifdef XK_dead_macron
7a13e894 3577 || orig_keysym == XK_dead_macron
69388238
RS
3578#endif
3579#ifdef XK_dead_degree
7a13e894 3580 || orig_keysym == XK_dead_degree
69388238
RS
3581#endif
3582#ifdef XK_dead_acute
7a13e894 3583 || orig_keysym == XK_dead_acute
69388238
RS
3584#endif
3585#ifdef XK_dead_cedilla
7a13e894 3586 || orig_keysym == XK_dead_cedilla
69388238
RS
3587#endif
3588#ifdef XK_dead_breve
7a13e894 3589 || orig_keysym == XK_dead_breve
69388238
RS
3590#endif
3591#ifdef XK_dead_ogonek
7a13e894 3592 || orig_keysym == XK_dead_ogonek
69388238
RS
3593#endif
3594#ifdef XK_dead_caron
7a13e894 3595 || orig_keysym == XK_dead_caron
69388238
RS
3596#endif
3597#ifdef XK_dead_doubleacute
7a13e894 3598 || orig_keysym == XK_dead_doubleacute
69388238
RS
3599#endif
3600#ifdef XK_dead_abovedot
7a13e894 3601 || orig_keysym == XK_dead_abovedot
c34790e0 3602#endif
7a13e894
RS
3603 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
3604 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
3605 /* Any "vendor-specific" key is ok. */
3606 || (orig_keysym & (1 << 28)))
3607 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
3608#ifndef HAVE_X11R5
3609#ifdef XK_Mode_switch
7a13e894 3610 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
3611#endif
3612#ifdef XK_Num_Lock
7a13e894 3613 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
3614#endif
3615#endif /* not HAVE_X11R5 */
7a13e894 3616 ))
dc6f92b8 3617 {
10e6549c
RS
3618 if (temp_index == sizeof temp_buffer / sizeof (short))
3619 temp_index = 0;
7a13e894
RS
3620 temp_buffer[temp_index++] = keysym;
3621 bufp->kind = non_ascii_keystroke;
3622 bufp->code = keysym;
e0c1aef2 3623 XSETFRAME (bufp->frame_or_window, f);
334208b7
RS
3624 bufp->modifiers
3625 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
3626 modifiers);
1113d9db 3627 bufp->timestamp = event.xkey.time;
dc6f92b8 3628 bufp++;
7a13e894
RS
3629 count++;
3630 numchars--;
dc6f92b8 3631 }
7a13e894
RS
3632 else if (numchars > nbytes)
3633 {
3634 register int i;
3635
3636 for (i = 0; i < nbytes; i++)
3637 {
3638 if (temp_index == sizeof temp_buffer / sizeof (short))
3639 temp_index = 0;
3640 temp_buffer[temp_index++] = copy_buffer[i];
3641 bufp->kind = ascii_keystroke;
3642 bufp->code = copy_buffer[i];
3643 XSETFRAME (bufp->frame_or_window, f);
3644 bufp->modifiers
3645 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
3646 modifiers);
3647 bufp->timestamp = event.xkey.time;
3648 bufp++;
3649 }
3650
3651 count += nbytes;
3652 numchars -= nbytes;
3653 }
3654 else
3655 abort ();
dc6f92b8 3656 }
10e6549c
RS
3657 else
3658 abort ();
dc6f92b8 3659 }
7a13e894 3660 break;
f451eb13 3661
7a13e894
RS
3662 /* Here's a possible interpretation of the whole
3663 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If you get a
3664 FocusIn event, you have to get a FocusOut event before you
3665 relinquish the focus. If you haven't received a FocusIn event,
3666 then a mere LeaveNotify is enough to free you. */
f451eb13 3667
7a13e894
RS
3668 case EnterNotify:
3669 f = x_any_window_to_frame (event.xcrossing.window);
6d4238f3 3670
7a13e894 3671 if (event.xcrossing.focus) /* Entered Window */
dc6f92b8 3672 {
7a13e894
RS
3673 /* Avoid nasty pop/raise loops. */
3674 if (f && (!(f->auto_raise)
3675 || !(f->auto_lower)
3676 || (event.xcrossing.time - enter_timestamp) > 500))
3677 {
3678 x_new_focus_frame (f);
3679 enter_timestamp = event.xcrossing.time;
3680 }
dc6f92b8 3681 }
7a13e894
RS
3682 else if (f == x_focus_frame)
3683 x_new_focus_frame (0);
3684 /* EnterNotify counts as mouse movement,
3685 so update things that depend on mouse position. */
3686 if (f)
3687 note_mouse_movement (f, &event.xmotion);
3afe33e7 3688#ifdef USE_X_TOOLKIT
7a13e894 3689 goto OTHER;
3afe33e7 3690#endif /* USE_X_TOOLKIT */
7a13e894 3691 break;
dc6f92b8 3692
7a13e894
RS
3693 case FocusIn:
3694 f = x_any_window_to_frame (event.xfocus.window);
3695 if (event.xfocus.detail != NotifyPointer)
3696 x_focus_event_frame = f;
3697 if (f)
3698 x_new_focus_frame (f);
3afe33e7 3699#ifdef USE_X_TOOLKIT
7a13e894 3700 goto OTHER;
3afe33e7 3701#endif /* USE_X_TOOLKIT */
7a13e894 3702 break;
f451eb13 3703
10c5e63d 3704
7a13e894
RS
3705 case LeaveNotify:
3706 f = x_top_window_to_frame (event.xcrossing.window);
3707 if (f)
10c5e63d 3708 {
7a13e894
RS
3709 if (f == dpyinfo->mouse_face_mouse_frame)
3710 /* If we move outside the frame,
3711 then we're certainly no longer on any text in the frame. */
3712 clear_mouse_face (dpyinfo);
3713
3714 if (event.xcrossing.focus)
37c2c98b 3715 x_mouse_leave ();
10c5e63d 3716 else
7a13e894
RS
3717 {
3718 if (f == x_focus_event_frame)
3719 x_focus_event_frame = 0;
3720 if (f == x_focus_frame)
3721 x_new_focus_frame (0);
3722 }
10c5e63d 3723 }
3afe33e7 3724#ifdef USE_X_TOOLKIT
7a13e894 3725 goto OTHER;
3afe33e7 3726#endif /* USE_X_TOOLKIT */
7a13e894 3727 break;
dc6f92b8 3728
7a13e894
RS
3729 case FocusOut:
3730 f = x_any_window_to_frame (event.xfocus.window);
3731 if (event.xfocus.detail != NotifyPointer
3732 && f == x_focus_event_frame)
3733 x_focus_event_frame = 0;
3734 if (f && f == x_focus_frame)
3735 x_new_focus_frame (0);
3afe33e7 3736#ifdef USE_X_TOOLKIT
7a13e894 3737 goto OTHER;
3afe33e7 3738#endif /* USE_X_TOOLKIT */
7a13e894 3739 break;
dc6f92b8 3740
7a13e894 3741 case MotionNotify:
dc6f92b8 3742 {
7a13e894
RS
3743 if (dpyinfo->grabbed && last_mouse_frame
3744 && FRAME_LIVE_P (last_mouse_frame))
3745 f = last_mouse_frame;
3746 else
3747 f = x_window_to_frame (event.xmotion.window);
3748 if (f)
3749 note_mouse_movement (f, &event.xmotion);
3750 else
3751 {
3752 struct scroll_bar *bar
3753 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 3754
7a13e894
RS
3755 if (bar)
3756 x_scroll_bar_note_movement (bar, &event);
b8009dd1 3757
7a13e894
RS
3758 /* If we move outside the frame,
3759 then we're certainly no longer on any text in the frame. */
3760 clear_mouse_face (dpyinfo);
3761 }
dc6f92b8 3762 }
0a178815 3763#if 0 /* This should be unnecessary, since the toolkit has no use
7a13e894
RS
3764 for motion events that happen outside of the menu event loop,
3765 and it seems to cause the bug that mouse events stop coming
3766 after a while. */
3afe33e7 3767#ifdef USE_X_TOOLKIT
7a13e894 3768 goto OTHER;
3afe33e7 3769#endif /* USE_X_TOOLKIT */
0a178815 3770#endif
7a13e894 3771 break;
dc6f92b8 3772
7a13e894
RS
3773 case ConfigureNotify:
3774 f = x_any_window_to_frame (event.xconfigure.window);
3afe33e7 3775#ifdef USE_X_TOOLKIT
7a13e894 3776 if (f
3a35ab44 3777#if 0
7a13e894 3778 && ! event.xconfigure.send_event
3a35ab44 3779#endif
7a13e894 3780 && (event.xconfigure.window == XtWindow (f->display.x->widget)))
af395ec1
RS
3781 {
3782 Window win, child;
3783 int win_x, win_y;
3784
6cc35d86
JB
3785 /* Find the position of the outside upper-left corner of
3786 the window, in the root coordinate system. Don't
3787 refer to the parent window here; we may be processing
3788 this event after the window manager has changed our
3789 parent, but before we have reached the ReparentNotify. */
334208b7 3790 XTranslateCoordinates (FRAME_X_DISPLAY (f),
58769bee 3791
af395ec1 3792 /* From-window, to-window. */
7a13e894 3793 XtWindow (f->display.x->widget),
334208b7 3794 FRAME_X_DISPLAY_INFO (f)->root_window,
af395ec1
RS
3795
3796 /* From-position, to-position. */
6cc35d86
JB
3797 -event.xconfigure.border_width,
3798 -event.xconfigure.border_width,
af395ec1
RS
3799 &win_x, &win_y,
3800
3801 /* Child of win. */
3802 &child);
3803 event.xconfigure.x = win_x;
3804 event.xconfigure.y = win_y;
7a13e894
RS
3805
3806 f->display.x->pixel_width = event.xconfigure.width;
3807 f->display.x->pixel_height = event.xconfigure.height;
3808 f->display.x->left_pos = event.xconfigure.x;
3809 f->display.x->top_pos = event.xconfigure.y;
3810
3811 /* What we have now is the position of Emacs's own window.
3812 Convert that to the position of the window manager window. */
3813 {
3814 int x, y;
3815 x_real_positions (f, &x, &y);
3816 f->display.x->left_pos = x;
3817 f->display.x->top_pos = y;
3818 }
af395ec1 3819 }
7a13e894
RS
3820 goto OTHER;
3821#else /* not USE_X_TOOLKIT */
3822 if (f)
3823 {
3824 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
3825 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
3826
3827 /* Even if the number of character rows and columns has
3828 not changed, the font size may have changed, so we need
3829 to check the pixel dimensions as well. */
3830 if (columns != f->width
3831 || rows != f->height
3832 || event.xconfigure.width != f->display.x->pixel_width
3833 || event.xconfigure.height != f->display.x->pixel_height)
3834 {
3835 change_frame_size (f, rows, columns, 0, 1);
3836 SET_FRAME_GARBAGED (f);
3837 }
af395ec1 3838
7a13e894
RS
3839 if (! event.xconfigure.send_event)
3840 {
3841 Window win, child;
3842 int win_x, win_y;
3843
3844 /* Find the position of the outside upper-left corner of
3845 the window, in the root coordinate system. Don't
3846 refer to the parent window here; we may be processing
3847 this event after the window manager has changed our
3848 parent, but before we have reached the ReparentNotify. */
3849 XTranslateCoordinates (FRAME_X_DISPLAY (f),
3850
3851 /* From-window, to-window. */
3852 f->display.x->window_desc,
3853 FRAME_X_DISPLAY_INFO (f)->root_window,
3854
3855 /* From-position, to-position. */
3856 -event.xconfigure.border_width,
3857 -event.xconfigure.border_width,
3858 &win_x, &win_y,
3859
3860 /* Child of win. */
3861 &child);
3862 event.xconfigure.x = win_x;
3863 event.xconfigure.y = win_y;
3864 }
3a35ab44 3865
7a13e894
RS
3866 f->display.x->pixel_width = event.xconfigure.width;
3867 f->display.x->pixel_height = event.xconfigure.height;
3868 f->display.x->left_pos = event.xconfigure.x;
3869 f->display.x->top_pos = event.xconfigure.y;
3870
3871 /* What we have now is the position of Emacs's own window.
3872 Convert that to the position of the window manager window. */
fd13dbb2 3873 {
7a13e894
RS
3874 int x, y;
3875 x_real_positions (f, &x, &y);
3876 f->display.x->left_pos = x;
3877 f->display.x->top_pos = y;
3878 if (y != event.xconfigure.y)
3879 {
3880 /* Since the WM decorations come below top_pos now,
3881 we must put them below top_pos in the future. */
3882 f->display.x->win_gravity = NorthWestGravity;
3883 x_wm_set_size_hint (f, 0, 0);
3884 }
fd13dbb2 3885 }
7a13e894 3886 }
3afe33e7 3887#endif /* not USE_X_TOOLKIT */
7a13e894 3888 break;
dc6f92b8 3889
7a13e894
RS
3890 case ButtonPress:
3891 case ButtonRelease:
3892 {
3893 /* If we decide we want to generate an event to be seen
3894 by the rest of Emacs, we put it here. */
3895 struct input_event emacs_event;
3896 emacs_event.kind = no_event;
dc6f92b8 3897
7a13e894 3898 bzero (&compose_status, sizeof (compose_status));
9b07615b 3899
9f67f20b
RS
3900 if (dpyinfo->grabbed && last_mouse_frame
3901 && FRAME_LIVE_P (last_mouse_frame))
3902 f = last_mouse_frame;
3903 else
3904 f = x_window_to_frame (event.xmotion.window);
3905
7a13e894
RS
3906 if (f)
3907 {
3908 if (!x_focus_frame || (f == x_focus_frame))
3909 construct_mouse_click (&emacs_event, &event, f);
3910 }
3911 else
3912 {
3913 struct scroll_bar *bar
3914 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 3915
7a13e894
RS
3916 if (bar)
3917 x_scroll_bar_handle_click (bar, &event, &emacs_event);
3afe33e7 3918#ifdef USE_X_TOOLKIT
7a13e894
RS
3919 else
3920 {
3921 /* Assume we have a menubar button press. A bad
3922 assumption should behave benignly. */
3923 popup_get_selection (&event);
3924 break;
3925 }
3926#endif /* USE_X_TOOLKIT */
3927 }
3928
3929 if (event.type == ButtonPress)
3930 {
3931 dpyinfo->grabbed |= (1 << event.xbutton.button);
3932 last_mouse_frame = f;
3933 }
3afe33e7
RS
3934 else
3935 {
7a13e894 3936 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 3937 }
23faf38f 3938
7a13e894
RS
3939 if (numchars >= 1 && emacs_event.kind != no_event)
3940 {
3941 bcopy (&emacs_event, bufp, sizeof (struct input_event));
3942 bufp++;
3943 count++;
3944 numchars--;
3945 }
3afe33e7
RS
3946
3947#ifdef USE_X_TOOLKIT
7a13e894 3948 goto OTHER;
3afe33e7 3949#endif /* USE_X_TOOLKIT */
7a13e894
RS
3950 }
3951 break;
dc6f92b8 3952
7a13e894
RS
3953 case CirculateNotify:
3954 break;
3955 case CirculateRequest:
3956 break;
dc6f92b8 3957
7a13e894
RS
3958 case MappingNotify:
3959 /* Someone has changed the keyboard mapping - update the
3960 local cache. */
3961 switch (event.xmapping.request)
3962 {
3963 case MappingModifier:
3964 x_find_modifier_meanings (dpyinfo);
3965 /* This is meant to fall through. */
3966 case MappingKeyboard:
3967 XRefreshKeyboardMapping (&event.xmapping);
3968 }
3afe33e7 3969#ifdef USE_X_TOOLKIT
7a13e894 3970 goto OTHER;
3afe33e7 3971#endif /* USE_X_TOOLKIT */
7a13e894 3972 break;
dc6f92b8 3973
7a13e894 3974 default:
3afe33e7 3975#ifdef USE_X_TOOLKIT
7a13e894
RS
3976 OTHER:
3977 BLOCK_INPUT;
3978 XtDispatchEvent (&event);
3979 UNBLOCK_INPUT;
3afe33e7 3980#endif /* USE_X_TOOLKIT */
7a13e894
RS
3981 break;
3982 }
dc6f92b8
JB
3983 }
3984 }
3985
9a5196d0
RS
3986 /* On some systems, an X bug causes Emacs to get no more events
3987 when the window is destroyed. Detect that. (1994.) */
58769bee 3988 if (! event_found)
ef2a22d0 3989 {
ef2a22d0
RS
3990 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
3991 One XNOOP in 100 loops will make Emacs terminate.
3992 B. Bretthauer, 1994 */
3993 x_noop_count++;
58769bee 3994 if (x_noop_count >= 100)
ef2a22d0
RS
3995 {
3996 x_noop_count=0;
7a13e894
RS
3997 /* Use the first display in the list. Why not? */
3998 XNoOp (x_display_list->display);
ef2a22d0
RS
3999 }
4000 }
502add23 4001
0134a210
RS
4002 /* If the focus was just given to an autoraising frame,
4003 raise it now. */
7a13e894 4004 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
4005 if (pending_autoraise_frame)
4006 {
4007 x_raise_frame (pending_autoraise_frame);
4008 pending_autoraise_frame = 0;
4009 }
0134a210 4010
dc6f92b8
JB
4011 UNBLOCK_INPUT;
4012 return count;
4013}
dc6f92b8 4014\f
f451eb13
JB
4015/* Drawing the cursor. */
4016
4017
dc6f92b8
JB
4018/* Draw a hollow box cursor. Don't change the inside of the box. */
4019
4020static void
f676886a
JB
4021x_draw_box (f)
4022 struct frame *f;
dc6f92b8 4023{
2a6cf806
RS
4024 int left = CHAR_TO_PIXEL_COL (f, curs_x);
4025 int top = CHAR_TO_PIXEL_ROW (f, curs_y);
f676886a 4026 int width = FONT_WIDTH (f->display.x->font);
a27f9f86 4027 int height = f->display.x->line_height;
dc6f92b8 4028
334208b7 4029 XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f676886a 4030 f->display.x->cursor_gc,
dc6f92b8 4031 left, top, width - 1, height - 1);
dc6f92b8
JB
4032}
4033
f676886a 4034/* Clear the cursor of frame F to background color,
dc6f92b8
JB
4035 and mark the cursor as not shown.
4036 This is used when the text where the cursor is
4037 is about to be rewritten. */
4038
4039static void
f676886a
JB
4040clear_cursor (f)
4041 struct frame *f;
dc6f92b8
JB
4042{
4043 int mask;
4044
f451eb13 4045 if (! FRAME_VISIBLE_P (f)
f676886a 4046 || f->phys_cursor_x < 0)
dc6f92b8
JB
4047 return;
4048
f676886a 4049 x_display_cursor (f, 0);
f676886a 4050 f->phys_cursor_x = -1;
dc6f92b8
JB
4051}
4052
f676886a 4053/* Redraw the glyph at ROW, COLUMN on frame F, in the style
90e65f07
JB
4054 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
4055 glyph drawn. */
dc6f92b8
JB
4056
4057static void
f676886a
JB
4058x_draw_single_glyph (f, row, column, glyph, highlight)
4059 struct frame *f;
dc6f92b8 4060 int row, column;
90e65f07 4061 GLYPH glyph;
dc6f92b8
JB
4062 int highlight;
4063{
f676886a 4064 dumpglyphs (f,
12ba150f
JB
4065 CHAR_TO_PIXEL_COL (f, column),
4066 CHAR_TO_PIXEL_ROW (f, row),
0cdd0c9f 4067 &glyph, 1, highlight, 0);
dc6f92b8
JB
4068}
4069
dc6f92b8 4070static void
dbc4e1c1 4071x_display_bar_cursor (f, on)
f676886a 4072 struct frame *f;
dc6f92b8
JB
4073 int on;
4074{
f676886a 4075 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
90e65f07 4076
49d838ea
JB
4077 /* This is pointless on invisible frames, and dangerous on garbaged
4078 frames; in the latter case, the frame may be in the midst of
4079 changing its size, and curs_x and curs_y may be off the frame. */
4080 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dbc4e1c1
JB
4081 return;
4082
4083 if (! on && f->phys_cursor_x < 0)
4084 return;
4085
f676886a 4086 /* If we're not updating, then we want to use the current frame's
1113d9db 4087 cursor position, not our local idea of where the cursor ought to be. */
f676886a 4088 if (f != updating_frame)
1113d9db 4089 {
f676886a
JB
4090 curs_x = FRAME_CURSOR_X (f);
4091 curs_y = FRAME_CURSOR_Y (f);
1113d9db
JB
4092 }
4093
dbc4e1c1
JB
4094 /* If there is anything wrong with the current cursor state, remove it. */
4095 if (f->phys_cursor_x >= 0
4096 && (!on
4097 || f->phys_cursor_x != curs_x
4098 || f->phys_cursor_y != curs_y
4099 || f->display.x->current_cursor != bar_cursor))
4100 {
4101 /* Erase the cursor by redrawing the character underneath it. */
4102 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4103 f->phys_cursor_glyph,
4104 current_glyphs->highlight[f->phys_cursor_y]);
4105 f->phys_cursor_x = -1;
4106 }
4107
4108 /* If we now need a cursor in the new place or in the new form, do it so. */
4109 if (on
4110 && (f->phys_cursor_x < 0
4111 || (f->display.x->current_cursor != bar_cursor)))
4112 {
4113 f->phys_cursor_glyph
4114 = ((current_glyphs->enable[curs_y]
4115 && curs_x < current_glyphs->used[curs_y])
4116 ? current_glyphs->glyphs[curs_y][curs_x]
4117 : SPACEGLYPH);
334208b7 4118 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
4119 f->display.x->cursor_gc,
4120 CHAR_TO_PIXEL_COL (f, curs_x),
4121 CHAR_TO_PIXEL_ROW (f, curs_y),
92e2441b
RS
4122 max (f->display.x->cursor_width, 1),
4123 f->display.x->line_height);
dbc4e1c1
JB
4124
4125 f->phys_cursor_x = curs_x;
4126 f->phys_cursor_y = curs_y;
4127
4128 f->display.x->current_cursor = bar_cursor;
4129 }
4130
4131 if (updating_frame != f)
334208b7 4132 XFlush (FRAME_X_DISPLAY (f));
dbc4e1c1
JB
4133}
4134
4135
4136/* Turn the displayed cursor of frame F on or off according to ON.
4137 If ON is nonzero, where to put the cursor is specified
4138 by F->cursor_x and F->cursor_y. */
4139
4140static void
4141x_display_box_cursor (f, on)
4142 struct frame *f;
4143 int on;
4144{
4145 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4146
49d838ea
JB
4147 /* This is pointless on invisible frames, and dangerous on garbaged
4148 frames; in the latter case, the frame may be in the midst of
4149 changing its size, and curs_x and curs_y may be off the frame. */
4150 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dc6f92b8
JB
4151 return;
4152
4153 /* If cursor is off and we want it off, return quickly. */
f676886a 4154 if (!on && f->phys_cursor_x < 0)
dc6f92b8
JB
4155 return;
4156
dbc4e1c1
JB
4157 /* If we're not updating, then we want to use the current frame's
4158 cursor position, not our local idea of where the cursor ought to be. */
4159 if (f != updating_frame)
4160 {
4161 curs_x = FRAME_CURSOR_X (f);
4162 curs_y = FRAME_CURSOR_Y (f);
4163 }
4164
dc6f92b8
JB
4165 /* If cursor is currently being shown and we don't want it to be
4166 or it is in the wrong place,
4167 or we want a hollow box and it's not so, (pout!)
4168 erase it. */
f676886a 4169 if (f->phys_cursor_x >= 0
dc6f92b8 4170 && (!on
f676886a
JB
4171 || f->phys_cursor_x != curs_x
4172 || f->phys_cursor_y != curs_y
dbc4e1c1 4173 || (f->display.x->current_cursor != hollow_box_cursor
f676886a 4174 && (f != x_highlight_frame))))
dc6f92b8 4175 {
79cf7456 4176 int mouse_face_here = 0;
9f67f20b 4177 struct frame_glyphs *active_glyphs = FRAME_CURRENT_GLYPHS (f);
79cf7456
RS
4178
4179 /* If the cursor is in the mouse face area, redisplay that when
4180 we clear the cursor. */
7a13e894 4181 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame
79cf7456 4182 &&
7a13e894
RS
4183 (f->phys_cursor_y > FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
4184 || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
4185 && f->phys_cursor_x >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col))
79cf7456 4186 &&
7a13e894
RS
4187 (f->phys_cursor_y < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
4188 || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
9f67f20b
RS
4189 && f->phys_cursor_x < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col))
4190 /* Don't redraw the cursor's spot in mouse face
4191 if it is at the end of a line (on a newline).
4192 The cursor appears there, but mouse highlighting does not. */
4193 && active_glyphs->used[f->phys_cursor_y] > f->phys_cursor_x)
79cf7456
RS
4194 mouse_face_here = 1;
4195
0cdd0c9f
RS
4196 /* If the font is not as tall as a whole line,
4197 we must explicitly clear the line's whole height. */
4198 if (FONT_HEIGHT (f->display.x->font) != f->display.x->line_height)
334208b7 4199 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
0cdd0c9f
RS
4200 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
4201 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
4202 FONT_WIDTH (f->display.x->font),
4203 f->display.x->line_height, False);
dc6f92b8 4204 /* Erase the cursor by redrawing the character underneath it. */
f676886a
JB
4205 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4206 f->phys_cursor_glyph,
79cf7456
RS
4207 (mouse_face_here
4208 ? 3
4209 : current_glyphs->highlight[f->phys_cursor_y]));
f676886a 4210 f->phys_cursor_x = -1;
dc6f92b8
JB
4211 }
4212
4213 /* If we want to show a cursor,
4214 or we want a box cursor and it's not so,
4215 write it in the right place. */
4216 if (on
f676886a 4217 && (f->phys_cursor_x < 0
dbc4e1c1 4218 || (f->display.x->current_cursor != filled_box_cursor
f676886a 4219 && f == x_highlight_frame)))
dc6f92b8 4220 {
f676886a 4221 f->phys_cursor_glyph
1113d9db
JB
4222 = ((current_glyphs->enable[curs_y]
4223 && curs_x < current_glyphs->used[curs_y])
4224 ? current_glyphs->glyphs[curs_y][curs_x]
90e65f07 4225 : SPACEGLYPH);
f676886a 4226 if (f != x_highlight_frame)
dc6f92b8 4227 {
f676886a 4228 x_draw_box (f);
dbc4e1c1 4229 f->display.x->current_cursor = hollow_box_cursor;
dc6f92b8
JB
4230 }
4231 else
4232 {
f676886a
JB
4233 x_draw_single_glyph (f, curs_y, curs_x,
4234 f->phys_cursor_glyph, 2);
dbc4e1c1 4235 f->display.x->current_cursor = filled_box_cursor;
dc6f92b8
JB
4236 }
4237
f676886a
JB
4238 f->phys_cursor_x = curs_x;
4239 f->phys_cursor_y = curs_y;
dc6f92b8
JB
4240 }
4241
f676886a 4242 if (updating_frame != f)
334208b7 4243 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
4244}
4245
f676886a
JB
4246x_display_cursor (f, on)
4247 struct frame *f;
dc6f92b8
JB
4248 int on;
4249{
f94397b5
KH
4250 BLOCK_INPUT;
4251
dbc4e1c1 4252 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
f676886a 4253 x_display_box_cursor (f, on);
dbc4e1c1 4254 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
f676886a 4255 x_display_bar_cursor (f, on);
dbc4e1c1
JB
4256 else
4257 /* Those are the only two we have implemented! */
4258 abort ();
f94397b5
KH
4259
4260 UNBLOCK_INPUT;
dc6f92b8
JB
4261}
4262\f
4263/* Icons. */
4264
f676886a 4265/* Refresh bitmap kitchen sink icon for frame F
dc6f92b8
JB
4266 when we get an expose event for it. */
4267
f676886a
JB
4268refreshicon (f)
4269 struct frame *f;
dc6f92b8 4270{
dc6f92b8 4271 /* Normally, the window manager handles this function. */
dc6f92b8
JB
4272}
4273
dbc4e1c1 4274/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
4275
4276int
990ba854 4277x_bitmap_icon (f, file)
f676886a 4278 struct frame *f;
990ba854 4279 Lisp_Object file;
dc6f92b8 4280{
7f2ae036 4281 int mask, bitmap_id;
dc6f92b8
JB
4282 Window icon_window;
4283
c118dd06 4284 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
4285 return 1;
4286
990ba854
RS
4287 /* Free up our existing icon bitmap if any. */
4288 if (f->display.x->icon_bitmap > 0)
4289 x_destroy_bitmap (f, f->display.x->icon_bitmap);
4290 f->display.x->icon_bitmap = 0;
4291
4292 if (STRINGP (file))
7f2ae036
RS
4293 bitmap_id = x_create_bitmap_from_file (f, file);
4294 else
4295 {
990ba854 4296 /* Create the GNU bitmap if necessary. */
5bf01b68 4297 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
4298 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
4299 = x_create_bitmap_from_data (f, gnu_bits,
4300 gnu_width, gnu_height);
990ba854
RS
4301
4302 /* The first time we create the GNU bitmap,
4303 this increments the refcount one extra time.
4304 As a result, the GNU bitmap is never freed.
4305 That way, we don't have to worry about allocating it again. */
334208b7 4306 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 4307
334208b7 4308 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
4309 }
4310
4311 x_wm_set_icon_pixmap (f, bitmap_id);
4312 f->display.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
4313
4314 return 0;
4315}
4316
4317
f676886a 4318/* Make the x-window of frame F use a rectangle with text. */
dc6f92b8
JB
4319
4320int
f676886a
JB
4321x_text_icon (f, icon_name)
4322 struct frame *f;
dc6f92b8
JB
4323 char *icon_name;
4324{
c118dd06 4325 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
4326 return 1;
4327
dc6f92b8 4328 if (icon_name)
f676886a 4329 f->display.x->icon_label = icon_name;
dc6f92b8 4330 else
f676886a
JB
4331 if (! f->display.x->icon_label)
4332 f->display.x->icon_label = " *emacs* ";
58769bee 4333
dfeccd2d 4334#if 0
334208b7 4335 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f676886a 4336 (char *) f->display.x->icon_label);
dfeccd2d 4337#endif
58769bee 4338
990ba854
RS
4339 if (f->display.x->icon_bitmap > 0)
4340 x_destroy_bitmap (f, f->display.x->icon_bitmap);
7f2ae036 4341 f->display.x->icon_bitmap = 0;
b1c884c3 4342 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
4343
4344 return 0;
4345}
4346\f
4746118a
JB
4347/* Handling X errors. */
4348
7a13e894 4349/* Handle the loss of connection to display DISPLAY. */
16bd92ea 4350
4746118a 4351static SIGTYPE
7a13e894
RS
4352x_connection_closed (display, error_message)
4353 Display *display;
4354 char *error_message;
4746118a 4355{
7a13e894
RS
4356 struct x_display_info *dpyinfo = x_display_info_for_display (display);
4357 Lisp_Object frame, tail;
4358
4746118a
JB
4359 if (_Xdebug)
4360 abort ();
12ba150f 4361
7a13e894
RS
4362 /* First delete frames whose minibuffers are on frames
4363 that are on the dead display. */
4364 FOR_EACH_FRAME (tail, frame)
4365 {
4366 Lisp_Object minibuf_frame;
4367 minibuf_frame
4368 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
4369 if (FRAME_X_P (XFRAME (frame))
4370 && FRAME_X_P (XFRAME (minibuf_frame))
4371 && ! EQ (frame, minibuf_frame)
4372 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
4373 Fdelete_frame (frame, Qt);
4374 }
4375
4376 /* Now delete all remaining frames on the dead display.
4377 We are now sure none of these is used as the minibuffer
4378 for another frame that we need to delete. */
4379 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
4380 if (FRAME_X_P (XFRAME (frame))
4381 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
7a13e894
RS
4382 Fdelete_frame (frame, Qt);
4383
4384 x_delete_display (dpyinfo);
4385
4386 if (x_display_list == 0)
4387 {
4388 fprintf (stderr, "%s", error_message);
4389 shut_down_emacs (0, 0, Qnil);
4390 exit (70);
4391 }
12ba150f 4392
7a13e894
RS
4393 /* Ordinary stack unwind doesn't deal with these. */
4394#ifdef SIGIO
4395 sigunblock (sigmask (SIGIO));
4396#endif
4397 sigunblock (sigmask (SIGALRM));
4398 TOTALLY_UNBLOCK_INPUT;
4399
4400 error ("%s", error_message);
4746118a
JB
4401}
4402
92e2441b
RS
4403static SIGTYPE
4404x_connection_signal (signalnum) /* If we don't have an argument, */
4405 int signalnum; /* some compilers complain in signal calls. */
4406{
4407 /* We really ought to close the connection to the display
4408 that actually failed.
4409 But do we actually get this signal ever with X11? */
4410 fprintf (stderr, "X connection closed");
4411 shut_down_emacs (0, 0, Qnil);
4412 exit (70);
4413}
4414
7a13e894
RS
4415/* This is the usual handler for X protocol errors.
4416 It kills all frames on the display that we got the error for.
4417 If that was the only one, it prints an error message and kills Emacs. */
4418
c118dd06
JB
4419static int
4420x_error_quitter (display, error)
4421 Display *display;
4422 XErrorEvent *error;
4423{
7a13e894 4424 char buf[256], buf1[356];
dc6f92b8 4425
58769bee 4426 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 4427 original error handler. */
dc6f92b8 4428
c118dd06 4429 XGetErrorText (display, error->error_code, buf, sizeof (buf));
7a13e894 4430 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 4431 buf, error->request_code);
7a13e894 4432 x_connection_closed (display, buf1);
dc6f92b8
JB
4433}
4434
7a13e894
RS
4435/* This is the handler for X IO errors, always.
4436 It kills all frames on the display that we lost touch with.
4437 If that was the only one, it prints an error message and kills Emacs. */
4438
8922af5f
JB
4439static int
4440x_io_error_quitter (display)
4441 Display *display;
4442{
7a13e894 4443 char buf[256];
8922af5f 4444
7a13e894
RS
4445 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
4446 x_connection_closed (display, buf);
8922af5f 4447}
7a13e894 4448\f
c118dd06 4449/* A buffer for storing X error messages. */
cef13e55
RS
4450static char *x_caught_error_message;
4451#define X_CAUGHT_ERROR_MESSAGE_SIZE 200
c118dd06
JB
4452
4453/* An X error handler which stores the error message in
4454 x_caught_error_message. This is what's installed when
4455 x_catch_errors is in effect. */
7a13e894 4456
c118dd06
JB
4457static int
4458x_error_catcher (display, error)
4459 Display *display;
4460 XErrorEvent *error;
4461{
4462 XGetErrorText (display, error->error_code,
cef13e55 4463 x_caught_error_message, X_CAUGHT_ERROR_MESSAGE_SIZE);
c118dd06
JB
4464}
4465
4466
7a13e894
RS
4467/* Begin trapping X errors for display DPY. Actually we trap X errors
4468 for all displays, but DPY should be the display you are actually
4469 operating on.
dc6f92b8 4470
c118dd06
JB
4471 After calling this function, X protocol errors no longer cause
4472 Emacs to exit; instead, they are recorded in x_cfc_error_message.
dc6f92b8 4473
c118dd06
JB
4474 Calling x_check_errors signals an Emacs error if an X error has
4475 occurred since the last call to x_catch_errors or x_check_errors.
4476
4477 Calling x_uncatch_errors resumes the normal error handling. */
4478
bc20ebbf 4479void x_catch_errors (), x_check_errors (), x_uncatch_errors ();
c118dd06
JB
4480
4481void
7a13e894
RS
4482x_catch_errors (dpy)
4483 Display *dpy;
dc6f92b8 4484{
c118dd06 4485 /* Make sure any errors from previous requests have been dealt with. */
7a13e894 4486 XSync (dpy, False);
dc6f92b8 4487
c118dd06 4488 /* Set up the error buffer. */
60f9aad3 4489 x_caught_error_message
cef13e55
RS
4490 = (char*) xmalloc (X_CAUGHT_ERROR_MESSAGE_SIZE);
4491 x_caught_error_message[0] = '\0';
16bd92ea 4492
c118dd06 4493 /* Install our little error handler. */
334208b7 4494 XSetErrorHandler (x_error_catcher);
c118dd06 4495}
16bd92ea 4496
c118dd06
JB
4497/* If any X protocol errors have arrived since the last call to
4498 x_catch_errors or x_check_errors, signal an Emacs error using
4499 sprintf (a buffer, FORMAT, the x error message text) as the text. */
812361a1 4500
c118dd06 4501void
7a13e894
RS
4502x_check_errors (dpy, format)
4503 Display *dpy;
c118dd06
JB
4504 char *format;
4505{
4506 /* Make sure to catch any errors incurred so far. */
7a13e894 4507 XSync (dpy, False);
16bd92ea 4508
cef13e55 4509 if (x_caught_error_message[0])
c118dd06 4510 {
cef13e55 4511 char buf[X_CAUGHT_ERROR_MESSAGE_SIZE + 56];
dc6f92b8 4512
cef13e55 4513 sprintf (buf, format, x_caught_error_message);
7a13e894 4514 x_uncatch_errors (dpy);
c118dd06
JB
4515 error (buf);
4516 }
4517}
4518
b849c413
RS
4519/* Nonzero if we had any X protocol errors since we did x_catch_errors. */
4520
4521int
7a13e894
RS
4522x_had_errors_p (dpy)
4523 Display *dpy;
b849c413
RS
4524{
4525 /* Make sure to catch any errors incurred so far. */
7a13e894 4526 XSync (dpy, False);
b849c413
RS
4527
4528 return x_caught_error_message[0] != 0;
4529}
4530
812361a1
RS
4531/* Stop catching X protocol errors and let them make Emacs die. */
4532
c118dd06 4533void
7a13e894
RS
4534x_uncatch_errors (dpy)
4535 Display *dpy;
c118dd06 4536{
9ac0d9e0 4537 xfree (x_caught_error_message);
cef13e55 4538 x_caught_error_message = 0;
334208b7 4539 XSetErrorHandler (x_error_quitter);
dc6f92b8
JB
4540}
4541
dc6f92b8
JB
4542#if 0
4543static unsigned int x_wire_count;
4544x_trace_wire ()
4545{
4546 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
4547}
c118dd06 4548#endif /* ! 0 */
dc6f92b8
JB
4549
4550\f
f451eb13
JB
4551/* Changing the font of the frame. */
4552
76bcdf39
RS
4553/* Give frame F the font named FONTNAME as its default font, and
4554 return the full name of that font. FONTNAME may be a wildcard
4555 pattern; in that case, we choose some font that fits the pattern.
4556 The return value shows which font we chose. */
4557
b5cf7a0e 4558Lisp_Object
f676886a
JB
4559x_new_font (f, fontname)
4560 struct frame *f;
dc6f92b8
JB
4561 register char *fontname;
4562{
dc6f92b8
JB
4563 int already_loaded;
4564 int n_matching_fonts;
4565 XFontStruct *font_info;
4566 char **font_names;
4567
4568 /* Get a list of all the fonts that match this name. Once we
4569 have a list of matching fonts, we compare them against the fonts
4570 we already have by comparing font ids. */
334208b7 4571 font_names = (char **) XListFonts (FRAME_X_DISPLAY (f), fontname,
2224a5fc 4572 1024, &n_matching_fonts);
0c94f6ee
JB
4573 /* Apparently it doesn't set n_matching_fonts to zero when it can't
4574 find any matches; font_names == 0 is the only clue. */
4575 if (! font_names)
4576 n_matching_fonts = 0;
4577
5835f860
RS
4578 /* Don't just give up if n_matching_fonts is 0.
4579 Apparently there's a bug on Suns: XListFontsWithInfo can
4580 fail to find a font, but XLoadQueryFont may still find it. */
dc6f92b8 4581
90e65f07 4582 /* See if we've already loaded a matching font. */
5835f860
RS
4583 already_loaded = -1;
4584 if (n_matching_fonts != 0)
4585 {
4586 int i, j;
dc6f92b8 4587
7a13e894 4588 for (i = 0; i < FRAME_X_DISPLAY_INFO (f)->n_fonts; i++)
5835f860 4589 for (j = 0; j < n_matching_fonts; j++)
7a13e894
RS
4590 if (!strcmp (FRAME_X_DISPLAY_INFO (f)->font_table[i].name, font_names[j])
4591 || !strcmp (FRAME_X_DISPLAY_INFO (f)->font_table[i].full_name, font_names[j]))
5835f860
RS
4592 {
4593 already_loaded = i;
7a13e894 4594 fontname = FRAME_X_DISPLAY_INFO (f)->font_table[i].full_name;
5835f860
RS
4595 goto found_font;
4596 }
4597 }
dc6f92b8 4598 found_font:
58769bee 4599
dc6f92b8 4600 /* If we have, just return it from the table. */
2224a5fc 4601 if (already_loaded >= 0)
7a13e894 4602 f->display.x->font = FRAME_X_DISPLAY_INFO (f)->font_table[already_loaded].font;
dc6f92b8
JB
4603 /* Otherwise, load the font and add it to the table. */
4604 else
4605 {
9696f58b 4606 int i;
76bcdf39 4607 char *full_name;
dc6f92b8 4608 XFontStruct *font;
7a13e894 4609 int n_fonts;
dc6f92b8 4610
9696f58b 4611 /* Try to find a character-cell font in the list. */
58769bee 4612#if 0
f126bd67 4613 /* A laudable goal, but this isn't how to do it. */
9696f58b
JB
4614 for (i = 0; i < n_matching_fonts; i++)
4615 if (! font_info[i].per_char)
4616 break;
f126bd67
JB
4617#else
4618 i = 0;
4619#endif
9696f58b 4620
5835f860
RS
4621 /* See comment above. */
4622 if (n_matching_fonts != 0)
9696f58b
JB
4623 fontname = font_names[i];
4624
334208b7 4625 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
dc6f92b8 4626 if (! font)
5835f860 4627 {
2224a5fc 4628 /* Free the information from XListFonts. */
5835f860 4629 if (n_matching_fonts)
2224a5fc 4630 XFreeFontNames (font_names);
5835f860
RS
4631 return Qnil;
4632 }
dc6f92b8
JB
4633
4634 /* Do we need to create the table? */
7a13e894 4635 if (FRAME_X_DISPLAY_INFO (f)->font_table_size == 0)
dc6f92b8 4636 {
7a13e894
RS
4637 FRAME_X_DISPLAY_INFO (f)->font_table_size = 16;
4638 FRAME_X_DISPLAY_INFO (f)->font_table
4639 = (struct font_info *) xmalloc (FRAME_X_DISPLAY_INFO (f)->font_table_size
4640 * sizeof (struct font_info));
dc6f92b8
JB
4641 }
4642 /* Do we need to grow the table? */
7a13e894
RS
4643 else if (FRAME_X_DISPLAY_INFO (f)->n_fonts
4644 >= FRAME_X_DISPLAY_INFO (f)->font_table_size)
dc6f92b8 4645 {
7a13e894
RS
4646 FRAME_X_DISPLAY_INFO (f)->font_table_size *= 2;
4647 FRAME_X_DISPLAY_INFO (f)->font_table
4648 = (struct font_info *) xrealloc (FRAME_X_DISPLAY_INFO (f)->font_table,
4649 (FRAME_X_DISPLAY_INFO (f)->font_table_size
4650 * sizeof (struct font_info)));
dc6f92b8
JB
4651 }
4652
76bcdf39
RS
4653 /* Try to get the full name of FONT. Put it in full_name. */
4654 full_name = 0;
4655 for (i = 0; i < font->n_properties; i++)
4656 {
4657 char *atom
334208b7 4658 = XGetAtomName (FRAME_X_DISPLAY (f), font->properties[i].name);
76bcdf39 4659 if (!strcmp (atom, "FONT"))
7965883b 4660 {
334208b7 4661 char *name = XGetAtomName (FRAME_X_DISPLAY (f),
7965883b
RS
4662 (Atom) (font->properties[i].card32));
4663 char *p = name;
4664 int dashes = 0;
4665
4666 /* Count the number of dashes in the "full name".
4667 If it is too few, this isn't really the font's full name,
4668 so don't use it.
4669 In X11R4, the fonts did not come with their canonical names
4670 stored in them. */
4671 while (*p)
4672 {
4673 if (*p == '-')
4674 dashes++;
4675 p++;
4676 }
4677
4678 if (dashes >= 13)
4679 full_name = name;
8ed24d5a
RS
4680
4681 break;
7965883b
RS
4682 }
4683
76bcdf39
RS
4684 XFree (atom);
4685 }
4686
7a13e894
RS
4687 n_fonts = FRAME_X_DISPLAY_INFO (f)->n_fonts;
4688 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name = (char *) xmalloc (strlen (fontname) + 1);
4689 bcopy (fontname, FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name, strlen (fontname) + 1);
76bcdf39 4690 if (full_name != 0)
7a13e894 4691 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].full_name = full_name;
76bcdf39 4692 else
7a13e894
RS
4693 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].full_name = FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name;
4694 f->display.x->font = FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].font = font;
4695 FRAME_X_DISPLAY_INFO (f)->n_fonts++;
76bcdf39 4696
d53067dc
RS
4697 if (full_name)
4698 fontname = full_name;
dc6f92b8 4699 }
2224a5fc 4700
b2cad826
KH
4701 /* Compute the scroll bar width in character columns. */
4702 if (f->scroll_bar_pixel_width > 0)
4703 {
4704 int wid = FONT_WIDTH (f->display.x->font);
4705 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
4706 }
4707 else
4708 f->scroll_bar_cols = 2;
4709
f676886a 4710 /* Now make the frame display the given font. */
c118dd06 4711 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 4712 {
334208b7 4713 XSetFont (FRAME_X_DISPLAY (f), f->display.x->normal_gc,
f676886a 4714 f->display.x->font->fid);
334208b7 4715 XSetFont (FRAME_X_DISPLAY (f), f->display.x->reverse_gc,
f676886a 4716 f->display.x->font->fid);
334208b7 4717 XSetFont (FRAME_X_DISPLAY (f), f->display.x->cursor_gc,
f676886a
JB
4718 f->display.x->font->fid);
4719
a27f9f86 4720 frame_update_line_height (f);
0134a210 4721 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 4722 }
a27f9f86
RS
4723 else
4724 /* If we are setting a new frame's font for the first time,
4725 there are no faces yet, so this font's height is the line height. */
0cdd0c9f 4726 f->display.x->line_height = FONT_HEIGHT (f->display.x->font);
dc6f92b8 4727
b5cf7a0e 4728 {
abdda982 4729 Lisp_Object lispy_name;
b5cf7a0e 4730
abdda982 4731 lispy_name = build_string (fontname);
b5cf7a0e 4732
2224a5fc 4733 /* Free the information from XListFonts. The data
b5cf7a0e 4734 we actually retain comes from XLoadQueryFont. */
2224a5fc 4735 XFreeFontNames (font_names);
b5cf7a0e
JB
4736
4737 return lispy_name;
4738 }
dc6f92b8 4739}
dc6f92b8 4740\f
43bca5d5 4741x_calc_absolute_position (f)
f676886a 4742 struct frame *f;
dc6f92b8 4743{
6dba1858
RS
4744 Window win, child;
4745 int win_x = 0, win_y = 0;
43bca5d5 4746 int flags = f->display.x->size_hint_flags;
6dba1858
RS
4747
4748 /* Find the position of the outside upper-left corner of
4749 the inner window, with respect to the outer window. */
334208b7 4750 if (f->display.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858
RS
4751 {
4752 BLOCK_INPUT;
334208b7 4753 XTranslateCoordinates (FRAME_X_DISPLAY (f),
58769bee 4754
6dba1858
RS
4755 /* From-window, to-window. */
4756 f->display.x->window_desc,
4757 f->display.x->parent_desc,
4758
4759 /* From-position, to-position. */
4760 0, 0, &win_x, &win_y,
4761
4762 /* Child of win. */
4763 &child);
4764 UNBLOCK_INPUT;
4765 }
4766
4767 /* Treat negative positions as relative to the leftmost bottommost
4768 position that fits on the screen. */
20f55f9a 4769 if (flags & XNegative)
334208b7 4770 f->display.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
69388238 4771 - 2 * f->display.x->border_width - win_x
31ea78fd
JB
4772 - PIXEL_WIDTH (f)
4773 + f->display.x->left_pos);
dc6f92b8 4774
20f55f9a 4775 if (flags & YNegative)
334208b7 4776 f->display.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
69388238 4777 - 2 * f->display.x->border_width - win_y
31ea78fd
JB
4778 - PIXEL_HEIGHT (f)
4779 + f->display.x->top_pos);
3a35ab44
RS
4780 /* The left_pos and top_pos
4781 are now relative to the top and left screen edges,
4782 so the flags should correspond. */
4783 f->display.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
4784}
4785
3a35ab44
RS
4786/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
4787 to really change the position, and 0 when calling from
4788 x_make_frame_visible (in that case, XOFF and YOFF are the current
4789 position values). */
4790
dc05a16b 4791x_set_offset (f, xoff, yoff, change_gravity)
f676886a 4792 struct frame *f;
dc6f92b8 4793 register int xoff, yoff;
dc05a16b 4794 int change_gravity;
dc6f92b8 4795{
3a35ab44
RS
4796 if (change_gravity)
4797 {
4798 f->display.x->top_pos = yoff;
4799 f->display.x->left_pos = xoff;
4800 f->display.x->size_hint_flags &= ~ (XNegative | YNegative);
4801 if (xoff < 0)
4802 f->display.x->size_hint_flags |= XNegative;
4803 if (yoff < 0)
4804 f->display.x->size_hint_flags |= YNegative;
4805 f->display.x->win_gravity = NorthWestGravity;
4806 }
43bca5d5 4807 x_calc_absolute_position (f);
dc6f92b8
JB
4808
4809 BLOCK_INPUT;
3a35ab44
RS
4810 x_wm_set_size_hint (f, 0, 0);
4811
3afe33e7 4812#ifdef USE_X_TOOLKIT
334208b7 4813 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget),
3afe33e7
RS
4814 f->display.x->left_pos, f->display.x->top_pos);
4815#else /* not USE_X_TOOLKIT */
334208b7 4816 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f676886a 4817 f->display.x->left_pos, f->display.x->top_pos);
3afe33e7 4818#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
4819 UNBLOCK_INPUT;
4820}
4821
bc20ebbf
FP
4822/* Call this to change the size of frame F's x-window.
4823 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
4824 for this size change and subsequent size changes.
4825 Otherwise we leave the window gravity unchanged. */
dc6f92b8 4826
bc20ebbf 4827x_set_window_size (f, change_gravity, cols, rows)
f676886a 4828 struct frame *f;
bc20ebbf 4829 int change_gravity;
b1c884c3 4830 int cols, rows;
dc6f92b8
JB
4831{
4832 int pixelwidth, pixelheight;
4833 int mask;
dc6f92b8 4834
80fd1fe2
FP
4835#ifdef USE_X_TOOLKIT
4836 BLOCK_INPUT;
3a20653d
RS
4837 {
4838 /* The x and y position of the widget is clobbered by the
4839 call to XtSetValues within EmacsFrameSetCharSize.
4840 This is a real kludge, but I don't understand Xt so I can't
4841 figure out a correct fix. Can anyone else tell me? -- rms. */
4842 int xpos = f->display.x->widget->core.x;
4843 int ypos = f->display.x->widget->core.y;
4844 EmacsFrameSetCharSize (f->display.x->edit_widget, cols, rows);
4845 f->display.x->widget->core.x = xpos;
4846 f->display.x->widget->core.y = ypos;
4847 }
80fd1fe2
FP
4848 UNBLOCK_INPUT;
4849
4850#else /* not USE_X_TOOLKIT */
4851
dc6f92b8
JB
4852 BLOCK_INPUT;
4853
b1c884c3 4854 check_frame_size (f, &rows, &cols);
6dba1858 4855 f->display.x->vertical_scroll_bar_extra
b2cad826
KH
4856 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4857 ? 0
4858 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 4859 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
b2cad826 4860 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->display.x->font)));
f451eb13
JB
4861 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
4862 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 4863
af31d76f
RS
4864 f->display.x->win_gravity = NorthWestGravity;
4865 x_wm_set_size_hint (f, 0, 0);
6ccf47d1 4866
334208b7
RS
4867 XSync (FRAME_X_DISPLAY (f), False);
4868 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4869 pixelwidth, pixelheight);
b1c884c3
JB
4870
4871 /* Now, strictly speaking, we can't be sure that this is accurate,
4872 but the window manager will get around to dealing with the size
4873 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
4874 ConfigureNotify event gets here.
4875
4876 We could just not bother storing any of this information here,
4877 and let the ConfigureNotify event set everything up, but that
4878 might be kind of confusing to the lisp code, since size changes
4879 wouldn't be reported in the frame parameters until some random
4880 point in the future when the ConfigureNotify event arrives. */
8922af5f 4881 change_frame_size (f, rows, cols, 0, 0);
b1c884c3
JB
4882 PIXEL_WIDTH (f) = pixelwidth;
4883 PIXEL_HEIGHT (f) = pixelheight;
4884
4d73d038
RS
4885 /* If cursor was outside the new size, mark it as off. */
4886 if (f->phys_cursor_y >= rows
4887 || f->phys_cursor_x >= cols)
4888 {
4889 f->phys_cursor_x = -1;
4890 f->phys_cursor_y = -1;
4891 }
4892
dbc4e1c1
JB
4893 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
4894 receive in the ConfigureNotify event; if we get what we asked
4895 for, then the event won't cause the screen to become garbaged, so
4896 we have to make sure to do it here. */
4897 SET_FRAME_GARBAGED (f);
4898
334208b7 4899 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 4900 UNBLOCK_INPUT;
80fd1fe2 4901#endif /* not USE_X_TOOLKIT */
dc6f92b8 4902}
dc6f92b8 4903\f
f451eb13 4904/* Mouse warping, focus shifting, raising and lowering. */
dc6f92b8 4905
9b378208 4906void
f676886a
JB
4907x_set_mouse_position (f, x, y)
4908 struct frame *f;
dc6f92b8
JB
4909 int x, y;
4910{
4911 int pix_x, pix_y;
4912
12ba150f 4913 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2;
a27f9f86 4914 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->display.x->line_height / 2;
f451eb13
JB
4915
4916 if (pix_x < 0) pix_x = 0;
4917 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
4918
4919 if (pix_y < 0) pix_y = 0;
4920 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
4921
4922 BLOCK_INPUT;
dc6f92b8 4923
334208b7
RS
4924 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
4925 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
4926 UNBLOCK_INPUT;
4927}
4928
9b378208
RS
4929/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
4930
4931void
4932x_set_mouse_pixel_position (f, pix_x, pix_y)
4933 struct frame *f;
4934 int pix_x, pix_y;
4935{
4936 BLOCK_INPUT;
4937
334208b7
RS
4938 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
4939 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
4940 UNBLOCK_INPUT;
4941}
4942
f676886a
JB
4943x_focus_on_frame (f)
4944 struct frame *f;
dc6f92b8 4945{
1fb20991 4946#if 0 /* This proves to be unpleasant. */
f676886a 4947 x_raise_frame (f);
1fb20991 4948#endif
6d4238f3
JB
4949#if 0
4950 /* I don't think that the ICCCM allows programs to do things like this
4951 without the interaction of the window manager. Whatever you end up
f676886a 4952 doing with this code, do it to x_unfocus_frame too. */
334208b7 4953 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 4954 RevertToPointerRoot, CurrentTime);
c118dd06 4955#endif /* ! 0 */
dc6f92b8
JB
4956}
4957
f676886a
JB
4958x_unfocus_frame (f)
4959 struct frame *f;
dc6f92b8 4960{
6d4238f3 4961#if 0
f676886a
JB
4962 /* Look at the remarks in x_focus_on_frame. */
4963 if (x_focus_frame == f)
334208b7 4964 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 4965 RevertToPointerRoot, CurrentTime);
c118dd06 4966#endif /* ! 0 */
dc6f92b8
JB
4967}
4968
f676886a 4969/* Raise frame F. */
dc6f92b8 4970
f676886a
JB
4971x_raise_frame (f)
4972 struct frame *f;
dc6f92b8 4973{
3a88c238 4974 if (f->async_visible)
dc6f92b8
JB
4975 {
4976 BLOCK_INPUT;
3afe33e7 4977#ifdef USE_X_TOOLKIT
334208b7 4978 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget));
3afe33e7 4979#else /* not USE_X_TOOLKIT */
334208b7 4980 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 4981#endif /* not USE_X_TOOLKIT */
334208b7 4982 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
4983 UNBLOCK_INPUT;
4984 }
4985}
4986
f676886a 4987/* Lower frame F. */
dc6f92b8 4988
f676886a
JB
4989x_lower_frame (f)
4990 struct frame *f;
dc6f92b8 4991{
3a88c238 4992 if (f->async_visible)
dc6f92b8
JB
4993 {
4994 BLOCK_INPUT;
3afe33e7 4995#ifdef USE_X_TOOLKIT
334208b7 4996 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget));
3afe33e7 4997#else /* not USE_X_TOOLKIT */
334208b7 4998 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 4999#endif /* not USE_X_TOOLKIT */
334208b7 5000 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
5001 UNBLOCK_INPUT;
5002 }
5003}
5004
dbc4e1c1
JB
5005static void
5006XTframe_raise_lower (f, raise)
5007 FRAME_PTR f;
5008 int raise;
5009{
5010 if (raise)
5011 x_raise_frame (f);
5012 else
5013 x_lower_frame (f);
5014}
5015
fd13dbb2
RS
5016/* Change from withdrawn state to mapped state,
5017 or deiconify. */
dc6f92b8 5018
f676886a
JB
5019x_make_frame_visible (f)
5020 struct frame *f;
dc6f92b8
JB
5021{
5022 int mask;
990ba854 5023 Lisp_Object type;
dc6f92b8 5024
dc6f92b8 5025 BLOCK_INPUT;
dc6f92b8 5026
990ba854
RS
5027 type = x_icon_type (f);
5028 if (!NILP (type))
5029 x_bitmap_icon (f, type);
bdcd49ba 5030
f676886a 5031 if (! FRAME_VISIBLE_P (f))
90e65f07 5032 {
af31d76f 5033#ifndef USE_X_TOOLKIT
fd13dbb2
RS
5034 if (! FRAME_ICONIFIED_P (f))
5035 x_set_offset (f, f->display.x->left_pos, f->display.x->top_pos, 0);
af31d76f 5036#endif
dc05a16b 5037
90e65f07 5038 if (! EQ (Vx_no_window_manager, Qt))
f676886a 5039 x_wm_set_window_state (f, NormalState);
3afe33e7 5040#ifdef USE_X_TOOLKIT
d7a38a2e
RS
5041 /* This was XtPopup, but that did nothing for an iconified frame. */
5042 XtMapWidget (f->display.x->widget);
3afe33e7 5043#else /* not USE_X_TOOLKIT */
7f9c7f94 5044 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 5045#endif /* not USE_X_TOOLKIT */
0134a210
RS
5046#if 0 /* This seems to bring back scroll bars in the wrong places
5047 if the window configuration has changed. They seem
5048 to come back ok without this. */
ab648270 5049 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 5050 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 5051#endif
90e65f07 5052 }
dc6f92b8 5053
334208b7 5054 XFlush (FRAME_X_DISPLAY (f));
90e65f07 5055
0dacf791
RS
5056 /* Synchronize to ensure Emacs knows the frame is visible
5057 before we do anything else. We do this loop with input not blocked
5058 so that incoming events are handled. */
5059 {
5060 Lisp_Object frame;
c0a04927
RS
5061 int count = input_signal_count;
5062
5063 /* This must come after we set COUNT. */
5064 UNBLOCK_INPUT;
5065
e0c1aef2 5066 XSETFRAME (frame, f);
c0a04927
RS
5067
5068 while (1)
2a6cf806 5069 {
334208b7 5070 x_sync (f);
c0a04927
RS
5071 /* Once we have handled input events,
5072 we should have received the MapNotify if one is coming.
5073 So if we have not got it yet, stop looping.
5074 Some window managers make their own decisions
5075 about visibility. */
5076 if (input_signal_count != count)
5077 break;
c12a7cbd 5078 /* Machines that do polling rather than SIGIO have been observed
23cf7c60
KH
5079 to go into a busy-wait here. So we'll fake an alarm signal
5080 to let the handler know that there's something to be read.
5081 We used to raise a real alarm, but it seems that the handler
5082 isn't always enabled here. This is probably a bug. */
8b2f8d4e 5083 if (input_polling_used ())
3b2fa4e6
RS
5084 {
5085 /* It could be confusing if a real alarm arrives while processing
5086 the fake one. Turn it off and let the handler reset it. */
5087 alarm (0);
5088 input_poll_signal ();
5089 }
c0a04927
RS
5090 /* Once we have handled input events,
5091 we should have received the MapNotify if one is coming.
5092 So if we have not got it yet, stop looping.
5093 Some window managers make their own decisions
5094 about visibility. */
5095 if (input_signal_count != count)
5096 break;
2a6cf806 5097 }
0dacf791
RS
5098 FRAME_SAMPLE_VISIBILITY (f);
5099 }
dc6f92b8
JB
5100}
5101
5102/* Change from mapped state to withdrawn state. */
5103
f676886a
JB
5104x_make_frame_invisible (f)
5105 struct frame *f;
dc6f92b8
JB
5106{
5107 int mask;
546e6d5b
RS
5108 Window window;
5109
5110#ifdef USE_X_TOOLKIT
5111 /* Use the frame's outermost window, not the one we normally draw on. */
5112 window = XtWindow (f->display.x->widget);
5113#else /* not USE_X_TOOLKIT */
5114 window = FRAME_X_WINDOW (f);
5115#endif /* not USE_X_TOOLKIT */
dc6f92b8 5116
9319ae23
RS
5117 /* Don't keep the highlight on an invisible frame. */
5118 if (x_highlight_frame == f)
5119 x_highlight_frame = 0;
5120
5627c40e 5121#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 5122 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 5123 return;
5627c40e 5124#endif
dc6f92b8
JB
5125
5126 BLOCK_INPUT;
c118dd06 5127
af31d76f
RS
5128 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
5129 that the current position of the window is user-specified, rather than
5130 program-specified, so that when the window is mapped again, it will be
5131 placed at the same location, without forcing the user to position it
5132 by hand again (they have already done that once for this window.) */
5133 x_wm_set_size_hint (f, 0, 1);
5134
c118dd06
JB
5135#ifdef HAVE_X11R4
5136
334208b7
RS
5137 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
5138 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
5139 {
5140 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 5141 error ("Can't notify window manager of window withdrawal");
c118dd06 5142 }
c118dd06 5143#else /* ! defined (HAVE_X11R4) */
16bd92ea 5144
c118dd06 5145 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
5146 if (! EQ (Vx_no_window_manager, Qt))
5147 {
16bd92ea 5148 XEvent unmap;
dc6f92b8 5149
16bd92ea 5150 unmap.xunmap.type = UnmapNotify;
546e6d5b 5151 unmap.xunmap.window = window;
334208b7 5152 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 5153 unmap.xunmap.from_configure = False;
334208b7
RS
5154 if (! XSendEvent (FRAME_X_DISPLAY (f),
5155 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
5156 False,
5157 SubstructureRedirectMask|SubstructureNotifyMask,
5158 &unmap))
5159 {
5160 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 5161 error ("Can't notify window manager of withdrawal");
16bd92ea 5162 }
dc6f92b8
JB
5163 }
5164
16bd92ea 5165 /* Unmap the window ourselves. Cheeky! */
334208b7 5166 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 5167#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 5168
5627c40e
RS
5169 /* We can't distinguish this from iconification
5170 just by the event that we get from the server.
5171 So we can't win using the usual strategy of letting
5172 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
5173 and synchronize with the server to make sure we agree. */
5174 f->visible = 0;
5175 FRAME_ICONIFIED_P (f) = 0;
5176 f->async_visible = 0;
5177 f->async_iconified = 0;
5178
334208b7 5179 x_sync (f);
5627c40e 5180
dc6f92b8
JB
5181 UNBLOCK_INPUT;
5182}
5183
dc6f92b8
JB
5184/* Change window state from mapped to iconified. */
5185
f676886a
JB
5186x_iconify_frame (f)
5187 struct frame *f;
dc6f92b8
JB
5188{
5189 int mask;
3afe33e7 5190 int result;
990ba854 5191 Lisp_Object type;
dc6f92b8 5192
9319ae23
RS
5193 /* Don't keep the highlight on an invisible frame. */
5194 if (x_highlight_frame == f)
5195 x_highlight_frame = 0;
5196
3a88c238 5197 if (f->async_iconified)
dc6f92b8
JB
5198 return;
5199
3afe33e7 5200 BLOCK_INPUT;
546e6d5b 5201
990ba854
RS
5202 type = x_icon_type (f);
5203 if (!NILP (type))
5204 x_bitmap_icon (f, type);
bdcd49ba
RS
5205
5206#ifdef USE_X_TOOLKIT
5207
546e6d5b
RS
5208 if (! FRAME_VISIBLE_P (f))
5209 {
5210 if (! EQ (Vx_no_window_manager, Qt))
5211 x_wm_set_window_state (f, IconicState);
5212 /* This was XtPopup, but that did nothing for an iconified frame. */
5213 XtMapWidget (f->display.x->widget);
5214 UNBLOCK_INPUT;
5215 return;
5216 }
5217
334208b7 5218 result = XIconifyWindow (FRAME_X_DISPLAY (f),
bc20ebbf 5219 XtWindow (f->display.x->widget),
334208b7 5220 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
5221 UNBLOCK_INPUT;
5222
5223 if (!result)
546e6d5b 5224 error ("Can't notify window manager of iconification");
3afe33e7
RS
5225
5226 f->async_iconified = 1;
8c002a25
KH
5227
5228 BLOCK_INPUT;
334208b7 5229 XFlush (FRAME_X_DISPLAY (f));
8c002a25 5230 UNBLOCK_INPUT;
3afe33e7
RS
5231#else /* not USE_X_TOOLKIT */
5232
fd13dbb2
RS
5233 /* Make sure the X server knows where the window should be positioned,
5234 in case the user deiconifies with the window manager. */
5235 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
5236 x_set_offset (f, f->display.x->left_pos, f->display.x->top_pos, 0);
5237
16bd92ea
JB
5238 /* Since we don't know which revision of X we're running, we'll use both
5239 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
5240
5241 /* X11R4: send a ClientMessage to the window manager using the
5242 WM_CHANGE_STATE type. */
5243 {
5244 XEvent message;
58769bee 5245
c118dd06 5246 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 5247 message.xclient.type = ClientMessage;
334208b7 5248 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
5249 message.xclient.format = 32;
5250 message.xclient.data.l[0] = IconicState;
5251
334208b7
RS
5252 if (! XSendEvent (FRAME_X_DISPLAY (f),
5253 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
5254 False,
5255 SubstructureRedirectMask | SubstructureNotifyMask,
5256 &message))
dc6f92b8
JB
5257 {
5258 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 5259 error ("Can't notify window manager of iconification");
dc6f92b8 5260 }
16bd92ea 5261 }
dc6f92b8 5262
58769bee 5263 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
5264 IconicState. */
5265 x_wm_set_window_state (f, IconicState);
dc6f92b8 5266
a9c00105
RS
5267 if (!FRAME_VISIBLE_P (f))
5268 {
5269 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 5270 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
5271 }
5272
3a88c238 5273 f->async_iconified = 1;
dc6f92b8 5274
334208b7 5275 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 5276 UNBLOCK_INPUT;
8c002a25 5277#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5278}
5279
c0ff3fab 5280/* Destroy the X window of frame F. */
dc6f92b8 5281
c0ff3fab 5282x_destroy_window (f)
f676886a 5283 struct frame *f;
dc6f92b8 5284{
7f9c7f94
RS
5285 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5286
dc6f92b8 5287 BLOCK_INPUT;
c0ff3fab
JB
5288
5289 if (f->display.x->icon_desc != 0)
334208b7
RS
5290 XDestroyWindow (FRAME_X_DISPLAY (f), f->display.x->icon_desc);
5291 XDestroyWindow (FRAME_X_DISPLAY (f), f->display.x->window_desc);
3afe33e7
RS
5292#ifdef USE_X_TOOLKIT
5293 XtDestroyWidget (f->display.x->widget);
9d7e2e3e 5294 free_frame_menubar (f);
3afe33e7
RS
5295#endif /* USE_X_TOOLKIT */
5296
07e34cb0 5297 free_frame_faces (f);
334208b7 5298 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 5299
9ac0d9e0 5300 xfree (f->display.x);
c0ff3fab 5301 f->display.x = 0;
f676886a
JB
5302 if (f == x_focus_frame)
5303 x_focus_frame = 0;
c5acd733
RS
5304 if (f == x_focus_event_frame)
5305 x_focus_event_frame = 0;
f676886a
JB
5306 if (f == x_highlight_frame)
5307 x_highlight_frame = 0;
c0ff3fab 5308
7f9c7f94
RS
5309 dpyinfo->reference_count--;
5310
5311 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 5312 {
7f9c7f94
RS
5313 dpyinfo->mouse_face_beg_row
5314 = dpyinfo->mouse_face_beg_col = -1;
5315 dpyinfo->mouse_face_end_row
5316 = dpyinfo->mouse_face_end_col = -1;
5317 dpyinfo->mouse_face_window = Qnil;
dc05a16b 5318 }
0134a210 5319
c0ff3fab 5320 UNBLOCK_INPUT;
dc6f92b8
JB
5321}
5322\f
f451eb13
JB
5323/* Setting window manager hints. */
5324
af31d76f
RS
5325/* Set the normal size hints for the window manager, for frame F.
5326 FLAGS is the flags word to use--or 0 meaning preserve the flags
5327 that the window now has.
5328 If USER_POSITION is nonzero, we set the USPosition
5329 flag (this is useful when FLAGS is 0). */
6dba1858 5330
af31d76f 5331x_wm_set_size_hint (f, flags, user_position)
f676886a 5332 struct frame *f;
af31d76f
RS
5333 long flags;
5334 int user_position;
dc6f92b8
JB
5335{
5336 XSizeHints size_hints;
3afe33e7
RS
5337
5338#ifdef USE_X_TOOLKIT
7e4f2521
FP
5339 Arg al[2];
5340 int ac = 0;
5341 Dimension widget_width, widget_height;
bc20ebbf 5342 Window window = XtWindow (f->display.x->widget);
3afe33e7 5343#else /* not USE_X_TOOLKIT */
c118dd06 5344 Window window = FRAME_X_WINDOW (f);
3afe33e7 5345#endif /* not USE_X_TOOLKIT */
dc6f92b8 5346
b72a58fd
RS
5347 /* Setting PMaxSize caused various problems. */
5348 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 5349
f676886a
JB
5350 flexlines = f->height;
5351
5352 size_hints.x = f->display.x->left_pos;
5353 size_hints.y = f->display.x->top_pos;
7553a6b7 5354
7e4f2521
FP
5355#ifdef USE_X_TOOLKIT
5356 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
5357 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
5358 XtGetValues (f->display.x->column_widget, al, ac);
5359 size_hints.height = widget_height;
5360 size_hints.width = widget_width;
5361#else /* not USE_X_TOOLKIT */
f676886a
JB
5362 size_hints.height = PIXEL_HEIGHT (f);
5363 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 5364#endif /* not USE_X_TOOLKIT */
7553a6b7 5365
f676886a 5366 size_hints.width_inc = FONT_WIDTH (f->display.x->font);
a27f9f86 5367 size_hints.height_inc = f->display.x->line_height;
334208b7
RS
5368 size_hints.max_width
5369 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
5370 size_hints.max_height
5371 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 5372
b1c884c3 5373 {
b0342f17 5374 int base_width, base_height;
0134a210 5375 int min_rows = 0, min_cols = 0;
b0342f17 5376
f451eb13
JB
5377 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
5378 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 5379
0134a210 5380 check_frame_size (f, &min_rows, &min_cols);
b0342f17 5381
0134a210
RS
5382 /* The window manager uses the base width hints to calculate the
5383 current number of rows and columns in the frame while
5384 resizing; min_width and min_height aren't useful for this
5385 purpose, since they might not give the dimensions for a
5386 zero-row, zero-column frame.
58769bee 5387
0134a210
RS
5388 We use the base_width and base_height members if we have
5389 them; otherwise, we set the min_width and min_height members
5390 to the size for a zero x zero frame. */
b0342f17
JB
5391
5392#ifdef HAVE_X11R4
0134a210
RS
5393 size_hints.flags |= PBaseSize;
5394 size_hints.base_width = base_width;
5395 size_hints.base_height = base_height;
5396 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
5397 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 5398#else
0134a210
RS
5399 size_hints.min_width = base_width;
5400 size_hints.min_height = base_height;
b0342f17 5401#endif
b1c884c3 5402 }
dc6f92b8 5403
af31d76f
RS
5404 if (flags)
5405 size_hints.flags |= flags;
dc6f92b8
JB
5406 else
5407 {
5408 XSizeHints hints; /* Sometimes I hate X Windows... */
af31d76f
RS
5409 long supplied_return;
5410 int value;
5411
5412#ifdef HAVE_X11R4
334208b7 5413 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
af31d76f
RS
5414 &supplied_return);
5415#else
334208b7 5416 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 5417#endif
58769bee 5418
af31d76f 5419 if (value == 0)
82ee0df4 5420 hints.flags = 0;
dc6f92b8
JB
5421 if (hints.flags & PSize)
5422 size_hints.flags |= PSize;
5423 if (hints.flags & PPosition)
5424 size_hints.flags |= PPosition;
5425 if (hints.flags & USPosition)
5426 size_hints.flags |= USPosition;
5427 if (hints.flags & USSize)
5428 size_hints.flags |= USSize;
5429 }
0134a210 5430
af31d76f 5431#ifdef PWinGravity
dc05a16b 5432 size_hints.win_gravity = f->display.x->win_gravity;
af31d76f 5433 size_hints.flags |= PWinGravity;
dc05a16b 5434
af31d76f 5435 if (user_position)
6dba1858 5436 {
af31d76f
RS
5437 size_hints.flags &= ~ PPosition;
5438 size_hints.flags |= USPosition;
6dba1858 5439 }
2554751d 5440#endif /* PWinGravity */
6dba1858 5441
b0342f17 5442#ifdef HAVE_X11R4
334208b7 5443 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 5444#else
334208b7 5445 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 5446#endif
dc6f92b8
JB
5447}
5448
5449/* Used for IconicState or NormalState */
f676886a
JB
5450x_wm_set_window_state (f, state)
5451 struct frame *f;
dc6f92b8
JB
5452 int state;
5453{
3afe33e7 5454#ifdef USE_X_TOOLKIT
546e6d5b
RS
5455 Arg al[1];
5456
5457 XtSetArg (al[0], XtNinitialState, state);
5458 XtSetValues (f->display.x->widget, al, 1);
3afe33e7 5459#else /* not USE_X_TOOLKIT */
c118dd06 5460 Window window = FRAME_X_WINDOW (f);
dc6f92b8 5461
16bd92ea
JB
5462 f->display.x->wm_hints.flags |= StateHint;
5463 f->display.x->wm_hints.initial_state = state;
b1c884c3 5464
334208b7 5465 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
546e6d5b 5466#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5467}
5468
7f2ae036 5469x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 5470 struct frame *f;
7f2ae036 5471 int pixmap_id;
dc6f92b8 5472{
75231bad
RS
5473#ifdef USE_X_TOOLKIT
5474 Window window = XtWindow (f->display.x->widget);
5475#else
c118dd06 5476 Window window = FRAME_X_WINDOW (f);
75231bad 5477#endif
dc6f92b8 5478
7f2ae036 5479 if (pixmap_id > 0)
dbc4e1c1 5480 {
7a13e894 5481 Pixmap icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
dbc4e1c1
JB
5482 f->display.x->wm_hints.icon_pixmap = icon_pixmap;
5483 f->display.x->wm_hints.flags |= IconPixmapHint;
5484 }
5485 else
7f2ae036
RS
5486 {
5487 f->display.x->wm_hints.icon_pixmap = None;
5488 f->display.x->wm_hints.flags &= ~IconPixmapHint;
5489 }
b1c884c3 5490
334208b7 5491 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
dc6f92b8
JB
5492}
5493
f676886a
JB
5494x_wm_set_icon_position (f, icon_x, icon_y)
5495 struct frame *f;
dc6f92b8
JB
5496 int icon_x, icon_y;
5497{
75231bad
RS
5498#ifdef USE_X_TOOLKIT
5499 Window window = XtWindow (f->display.x->widget);
5500#else
c118dd06 5501 Window window = FRAME_X_WINDOW (f);
75231bad 5502#endif
dc6f92b8 5503
16bd92ea
JB
5504 f->display.x->wm_hints.flags |= IconPositionHint;
5505 f->display.x->wm_hints.icon_x = icon_x;
5506 f->display.x->wm_hints.icon_y = icon_y;
b1c884c3 5507
334208b7 5508 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
dc6f92b8
JB
5509}
5510
5511\f
f451eb13
JB
5512/* Initialization. */
5513
3afe33e7
RS
5514#ifdef USE_X_TOOLKIT
5515static XrmOptionDescRec emacs_options[] = {
5516 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
5517 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
5518
5519 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
5520 XrmoptionSepArg, NULL},
5521 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
5522
5523 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5524 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5525 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5526 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5527 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5528 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
5529 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
5530};
5531#endif /* USE_X_TOOLKIT */
5532
7a13e894
RS
5533static int x_initialized;
5534
29b38361
KH
5535#ifdef MULTI_KBOARD
5536/* Test whether two display-name strings agree up to the dot that separates
5537 the screen number from the server number. */
5538static int
5539same_x_server (name1, name2)
5540 char *name1, *name2;
5541{
5542 int seen_colon = 0;
5543 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
5544 {
5545 if (*name1 == ':')
5546 seen_colon++;
5547 if (seen_colon && *name1 == '.')
5548 return 1;
5549 }
5550 return (seen_colon
5551 && (*name1 == '.' || *name1 == '\0')
5552 && (*name2 == '.' || *name2 == '\0'));
5553}
5554#endif
5555
334208b7 5556struct x_display_info *
1f8255f2 5557x_term_init (display_name, xrm_option, resource_name)
334208b7 5558 Lisp_Object display_name;
1f8255f2
RS
5559 char *xrm_option;
5560 char *resource_name;
dc6f92b8 5561{
f676886a 5562 Lisp_Object frame;
dc6f92b8 5563 char *defaultvalue;
334208b7 5564 int connection;
7a13e894 5565 Display *dpy;
334208b7
RS
5566 struct x_display_info *dpyinfo;
5567 XrmDatabase xrdb;
5568
7a13e894
RS
5569 if (!x_initialized)
5570 {
5571 x_initialize ();
5572 x_initialized = 1;
5573 }
dc6f92b8 5574
3afe33e7 5575#ifdef USE_X_TOOLKIT
bdcd49ba
RS
5576#ifdef HAVE_X11R5
5577 XtSetLanguageProc (NULL, NULL, NULL);
5578#endif
5579
7f9c7f94
RS
5580 {
5581 int argc = 0;
5582 char *argv[3];
5583
5584 argv[0] = "";
5585 argc = 1;
5586 if (xrm_option)
5587 {
5588 argv[argc++] = "-xrm";
5589 argv[argc++] = xrm_option;
5590 }
5591 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
5592 resource_name, EMACS_CLASS,
5593 emacs_options, XtNumber (emacs_options),
5594 &argc, argv);
5595 }
3afe33e7
RS
5596
5597#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
5598#ifdef HAVE_X11R5
5599 XSetLocaleModifiers ("");
5600#endif
7a13e894 5601 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 5602#endif /* not USE_X_TOOLKIT */
334208b7 5603
7a13e894
RS
5604 /* Detect failure. */
5605 if (dpy == 0)
5606 return 0;
5607
5608 /* We have definitely succeeded. Record the new connection. */
5609
5610 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
5611
29b38361
KH
5612#ifdef MULTI_KBOARD
5613 {
5614 struct x_display_info *share;
5615 Lisp_Object tail;
5616
5617 for (share = x_display_list, tail = x_display_name_list; share;
5618 share = share->next, tail = XCONS (tail)->cdr)
5619 if (same_x_server (XSTRING (XCONS (XCONS (tail)->car)->car)->data,
5620 XSTRING (display_name)->data))
5621 break;
5622 if (share)
5623 dpyinfo->kboard = share->kboard;
5624 else
5625 {
5626 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
5627 init_kboard (dpyinfo->kboard);
5628 dpyinfo->kboard->next_kboard = all_kboards;
5629 all_kboards = dpyinfo->kboard;
5630 }
5631 dpyinfo->kboard->reference_count++;
5632 }
b9737ad3
KH
5633#endif
5634
7a13e894
RS
5635 /* Put this display on the chain. */
5636 dpyinfo->next = x_display_list;
5637 x_display_list = dpyinfo;
5638
5639 /* Put it on x_display_name_list as well, to keep them parallel. */
5640 x_display_name_list = Fcons (Fcons (display_name, Qnil),
5641 x_display_name_list);
5642 dpyinfo->name_list_element = XCONS (x_display_name_list)->car;
5643
5644 dpyinfo->display = dpy;
dc6f92b8 5645
dc6f92b8 5646#if 0
7a13e894 5647 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 5648#endif /* ! 0 */
7a13e894
RS
5649
5650 dpyinfo->x_id_name
5651 = (char *) xmalloc (XSTRING (Vinvocation_name)->size
5652 + XSTRING (Vsystem_name)->size
5653 + 2);
5654 sprintf (dpyinfo->x_id_name, "%s@%s",
5655 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
5656
5657 /* Figure out which modifier bits mean what. */
334208b7 5658 x_find_modifier_meanings (dpyinfo);
f451eb13 5659
ab648270 5660 /* Get the scroll bar cursor. */
7a13e894 5661 dpyinfo->vertical_scroll_bar_cursor
334208b7 5662 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 5663
334208b7
RS
5664 xrdb = x_load_resources (dpyinfo->display, xrm_option,
5665 resource_name, EMACS_CLASS);
5666#ifdef HAVE_XRMSETDATABASE
5667 XrmSetDatabase (dpyinfo->display, xrdb);
5668#else
5669 dpyinfo->display->db = xrdb;
5670#endif
547d9db8 5671 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
5672 all versions. */
5673 dpyinfo->xrdb = xrdb;
334208b7
RS
5674
5675 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
5676 DefaultScreen (dpyinfo->display));
5677 dpyinfo->visual = select_visual (dpyinfo->display, dpyinfo->screen,
5678 &dpyinfo->n_planes);
5679 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
5680 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
5681 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
5682 dpyinfo->grabbed = 0;
5683 dpyinfo->reference_count = 0;
5684 dpyinfo->icon_bitmap_id = -1;
7a13e894
RS
5685 dpyinfo->n_fonts = 0;
5686 dpyinfo->font_table_size = 0;
5687 dpyinfo->bitmaps = 0;
5688 dpyinfo->bitmaps_size = 0;
5689 dpyinfo->bitmaps_last = 0;
5690 dpyinfo->scratch_cursor_gc = 0;
5691 dpyinfo->mouse_face_mouse_frame = 0;
5692 dpyinfo->mouse_face_deferred_gc = 0;
5693 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
5694 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
5695 dpyinfo->mouse_face_face_id = 0;
5696 dpyinfo->mouse_face_window = Qnil;
5697 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
5698 dpyinfo->mouse_face_defer = 0;
334208b7
RS
5699
5700 dpyinfo->Xatom_wm_protocols
5701 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
5702 dpyinfo->Xatom_wm_take_focus
5703 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
5704 dpyinfo->Xatom_wm_save_yourself
5705 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
5706 dpyinfo->Xatom_wm_delete_window
5707 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
5708 dpyinfo->Xatom_wm_change_state
5709 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
5710 dpyinfo->Xatom_wm_configure_denied
5711 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
5712 dpyinfo->Xatom_wm_window_moved
5713 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
5714 dpyinfo->Xatom_editres
5715 = XInternAtom (dpyinfo->display, "Editres", False);
5716 dpyinfo->Xatom_CLIPBOARD
5717 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
5718 dpyinfo->Xatom_TIMESTAMP
5719 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
5720 dpyinfo->Xatom_TEXT
5721 = XInternAtom (dpyinfo->display, "TEXT", False);
5722 dpyinfo->Xatom_DELETE
5723 = XInternAtom (dpyinfo->display, "DELETE", False);
5724 dpyinfo->Xatom_MULTIPLE
5725 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
5726 dpyinfo->Xatom_INCR
5727 = XInternAtom (dpyinfo->display, "INCR", False);
5728 dpyinfo->Xatom_EMACS_TMP
5729 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
5730 dpyinfo->Xatom_TARGETS
5731 = XInternAtom (dpyinfo->display, "TARGETS", False);
5732 dpyinfo->Xatom_NULL
5733 = XInternAtom (dpyinfo->display, "NULL", False);
5734 dpyinfo->Xatom_ATOM_PAIR
5735 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
5736
547d9db8
KH
5737 dpyinfo->cut_buffers_initialized = 0;
5738
334208b7
RS
5739 connection = ConnectionNumber (dpyinfo->display);
5740 dpyinfo->connection = connection;
5741
87485d6f
MW
5742#ifdef subprocesses
5743 /* This is only needed for distinguishing keyboard and process input. */
334208b7 5744 if (connection != 0)
7a13e894 5745 add_keyboard_wait_descriptor (connection);
87485d6f 5746#endif
6d4238f3 5747
041b69ac 5748#ifndef F_SETOWN_BUG
dc6f92b8 5749#ifdef F_SETOWN
dc6f92b8 5750#ifdef F_SETOWN_SOCK_NEG
61c3ce62 5751 /* stdin is a socket here */
334208b7 5752 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 5753#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 5754 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
5755#endif /* ! defined (F_SETOWN_SOCK_NEG) */
5756#endif /* ! defined (F_SETOWN) */
041b69ac 5757#endif /* F_SETOWN_BUG */
dc6f92b8
JB
5758
5759#ifdef SIGIO
7a13e894 5760 init_sigio (connection);
c118dd06 5761#endif /* ! defined (SIGIO) */
dc6f92b8 5762
7a13e894
RS
5763 return dpyinfo;
5764}
5765\f
5766/* Get rid of display DPYINFO, assuming all frames are already gone,
5767 and without sending any more commands to the X server. */
dc6f92b8 5768
7a13e894
RS
5769void
5770x_delete_display (dpyinfo)
5771 struct x_display_info *dpyinfo;
5772{
5773 delete_keyboard_wait_descriptor (dpyinfo->connection);
5774
5775 /* Discard this display from x_display_name_list and x_display_list.
5776 We can't use Fdelq because that can quit. */
5777 if (! NILP (x_display_name_list)
5778 && EQ (XCONS (x_display_name_list)->car, dpyinfo->name_list_element))
5779 x_display_name_list = XCONS (x_display_name_list)->cdr;
5780 else
5781 {
5782 Lisp_Object tail;
5783
5784 tail = x_display_name_list;
5785 while (CONSP (tail) && CONSP (XCONS (tail)->cdr))
5786 {
5787 if (EQ (XCONS (XCONS (tail)->cdr)->car,
5788 dpyinfo->name_list_element))
5789 {
5790 XCONS (tail)->cdr = XCONS (XCONS (tail)->cdr)->cdr;
5791 break;
5792 }
5793 tail = XCONS (tail)->cdr;
5794 }
5795 }
5796
5797 if (x_display_list == dpyinfo)
5798 x_display_list = dpyinfo->next;
7f9c7f94
RS
5799 else
5800 {
5801 struct x_display_info *tail;
7a13e894 5802
7f9c7f94
RS
5803 for (tail = x_display_list; tail; tail = tail->next)
5804 if (tail->next == dpyinfo)
5805 tail->next = tail->next->next;
5806 }
7a13e894 5807
7f9c7f94
RS
5808#ifndef USE_X_TOOLKIT
5809 /* I'm told Xt does this itself. */
5810 XrmDestroyDatabase (dpyinfo->xrdb);
5811#endif
29b38361
KH
5812#ifdef MULTI_KBOARD
5813 if (--dpyinfo->kboard->reference_count == 0)
39f79001 5814 delete_kboard (dpyinfo->kboard);
b9737ad3
KH
5815#endif
5816 xfree (dpyinfo->font_table);
5817 xfree (dpyinfo->x_id_name);
5818 xfree (dpyinfo);
7a13e894
RS
5819}
5820\f
5821/* Set up use of X before we make the first connection. */
5822
5823x_initialize ()
5824{
f676886a 5825 clear_frame_hook = XTclear_frame;
dc6f92b8
JB
5826 clear_end_of_line_hook = XTclear_end_of_line;
5827 ins_del_lines_hook = XTins_del_lines;
5828 change_line_highlight_hook = XTchange_line_highlight;
5829 insert_glyphs_hook = XTinsert_glyphs;
5830 write_glyphs_hook = XTwrite_glyphs;
5831 delete_glyphs_hook = XTdelete_glyphs;
5832 ring_bell_hook = XTring_bell;
5833 reset_terminal_modes_hook = XTreset_terminal_modes;
5834 set_terminal_modes_hook = XTset_terminal_modes;
5835 update_begin_hook = XTupdate_begin;
5836 update_end_hook = XTupdate_end;
5837 set_terminal_window_hook = XTset_terminal_window;
5838 read_socket_hook = XTread_socket;
b8009dd1 5839 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8
JB
5840 cursor_to_hook = XTcursor_to;
5841 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 5842 mouse_position_hook = XTmouse_position;
f451eb13 5843 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 5844 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
5845 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
5846 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
5847 redeem_scroll_bar_hook = XTredeem_scroll_bar;
5848 judge_scroll_bars_hook = XTjudge_scroll_bars;
58769bee 5849
f676886a 5850 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
5851 char_ins_del_ok = 0; /* just as fast to write the line */
5852 line_ins_del_ok = 1; /* we'll just blt 'em */
5853 fast_clear_end_of_line = 1; /* X does this well */
58769bee 5854 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
5855 off the bottom */
5856 baud_rate = 19200;
5857
7a13e894
RS
5858 x_noop_count = 0;
5859
5860 x_focus_frame = x_highlight_frame = 0;
5861
b30b24cb
RS
5862 /* Try to use interrupt input; if we can't, then start polling. */
5863 Fset_input_mode (Qt, Qnil, Qt, Qnil);
5864
7f9c7f94
RS
5865#ifdef USE_X_TOOLKIT
5866 XtToolkitInitialize ();
5867 Xt_app_con = XtCreateApplicationContext ();
5868#endif
5869
58769bee 5870 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 5871 original error handler. */
334208b7
RS
5872 XSetErrorHandler (x_error_quitter);
5873 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8
JB
5874
5875 /* Disable Window Change signals; they are handled by X events. */
5876#ifdef SIGWINCH
5877 signal (SIGWINCH, SIG_DFL);
c118dd06 5878#endif /* ! defined (SIGWINCH) */
dc6f92b8 5879
92e2441b 5880 signal (SIGPIPE, x_connection_signal);
dc6f92b8 5881}
55123275
JB
5882
5883void
5884syms_of_xterm ()
5885{
7a13e894
RS
5886 staticpro (&x_display_name_list);
5887 x_display_name_list = Qnil;
334208b7 5888
ab648270 5889 staticpro (&last_mouse_scroll_bar);
e53cb100 5890 last_mouse_scroll_bar = Qnil;
55123275 5891}
c118dd06 5892#endif /* ! defined (HAVE_X_WINDOWS) */