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