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