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