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