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