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