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