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