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