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