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