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