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