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