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