(start-process-shell-command): Don't use exec on windows-nt.
[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;
3460 }
3afe33e7 3461#ifdef USE_X_TOOLKIT
7a13e894 3462 goto OTHER;
3afe33e7 3463#endif /* USE_X_TOOLKIT */
7a13e894 3464 break;
dc6f92b8 3465
7a13e894
RS
3466 case MapNotify:
3467 /* We use x_top_window_to_frame because map events can come
3468 for subwindows and they don't mean that the frame is visible. */
3469 f = x_top_window_to_frame (event.xmap.window);
3470 if (f)
3471 {
3472 f->async_visible = 1;
3473 f->async_iconified = 0;
dc6f92b8 3474
7a13e894
RS
3475 /* wait_reading_process_input will notice this and update
3476 the frame's display structures. */
3477 SET_FRAME_GARBAGED (f);
3478 }
3afe33e7 3479#ifdef USE_X_TOOLKIT
7a13e894 3480 goto OTHER;
3afe33e7 3481#endif /* USE_X_TOOLKIT */
7a13e894 3482 break;
dc6f92b8 3483
7a13e894
RS
3484 /* Turn off processing if we become fully obscured. */
3485 case VisibilityNotify:
3486 break;
dc6f92b8 3487
7a13e894
RS
3488 case KeyPress:
3489 f = x_any_window_to_frame (event.xkey.window);
f451eb13 3490
7a13e894
RS
3491 if (f != 0)
3492 {
3493 KeySym keysym, orig_keysym;
3494 /* al%imercury@uunet.uu.net says that making this 81 instead of
3495 80 fixed a bug whereby meta chars made his Emacs hang. */
3496 unsigned char copy_buffer[81];
3497 int modifiers;
64bb1782 3498
7a13e894
RS
3499 event.xkey.state
3500 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
3501 extra_keyboard_modifiers);
3502 modifiers = event.xkey.state;
3a2712f9 3503
7a13e894 3504 /* This will have to go some day... */
752a043f 3505
7a13e894
RS
3506 /* make_lispy_event turns chars into control chars.
3507 Don't do it here because XLookupString is too eager. */
3508 event.xkey.state &= ~ControlMask;
3509 nbytes =
3510 XLookupString (&event.xkey, copy_buffer, 80, &keysym,
3511 &compose_status);
dc6f92b8 3512
7a13e894 3513 orig_keysym = keysym;
55123275 3514
7a13e894
RS
3515 if (numchars > 1)
3516 {
3517 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
3518 || keysym == XK_Delete
3519 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
3520 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 3521#ifdef HPUX
7a13e894
RS
3522 /* This recognizes the "extended function keys".
3523 It seems there's no cleaner way.
3524 Test IsModifierKey to avoid handling mode_switch
3525 incorrectly. */
3526 || ((unsigned) (keysym) >= XK_Select
3527 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
3528#endif
3529#ifdef XK_dead_circumflex
7a13e894 3530 || orig_keysym == XK_dead_circumflex
69388238
RS
3531#endif
3532#ifdef XK_dead_grave
7a13e894 3533 || orig_keysym == XK_dead_grave
69388238
RS
3534#endif
3535#ifdef XK_dead_tilde
7a13e894 3536 || orig_keysym == XK_dead_tilde
69388238
RS
3537#endif
3538#ifdef XK_dead_diaeresis
7a13e894 3539 || orig_keysym == XK_dead_diaeresis
69388238
RS
3540#endif
3541#ifdef XK_dead_macron
7a13e894 3542 || orig_keysym == XK_dead_macron
69388238
RS
3543#endif
3544#ifdef XK_dead_degree
7a13e894 3545 || orig_keysym == XK_dead_degree
69388238
RS
3546#endif
3547#ifdef XK_dead_acute
7a13e894 3548 || orig_keysym == XK_dead_acute
69388238
RS
3549#endif
3550#ifdef XK_dead_cedilla
7a13e894 3551 || orig_keysym == XK_dead_cedilla
69388238
RS
3552#endif
3553#ifdef XK_dead_breve
7a13e894 3554 || orig_keysym == XK_dead_breve
69388238
RS
3555#endif
3556#ifdef XK_dead_ogonek
7a13e894 3557 || orig_keysym == XK_dead_ogonek
69388238
RS
3558#endif
3559#ifdef XK_dead_caron
7a13e894 3560 || orig_keysym == XK_dead_caron
69388238
RS
3561#endif
3562#ifdef XK_dead_doubleacute
7a13e894 3563 || orig_keysym == XK_dead_doubleacute
69388238
RS
3564#endif
3565#ifdef XK_dead_abovedot
7a13e894 3566 || orig_keysym == XK_dead_abovedot
c34790e0 3567#endif
7a13e894
RS
3568 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
3569 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
3570 /* Any "vendor-specific" key is ok. */
3571 || (orig_keysym & (1 << 28)))
3572 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
3573#ifndef HAVE_X11R5
3574#ifdef XK_Mode_switch
7a13e894 3575 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
3576#endif
3577#ifdef XK_Num_Lock
7a13e894 3578 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
3579#endif
3580#endif /* not HAVE_X11R5 */
7a13e894 3581 ))
dc6f92b8 3582 {
10e6549c
RS
3583 if (temp_index == sizeof temp_buffer / sizeof (short))
3584 temp_index = 0;
7a13e894
RS
3585 temp_buffer[temp_index++] = keysym;
3586 bufp->kind = non_ascii_keystroke;
3587 bufp->code = keysym;
e0c1aef2 3588 XSETFRAME (bufp->frame_or_window, f);
334208b7
RS
3589 bufp->modifiers
3590 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
3591 modifiers);
1113d9db 3592 bufp->timestamp = event.xkey.time;
dc6f92b8 3593 bufp++;
7a13e894
RS
3594 count++;
3595 numchars--;
dc6f92b8 3596 }
7a13e894
RS
3597 else if (numchars > nbytes)
3598 {
3599 register int i;
3600
3601 for (i = 0; i < nbytes; i++)
3602 {
3603 if (temp_index == sizeof temp_buffer / sizeof (short))
3604 temp_index = 0;
3605 temp_buffer[temp_index++] = copy_buffer[i];
3606 bufp->kind = ascii_keystroke;
3607 bufp->code = copy_buffer[i];
3608 XSETFRAME (bufp->frame_or_window, f);
3609 bufp->modifiers
3610 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
3611 modifiers);
3612 bufp->timestamp = event.xkey.time;
3613 bufp++;
3614 }
3615
3616 count += nbytes;
3617 numchars -= nbytes;
3618 }
3619 else
3620 abort ();
dc6f92b8 3621 }
10e6549c
RS
3622 else
3623 abort ();
dc6f92b8 3624 }
7a13e894 3625 break;
f451eb13 3626
7a13e894
RS
3627 /* Here's a possible interpretation of the whole
3628 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If you get a
3629 FocusIn event, you have to get a FocusOut event before you
3630 relinquish the focus. If you haven't received a FocusIn event,
3631 then a mere LeaveNotify is enough to free you. */
f451eb13 3632
7a13e894
RS
3633 case EnterNotify:
3634 f = x_any_window_to_frame (event.xcrossing.window);
6d4238f3 3635
7a13e894 3636 if (event.xcrossing.focus) /* Entered Window */
dc6f92b8 3637 {
7a13e894
RS
3638 /* Avoid nasty pop/raise loops. */
3639 if (f && (!(f->auto_raise)
3640 || !(f->auto_lower)
3641 || (event.xcrossing.time - enter_timestamp) > 500))
3642 {
3643 x_new_focus_frame (f);
3644 enter_timestamp = event.xcrossing.time;
3645 }
dc6f92b8 3646 }
7a13e894
RS
3647 else if (f == x_focus_frame)
3648 x_new_focus_frame (0);
3649 /* EnterNotify counts as mouse movement,
3650 so update things that depend on mouse position. */
3651 if (f)
3652 note_mouse_movement (f, &event.xmotion);
3afe33e7 3653#ifdef USE_X_TOOLKIT
7a13e894 3654 goto OTHER;
3afe33e7 3655#endif /* USE_X_TOOLKIT */
7a13e894 3656 break;
dc6f92b8 3657
7a13e894
RS
3658 case FocusIn:
3659 f = x_any_window_to_frame (event.xfocus.window);
3660 if (event.xfocus.detail != NotifyPointer)
3661 x_focus_event_frame = f;
3662 if (f)
3663 x_new_focus_frame (f);
3afe33e7 3664#ifdef USE_X_TOOLKIT
7a13e894 3665 goto OTHER;
3afe33e7 3666#endif /* USE_X_TOOLKIT */
7a13e894 3667 break;
f451eb13 3668
10c5e63d 3669
7a13e894
RS
3670 case LeaveNotify:
3671 f = x_top_window_to_frame (event.xcrossing.window);
3672 if (f)
10c5e63d 3673 {
7a13e894
RS
3674 if (f == dpyinfo->mouse_face_mouse_frame)
3675 /* If we move outside the frame,
3676 then we're certainly no longer on any text in the frame. */
3677 clear_mouse_face (dpyinfo);
3678
3679 if (event.xcrossing.focus)
3680 {
3681 if (! x_focus_event_frame)
3682 x_new_focus_frame (0);
3683 else
3684 x_new_focus_frame (f);
3685 }
10c5e63d 3686 else
7a13e894
RS
3687 {
3688 if (f == x_focus_event_frame)
3689 x_focus_event_frame = 0;
3690 if (f == x_focus_frame)
3691 x_new_focus_frame (0);
3692 }
10c5e63d 3693 }
3afe33e7 3694#ifdef USE_X_TOOLKIT
7a13e894 3695 goto OTHER;
3afe33e7 3696#endif /* USE_X_TOOLKIT */
7a13e894 3697 break;
dc6f92b8 3698
7a13e894
RS
3699 case FocusOut:
3700 f = x_any_window_to_frame (event.xfocus.window);
3701 if (event.xfocus.detail != NotifyPointer
3702 && f == x_focus_event_frame)
3703 x_focus_event_frame = 0;
3704 if (f && f == x_focus_frame)
3705 x_new_focus_frame (0);
3afe33e7 3706#ifdef USE_X_TOOLKIT
7a13e894 3707 goto OTHER;
3afe33e7 3708#endif /* USE_X_TOOLKIT */
7a13e894 3709 break;
dc6f92b8 3710
7a13e894 3711 case MotionNotify:
dc6f92b8 3712 {
7a13e894
RS
3713 if (dpyinfo->grabbed && last_mouse_frame
3714 && FRAME_LIVE_P (last_mouse_frame))
3715 f = last_mouse_frame;
3716 else
3717 f = x_window_to_frame (event.xmotion.window);
3718 if (f)
3719 note_mouse_movement (f, &event.xmotion);
3720 else
3721 {
3722 struct scroll_bar *bar
3723 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 3724
7a13e894
RS
3725 if (bar)
3726 x_scroll_bar_note_movement (bar, &event);
b8009dd1 3727
7a13e894
RS
3728 /* If we move outside the frame,
3729 then we're certainly no longer on any text in the frame. */
3730 clear_mouse_face (dpyinfo);
3731 }
dc6f92b8 3732 }
0a178815 3733#if 0 /* This should be unnecessary, since the toolkit has no use
7a13e894
RS
3734 for motion events that happen outside of the menu event loop,
3735 and it seems to cause the bug that mouse events stop coming
3736 after a while. */
3afe33e7 3737#ifdef USE_X_TOOLKIT
7a13e894 3738 goto OTHER;
3afe33e7 3739#endif /* USE_X_TOOLKIT */
0a178815 3740#endif
7a13e894 3741 break;
dc6f92b8 3742
7a13e894
RS
3743 case ConfigureNotify:
3744 f = x_any_window_to_frame (event.xconfigure.window);
3afe33e7 3745#ifdef USE_X_TOOLKIT
7a13e894 3746 if (f
3a35ab44 3747#if 0
7a13e894 3748 && ! event.xconfigure.send_event
3a35ab44 3749#endif
7a13e894 3750 && (event.xconfigure.window == XtWindow (f->display.x->widget)))
af395ec1
RS
3751 {
3752 Window win, child;
3753 int win_x, win_y;
3754
6cc35d86
JB
3755 /* Find the position of the outside upper-left corner of
3756 the window, in the root coordinate system. Don't
3757 refer to the parent window here; we may be processing
3758 this event after the window manager has changed our
3759 parent, but before we have reached the ReparentNotify. */
334208b7 3760 XTranslateCoordinates (FRAME_X_DISPLAY (f),
58769bee 3761
af395ec1 3762 /* From-window, to-window. */
7a13e894 3763 XtWindow (f->display.x->widget),
334208b7 3764 FRAME_X_DISPLAY_INFO (f)->root_window,
af395ec1
RS
3765
3766 /* From-position, to-position. */
6cc35d86
JB
3767 -event.xconfigure.border_width,
3768 -event.xconfigure.border_width,
af395ec1
RS
3769 &win_x, &win_y,
3770
3771 /* Child of win. */
3772 &child);
3773 event.xconfigure.x = win_x;
3774 event.xconfigure.y = win_y;
7a13e894
RS
3775
3776 f->display.x->pixel_width = event.xconfigure.width;
3777 f->display.x->pixel_height = event.xconfigure.height;
3778 f->display.x->left_pos = event.xconfigure.x;
3779 f->display.x->top_pos = event.xconfigure.y;
3780
3781 /* What we have now is the position of Emacs's own window.
3782 Convert that to the position of the window manager window. */
3783 {
3784 int x, y;
3785 x_real_positions (f, &x, &y);
3786 f->display.x->left_pos = x;
3787 f->display.x->top_pos = y;
3788 }
af395ec1 3789 }
7a13e894
RS
3790 goto OTHER;
3791#else /* not USE_X_TOOLKIT */
3792 if (f)
3793 {
3794 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
3795 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
3796
3797 /* Even if the number of character rows and columns has
3798 not changed, the font size may have changed, so we need
3799 to check the pixel dimensions as well. */
3800 if (columns != f->width
3801 || rows != f->height
3802 || event.xconfigure.width != f->display.x->pixel_width
3803 || event.xconfigure.height != f->display.x->pixel_height)
3804 {
3805 change_frame_size (f, rows, columns, 0, 1);
3806 SET_FRAME_GARBAGED (f);
3807 }
af395ec1 3808
7a13e894
RS
3809 if (! event.xconfigure.send_event)
3810 {
3811 Window win, child;
3812 int win_x, win_y;
3813
3814 /* Find the position of the outside upper-left corner of
3815 the window, in the root coordinate system. Don't
3816 refer to the parent window here; we may be processing
3817 this event after the window manager has changed our
3818 parent, but before we have reached the ReparentNotify. */
3819 XTranslateCoordinates (FRAME_X_DISPLAY (f),
3820
3821 /* From-window, to-window. */
3822 f->display.x->window_desc,
3823 FRAME_X_DISPLAY_INFO (f)->root_window,
3824
3825 /* From-position, to-position. */
3826 -event.xconfigure.border_width,
3827 -event.xconfigure.border_width,
3828 &win_x, &win_y,
3829
3830 /* Child of win. */
3831 &child);
3832 event.xconfigure.x = win_x;
3833 event.xconfigure.y = win_y;
3834 }
3a35ab44 3835
7a13e894
RS
3836 f->display.x->pixel_width = event.xconfigure.width;
3837 f->display.x->pixel_height = event.xconfigure.height;
3838 f->display.x->left_pos = event.xconfigure.x;
3839 f->display.x->top_pos = event.xconfigure.y;
3840
3841 /* What we have now is the position of Emacs's own window.
3842 Convert that to the position of the window manager window. */
fd13dbb2 3843 {
7a13e894
RS
3844 int x, y;
3845 x_real_positions (f, &x, &y);
3846 f->display.x->left_pos = x;
3847 f->display.x->top_pos = y;
3848 if (y != event.xconfigure.y)
3849 {
3850 /* Since the WM decorations come below top_pos now,
3851 we must put them below top_pos in the future. */
3852 f->display.x->win_gravity = NorthWestGravity;
3853 x_wm_set_size_hint (f, 0, 0);
3854 }
fd13dbb2 3855 }
7a13e894 3856 }
3afe33e7 3857#endif /* not USE_X_TOOLKIT */
7a13e894 3858 break;
dc6f92b8 3859
7a13e894
RS
3860 case ButtonPress:
3861 case ButtonRelease:
3862 {
3863 /* If we decide we want to generate an event to be seen
3864 by the rest of Emacs, we put it here. */
3865 struct input_event emacs_event;
3866 emacs_event.kind = no_event;
dc6f92b8 3867
7a13e894 3868 bzero (&compose_status, sizeof (compose_status));
9b07615b 3869
7a13e894
RS
3870 f = x_window_to_frame (event.xbutton.window);
3871 if (f)
3872 {
3873 if (!x_focus_frame || (f == x_focus_frame))
3874 construct_mouse_click (&emacs_event, &event, f);
3875 }
3876 else
3877 {
3878 struct scroll_bar *bar
3879 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 3880
7a13e894
RS
3881 if (bar)
3882 x_scroll_bar_handle_click (bar, &event, &emacs_event);
3afe33e7 3883#ifdef USE_X_TOOLKIT
7a13e894
RS
3884 else
3885 {
3886 /* Assume we have a menubar button press. A bad
3887 assumption should behave benignly. */
3888 popup_get_selection (&event);
3889 break;
3890 }
3891#endif /* USE_X_TOOLKIT */
3892 }
3893
3894 if (event.type == ButtonPress)
3895 {
3896 dpyinfo->grabbed |= (1 << event.xbutton.button);
3897 last_mouse_frame = f;
3898 }
3afe33e7
RS
3899 else
3900 {
7a13e894 3901 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 3902 }
23faf38f 3903
7a13e894
RS
3904 if (numchars >= 1 && emacs_event.kind != no_event)
3905 {
3906 bcopy (&emacs_event, bufp, sizeof (struct input_event));
3907 bufp++;
3908 count++;
3909 numchars--;
3910 }
3afe33e7
RS
3911
3912#ifdef USE_X_TOOLKIT
7a13e894 3913 goto OTHER;
3afe33e7 3914#endif /* USE_X_TOOLKIT */
7a13e894
RS
3915 }
3916 break;
dc6f92b8 3917
7a13e894
RS
3918 case CirculateNotify:
3919 break;
3920 case CirculateRequest:
3921 break;
dc6f92b8 3922
7a13e894
RS
3923 case MappingNotify:
3924 /* Someone has changed the keyboard mapping - update the
3925 local cache. */
3926 switch (event.xmapping.request)
3927 {
3928 case MappingModifier:
3929 x_find_modifier_meanings (dpyinfo);
3930 /* This is meant to fall through. */
3931 case MappingKeyboard:
3932 XRefreshKeyboardMapping (&event.xmapping);
3933 }
3afe33e7 3934#ifdef USE_X_TOOLKIT
7a13e894 3935 goto OTHER;
3afe33e7 3936#endif /* USE_X_TOOLKIT */
7a13e894 3937 break;
dc6f92b8 3938
7a13e894 3939 default:
3afe33e7 3940#ifdef USE_X_TOOLKIT
7a13e894
RS
3941 OTHER:
3942 BLOCK_INPUT;
3943 XtDispatchEvent (&event);
3944 UNBLOCK_INPUT;
3afe33e7 3945#endif /* USE_X_TOOLKIT */
7a13e894
RS
3946 break;
3947 }
dc6f92b8
JB
3948 }
3949 }
3950
9a5196d0
RS
3951 /* On some systems, an X bug causes Emacs to get no more events
3952 when the window is destroyed. Detect that. (1994.) */
58769bee 3953 if (! event_found)
ef2a22d0 3954 {
ef2a22d0
RS
3955 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
3956 One XNOOP in 100 loops will make Emacs terminate.
3957 B. Bretthauer, 1994 */
3958 x_noop_count++;
58769bee 3959 if (x_noop_count >= 100)
ef2a22d0
RS
3960 {
3961 x_noop_count=0;
7a13e894
RS
3962 /* Use the first display in the list. Why not? */
3963 XNoOp (x_display_list->display);
ef2a22d0
RS
3964 }
3965 }
502add23 3966
0134a210
RS
3967 /* If the focus was just given to an autoraising frame,
3968 raise it now. */
7a13e894 3969 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
3970 if (pending_autoraise_frame)
3971 {
3972 x_raise_frame (pending_autoraise_frame);
3973 pending_autoraise_frame = 0;
3974 }
0134a210 3975
dc6f92b8
JB
3976 UNBLOCK_INPUT;
3977 return count;
3978}
dc6f92b8 3979\f
f451eb13
JB
3980/* Drawing the cursor. */
3981
3982
dc6f92b8
JB
3983/* Draw a hollow box cursor. Don't change the inside of the box. */
3984
3985static void
f676886a
JB
3986x_draw_box (f)
3987 struct frame *f;
dc6f92b8 3988{
2a6cf806
RS
3989 int left = CHAR_TO_PIXEL_COL (f, curs_x);
3990 int top = CHAR_TO_PIXEL_ROW (f, curs_y);
f676886a 3991 int width = FONT_WIDTH (f->display.x->font);
a27f9f86 3992 int height = f->display.x->line_height;
dc6f92b8 3993
334208b7 3994 XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f676886a 3995 f->display.x->cursor_gc,
dc6f92b8 3996 left, top, width - 1, height - 1);
dc6f92b8
JB
3997}
3998
f676886a 3999/* Clear the cursor of frame F to background color,
dc6f92b8
JB
4000 and mark the cursor as not shown.
4001 This is used when the text where the cursor is
4002 is about to be rewritten. */
4003
4004static void
f676886a
JB
4005clear_cursor (f)
4006 struct frame *f;
dc6f92b8
JB
4007{
4008 int mask;
4009
f451eb13 4010 if (! FRAME_VISIBLE_P (f)
f676886a 4011 || f->phys_cursor_x < 0)
dc6f92b8
JB
4012 return;
4013
f676886a 4014 x_display_cursor (f, 0);
f676886a 4015 f->phys_cursor_x = -1;
dc6f92b8
JB
4016}
4017
f676886a 4018/* Redraw the glyph at ROW, COLUMN on frame F, in the style
90e65f07
JB
4019 HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the
4020 glyph drawn. */
dc6f92b8
JB
4021
4022static void
f676886a
JB
4023x_draw_single_glyph (f, row, column, glyph, highlight)
4024 struct frame *f;
dc6f92b8 4025 int row, column;
90e65f07 4026 GLYPH glyph;
dc6f92b8
JB
4027 int highlight;
4028{
f676886a 4029 dumpglyphs (f,
12ba150f
JB
4030 CHAR_TO_PIXEL_COL (f, column),
4031 CHAR_TO_PIXEL_ROW (f, row),
0cdd0c9f 4032 &glyph, 1, highlight, 0);
dc6f92b8
JB
4033}
4034
dc6f92b8 4035static void
dbc4e1c1 4036x_display_bar_cursor (f, on)
f676886a 4037 struct frame *f;
dc6f92b8
JB
4038 int on;
4039{
f676886a 4040 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
90e65f07 4041
49d838ea
JB
4042 /* This is pointless on invisible frames, and dangerous on garbaged
4043 frames; in the latter case, the frame may be in the midst of
4044 changing its size, and curs_x and curs_y may be off the frame. */
4045 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dbc4e1c1
JB
4046 return;
4047
4048 if (! on && f->phys_cursor_x < 0)
4049 return;
4050
f676886a 4051 /* If we're not updating, then we want to use the current frame's
1113d9db 4052 cursor position, not our local idea of where the cursor ought to be. */
f676886a 4053 if (f != updating_frame)
1113d9db 4054 {
f676886a
JB
4055 curs_x = FRAME_CURSOR_X (f);
4056 curs_y = FRAME_CURSOR_Y (f);
1113d9db
JB
4057 }
4058
dbc4e1c1
JB
4059 /* If there is anything wrong with the current cursor state, remove it. */
4060 if (f->phys_cursor_x >= 0
4061 && (!on
4062 || f->phys_cursor_x != curs_x
4063 || f->phys_cursor_y != curs_y
4064 || f->display.x->current_cursor != bar_cursor))
4065 {
4066 /* Erase the cursor by redrawing the character underneath it. */
4067 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4068 f->phys_cursor_glyph,
4069 current_glyphs->highlight[f->phys_cursor_y]);
4070 f->phys_cursor_x = -1;
4071 }
4072
4073 /* If we now need a cursor in the new place or in the new form, do it so. */
4074 if (on
4075 && (f->phys_cursor_x < 0
4076 || (f->display.x->current_cursor != bar_cursor)))
4077 {
4078 f->phys_cursor_glyph
4079 = ((current_glyphs->enable[curs_y]
4080 && curs_x < current_glyphs->used[curs_y])
4081 ? current_glyphs->glyphs[curs_y][curs_x]
4082 : SPACEGLYPH);
334208b7 4083 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
4084 f->display.x->cursor_gc,
4085 CHAR_TO_PIXEL_COL (f, curs_x),
4086 CHAR_TO_PIXEL_ROW (f, curs_y),
a27f9f86 4087 1, f->display.x->line_height);
dbc4e1c1
JB
4088
4089 f->phys_cursor_x = curs_x;
4090 f->phys_cursor_y = curs_y;
4091
4092 f->display.x->current_cursor = bar_cursor;
4093 }
4094
4095 if (updating_frame != f)
334208b7 4096 XFlush (FRAME_X_DISPLAY (f));
dbc4e1c1
JB
4097}
4098
4099
4100/* Turn the displayed cursor of frame F on or off according to ON.
4101 If ON is nonzero, where to put the cursor is specified
4102 by F->cursor_x and F->cursor_y. */
4103
4104static void
4105x_display_box_cursor (f, on)
4106 struct frame *f;
4107 int on;
4108{
4109 struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
4110
49d838ea
JB
4111 /* This is pointless on invisible frames, and dangerous on garbaged
4112 frames; in the latter case, the frame may be in the midst of
4113 changing its size, and curs_x and curs_y may be off the frame. */
4114 if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
dc6f92b8
JB
4115 return;
4116
4117 /* If cursor is off and we want it off, return quickly. */
f676886a 4118 if (!on && f->phys_cursor_x < 0)
dc6f92b8
JB
4119 return;
4120
dbc4e1c1
JB
4121 /* If we're not updating, then we want to use the current frame's
4122 cursor position, not our local idea of where the cursor ought to be. */
4123 if (f != updating_frame)
4124 {
4125 curs_x = FRAME_CURSOR_X (f);
4126 curs_y = FRAME_CURSOR_Y (f);
4127 }
4128
dc6f92b8
JB
4129 /* If cursor is currently being shown and we don't want it to be
4130 or it is in the wrong place,
4131 or we want a hollow box and it's not so, (pout!)
4132 erase it. */
f676886a 4133 if (f->phys_cursor_x >= 0
dc6f92b8 4134 && (!on
f676886a
JB
4135 || f->phys_cursor_x != curs_x
4136 || f->phys_cursor_y != curs_y
dbc4e1c1 4137 || (f->display.x->current_cursor != hollow_box_cursor
f676886a 4138 && (f != x_highlight_frame))))
dc6f92b8 4139 {
79cf7456
RS
4140 int mouse_face_here = 0;
4141
4142 /* If the cursor is in the mouse face area, redisplay that when
4143 we clear the cursor. */
7a13e894 4144 if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame
79cf7456 4145 &&
7a13e894
RS
4146 (f->phys_cursor_y > FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
4147 || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
4148 && f->phys_cursor_x >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col))
79cf7456 4149 &&
7a13e894
RS
4150 (f->phys_cursor_y < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
4151 || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
4152 && f->phys_cursor_x < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col)))
79cf7456
RS
4153 mouse_face_here = 1;
4154
0cdd0c9f
RS
4155 /* If the font is not as tall as a whole line,
4156 we must explicitly clear the line's whole height. */
4157 if (FONT_HEIGHT (f->display.x->font) != f->display.x->line_height)
334208b7 4158 XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
0cdd0c9f
RS
4159 CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
4160 CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
4161 FONT_WIDTH (f->display.x->font),
4162 f->display.x->line_height, False);
dc6f92b8 4163 /* Erase the cursor by redrawing the character underneath it. */
f676886a
JB
4164 x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
4165 f->phys_cursor_glyph,
79cf7456
RS
4166 (mouse_face_here
4167 ? 3
4168 : current_glyphs->highlight[f->phys_cursor_y]));
f676886a 4169 f->phys_cursor_x = -1;
dc6f92b8
JB
4170 }
4171
4172 /* If we want to show a cursor,
4173 or we want a box cursor and it's not so,
4174 write it in the right place. */
4175 if (on
f676886a 4176 && (f->phys_cursor_x < 0
dbc4e1c1 4177 || (f->display.x->current_cursor != filled_box_cursor
f676886a 4178 && f == x_highlight_frame)))
dc6f92b8 4179 {
f676886a 4180 f->phys_cursor_glyph
1113d9db
JB
4181 = ((current_glyphs->enable[curs_y]
4182 && curs_x < current_glyphs->used[curs_y])
4183 ? current_glyphs->glyphs[curs_y][curs_x]
90e65f07 4184 : SPACEGLYPH);
f676886a 4185 if (f != x_highlight_frame)
dc6f92b8 4186 {
f676886a 4187 x_draw_box (f);
dbc4e1c1 4188 f->display.x->current_cursor = hollow_box_cursor;
dc6f92b8
JB
4189 }
4190 else
4191 {
f676886a
JB
4192 x_draw_single_glyph (f, curs_y, curs_x,
4193 f->phys_cursor_glyph, 2);
dbc4e1c1 4194 f->display.x->current_cursor = filled_box_cursor;
dc6f92b8
JB
4195 }
4196
f676886a
JB
4197 f->phys_cursor_x = curs_x;
4198 f->phys_cursor_y = curs_y;
dc6f92b8
JB
4199 }
4200
f676886a 4201 if (updating_frame != f)
334208b7 4202 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
4203}
4204
f676886a
JB
4205x_display_cursor (f, on)
4206 struct frame *f;
dc6f92b8
JB
4207 int on;
4208{
f94397b5
KH
4209 BLOCK_INPUT;
4210
dbc4e1c1 4211 if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
f676886a 4212 x_display_box_cursor (f, on);
dbc4e1c1 4213 else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
f676886a 4214 x_display_bar_cursor (f, on);
dbc4e1c1
JB
4215 else
4216 /* Those are the only two we have implemented! */
4217 abort ();
f94397b5
KH
4218
4219 UNBLOCK_INPUT;
dc6f92b8
JB
4220}
4221\f
4222/* Icons. */
4223
f676886a 4224/* Refresh bitmap kitchen sink icon for frame F
dc6f92b8
JB
4225 when we get an expose event for it. */
4226
f676886a
JB
4227refreshicon (f)
4228 struct frame *f;
dc6f92b8 4229{
dc6f92b8 4230 /* Normally, the window manager handles this function. */
dc6f92b8
JB
4231}
4232
dbc4e1c1 4233/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
4234
4235int
990ba854 4236x_bitmap_icon (f, file)
f676886a 4237 struct frame *f;
990ba854 4238 Lisp_Object file;
dc6f92b8 4239{
7f2ae036 4240 int mask, bitmap_id;
dc6f92b8
JB
4241 Window icon_window;
4242
c118dd06 4243 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
4244 return 1;
4245
990ba854
RS
4246 /* Free up our existing icon bitmap if any. */
4247 if (f->display.x->icon_bitmap > 0)
4248 x_destroy_bitmap (f, f->display.x->icon_bitmap);
4249 f->display.x->icon_bitmap = 0;
4250
4251 if (STRINGP (file))
7f2ae036
RS
4252 bitmap_id = x_create_bitmap_from_file (f, file);
4253 else
4254 {
990ba854 4255 /* Create the GNU bitmap if necessary. */
334208b7
RS
4256 if (!FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
4257 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
4258 = x_create_bitmap_from_data (f, gnu_bits,
4259 gnu_width, gnu_height);
990ba854
RS
4260
4261 /* The first time we create the GNU bitmap,
4262 this increments the refcount one extra time.
4263 As a result, the GNU bitmap is never freed.
4264 That way, we don't have to worry about allocating it again. */
334208b7 4265 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 4266
334208b7 4267 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
4268 }
4269
4270 x_wm_set_icon_pixmap (f, bitmap_id);
4271 f->display.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
4272
4273 return 0;
4274}
4275
4276
f676886a 4277/* Make the x-window of frame F use a rectangle with text. */
dc6f92b8
JB
4278
4279int
f676886a
JB
4280x_text_icon (f, icon_name)
4281 struct frame *f;
dc6f92b8
JB
4282 char *icon_name;
4283{
c118dd06 4284 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
4285 return 1;
4286
dc6f92b8 4287 if (icon_name)
f676886a 4288 f->display.x->icon_label = icon_name;
dc6f92b8 4289 else
f676886a
JB
4290 if (! f->display.x->icon_label)
4291 f->display.x->icon_label = " *emacs* ";
58769bee 4292
dfeccd2d 4293#if 0
334208b7 4294 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f676886a 4295 (char *) f->display.x->icon_label);
dfeccd2d 4296#endif
58769bee 4297
990ba854
RS
4298 if (f->display.x->icon_bitmap > 0)
4299 x_destroy_bitmap (f, f->display.x->icon_bitmap);
7f2ae036 4300 f->display.x->icon_bitmap = 0;
b1c884c3 4301 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
4302
4303 return 0;
4304}
4305\f
4746118a
JB
4306/* Handling X errors. */
4307
7a13e894 4308/* Handle the loss of connection to display DISPLAY. */
16bd92ea 4309
4746118a 4310static SIGTYPE
7a13e894
RS
4311x_connection_closed (display, error_message)
4312 Display *display;
4313 char *error_message;
4746118a 4314{
7a13e894
RS
4315 struct x_display_info *dpyinfo = x_display_info_for_display (display);
4316 Lisp_Object frame, tail;
4317
4746118a
JB
4318 if (_Xdebug)
4319 abort ();
12ba150f 4320
7a13e894
RS
4321 /* First delete frames whose minibuffers are on frames
4322 that are on the dead display. */
4323 FOR_EACH_FRAME (tail, frame)
4324 {
4325 Lisp_Object minibuf_frame;
4326 minibuf_frame
4327 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
4328 if (! EQ (frame, minibuf_frame)
4329 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
4330 Fdelete_frame (frame, Qt);
4331 }
4332
4333 /* Now delete all remaining frames on the dead display.
4334 We are now sure none of these is used as the minibuffer
4335 for another frame that we need to delete. */
4336 FOR_EACH_FRAME (tail, frame)
4337 if (FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
4338 Fdelete_frame (frame, Qt);
4339
4340 x_delete_display (dpyinfo);
4341
4342 if (x_display_list == 0)
4343 {
4344 fprintf (stderr, "%s", error_message);
4345 shut_down_emacs (0, 0, Qnil);
4346 exit (70);
4347 }
12ba150f 4348
7a13e894
RS
4349 /* Ordinary stack unwind doesn't deal with these. */
4350#ifdef SIGIO
4351 sigunblock (sigmask (SIGIO));
4352#endif
4353 sigunblock (sigmask (SIGALRM));
4354 TOTALLY_UNBLOCK_INPUT;
4355
4356 error ("%s", error_message);
4746118a
JB
4357}
4358
7a13e894
RS
4359/* This is the usual handler for X protocol errors.
4360 It kills all frames on the display that we got the error for.
4361 If that was the only one, it prints an error message and kills Emacs. */
4362
c118dd06
JB
4363static int
4364x_error_quitter (display, error)
4365 Display *display;
4366 XErrorEvent *error;
4367{
7a13e894 4368 char buf[256], buf1[356];
dc6f92b8 4369
58769bee 4370 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 4371 original error handler. */
dc6f92b8 4372
c118dd06 4373 XGetErrorText (display, error->error_code, buf, sizeof (buf));
7a13e894 4374 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 4375 buf, error->request_code);
7a13e894 4376 x_connection_closed (display, buf1);
dc6f92b8
JB
4377}
4378
7a13e894
RS
4379/* This is the handler for X IO errors, always.
4380 It kills all frames on the display that we lost touch with.
4381 If that was the only one, it prints an error message and kills Emacs. */
4382
8922af5f
JB
4383static int
4384x_io_error_quitter (display)
4385 Display *display;
4386{
7a13e894 4387 char buf[256];
8922af5f 4388
7a13e894
RS
4389 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
4390 x_connection_closed (display, buf);
8922af5f 4391}
7a13e894 4392\f
c118dd06 4393/* A buffer for storing X error messages. */
cef13e55
RS
4394static char *x_caught_error_message;
4395#define X_CAUGHT_ERROR_MESSAGE_SIZE 200
c118dd06
JB
4396
4397/* An X error handler which stores the error message in
4398 x_caught_error_message. This is what's installed when
4399 x_catch_errors is in effect. */
7a13e894 4400
c118dd06
JB
4401static int
4402x_error_catcher (display, error)
4403 Display *display;
4404 XErrorEvent *error;
4405{
4406 XGetErrorText (display, error->error_code,
cef13e55 4407 x_caught_error_message, X_CAUGHT_ERROR_MESSAGE_SIZE);
c118dd06
JB
4408}
4409
4410
7a13e894
RS
4411/* Begin trapping X errors for display DPY. Actually we trap X errors
4412 for all displays, but DPY should be the display you are actually
4413 operating on.
dc6f92b8 4414
c118dd06
JB
4415 After calling this function, X protocol errors no longer cause
4416 Emacs to exit; instead, they are recorded in x_cfc_error_message.
dc6f92b8 4417
c118dd06
JB
4418 Calling x_check_errors signals an Emacs error if an X error has
4419 occurred since the last call to x_catch_errors or x_check_errors.
4420
4421 Calling x_uncatch_errors resumes the normal error handling. */
4422
bc20ebbf 4423void x_catch_errors (), x_check_errors (), x_uncatch_errors ();
c118dd06
JB
4424
4425void
7a13e894
RS
4426x_catch_errors (dpy)
4427 Display *dpy;
dc6f92b8 4428{
c118dd06 4429 /* Make sure any errors from previous requests have been dealt with. */
7a13e894 4430 XSync (dpy, False);
dc6f92b8 4431
c118dd06 4432 /* Set up the error buffer. */
60f9aad3 4433 x_caught_error_message
cef13e55
RS
4434 = (char*) xmalloc (X_CAUGHT_ERROR_MESSAGE_SIZE);
4435 x_caught_error_message[0] = '\0';
16bd92ea 4436
c118dd06 4437 /* Install our little error handler. */
334208b7 4438 XSetErrorHandler (x_error_catcher);
c118dd06 4439}
16bd92ea 4440
c118dd06
JB
4441/* If any X protocol errors have arrived since the last call to
4442 x_catch_errors or x_check_errors, signal an Emacs error using
4443 sprintf (a buffer, FORMAT, the x error message text) as the text. */
812361a1 4444
c118dd06 4445void
7a13e894
RS
4446x_check_errors (dpy, format)
4447 Display *dpy;
c118dd06
JB
4448 char *format;
4449{
4450 /* Make sure to catch any errors incurred so far. */
7a13e894 4451 XSync (dpy, False);
16bd92ea 4452
cef13e55 4453 if (x_caught_error_message[0])
c118dd06 4454 {
cef13e55 4455 char buf[X_CAUGHT_ERROR_MESSAGE_SIZE + 56];
dc6f92b8 4456
cef13e55 4457 sprintf (buf, format, x_caught_error_message);
7a13e894 4458 x_uncatch_errors (dpy);
c118dd06
JB
4459 error (buf);
4460 }
4461}
4462
b849c413
RS
4463/* Nonzero if we had any X protocol errors since we did x_catch_errors. */
4464
4465int
7a13e894
RS
4466x_had_errors_p (dpy)
4467 Display *dpy;
b849c413
RS
4468{
4469 /* Make sure to catch any errors incurred so far. */
7a13e894 4470 XSync (dpy, False);
b849c413
RS
4471
4472 return x_caught_error_message[0] != 0;
4473}
4474
812361a1
RS
4475/* Stop catching X protocol errors and let them make Emacs die. */
4476
c118dd06 4477void
7a13e894
RS
4478x_uncatch_errors (dpy)
4479 Display *dpy;
c118dd06 4480{
9ac0d9e0 4481 xfree (x_caught_error_message);
cef13e55 4482 x_caught_error_message = 0;
334208b7 4483 XSetErrorHandler (x_error_quitter);
dc6f92b8
JB
4484}
4485
dc6f92b8
JB
4486#if 0
4487static unsigned int x_wire_count;
4488x_trace_wire ()
4489{
4490 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
4491}
c118dd06 4492#endif /* ! 0 */
dc6f92b8
JB
4493
4494\f
f451eb13
JB
4495/* Changing the font of the frame. */
4496
76bcdf39
RS
4497/* Give frame F the font named FONTNAME as its default font, and
4498 return the full name of that font. FONTNAME may be a wildcard
4499 pattern; in that case, we choose some font that fits the pattern.
4500 The return value shows which font we chose. */
4501
b5cf7a0e 4502Lisp_Object
f676886a
JB
4503x_new_font (f, fontname)
4504 struct frame *f;
dc6f92b8
JB
4505 register char *fontname;
4506{
dc6f92b8
JB
4507 int already_loaded;
4508 int n_matching_fonts;
4509 XFontStruct *font_info;
4510 char **font_names;
4511
4512 /* Get a list of all the fonts that match this name. Once we
4513 have a list of matching fonts, we compare them against the fonts
4514 we already have by comparing font ids. */
334208b7 4515 font_names = (char **) XListFonts (FRAME_X_DISPLAY (f), fontname,
2224a5fc 4516 1024, &n_matching_fonts);
0c94f6ee
JB
4517 /* Apparently it doesn't set n_matching_fonts to zero when it can't
4518 find any matches; font_names == 0 is the only clue. */
4519 if (! font_names)
4520 n_matching_fonts = 0;
4521
5835f860
RS
4522 /* Don't just give up if n_matching_fonts is 0.
4523 Apparently there's a bug on Suns: XListFontsWithInfo can
4524 fail to find a font, but XLoadQueryFont may still find it. */
dc6f92b8 4525
90e65f07 4526 /* See if we've already loaded a matching font. */
5835f860
RS
4527 already_loaded = -1;
4528 if (n_matching_fonts != 0)
4529 {
4530 int i, j;
dc6f92b8 4531
7a13e894 4532 for (i = 0; i < FRAME_X_DISPLAY_INFO (f)->n_fonts; i++)
5835f860 4533 for (j = 0; j < n_matching_fonts; j++)
7a13e894
RS
4534 if (!strcmp (FRAME_X_DISPLAY_INFO (f)->font_table[i].name, font_names[j])
4535 || !strcmp (FRAME_X_DISPLAY_INFO (f)->font_table[i].full_name, font_names[j]))
5835f860
RS
4536 {
4537 already_loaded = i;
7a13e894 4538 fontname = FRAME_X_DISPLAY_INFO (f)->font_table[i].full_name;
5835f860
RS
4539 goto found_font;
4540 }
4541 }
dc6f92b8 4542 found_font:
58769bee 4543
dc6f92b8 4544 /* If we have, just return it from the table. */
2224a5fc 4545 if (already_loaded >= 0)
7a13e894 4546 f->display.x->font = FRAME_X_DISPLAY_INFO (f)->font_table[already_loaded].font;
dc6f92b8
JB
4547 /* Otherwise, load the font and add it to the table. */
4548 else
4549 {
9696f58b 4550 int i;
76bcdf39 4551 char *full_name;
dc6f92b8 4552 XFontStruct *font;
7a13e894 4553 int n_fonts;
dc6f92b8 4554
9696f58b 4555 /* Try to find a character-cell font in the list. */
58769bee 4556#if 0
f126bd67 4557 /* A laudable goal, but this isn't how to do it. */
9696f58b
JB
4558 for (i = 0; i < n_matching_fonts; i++)
4559 if (! font_info[i].per_char)
4560 break;
f126bd67
JB
4561#else
4562 i = 0;
4563#endif
9696f58b 4564
5835f860
RS
4565 /* See comment above. */
4566 if (n_matching_fonts != 0)
9696f58b
JB
4567 fontname = font_names[i];
4568
334208b7 4569 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
dc6f92b8 4570 if (! font)
5835f860 4571 {
2224a5fc 4572 /* Free the information from XListFonts. */
5835f860 4573 if (n_matching_fonts)
2224a5fc 4574 XFreeFontNames (font_names);
5835f860
RS
4575 return Qnil;
4576 }
dc6f92b8
JB
4577
4578 /* Do we need to create the table? */
7a13e894 4579 if (FRAME_X_DISPLAY_INFO (f)->font_table_size == 0)
dc6f92b8 4580 {
7a13e894
RS
4581 FRAME_X_DISPLAY_INFO (f)->font_table_size = 16;
4582 FRAME_X_DISPLAY_INFO (f)->font_table
4583 = (struct font_info *) xmalloc (FRAME_X_DISPLAY_INFO (f)->font_table_size
4584 * sizeof (struct font_info));
dc6f92b8
JB
4585 }
4586 /* Do we need to grow the table? */
7a13e894
RS
4587 else if (FRAME_X_DISPLAY_INFO (f)->n_fonts
4588 >= FRAME_X_DISPLAY_INFO (f)->font_table_size)
dc6f92b8 4589 {
7a13e894
RS
4590 FRAME_X_DISPLAY_INFO (f)->font_table_size *= 2;
4591 FRAME_X_DISPLAY_INFO (f)->font_table
4592 = (struct font_info *) xrealloc (FRAME_X_DISPLAY_INFO (f)->font_table,
4593 (FRAME_X_DISPLAY_INFO (f)->font_table_size
4594 * sizeof (struct font_info)));
dc6f92b8
JB
4595 }
4596
76bcdf39
RS
4597 /* Try to get the full name of FONT. Put it in full_name. */
4598 full_name = 0;
4599 for (i = 0; i < font->n_properties; i++)
4600 {
4601 char *atom
334208b7 4602 = XGetAtomName (FRAME_X_DISPLAY (f), font->properties[i].name);
76bcdf39 4603 if (!strcmp (atom, "FONT"))
7965883b 4604 {
334208b7 4605 char *name = XGetAtomName (FRAME_X_DISPLAY (f),
7965883b
RS
4606 (Atom) (font->properties[i].card32));
4607 char *p = name;
4608 int dashes = 0;
4609
4610 /* Count the number of dashes in the "full name".
4611 If it is too few, this isn't really the font's full name,
4612 so don't use it.
4613 In X11R4, the fonts did not come with their canonical names
4614 stored in them. */
4615 while (*p)
4616 {
4617 if (*p == '-')
4618 dashes++;
4619 p++;
4620 }
4621
4622 if (dashes >= 13)
4623 full_name = name;
8ed24d5a
RS
4624
4625 break;
7965883b
RS
4626 }
4627
76bcdf39
RS
4628 XFree (atom);
4629 }
4630
7a13e894
RS
4631 n_fonts = FRAME_X_DISPLAY_INFO (f)->n_fonts;
4632 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name = (char *) xmalloc (strlen (fontname) + 1);
4633 bcopy (fontname, FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name, strlen (fontname) + 1);
76bcdf39 4634 if (full_name != 0)
7a13e894 4635 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].full_name = full_name;
76bcdf39 4636 else
7a13e894
RS
4637 FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].full_name = FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].name;
4638 f->display.x->font = FRAME_X_DISPLAY_INFO (f)->font_table[n_fonts].font = font;
4639 FRAME_X_DISPLAY_INFO (f)->n_fonts++;
76bcdf39 4640
d53067dc
RS
4641 if (full_name)
4642 fontname = full_name;
dc6f92b8 4643 }
2224a5fc 4644
b2cad826
KH
4645 /* Compute the scroll bar width in character columns. */
4646 if (f->scroll_bar_pixel_width > 0)
4647 {
4648 int wid = FONT_WIDTH (f->display.x->font);
4649 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
4650 }
4651 else
4652 f->scroll_bar_cols = 2;
4653
f676886a 4654 /* Now make the frame display the given font. */
c118dd06 4655 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 4656 {
334208b7 4657 XSetFont (FRAME_X_DISPLAY (f), f->display.x->normal_gc,
f676886a 4658 f->display.x->font->fid);
334208b7 4659 XSetFont (FRAME_X_DISPLAY (f), f->display.x->reverse_gc,
f676886a 4660 f->display.x->font->fid);
334208b7 4661 XSetFont (FRAME_X_DISPLAY (f), f->display.x->cursor_gc,
f676886a
JB
4662 f->display.x->font->fid);
4663
a27f9f86 4664 frame_update_line_height (f);
0134a210 4665 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 4666 }
a27f9f86
RS
4667 else
4668 /* If we are setting a new frame's font for the first time,
4669 there are no faces yet, so this font's height is the line height. */
0cdd0c9f 4670 f->display.x->line_height = FONT_HEIGHT (f->display.x->font);
dc6f92b8 4671
b5cf7a0e 4672 {
abdda982 4673 Lisp_Object lispy_name;
b5cf7a0e 4674
abdda982 4675 lispy_name = build_string (fontname);
b5cf7a0e 4676
2224a5fc 4677 /* Free the information from XListFonts. The data
b5cf7a0e 4678 we actually retain comes from XLoadQueryFont. */
2224a5fc 4679 XFreeFontNames (font_names);
b5cf7a0e
JB
4680
4681 return lispy_name;
4682 }
dc6f92b8 4683}
dc6f92b8 4684\f
43bca5d5 4685x_calc_absolute_position (f)
f676886a 4686 struct frame *f;
dc6f92b8 4687{
6dba1858
RS
4688 Window win, child;
4689 int win_x = 0, win_y = 0;
43bca5d5 4690 int flags = f->display.x->size_hint_flags;
6dba1858
RS
4691
4692 /* Find the position of the outside upper-left corner of
4693 the inner window, with respect to the outer window. */
334208b7 4694 if (f->display.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858
RS
4695 {
4696 BLOCK_INPUT;
334208b7 4697 XTranslateCoordinates (FRAME_X_DISPLAY (f),
58769bee 4698
6dba1858
RS
4699 /* From-window, to-window. */
4700 f->display.x->window_desc,
4701 f->display.x->parent_desc,
4702
4703 /* From-position, to-position. */
4704 0, 0, &win_x, &win_y,
4705
4706 /* Child of win. */
4707 &child);
4708 UNBLOCK_INPUT;
4709 }
4710
4711 /* Treat negative positions as relative to the leftmost bottommost
4712 position that fits on the screen. */
20f55f9a 4713 if (flags & XNegative)
334208b7 4714 f->display.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
69388238 4715 - 2 * f->display.x->border_width - win_x
31ea78fd
JB
4716 - PIXEL_WIDTH (f)
4717 + f->display.x->left_pos);
dc6f92b8 4718
20f55f9a 4719 if (flags & YNegative)
334208b7 4720 f->display.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
69388238 4721 - 2 * f->display.x->border_width - win_y
31ea78fd
JB
4722 - PIXEL_HEIGHT (f)
4723 + f->display.x->top_pos);
3a35ab44
RS
4724 /* The left_pos and top_pos
4725 are now relative to the top and left screen edges,
4726 so the flags should correspond. */
4727 f->display.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
4728}
4729
3a35ab44
RS
4730/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
4731 to really change the position, and 0 when calling from
4732 x_make_frame_visible (in that case, XOFF and YOFF are the current
4733 position values). */
4734
dc05a16b 4735x_set_offset (f, xoff, yoff, change_gravity)
f676886a 4736 struct frame *f;
dc6f92b8 4737 register int xoff, yoff;
dc05a16b 4738 int change_gravity;
dc6f92b8 4739{
3a35ab44
RS
4740 if (change_gravity)
4741 {
4742 f->display.x->top_pos = yoff;
4743 f->display.x->left_pos = xoff;
4744 f->display.x->size_hint_flags &= ~ (XNegative | YNegative);
4745 if (xoff < 0)
4746 f->display.x->size_hint_flags |= XNegative;
4747 if (yoff < 0)
4748 f->display.x->size_hint_flags |= YNegative;
4749 f->display.x->win_gravity = NorthWestGravity;
4750 }
43bca5d5 4751 x_calc_absolute_position (f);
dc6f92b8
JB
4752
4753 BLOCK_INPUT;
3a35ab44
RS
4754 x_wm_set_size_hint (f, 0, 0);
4755
3afe33e7 4756#ifdef USE_X_TOOLKIT
334208b7 4757 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget),
3afe33e7
RS
4758 f->display.x->left_pos, f->display.x->top_pos);
4759#else /* not USE_X_TOOLKIT */
334208b7 4760 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f676886a 4761 f->display.x->left_pos, f->display.x->top_pos);
3afe33e7 4762#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
4763 UNBLOCK_INPUT;
4764}
4765
bc20ebbf
FP
4766/* Call this to change the size of frame F's x-window.
4767 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
4768 for this size change and subsequent size changes.
4769 Otherwise we leave the window gravity unchanged. */
dc6f92b8 4770
bc20ebbf 4771x_set_window_size (f, change_gravity, cols, rows)
f676886a 4772 struct frame *f;
bc20ebbf 4773 int change_gravity;
b1c884c3 4774 int cols, rows;
dc6f92b8
JB
4775{
4776 int pixelwidth, pixelheight;
4777 int mask;
dc6f92b8 4778
80fd1fe2
FP
4779#ifdef USE_X_TOOLKIT
4780 BLOCK_INPUT;
3a20653d
RS
4781 {
4782 /* The x and y position of the widget is clobbered by the
4783 call to XtSetValues within EmacsFrameSetCharSize.
4784 This is a real kludge, but I don't understand Xt so I can't
4785 figure out a correct fix. Can anyone else tell me? -- rms. */
4786 int xpos = f->display.x->widget->core.x;
4787 int ypos = f->display.x->widget->core.y;
4788 EmacsFrameSetCharSize (f->display.x->edit_widget, cols, rows);
4789 f->display.x->widget->core.x = xpos;
4790 f->display.x->widget->core.y = ypos;
4791 }
80fd1fe2
FP
4792 UNBLOCK_INPUT;
4793
4794#else /* not USE_X_TOOLKIT */
4795
dc6f92b8
JB
4796 BLOCK_INPUT;
4797
b1c884c3 4798 check_frame_size (f, &rows, &cols);
6dba1858 4799 f->display.x->vertical_scroll_bar_extra
b2cad826
KH
4800 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
4801 ? 0
4802 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 4803 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
b2cad826 4804 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->display.x->font)));
f451eb13
JB
4805 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
4806 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 4807
af31d76f
RS
4808 f->display.x->win_gravity = NorthWestGravity;
4809 x_wm_set_size_hint (f, 0, 0);
6ccf47d1 4810
334208b7
RS
4811 XSync (FRAME_X_DISPLAY (f), False);
4812 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4813 pixelwidth, pixelheight);
b1c884c3
JB
4814
4815 /* Now, strictly speaking, we can't be sure that this is accurate,
4816 but the window manager will get around to dealing with the size
4817 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
4818 ConfigureNotify event gets here.
4819
4820 We could just not bother storing any of this information here,
4821 and let the ConfigureNotify event set everything up, but that
4822 might be kind of confusing to the lisp code, since size changes
4823 wouldn't be reported in the frame parameters until some random
4824 point in the future when the ConfigureNotify event arrives. */
8922af5f 4825 change_frame_size (f, rows, cols, 0, 0);
b1c884c3
JB
4826 PIXEL_WIDTH (f) = pixelwidth;
4827 PIXEL_HEIGHT (f) = pixelheight;
4828
4d73d038
RS
4829 /* If cursor was outside the new size, mark it as off. */
4830 if (f->phys_cursor_y >= rows
4831 || f->phys_cursor_x >= cols)
4832 {
4833 f->phys_cursor_x = -1;
4834 f->phys_cursor_y = -1;
4835 }
4836
dbc4e1c1
JB
4837 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
4838 receive in the ConfigureNotify event; if we get what we asked
4839 for, then the event won't cause the screen to become garbaged, so
4840 we have to make sure to do it here. */
4841 SET_FRAME_GARBAGED (f);
4842
334208b7 4843 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 4844 UNBLOCK_INPUT;
80fd1fe2 4845#endif /* not USE_X_TOOLKIT */
dc6f92b8 4846}
dc6f92b8 4847\f
f451eb13 4848/* Mouse warping, focus shifting, raising and lowering. */
dc6f92b8 4849
9b378208 4850void
f676886a
JB
4851x_set_mouse_position (f, x, y)
4852 struct frame *f;
dc6f92b8
JB
4853 int x, y;
4854{
4855 int pix_x, pix_y;
4856
12ba150f 4857 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2;
a27f9f86 4858 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->display.x->line_height / 2;
f451eb13
JB
4859
4860 if (pix_x < 0) pix_x = 0;
4861 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
4862
4863 if (pix_y < 0) pix_y = 0;
4864 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
4865
4866 BLOCK_INPUT;
dc6f92b8 4867
334208b7
RS
4868 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
4869 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
4870 UNBLOCK_INPUT;
4871}
4872
9b378208
RS
4873/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
4874
4875void
4876x_set_mouse_pixel_position (f, pix_x, pix_y)
4877 struct frame *f;
4878 int pix_x, pix_y;
4879{
4880 BLOCK_INPUT;
4881
334208b7
RS
4882 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
4883 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
4884 UNBLOCK_INPUT;
4885}
4886
f676886a
JB
4887x_focus_on_frame (f)
4888 struct frame *f;
dc6f92b8 4889{
1fb20991 4890#if 0 /* This proves to be unpleasant. */
f676886a 4891 x_raise_frame (f);
1fb20991 4892#endif
6d4238f3
JB
4893#if 0
4894 /* I don't think that the ICCCM allows programs to do things like this
4895 without the interaction of the window manager. Whatever you end up
f676886a 4896 doing with this code, do it to x_unfocus_frame too. */
334208b7 4897 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 4898 RevertToPointerRoot, CurrentTime);
c118dd06 4899#endif /* ! 0 */
dc6f92b8
JB
4900}
4901
f676886a
JB
4902x_unfocus_frame (f)
4903 struct frame *f;
dc6f92b8 4904{
6d4238f3 4905#if 0
f676886a
JB
4906 /* Look at the remarks in x_focus_on_frame. */
4907 if (x_focus_frame == f)
334208b7 4908 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 4909 RevertToPointerRoot, CurrentTime);
c118dd06 4910#endif /* ! 0 */
dc6f92b8
JB
4911}
4912
f676886a 4913/* Raise frame F. */
dc6f92b8 4914
f676886a
JB
4915x_raise_frame (f)
4916 struct frame *f;
dc6f92b8 4917{
3a88c238 4918 if (f->async_visible)
dc6f92b8
JB
4919 {
4920 BLOCK_INPUT;
3afe33e7 4921#ifdef USE_X_TOOLKIT
334208b7 4922 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget));
3afe33e7 4923#else /* not USE_X_TOOLKIT */
334208b7 4924 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 4925#endif /* not USE_X_TOOLKIT */
334208b7 4926 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
4927 UNBLOCK_INPUT;
4928 }
4929}
4930
f676886a 4931/* Lower frame F. */
dc6f92b8 4932
f676886a
JB
4933x_lower_frame (f)
4934 struct frame *f;
dc6f92b8 4935{
3a88c238 4936 if (f->async_visible)
dc6f92b8
JB
4937 {
4938 BLOCK_INPUT;
3afe33e7 4939#ifdef USE_X_TOOLKIT
334208b7 4940 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->display.x->widget));
3afe33e7 4941#else /* not USE_X_TOOLKIT */
334208b7 4942 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 4943#endif /* not USE_X_TOOLKIT */
334208b7 4944 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
4945 UNBLOCK_INPUT;
4946 }
4947}
4948
dbc4e1c1
JB
4949static void
4950XTframe_raise_lower (f, raise)
4951 FRAME_PTR f;
4952 int raise;
4953{
4954 if (raise)
4955 x_raise_frame (f);
4956 else
4957 x_lower_frame (f);
4958}
4959
fd13dbb2
RS
4960/* Change from withdrawn state to mapped state,
4961 or deiconify. */
dc6f92b8 4962
f676886a
JB
4963x_make_frame_visible (f)
4964 struct frame *f;
dc6f92b8
JB
4965{
4966 int mask;
990ba854 4967 Lisp_Object type;
dc6f92b8 4968
dc6f92b8 4969 BLOCK_INPUT;
dc6f92b8 4970
990ba854
RS
4971 type = x_icon_type (f);
4972 if (!NILP (type))
4973 x_bitmap_icon (f, type);
bdcd49ba 4974
f676886a 4975 if (! FRAME_VISIBLE_P (f))
90e65f07 4976 {
af31d76f 4977#ifndef USE_X_TOOLKIT
fd13dbb2
RS
4978 if (! FRAME_ICONIFIED_P (f))
4979 x_set_offset (f, f->display.x->left_pos, f->display.x->top_pos, 0);
af31d76f 4980#endif
dc05a16b 4981
90e65f07 4982 if (! EQ (Vx_no_window_manager, Qt))
f676886a 4983 x_wm_set_window_state (f, NormalState);
3afe33e7 4984#ifdef USE_X_TOOLKIT
d7a38a2e
RS
4985 /* This was XtPopup, but that did nothing for an iconified frame. */
4986 XtMapWidget (f->display.x->widget);
3afe33e7 4987#else /* not USE_X_TOOLKIT */
7f9c7f94 4988 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 4989#endif /* not USE_X_TOOLKIT */
0134a210
RS
4990#if 0 /* This seems to bring back scroll bars in the wrong places
4991 if the window configuration has changed. They seem
4992 to come back ok without this. */
ab648270 4993 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 4994 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 4995#endif
90e65f07 4996 }
dc6f92b8 4997
334208b7 4998 XFlush (FRAME_X_DISPLAY (f));
90e65f07 4999
0dacf791
RS
5000 /* Synchronize to ensure Emacs knows the frame is visible
5001 before we do anything else. We do this loop with input not blocked
5002 so that incoming events are handled. */
5003 {
5004 Lisp_Object frame;
c0a04927
RS
5005 int count = input_signal_count;
5006
5007 /* This must come after we set COUNT. */
5008 UNBLOCK_INPUT;
5009
e0c1aef2 5010 XSETFRAME (frame, f);
c0a04927
RS
5011
5012 while (1)
2a6cf806 5013 {
334208b7 5014 x_sync (f);
c0a04927
RS
5015 /* Once we have handled input events,
5016 we should have received the MapNotify if one is coming.
5017 So if we have not got it yet, stop looping.
5018 Some window managers make their own decisions
5019 about visibility. */
5020 if (input_signal_count != count)
5021 break;
c12a7cbd 5022 /* Machines that do polling rather than SIGIO have been observed
23cf7c60
KH
5023 to go into a busy-wait here. So we'll fake an alarm signal
5024 to let the handler know that there's something to be read.
5025 We used to raise a real alarm, but it seems that the handler
5026 isn't always enabled here. This is probably a bug. */
8b2f8d4e 5027 if (input_polling_used ())
3b2fa4e6
RS
5028 {
5029 /* It could be confusing if a real alarm arrives while processing
5030 the fake one. Turn it off and let the handler reset it. */
5031 alarm (0);
5032 input_poll_signal ();
5033 }
c0a04927
RS
5034 /* Once we have handled input events,
5035 we should have received the MapNotify if one is coming.
5036 So if we have not got it yet, stop looping.
5037 Some window managers make their own decisions
5038 about visibility. */
5039 if (input_signal_count != count)
5040 break;
2a6cf806 5041 }
0dacf791
RS
5042 FRAME_SAMPLE_VISIBILITY (f);
5043 }
dc6f92b8
JB
5044}
5045
5046/* Change from mapped state to withdrawn state. */
5047
f676886a
JB
5048x_make_frame_invisible (f)
5049 struct frame *f;
dc6f92b8
JB
5050{
5051 int mask;
546e6d5b
RS
5052 Window window;
5053
5054#ifdef USE_X_TOOLKIT
5055 /* Use the frame's outermost window, not the one we normally draw on. */
5056 window = XtWindow (f->display.x->widget);
5057#else /* not USE_X_TOOLKIT */
5058 window = FRAME_X_WINDOW (f);
5059#endif /* not USE_X_TOOLKIT */
dc6f92b8 5060
9319ae23
RS
5061 /* Don't keep the highlight on an invisible frame. */
5062 if (x_highlight_frame == f)
5063 x_highlight_frame = 0;
5064
5627c40e 5065#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 5066 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 5067 return;
5627c40e 5068#endif
dc6f92b8
JB
5069
5070 BLOCK_INPUT;
c118dd06 5071
af31d76f
RS
5072 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
5073 that the current position of the window is user-specified, rather than
5074 program-specified, so that when the window is mapped again, it will be
5075 placed at the same location, without forcing the user to position it
5076 by hand again (they have already done that once for this window.) */
5077 x_wm_set_size_hint (f, 0, 1);
5078
c118dd06
JB
5079#ifdef HAVE_X11R4
5080
334208b7
RS
5081 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
5082 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
5083 {
5084 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 5085 error ("Can't notify window manager of window withdrawal");
c118dd06 5086 }
c118dd06 5087#else /* ! defined (HAVE_X11R4) */
16bd92ea 5088
c118dd06 5089 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
5090 if (! EQ (Vx_no_window_manager, Qt))
5091 {
16bd92ea 5092 XEvent unmap;
dc6f92b8 5093
16bd92ea 5094 unmap.xunmap.type = UnmapNotify;
546e6d5b 5095 unmap.xunmap.window = window;
334208b7 5096 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 5097 unmap.xunmap.from_configure = False;
334208b7
RS
5098 if (! XSendEvent (FRAME_X_DISPLAY (f),
5099 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
5100 False,
5101 SubstructureRedirectMask|SubstructureNotifyMask,
5102 &unmap))
5103 {
5104 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 5105 error ("Can't notify window manager of withdrawal");
16bd92ea 5106 }
dc6f92b8
JB
5107 }
5108
16bd92ea 5109 /* Unmap the window ourselves. Cheeky! */
334208b7 5110 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 5111#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 5112
5627c40e
RS
5113 /* We can't distinguish this from iconification
5114 just by the event that we get from the server.
5115 So we can't win using the usual strategy of letting
5116 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
5117 and synchronize with the server to make sure we agree. */
5118 f->visible = 0;
5119 FRAME_ICONIFIED_P (f) = 0;
5120 f->async_visible = 0;
5121 f->async_iconified = 0;
5122
334208b7 5123 x_sync (f);
5627c40e 5124
dc6f92b8
JB
5125 UNBLOCK_INPUT;
5126}
5127
dc6f92b8
JB
5128/* Change window state from mapped to iconified. */
5129
f676886a
JB
5130x_iconify_frame (f)
5131 struct frame *f;
dc6f92b8
JB
5132{
5133 int mask;
3afe33e7 5134 int result;
990ba854 5135 Lisp_Object type;
dc6f92b8 5136
9319ae23
RS
5137 /* Don't keep the highlight on an invisible frame. */
5138 if (x_highlight_frame == f)
5139 x_highlight_frame = 0;
5140
3a88c238 5141 if (f->async_iconified)
dc6f92b8
JB
5142 return;
5143
3afe33e7 5144 BLOCK_INPUT;
546e6d5b 5145
990ba854
RS
5146 type = x_icon_type (f);
5147 if (!NILP (type))
5148 x_bitmap_icon (f, type);
bdcd49ba
RS
5149
5150#ifdef USE_X_TOOLKIT
5151
546e6d5b
RS
5152 if (! FRAME_VISIBLE_P (f))
5153 {
5154 if (! EQ (Vx_no_window_manager, Qt))
5155 x_wm_set_window_state (f, IconicState);
5156 /* This was XtPopup, but that did nothing for an iconified frame. */
5157 XtMapWidget (f->display.x->widget);
5158 UNBLOCK_INPUT;
5159 return;
5160 }
5161
334208b7 5162 result = XIconifyWindow (FRAME_X_DISPLAY (f),
bc20ebbf 5163 XtWindow (f->display.x->widget),
334208b7 5164 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
5165 UNBLOCK_INPUT;
5166
5167 if (!result)
546e6d5b 5168 error ("Can't notify window manager of iconification");
3afe33e7
RS
5169
5170 f->async_iconified = 1;
8c002a25
KH
5171
5172 BLOCK_INPUT;
334208b7 5173 XFlush (FRAME_X_DISPLAY (f));
8c002a25 5174 UNBLOCK_INPUT;
3afe33e7
RS
5175#else /* not USE_X_TOOLKIT */
5176
fd13dbb2
RS
5177 /* Make sure the X server knows where the window should be positioned,
5178 in case the user deiconifies with the window manager. */
5179 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
5180 x_set_offset (f, f->display.x->left_pos, f->display.x->top_pos, 0);
5181
16bd92ea
JB
5182 /* Since we don't know which revision of X we're running, we'll use both
5183 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
5184
5185 /* X11R4: send a ClientMessage to the window manager using the
5186 WM_CHANGE_STATE type. */
5187 {
5188 XEvent message;
58769bee 5189
c118dd06 5190 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 5191 message.xclient.type = ClientMessage;
334208b7 5192 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
5193 message.xclient.format = 32;
5194 message.xclient.data.l[0] = IconicState;
5195
334208b7
RS
5196 if (! XSendEvent (FRAME_X_DISPLAY (f),
5197 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
5198 False,
5199 SubstructureRedirectMask | SubstructureNotifyMask,
5200 &message))
dc6f92b8
JB
5201 {
5202 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 5203 error ("Can't notify window manager of iconification");
dc6f92b8 5204 }
16bd92ea 5205 }
dc6f92b8 5206
58769bee 5207 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
5208 IconicState. */
5209 x_wm_set_window_state (f, IconicState);
dc6f92b8 5210
a9c00105
RS
5211 if (!FRAME_VISIBLE_P (f))
5212 {
5213 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 5214 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
5215 }
5216
3a88c238 5217 f->async_iconified = 1;
dc6f92b8 5218
334208b7 5219 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 5220 UNBLOCK_INPUT;
8c002a25 5221#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5222}
5223
c0ff3fab 5224/* Destroy the X window of frame F. */
dc6f92b8 5225
c0ff3fab 5226x_destroy_window (f)
f676886a 5227 struct frame *f;
dc6f92b8 5228{
7f9c7f94
RS
5229 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5230
dc6f92b8 5231 BLOCK_INPUT;
c0ff3fab
JB
5232
5233 if (f->display.x->icon_desc != 0)
334208b7
RS
5234 XDestroyWindow (FRAME_X_DISPLAY (f), f->display.x->icon_desc);
5235 XDestroyWindow (FRAME_X_DISPLAY (f), f->display.x->window_desc);
3afe33e7
RS
5236#ifdef USE_X_TOOLKIT
5237 XtDestroyWidget (f->display.x->widget);
9d7e2e3e 5238 free_frame_menubar (f);
3afe33e7
RS
5239#endif /* USE_X_TOOLKIT */
5240
07e34cb0 5241 free_frame_faces (f);
334208b7 5242 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 5243
9ac0d9e0 5244 xfree (f->display.x);
c0ff3fab 5245 f->display.x = 0;
f676886a
JB
5246 if (f == x_focus_frame)
5247 x_focus_frame = 0;
5248 if (f == x_highlight_frame)
5249 x_highlight_frame = 0;
c0ff3fab 5250
7f9c7f94
RS
5251 dpyinfo->reference_count--;
5252
5253 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 5254 {
7f9c7f94
RS
5255 dpyinfo->mouse_face_beg_row
5256 = dpyinfo->mouse_face_beg_col = -1;
5257 dpyinfo->mouse_face_end_row
5258 = dpyinfo->mouse_face_end_col = -1;
5259 dpyinfo->mouse_face_window = Qnil;
dc05a16b 5260 }
0134a210 5261
c0ff3fab 5262 UNBLOCK_INPUT;
dc6f92b8
JB
5263}
5264\f
f451eb13
JB
5265/* Setting window manager hints. */
5266
af31d76f
RS
5267/* Set the normal size hints for the window manager, for frame F.
5268 FLAGS is the flags word to use--or 0 meaning preserve the flags
5269 that the window now has.
5270 If USER_POSITION is nonzero, we set the USPosition
5271 flag (this is useful when FLAGS is 0). */
6dba1858 5272
af31d76f 5273x_wm_set_size_hint (f, flags, user_position)
f676886a 5274 struct frame *f;
af31d76f
RS
5275 long flags;
5276 int user_position;
dc6f92b8
JB
5277{
5278 XSizeHints size_hints;
3afe33e7
RS
5279
5280#ifdef USE_X_TOOLKIT
7e4f2521
FP
5281 Arg al[2];
5282 int ac = 0;
5283 Dimension widget_width, widget_height;
bc20ebbf 5284 Window window = XtWindow (f->display.x->widget);
3afe33e7 5285#else /* not USE_X_TOOLKIT */
c118dd06 5286 Window window = FRAME_X_WINDOW (f);
3afe33e7 5287#endif /* not USE_X_TOOLKIT */
dc6f92b8 5288
b72a58fd
RS
5289 /* Setting PMaxSize caused various problems. */
5290 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 5291
f676886a
JB
5292 flexlines = f->height;
5293
5294 size_hints.x = f->display.x->left_pos;
5295 size_hints.y = f->display.x->top_pos;
7553a6b7 5296
7e4f2521
FP
5297#ifdef USE_X_TOOLKIT
5298 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
5299 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
5300 XtGetValues (f->display.x->column_widget, al, ac);
5301 size_hints.height = widget_height;
5302 size_hints.width = widget_width;
5303#else /* not USE_X_TOOLKIT */
f676886a
JB
5304 size_hints.height = PIXEL_HEIGHT (f);
5305 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 5306#endif /* not USE_X_TOOLKIT */
7553a6b7 5307
f676886a 5308 size_hints.width_inc = FONT_WIDTH (f->display.x->font);
a27f9f86 5309 size_hints.height_inc = f->display.x->line_height;
334208b7
RS
5310 size_hints.max_width
5311 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
5312 size_hints.max_height
5313 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 5314
b1c884c3 5315 {
b0342f17 5316 int base_width, base_height;
0134a210 5317 int min_rows = 0, min_cols = 0;
b0342f17 5318
f451eb13
JB
5319 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
5320 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 5321
0134a210 5322 check_frame_size (f, &min_rows, &min_cols);
b0342f17 5323
0134a210
RS
5324 /* The window manager uses the base width hints to calculate the
5325 current number of rows and columns in the frame while
5326 resizing; min_width and min_height aren't useful for this
5327 purpose, since they might not give the dimensions for a
5328 zero-row, zero-column frame.
58769bee 5329
0134a210
RS
5330 We use the base_width and base_height members if we have
5331 them; otherwise, we set the min_width and min_height members
5332 to the size for a zero x zero frame. */
b0342f17
JB
5333
5334#ifdef HAVE_X11R4
0134a210
RS
5335 size_hints.flags |= PBaseSize;
5336 size_hints.base_width = base_width;
5337 size_hints.base_height = base_height;
5338 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
5339 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 5340#else
0134a210
RS
5341 size_hints.min_width = base_width;
5342 size_hints.min_height = base_height;
b0342f17 5343#endif
b1c884c3 5344 }
dc6f92b8 5345
af31d76f
RS
5346 if (flags)
5347 size_hints.flags |= flags;
dc6f92b8
JB
5348 else
5349 {
5350 XSizeHints hints; /* Sometimes I hate X Windows... */
af31d76f
RS
5351 long supplied_return;
5352 int value;
5353
5354#ifdef HAVE_X11R4
334208b7 5355 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
af31d76f
RS
5356 &supplied_return);
5357#else
334208b7 5358 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 5359#endif
58769bee 5360
af31d76f 5361 if (value == 0)
82ee0df4 5362 hints.flags = 0;
dc6f92b8
JB
5363 if (hints.flags & PSize)
5364 size_hints.flags |= PSize;
5365 if (hints.flags & PPosition)
5366 size_hints.flags |= PPosition;
5367 if (hints.flags & USPosition)
5368 size_hints.flags |= USPosition;
5369 if (hints.flags & USSize)
5370 size_hints.flags |= USSize;
5371 }
0134a210 5372
af31d76f 5373#ifdef PWinGravity
dc05a16b 5374 size_hints.win_gravity = f->display.x->win_gravity;
af31d76f 5375 size_hints.flags |= PWinGravity;
dc05a16b 5376
af31d76f 5377 if (user_position)
6dba1858 5378 {
af31d76f
RS
5379 size_hints.flags &= ~ PPosition;
5380 size_hints.flags |= USPosition;
6dba1858 5381 }
2554751d 5382#endif /* PWinGravity */
6dba1858 5383
b0342f17 5384#ifdef HAVE_X11R4
334208b7 5385 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 5386#else
334208b7 5387 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 5388#endif
dc6f92b8
JB
5389}
5390
5391/* Used for IconicState or NormalState */
f676886a
JB
5392x_wm_set_window_state (f, state)
5393 struct frame *f;
dc6f92b8
JB
5394 int state;
5395{
3afe33e7 5396#ifdef USE_X_TOOLKIT
546e6d5b
RS
5397 Arg al[1];
5398
5399 XtSetArg (al[0], XtNinitialState, state);
5400 XtSetValues (f->display.x->widget, al, 1);
3afe33e7 5401#else /* not USE_X_TOOLKIT */
c118dd06 5402 Window window = FRAME_X_WINDOW (f);
dc6f92b8 5403
16bd92ea
JB
5404 f->display.x->wm_hints.flags |= StateHint;
5405 f->display.x->wm_hints.initial_state = state;
b1c884c3 5406
334208b7 5407 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
546e6d5b 5408#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5409}
5410
7f2ae036 5411x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 5412 struct frame *f;
7f2ae036 5413 int pixmap_id;
dc6f92b8 5414{
75231bad
RS
5415#ifdef USE_X_TOOLKIT
5416 Window window = XtWindow (f->display.x->widget);
5417#else
c118dd06 5418 Window window = FRAME_X_WINDOW (f);
75231bad 5419#endif
dc6f92b8 5420
7f2ae036 5421 if (pixmap_id > 0)
dbc4e1c1 5422 {
7a13e894 5423 Pixmap icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
dbc4e1c1
JB
5424 f->display.x->wm_hints.icon_pixmap = icon_pixmap;
5425 f->display.x->wm_hints.flags |= IconPixmapHint;
5426 }
5427 else
7f2ae036
RS
5428 {
5429 f->display.x->wm_hints.icon_pixmap = None;
5430 f->display.x->wm_hints.flags &= ~IconPixmapHint;
5431 }
b1c884c3 5432
334208b7 5433 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
dc6f92b8
JB
5434}
5435
f676886a
JB
5436x_wm_set_icon_position (f, icon_x, icon_y)
5437 struct frame *f;
dc6f92b8
JB
5438 int icon_x, icon_y;
5439{
75231bad
RS
5440#ifdef USE_X_TOOLKIT
5441 Window window = XtWindow (f->display.x->widget);
5442#else
c118dd06 5443 Window window = FRAME_X_WINDOW (f);
75231bad 5444#endif
dc6f92b8 5445
16bd92ea
JB
5446 f->display.x->wm_hints.flags |= IconPositionHint;
5447 f->display.x->wm_hints.icon_x = icon_x;
5448 f->display.x->wm_hints.icon_y = icon_y;
b1c884c3 5449
334208b7 5450 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->display.x->wm_hints);
dc6f92b8
JB
5451}
5452
5453\f
f451eb13
JB
5454/* Initialization. */
5455
3afe33e7
RS
5456#ifdef USE_X_TOOLKIT
5457static XrmOptionDescRec emacs_options[] = {
5458 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
5459 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
5460
5461 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
5462 XrmoptionSepArg, NULL},
5463 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
5464
5465 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5466 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5467 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
5468 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5469 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
5470 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
5471 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
5472};
5473#endif /* USE_X_TOOLKIT */
5474
7a13e894
RS
5475static int x_initialized;
5476
334208b7 5477struct x_display_info *
1f8255f2 5478x_term_init (display_name, xrm_option, resource_name)
334208b7 5479 Lisp_Object display_name;
1f8255f2
RS
5480 char *xrm_option;
5481 char *resource_name;
dc6f92b8 5482{
f676886a 5483 Lisp_Object frame;
dc6f92b8 5484 char *defaultvalue;
334208b7 5485 int connection;
7a13e894 5486 Display *dpy;
334208b7
RS
5487 struct x_display_info *dpyinfo;
5488 XrmDatabase xrdb;
5489
7a13e894
RS
5490 if (!x_initialized)
5491 {
5492 x_initialize ();
5493 x_initialized = 1;
5494 }
dc6f92b8 5495
3afe33e7 5496#ifdef USE_X_TOOLKIT
bdcd49ba
RS
5497#ifdef HAVE_X11R5
5498 XtSetLanguageProc (NULL, NULL, NULL);
5499#endif
5500
7f9c7f94
RS
5501 {
5502 int argc = 0;
5503 char *argv[3];
5504
5505 argv[0] = "";
5506 argc = 1;
5507 if (xrm_option)
5508 {
5509 argv[argc++] = "-xrm";
5510 argv[argc++] = xrm_option;
5511 }
5512 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
5513 resource_name, EMACS_CLASS,
5514 emacs_options, XtNumber (emacs_options),
5515 &argc, argv);
5516 }
3afe33e7
RS
5517
5518#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
5519#ifdef HAVE_X11R5
5520 XSetLocaleModifiers ("");
5521#endif
7a13e894 5522 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 5523#endif /* not USE_X_TOOLKIT */
334208b7 5524
7a13e894
RS
5525 /* Detect failure. */
5526 if (dpy == 0)
5527 return 0;
5528
5529 /* We have definitely succeeded. Record the new connection. */
5530
5531 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
5532
5533 /* Put this display on the chain. */
5534 dpyinfo->next = x_display_list;
5535 x_display_list = dpyinfo;
5536
5537 /* Put it on x_display_name_list as well, to keep them parallel. */
5538 x_display_name_list = Fcons (Fcons (display_name, Qnil),
5539 x_display_name_list);
5540 dpyinfo->name_list_element = XCONS (x_display_name_list)->car;
5541
5542 dpyinfo->display = dpy;
dc6f92b8 5543
dc6f92b8 5544#if 0
7a13e894 5545 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 5546#endif /* ! 0 */
7a13e894
RS
5547
5548 dpyinfo->x_id_name
5549 = (char *) xmalloc (XSTRING (Vinvocation_name)->size
5550 + XSTRING (Vsystem_name)->size
5551 + 2);
5552 sprintf (dpyinfo->x_id_name, "%s@%s",
5553 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
5554
5555 /* Figure out which modifier bits mean what. */
334208b7 5556 x_find_modifier_meanings (dpyinfo);
f451eb13 5557
ab648270 5558 /* Get the scroll bar cursor. */
7a13e894 5559 dpyinfo->vertical_scroll_bar_cursor
334208b7 5560 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 5561
334208b7
RS
5562 xrdb = x_load_resources (dpyinfo->display, xrm_option,
5563 resource_name, EMACS_CLASS);
5564#ifdef HAVE_XRMSETDATABASE
5565 XrmSetDatabase (dpyinfo->display, xrdb);
5566#else
5567 dpyinfo->display->db = xrdb;
5568#endif
7a13e894
RS
5569 /* Put thr rdb where we can find it in a way that works on
5570 all versions. */
5571 dpyinfo->xrdb = xrdb;
334208b7
RS
5572
5573 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
5574 DefaultScreen (dpyinfo->display));
5575 dpyinfo->visual = select_visual (dpyinfo->display, dpyinfo->screen,
5576 &dpyinfo->n_planes);
5577 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
5578 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
5579 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
5580 dpyinfo->grabbed = 0;
5581 dpyinfo->reference_count = 0;
5582 dpyinfo->icon_bitmap_id = -1;
7a13e894
RS
5583 dpyinfo->n_fonts = 0;
5584 dpyinfo->font_table_size = 0;
5585 dpyinfo->bitmaps = 0;
5586 dpyinfo->bitmaps_size = 0;
5587 dpyinfo->bitmaps_last = 0;
5588 dpyinfo->scratch_cursor_gc = 0;
5589 dpyinfo->mouse_face_mouse_frame = 0;
5590 dpyinfo->mouse_face_deferred_gc = 0;
5591 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
5592 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
5593 dpyinfo->mouse_face_face_id = 0;
5594 dpyinfo->mouse_face_window = Qnil;
5595 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
5596 dpyinfo->mouse_face_defer = 0;
334208b7
RS
5597
5598 dpyinfo->Xatom_wm_protocols
5599 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
5600 dpyinfo->Xatom_wm_take_focus
5601 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
5602 dpyinfo->Xatom_wm_save_yourself
5603 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
5604 dpyinfo->Xatom_wm_delete_window
5605 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
5606 dpyinfo->Xatom_wm_change_state
5607 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
5608 dpyinfo->Xatom_wm_configure_denied
5609 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
5610 dpyinfo->Xatom_wm_window_moved
5611 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
5612 dpyinfo->Xatom_editres
5613 = XInternAtom (dpyinfo->display, "Editres", False);
5614 dpyinfo->Xatom_CLIPBOARD
5615 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
5616 dpyinfo->Xatom_TIMESTAMP
5617 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
5618 dpyinfo->Xatom_TEXT
5619 = XInternAtom (dpyinfo->display, "TEXT", False);
5620 dpyinfo->Xatom_DELETE
5621 = XInternAtom (dpyinfo->display, "DELETE", False);
5622 dpyinfo->Xatom_MULTIPLE
5623 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
5624 dpyinfo->Xatom_INCR
5625 = XInternAtom (dpyinfo->display, "INCR", False);
5626 dpyinfo->Xatom_EMACS_TMP
5627 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
5628 dpyinfo->Xatom_TARGETS
5629 = XInternAtom (dpyinfo->display, "TARGETS", False);
5630 dpyinfo->Xatom_NULL
5631 = XInternAtom (dpyinfo->display, "NULL", False);
5632 dpyinfo->Xatom_ATOM_PAIR
5633 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
5634
5635 connection = ConnectionNumber (dpyinfo->display);
5636 dpyinfo->connection = connection;
5637
87485d6f
MW
5638#ifdef subprocesses
5639 /* This is only needed for distinguishing keyboard and process input. */
334208b7 5640 if (connection != 0)
7a13e894 5641 add_keyboard_wait_descriptor (connection);
87485d6f 5642#endif
6d4238f3 5643
041b69ac 5644#ifndef F_SETOWN_BUG
dc6f92b8 5645#ifdef F_SETOWN
dc6f92b8 5646#ifdef F_SETOWN_SOCK_NEG
61c3ce62 5647 /* stdin is a socket here */
334208b7 5648 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 5649#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 5650 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
5651#endif /* ! defined (F_SETOWN_SOCK_NEG) */
5652#endif /* ! defined (F_SETOWN) */
041b69ac 5653#endif /* F_SETOWN_BUG */
dc6f92b8
JB
5654
5655#ifdef SIGIO
7a13e894 5656 init_sigio (connection);
c118dd06 5657#endif /* ! defined (SIGIO) */
dc6f92b8 5658
7a13e894
RS
5659 return dpyinfo;
5660}
5661\f
5662/* Get rid of display DPYINFO, assuming all frames are already gone,
5663 and without sending any more commands to the X server. */
dc6f92b8 5664
7a13e894
RS
5665void
5666x_delete_display (dpyinfo)
5667 struct x_display_info *dpyinfo;
5668{
5669 delete_keyboard_wait_descriptor (dpyinfo->connection);
5670
5671 /* Discard this display from x_display_name_list and x_display_list.
5672 We can't use Fdelq because that can quit. */
5673 if (! NILP (x_display_name_list)
5674 && EQ (XCONS (x_display_name_list)->car, dpyinfo->name_list_element))
5675 x_display_name_list = XCONS (x_display_name_list)->cdr;
5676 else
5677 {
5678 Lisp_Object tail;
5679
5680 tail = x_display_name_list;
5681 while (CONSP (tail) && CONSP (XCONS (tail)->cdr))
5682 {
5683 if (EQ (XCONS (XCONS (tail)->cdr)->car,
5684 dpyinfo->name_list_element))
5685 {
5686 XCONS (tail)->cdr = XCONS (XCONS (tail)->cdr)->cdr;
5687 break;
5688 }
5689 tail = XCONS (tail)->cdr;
5690 }
5691 }
5692
5693 if (x_display_list == dpyinfo)
5694 x_display_list = dpyinfo->next;
7f9c7f94
RS
5695 else
5696 {
5697 struct x_display_info *tail;
7a13e894 5698
7f9c7f94
RS
5699 for (tail = x_display_list; tail; tail = tail->next)
5700 if (tail->next == dpyinfo)
5701 tail->next = tail->next->next;
5702 }
7a13e894 5703
7f9c7f94
RS
5704#ifndef USE_X_TOOLKIT
5705 /* I'm told Xt does this itself. */
5706 XrmDestroyDatabase (dpyinfo->xrdb);
5707#endif
7a13e894
RS
5708 free (dpyinfo->font_table);
5709 free (dpyinfo->x_id_name);
5710 free (dpyinfo);
5711}
5712\f
5713/* Set up use of X before we make the first connection. */
5714
5715x_initialize ()
5716{
f676886a 5717 clear_frame_hook = XTclear_frame;
dc6f92b8
JB
5718 clear_end_of_line_hook = XTclear_end_of_line;
5719 ins_del_lines_hook = XTins_del_lines;
5720 change_line_highlight_hook = XTchange_line_highlight;
5721 insert_glyphs_hook = XTinsert_glyphs;
5722 write_glyphs_hook = XTwrite_glyphs;
5723 delete_glyphs_hook = XTdelete_glyphs;
5724 ring_bell_hook = XTring_bell;
5725 reset_terminal_modes_hook = XTreset_terminal_modes;
5726 set_terminal_modes_hook = XTset_terminal_modes;
5727 update_begin_hook = XTupdate_begin;
5728 update_end_hook = XTupdate_end;
5729 set_terminal_window_hook = XTset_terminal_window;
5730 read_socket_hook = XTread_socket;
b8009dd1 5731 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8
JB
5732 cursor_to_hook = XTcursor_to;
5733 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 5734 mouse_position_hook = XTmouse_position;
f451eb13 5735 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 5736 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
5737 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
5738 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
5739 redeem_scroll_bar_hook = XTredeem_scroll_bar;
5740 judge_scroll_bars_hook = XTjudge_scroll_bars;
58769bee 5741
f676886a 5742 scroll_region_ok = 1; /* we'll scroll partial frames */
dc6f92b8
JB
5743 char_ins_del_ok = 0; /* just as fast to write the line */
5744 line_ins_del_ok = 1; /* we'll just blt 'em */
5745 fast_clear_end_of_line = 1; /* X does this well */
58769bee 5746 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
5747 off the bottom */
5748 baud_rate = 19200;
5749
7a13e894
RS
5750 x_noop_count = 0;
5751
5752 x_focus_frame = x_highlight_frame = 0;
5753
b30b24cb
RS
5754 /* Try to use interrupt input; if we can't, then start polling. */
5755 Fset_input_mode (Qt, Qnil, Qt, Qnil);
5756
7f9c7f94
RS
5757#ifdef USE_X_TOOLKIT
5758 XtToolkitInitialize ();
5759 Xt_app_con = XtCreateApplicationContext ();
5760#endif
5761
58769bee 5762 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 5763 original error handler. */
334208b7
RS
5764 XSetErrorHandler (x_error_quitter);
5765 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8
JB
5766
5767 /* Disable Window Change signals; they are handled by X events. */
5768#ifdef SIGWINCH
5769 signal (SIGWINCH, SIG_DFL);
c118dd06 5770#endif /* ! defined (SIGWINCH) */
dc6f92b8 5771
c118dd06 5772 signal (SIGPIPE, x_connection_closed);
dc6f92b8 5773}
55123275
JB
5774
5775void
5776syms_of_xterm ()
5777{
7a13e894
RS
5778 staticpro (&x_display_name_list);
5779 x_display_name_list = Qnil;
334208b7 5780
ab648270 5781 staticpro (&last_mouse_scroll_bar);
e53cb100 5782 last_mouse_scroll_bar = Qnil;
55123275 5783}
c118dd06 5784#endif /* ! defined (HAVE_X_WINDOWS) */