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