Merge from emacs--devo--0
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
043f7f73 2 Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
5badc98d 3 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
dc6f92b8
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
4746118a 9the Free Software Foundation; either version 2, or (at your option)
dc6f92b8
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
4fc5845f
LK
19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20Boston, MA 02110-1301, USA. */
dc6f92b8 21
06a2c219 22/* New display code by Gerd Moellmann <gerd@gnu.org>. */
3afe33e7
RS
23/* Xt features made by Fred Pierresteguy. */
24
68c45bf0
PE
25#include <config.h>
26
039440c4 27/* On 4.3 these lose if they come after xterm.h. */
039440c4 28/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
29#include <signal.h>
30
4846819e
RS
31#include <stdio.h>
32
dc6f92b8
JB
33#ifdef HAVE_X_WINDOWS
34
35#include "lisp.h"
9ac0d9e0 36#include "blockinput.h"
dc6f92b8 37
ae79c227
AS
38/* Need syssignal.h for various externs and definitions that may be required
39 by some configurations for calls to signal later in this source file. */
40#include "syssignal.h"
41
dc6f92b8
JB
42/* This may include sys/types.h, and that somehow loses
43 if this is not done before the other system files. */
44#include "xterm.h"
f451eb13 45#include <X11/cursorfont.h>
dc6f92b8
JB
46
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 51#endif /* makedev */
dc6f92b8 52
6df54671 53#ifdef BSD_SYSTEM
dc6f92b8 54#include <sys/ioctl.h>
6df54671 55#endif /* ! defined (BSD_SYSTEM) */
dc6f92b8 56
2d368234 57#include "systty.h"
3a2712f9 58#include "systime.h"
dc6f92b8 59
b8009dd1 60#ifndef INCLUDED_FCNTL
dc6f92b8 61#include <fcntl.h>
b8009dd1 62#endif
dc6f92b8
JB
63#include <ctype.h>
64#include <errno.h>
65#include <setjmp.h>
66#include <sys/stat.h>
a0a7635f
RS
67/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
68/* #include <sys/param.h> */
dc6f92b8 69
dc43ef94 70#include "charset.h"
8a78c965 71#include "character.h"
379b5ac0 72#include "coding.h"
dc43ef94 73#include "ccl.h"
7a13e894 74#include "frame.h"
dc6f92b8 75#include "dispextern.h"
ee569018 76#include "fontset.h"
dc6f92b8
JB
77#include "termhooks.h"
78#include "termopts.h"
79#include "termchar.h"
dc6f92b8 80#include "gnu.h"
dc6f92b8 81#include "disptab.h"
dc6f92b8 82#include "buffer.h"
f451eb13 83#include "window.h"
3b2fa4e6 84#include "keyboard.h"
bde7c500 85#include "intervals.h"
dfcf069d 86#include "process.h"
bffcfca9 87#include "atimer.h"
8feddab4 88#include "keymap.h"
dc6f92b8 89
d2bd6bc4
RS
90#ifdef USE_X_TOOLKIT
91#include <X11/Shell.h>
92#endif
93
06a2c219
GM
94#ifdef HAVE_SYS_TIME_H
95#include <sys/time.h>
96#endif
97#ifdef HAVE_UNISTD_H
98#include <unistd.h>
99#endif
100
488dd4c4
JD
101#ifdef USE_GTK
102#include "gtkutil.h"
103#endif
104
c9ff09ee
KH
105#ifdef USE_FONT_BACKEND
106#include "font.h"
107#endif /* USE_FONT_BACKEND */
108
d624284c 109#ifdef USE_LUCID
55a8b3ed 110extern int xlwmenu_window_p P_ ((Widget w, Window window));
d624284c
PJ
111extern void xlwmenu_redisplay P_ ((Widget));
112#endif
113
488dd4c4 114#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
06a2c219 115
952291d9
GM
116extern void free_frame_menubar P_ ((struct frame *));
117extern struct frame *x_menubar_window_to_frame P_ ((struct x_display_info *,
118 int));
488dd4c4 119#endif
06a2c219 120
488dd4c4 121#ifdef USE_X_TOOLKIT
0fdff6bb
RS
122#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
123#define HACK_EDITRES
124extern void _XEditResCheckMessages ();
125#endif /* not NO_EDITRES */
06a2c219
GM
126
127/* Include toolkit specific headers for the scroll bar widget. */
128
129#ifdef USE_TOOLKIT_SCROLL_BARS
130#if defined USE_MOTIF
131#include <Xm/Xm.h> /* for LESSTIF_VERSION */
132#include <Xm/ScrollBar.h>
ec18280f
SM
133#else /* !USE_MOTIF i.e. use Xaw */
134
135#ifdef HAVE_XAW3D
06a2c219 136#include <X11/Xaw3d/Simple.h>
06a2c219 137#include <X11/Xaw3d/Scrollbar.h>
6ca53601 138#include <X11/Xaw3d/ThreeD.h>
ec18280f
SM
139#else /* !HAVE_XAW3D */
140#include <X11/Xaw/Simple.h>
141#include <X11/Xaw/Scrollbar.h>
142#endif /* !HAVE_XAW3D */
143#ifndef XtNpickTop
144#define XtNpickTop "pickTop"
145#endif /* !XtNpickTop */
146#endif /* !USE_MOTIF */
06a2c219
GM
147#endif /* USE_TOOLKIT_SCROLL_BARS */
148
3afe33e7
RS
149#endif /* USE_X_TOOLKIT */
150
488dd4c4 151#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
b849c413 152#define x_any_window_to_frame x_window_to_frame
5627c40e 153#define x_top_window_to_frame x_window_to_frame
b849c413
RS
154#endif
155
546e6d5b 156#ifdef USE_X_TOOLKIT
d067ea8b 157#include "widget.h"
546e6d5b
RS
158#ifndef XtNinitialState
159#define XtNinitialState "initialState"
160#endif
161#endif
162
06a2c219
GM
163#define abs(x) ((x) < 0 ? -(x) : (x))
164
51f3cc3b 165/* Default to using XIM if available. */
3ff483be 166#ifdef USE_XIM
51f3cc3b 167int use_xim = 1;
3ff483be
KS
168#else
169int use_xim = 0; /* configure --without-xim */
170#endif
171
06a2c219 172\f
06a2c219 173
5bf04520 174/* Non-nil means Emacs uses toolkit scroll bars. */
06a2c219 175
5bf04520 176Lisp_Object Vx_toolkit_scroll_bars;
06a2c219 177
06a2c219
GM
178/* Non-zero means that a HELP_EVENT has been generated since Emacs
179 start. */
180
181static int any_help_event_p;
182
ee8ceff8 183/* Last window where we saw the mouse. Used by mouse-autoselect-window. */
5bc62483 184static Lisp_Object last_window;
503e457e 185
a72d5ce5
GM
186/* Non-zero means make use of UNDERLINE_POSITION font properties. */
187
188int x_use_underline_position_properties;
189
30f27523
KS
190/* Non-zero means to draw the underline at the same place as the descent line. */
191
192int x_underline_at_descent_line;
193
06a2c219
GM
194/* This is a chain of structures for all the X displays currently in
195 use. */
196
334208b7 197struct x_display_info *x_display_list;
dc6f92b8 198
06a2c219
GM
199/* This is a list of cons cells, each of the form (NAME
200 . FONT-LIST-CACHE), one for each element of x_display_list and in
201 the same order. NAME is the name of the frame. FONT-LIST-CACHE
202 records previous values returned by x-list-fonts. */
203
7a13e894 204Lisp_Object x_display_name_list;
f451eb13 205
987d2ad1 206/* Frame being updated by update_frame. This is declared in term.c.
06a2c219
GM
207 This is set by update_begin and looked at by all the XT functions.
208 It is zero while not inside an update. In that case, the XT
209 functions assume that `selected_frame' is the frame to apply to. */
210
d0386f2a 211extern struct frame *updating_frame;
dc6f92b8 212
06a2c219
GM
213/* This is a frame waiting to be auto-raised, within XTread_socket. */
214
0134a210
RS
215struct frame *pending_autoraise_frame;
216
7f9c7f94
RS
217#ifdef USE_X_TOOLKIT
218/* The application context for Xt use. */
219XtAppContext Xt_app_con;
06a2c219
GM
220static String Xt_default_resources[] = {0};
221#endif /* USE_X_TOOLKIT */
665881ad 222
bffcfca9
GM
223/* Non-zero means user is interacting with a toolkit scroll bar. */
224
225static int toolkit_scroll_bar_interaction;
dc6f92b8 226
6b61353c
KH
227/* Non-zero means to not move point as a result of clicking on a
228 frame to focus it (when focus-follows-mouse is nil). */
229
230int x_mouse_click_focus_ignore_position;
231
232/* Non-zero timeout value means ignore next mouse click if it arrives
233 before that timeout elapses (i.e. as part of the same sequence of
234 events resulting from clicking on a frame to select it). */
235
236static unsigned long ignore_next_mouse_click_timeout;
237
69388238
RS
238/* Mouse movement.
239
06a2c219 240 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
241 so that we would have to call XQueryPointer after each MotionNotify
242 event to ask for another such event. However, this made mouse tracking
243 slow, and there was a bug that made it eventually stop.
244
245 Simply asking for MotionNotify all the time seems to work better.
246
69388238
RS
247 In order to avoid asking for motion events and then throwing most
248 of them away or busy-polling the server for mouse positions, we ask
249 the server for pointer motion hints. This means that we get only
250 one event per group of mouse movements. "Groups" are delimited by
251 other kinds of events (focus changes and button clicks, for
252 example), or by XQueryPointer calls; when one of these happens, we
253 get another MotionNotify event the next time the mouse moves. This
254 is at least as efficient as getting motion events when mouse
255 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 256 is off. */
69388238
RS
257
258/* Where the mouse was last time we reported a mouse event. */
69388238 259
06a2c219 260static XRectangle last_mouse_glyph;
0a3fde9d 261static FRAME_PTR last_mouse_glyph_frame;
2237cac9
RS
262static Lisp_Object last_mouse_press_frame;
263
69388238
RS
264/* The scroll bar in which the last X motion event occurred.
265
06a2c219
GM
266 If the last X motion event occurred in a scroll bar, we set this so
267 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
268 an ordinary motion.
269
06a2c219
GM
270 If the last X motion event didn't occur in a scroll bar, we set
271 this to Qnil, to tell XTmouse_position to return an ordinary motion
272 event. */
273
69388238
RS
274static Lisp_Object last_mouse_scroll_bar;
275
69388238
RS
276/* This is a hack. We would really prefer that XTmouse_position would
277 return the time associated with the position it returns, but there
06a2c219 278 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
279 along with the position query. So, we just keep track of the time
280 of the last movement we received, and return that in hopes that
281 it's somewhat accurate. */
06a2c219 282
69388238
RS
283static Time last_mouse_movement_time;
284
06a2c219
GM
285/* Incremented by XTread_socket whenever it really tries to read
286 events. */
287
c0a04927
RS
288#ifdef __STDC__
289static int volatile input_signal_count;
290#else
291static int input_signal_count;
292#endif
293
7a13e894 294/* Used locally within XTread_socket. */
06a2c219 295
7a13e894 296static int x_noop_count;
dc6f92b8 297
7a13e894 298/* Initial values of argv and argc. */
06a2c219 299
7a13e894
RS
300extern char **initial_argv;
301extern int initial_argc;
dc6f92b8 302
7a13e894 303extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 304
06a2c219 305/* Tells if a window manager is present or not. */
7a13e894
RS
306
307extern Lisp_Object Vx_no_window_manager;
dc6f92b8 308
6b61353c 309extern Lisp_Object Qeql;
b8009dd1 310
dc6f92b8
JB
311extern int errno;
312
dfeccd2d 313/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 314
31ade731 315extern EMACS_INT extra_keyboard_modifiers;
64bb1782 316
98659da6
KG
317/* The keysyms to use for the various modifiers. */
318
319Lisp_Object Vx_alt_keysym, Vx_hyper_keysym, Vx_meta_keysym, Vx_super_keysym;
dbd4b028 320Lisp_Object Vx_keysym_table;
98659da6
KG
321static Lisp_Object Qalt, Qhyper, Qmeta, Qsuper, Qmodifier_value;
322
59e755be 323static Lisp_Object Qvendor_specific_keysyms;
3db9e31e 324static Lisp_Object Qlatin_1;
59e755be 325
952291d9 326extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
3c5034e9 327extern int x_bitmap_mask P_ ((FRAME_PTR, int));
7a13e894 328
651f03b6 329static int x_alloc_nearest_color_1 P_ ((Display *, Colormap, XColor *));
499b1844 330static void x_set_window_size_1 P_ ((struct frame *, int, int, int));
651f03b6 331static const XColor *x_color_cells P_ ((Display *, int *));
71b8321e 332static void x_update_window_end P_ ((struct window *, int, int));
e92928a7 333
06a2c219 334static int x_io_error_quitter P_ ((Display *));
06a2c219
GM
335static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
336static int x_compute_min_glyph_bounds P_ ((struct frame *));
06a2c219
GM
337static void x_update_end P_ ((struct frame *));
338static void XTframe_up_to_date P_ ((struct frame *));
06a2c219
GM
339static void XTset_terminal_modes P_ ((void));
340static void XTreset_terminal_modes P_ ((void));
06a2c219 341static void x_clear_frame P_ ((void));
06a2c219
GM
342static void frame_highlight P_ ((struct frame *));
343static void frame_unhighlight P_ ((struct frame *));
344static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
6b61353c
KH
345static void x_focus_changed P_ ((int, int, struct x_display_info *,
346 struct frame *, struct input_event *));
347static void x_detect_focus_change P_ ((struct x_display_info *,
348 XEvent *, struct input_event *));
06a2c219
GM
349static void XTframe_rehighlight P_ ((struct frame *));
350static void x_frame_rehighlight P_ ((struct x_display_info *));
351static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
65c26775
EZ
352static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int,
353 enum text_cursor_kinds));
06a2c219 354
08f66682 355static void x_clip_to_row P_ ((struct window *, struct glyph_row *, int, GC));
06a2c219 356static void x_flush P_ ((struct frame *f));
952291d9
GM
357static void x_update_begin P_ ((struct frame *));
358static void x_update_window_begin P_ ((struct window *));
952291d9 359static void x_after_update_window_line P_ ((struct glyph_row *));
6b61353c 360static struct scroll_bar *x_window_to_scroll_bar P_ ((Display *, Window));
b52b65bd
GM
361static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
362 enum scroll_bar_part *,
363 Lisp_Object *, Lisp_Object *,
364 unsigned long *));
d0fa3e56 365static void x_check_fullscreen P_ ((struct frame *));
d692a3d5
JD
366static void x_check_expected_move P_ ((struct frame *, int, int));
367static void x_sync_with_move P_ ((struct frame *, int, int, int));
6b61353c
KH
368static int handle_one_xevent P_ ((struct x_display_info *, XEvent *,
369 int *, struct input_event *));
2381d38d 370static SIGTYPE x_connection_closed P_ ((Display *, char *)) NO_RETURN;
488dd4c4 371
06a2c219
GM
372
373/* Flush display of frame F, or of all frames if F is null. */
374
375static void
376x_flush (f)
377 struct frame *f;
378{
379 BLOCK_INPUT;
380 if (f == NULL)
381 {
382 Lisp_Object rest, frame;
383 FOR_EACH_FRAME (rest, frame)
384 x_flush (XFRAME (frame));
385 }
386 else if (FRAME_X_P (f))
387 XFlush (FRAME_X_DISPLAY (f));
388 UNBLOCK_INPUT;
389}
390
dc6f92b8 391
06a2c219
GM
392/* Remove calls to XFlush by defining XFlush to an empty replacement.
393 Calls to XFlush should be unnecessary because the X output buffer
394 is flushed automatically as needed by calls to XPending,
395 XNextEvent, or XWindowEvent according to the XFlush man page.
396 XTread_socket calls XPending. Removing XFlush improves
397 performance. */
398
7d0393cf 399#define XFlush(DISPLAY) (void) 0
b8009dd1 400
334208b7 401\f
06a2c219
GM
402/***********************************************************************
403 Debugging
404 ***********************************************************************/
405
9382638d 406#if 0
06a2c219
GM
407
408/* This is a function useful for recording debugging information about
409 the sequence of occurrences in this file. */
9382638d 410
7d0393cf 411struct record
9382638d
KH
412{
413 char *locus;
414 int type;
415};
416
417struct record event_record[100];
418
419int event_record_index;
420
421record_event (locus, type)
422 char *locus;
423 int type;
424{
425 if (event_record_index == sizeof (event_record) / sizeof (struct record))
426 event_record_index = 0;
427
428 event_record[event_record_index].locus = locus;
429 event_record[event_record_index].type = type;
430 event_record_index++;
431}
432
433#endif /* 0 */
06a2c219
GM
434
435
9382638d 436\f
334208b7
RS
437/* Return the struct x_display_info corresponding to DPY. */
438
439struct x_display_info *
440x_display_info_for_display (dpy)
441 Display *dpy;
442{
443 struct x_display_info *dpyinfo;
444
445 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
446 if (dpyinfo->display == dpy)
447 return dpyinfo;
16bd92ea 448
334208b7
RS
449 return 0;
450}
f451eb13 451
06a2c219
GM
452
453\f
454/***********************************************************************
455 Starting and ending an update
456 ***********************************************************************/
7d0393cf 457
06a2c219
GM
458/* Start an update of frame F. This function is installed as a hook
459 for update_begin, i.e. it is called when update_begin is called.
460 This function is called prior to calls to x_update_window_begin for
461 each window being updated. Currently, there is nothing to do here
462 because all interesting stuff is done on a window basis. */
dc6f92b8 463
dfcf069d 464static void
06a2c219 465x_update_begin (f)
f676886a 466 struct frame *f;
58769bee 467{
06a2c219
GM
468 /* Nothing to do. */
469}
dc6f92b8 470
dc6f92b8 471
06a2c219
GM
472/* Start update of window W. Set the global variable updated_window
473 to the window being updated and set output_cursor to the cursor
474 position of W. */
dc6f92b8 475
06a2c219
GM
476static void
477x_update_window_begin (w)
478 struct window *w;
479{
480 struct frame *f = XFRAME (WINDOW_FRAME (w));
481 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
7d0393cf 482
06a2c219
GM
483 updated_window = w;
484 set_output_cursor (&w->cursor);
b8009dd1 485
06a2c219 486 BLOCK_INPUT;
d1bc4182 487
06a2c219 488 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 489 {
514e4681 490 /* Don't do highlighting for mouse motion during the update. */
06a2c219 491 display_info->mouse_face_defer = 1;
37c2c98b 492
06a2c219
GM
493 /* If F needs to be redrawn, simply forget about any prior mouse
494 highlighting. */
9f67f20b 495 if (FRAME_GARBAGED_P (f))
06a2c219
GM
496 display_info->mouse_face_window = Qnil;
497
64f26cf5
GM
498#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
499 their mouse_face_p flag set, which means that they are always
500 unequal to rows in a desired matrix which never have that
501 flag set. So, rows containing mouse-face glyphs are never
502 scrolled, and we don't have to switch the mouse highlight off
503 here to prevent it from being scrolled. */
7d0393cf 504
06a2c219
GM
505 /* Can we tell that this update does not affect the window
506 where the mouse highlight is? If so, no need to turn off.
507 Likewise, don't do anything if the frame is garbaged;
508 in that case, the frame's current matrix that we would use
509 is all wrong, and we will redisplay that line anyway. */
510 if (!NILP (display_info->mouse_face_window)
511 && w == XWINDOW (display_info->mouse_face_window))
514e4681 512 {
06a2c219 513 int i;
514e4681 514
06a2c219
GM
515 for (i = 0; i < w->desired_matrix->nrows; ++i)
516 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
517 break;
518
06a2c219
GM
519 if (i < w->desired_matrix->nrows)
520 clear_mouse_face (display_info);
514e4681 521 }
64f26cf5 522#endif /* 0 */
b8009dd1 523 }
6ccf47d1 524
dc6f92b8
JB
525 UNBLOCK_INPUT;
526}
527
06a2c219 528
442a09ea 529/* Draw a vertical window border from (x,y0) to (x,y1) */
06a2c219 530
dfcf069d 531static void
442a09ea 532x_draw_vertical_window_border (w, x, y0, y1)
06a2c219 533 struct window *w;
442a09ea 534 int x, y0, y1;
58769bee 535{
06a2c219 536 struct frame *f = XFRAME (WINDOW_FRAME (w));
7ecc34e9
JL
537 struct face *face;
538
539 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
540 if (face)
541 XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
542 face->foreground);
62fe13a4 543
442a09ea
KS
544 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
545 f->output_data.x->normal_gc, x, y0, x, y1);
06a2c219 546}
7d0393cf 547
71b8321e
GM
548/* End update of window W (which is equal to updated_window).
549
550 Draw vertical borders between horizontally adjacent windows, and
551 display W's cursor if CURSOR_ON_P is non-zero.
552
553 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
554 glyphs in mouse-face were overwritten. In that case we have to
555 make sure that the mouse-highlight is properly redrawn.
556
557 W may be a menu bar pseudo-window in case we don't have X toolkit
558 support. Such windows don't have a cursor, so don't display it
559 here. */
06a2c219
GM
560
561static void
71b8321e 562x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 563 struct window *w;
71b8321e 564 int cursor_on_p, mouse_face_overwritten_p;
06a2c219 565{
140330de 566 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7d0393cf 567
06a2c219
GM
568 if (!w->pseudo_window_p)
569 {
570 BLOCK_INPUT;
71b8321e 571
06a2c219 572 if (cursor_on_p)
442a09ea
KS
573 display_and_set_cursor (w, 1, output_cursor.hpos,
574 output_cursor.vpos,
575 output_cursor.x, output_cursor.y);
7d0393cf 576
f94a2622
KS
577 if (draw_window_fringes (w, 1))
578 x_draw_vertical_border (w);
6b61353c 579
06a2c219
GM
580 UNBLOCK_INPUT;
581 }
7d0393cf 582
140330de
GM
583 /* If a row with mouse-face was overwritten, arrange for
584 XTframe_up_to_date to redisplay the mouse highlight. */
585 if (mouse_face_overwritten_p)
586 {
587 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
588 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
589 dpyinfo->mouse_face_window = Qnil;
590 }
7d0393cf 591
06a2c219
GM
592 updated_window = NULL;
593}
dc6f92b8 594
dc6f92b8 595
06a2c219
GM
596/* End update of frame F. This function is installed as a hook in
597 update_end. */
598
599static void
600x_update_end (f)
601 struct frame *f;
602{
603 /* Mouse highlight may be displayed again. */
aa8bff2e 604 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 605
442a09ea 606#ifndef XFlush
06a2c219 607 BLOCK_INPUT;
334208b7 608 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 609 UNBLOCK_INPUT;
442a09ea 610#endif
dc6f92b8 611}
b8009dd1 612
06a2c219
GM
613
614/* This function is called from various places in xdisp.c whenever a
615 complete update has been performed. The global variable
616 updated_window is not available here. */
b8009dd1 617
dfcf069d 618static void
b8009dd1 619XTframe_up_to_date (f)
06a2c219 620 struct frame *f;
b8009dd1 621{
06a2c219 622 if (FRAME_X_P (f))
514e4681 623 {
06a2c219 624 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 625
06a2c219
GM
626 if (dpyinfo->mouse_face_deferred_gc
627 || f == dpyinfo->mouse_face_mouse_frame)
628 {
629 BLOCK_INPUT;
630 if (dpyinfo->mouse_face_mouse_frame)
631 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
632 dpyinfo->mouse_face_mouse_x,
633 dpyinfo->mouse_face_mouse_y);
634 dpyinfo->mouse_face_deferred_gc = 0;
635 UNBLOCK_INPUT;
636 }
514e4681 637 }
b8009dd1 638}
06a2c219
GM
639
640
641/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
3f332ef3 642 arrow bitmaps, or clear the fringes if no bitmaps are required
06a2c219
GM
643 before DESIRED_ROW is made current. The window being updated is
644 found in updated_window. This function It is called from
645 update_window_line only if it is known that there are differences
646 between bitmaps to be drawn between current row and DESIRED_ROW. */
647
648static void
649x_after_update_window_line (desired_row)
650 struct glyph_row *desired_row;
651{
652 struct window *w = updated_window;
ef253080 653 struct frame *f;
259cf6bc 654 int width, height;
7d0393cf 655
06a2c219 656 xassert (w);
7d0393cf 657
06a2c219 658 if (!desired_row->mode_line_p && !w->pseudo_window_p)
6b61353c 659 desired_row->redraw_fringe_bitmaps_p = 1;
7d0393cf 660
ef253080
GM
661 /* When a window has disappeared, make sure that no rest of
662 full-width rows stays visible in the internal border. Could
663 check here if updated_window is the leftmost/rightmost window,
664 but I guess it's not worth doing since vertically split windows
665 are almost never used, internal border is rarely set, and the
666 overhead is very small. */
667 if (windows_or_buffers_changed
668 && desired_row->full_width_p
669 && (f = XFRAME (w->frame),
670 width = FRAME_INTERNAL_BORDER_WIDTH (f),
259cf6bc
GM
671 width != 0)
672 && (height = desired_row->visible_height,
673 height > 0))
ef253080 674 {
ef253080 675 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
06a2c219 676
ef253080
GM
677 /* Internal border is drawn below the tool bar. */
678 if (WINDOWP (f->tool_bar_window)
679 && w == XWINDOW (f->tool_bar_window))
680 y -= width;
7d0393cf 681
ef253080
GM
682 BLOCK_INPUT;
683 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
684 0, y, width, height, False);
685 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
0899d58c 686 FRAME_PIXEL_WIDTH (f) - width,
ef253080 687 y, width, height, False);
06a2c219
GM
688 UNBLOCK_INPUT;
689 }
690}
691
06a2c219 692static void
5958f265 693x_draw_fringe_bitmap (w, row, p)
06a2c219
GM
694 struct window *w;
695 struct glyph_row *row;
5958f265 696 struct draw_fringe_bitmap_params *p;
06a2c219
GM
697{
698 struct frame *f = XFRAME (WINDOW_FRAME (w));
699 Display *display = FRAME_X_DISPLAY (f);
700 Window window = FRAME_X_WINDOW (f);
06a2c219 701 GC gc = f->output_data.x->normal_gc;
5958f265 702 struct face *face = p->face;
6b61353c 703 int rowY;
06a2c219
GM
704
705 /* Must clip because of partially visible lines. */
6b61353c
KH
706 rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
707 if (p->y < rowY)
708 {
709 /* Adjust position of "bottom aligned" bitmap on partially
710 visible last row. */
711 int oldY = row->y;
712 int oldVH = row->visible_height;
713 row->visible_height = p->h;
714 row->y -= rowY - p->y;
08f66682 715 x_clip_to_row (w, row, -1, gc);
6b61353c
KH
716 row->y = oldY;
717 row->visible_height = oldVH;
718 }
719 else
08f66682 720 x_clip_to_row (w, row, -1, gc);
06a2c219 721
6b61353c 722 if (p->bx >= 0 && !p->overlay_p)
976b73d7 723 {
976b73d7
KS
724 /* In case the same realized face is used for fringes and
725 for something displayed in the text (e.g. face `region' on
726 mono-displays, the fill style may have been changed to
727 FillSolid in x_draw_glyph_string_background. */
728 if (face->stipple)
729 XSetFillStyle (display, face->gc, FillOpaqueStippled);
730 else
731 XSetForeground (display, face->gc, face->background);
7d0393cf 732
976b73d7 733 XFillRectangle (display, window, face->gc,
5958f265
KS
734 p->bx, p->by, p->nx, p->ny);
735
976b73d7
KS
736 if (!face->stipple)
737 XSetForeground (display, face->gc, face->foreground);
738 }
739
6b61353c 740 if (p->which)
dbdc9702 741 {
6b61353c
KH
742 unsigned char *bits;
743 Pixmap pixmap, clipmask = (Pixmap) 0;
5958f265 744 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
6b61353c
KH
745 XGCValues gcv;
746
747 if (p->wd > 8)
748 bits = (unsigned char *)(p->bits + p->dh);
749 else
750 bits = (unsigned char *)p->bits + p->dh;
5958f265 751
dbdc9702
GM
752 /* Draw the bitmap. I believe these small pixmaps can be cached
753 by the server. */
5958f265 754 pixmap = XCreatePixmapFromBitmapData (display, window, bits, p->wd, p->h,
6b61353c
KH
755 (p->cursor_p
756 ? (p->overlay_p ? face->background
757 : f->output_data.x->cursor_pixel)
758 : face->foreground),
dbdc9702 759 face->background, depth);
6b61353c
KH
760
761 if (p->overlay_p)
762 {
763 clipmask = XCreatePixmapFromBitmapData (display,
764 FRAME_X_DISPLAY_INFO (f)->root_window,
765 bits, p->wd, p->h,
766 1, 0, 1);
767 gcv.clip_mask = clipmask;
768 gcv.clip_x_origin = p->x;
769 gcv.clip_y_origin = p->y;
770 XChangeGC (display, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
771 }
772
5958f265
KS
773 XCopyArea (display, pixmap, window, gc, 0, 0,
774 p->wd, p->h, p->x, p->y);
dbdc9702 775 XFreePixmap (display, pixmap);
6b61353c
KH
776
777 if (p->overlay_p)
778 {
779 gcv.clip_mask = (Pixmap) 0;
780 XChangeGC (display, gc, GCClipMask, &gcv);
781 XFreePixmap (display, clipmask);
782 }
dbdc9702 783 }
7d0393cf 784
06a2c219
GM
785 XSetClipMask (display, gc, None);
786}
787
dc6f92b8 788\f
06a2c219
GM
789
790/* This is called when starting Emacs and when restarting after
791 suspend. When starting Emacs, no X window is mapped. And nothing
792 must be done to Emacs's own window if it is suspended (though that
793 rarely happens). */
dc6f92b8 794
dfcf069d 795static void
dc6f92b8
JB
796XTset_terminal_modes ()
797{
798}
799
06a2c219
GM
800/* This is called when exiting or suspending Emacs. Exiting will make
801 the X-windows go away, and suspending requires no action. */
dc6f92b8 802
dfcf069d 803static void
dc6f92b8
JB
804XTreset_terminal_modes ()
805{
dc6f92b8 806}
06a2c219
GM
807
808
dc6f92b8 809\f
06a2c219
GM
810/***********************************************************************
811 Display Iterator
812 ***********************************************************************/
813
814/* Function prototypes of this page. */
815
8f924df7
KH
816static int x_encode_char P_ ((int, XChar2b *, struct font_info *,
817 struct charset *, int *));
ee569018
KH
818
819
e2ef8ee6
GM
820/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
821 is not contained in the font. */
dc43ef94 822
5da0698e
KS
823static XCharStruct *
824x_per_char_metric (font, char2b, font_type)
06a2c219
GM
825 XFontStruct *font;
826 XChar2b *char2b;
5da0698e 827 int font_type; /* unused on X */
06a2c219
GM
828{
829 /* The result metric information. */
830 XCharStruct *pcm = NULL;
dc6f92b8 831
06a2c219 832 xassert (font && char2b);
dc6f92b8 833
06a2c219 834 if (font->per_char != NULL)
dc6f92b8 835 {
06a2c219 836 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 837 {
06a2c219
GM
838 /* min_char_or_byte2 specifies the linear character index
839 corresponding to the first element of the per_char array,
840 max_char_or_byte2 is the index of the last character. A
841 character with non-zero CHAR2B->byte1 is not in the font.
842 A character with byte2 less than min_char_or_byte2 or
843 greater max_char_or_byte2 is not in the font. */
844 if (char2b->byte1 == 0
845 && char2b->byte2 >= font->min_char_or_byte2
846 && char2b->byte2 <= font->max_char_or_byte2)
847 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 848 }
06a2c219 849 else
dc6f92b8 850 {
06a2c219
GM
851 /* If either min_byte1 or max_byte1 are nonzero, both
852 min_char_or_byte2 and max_char_or_byte2 are less than
853 256, and the 2-byte character index values corresponding
854 to the per_char array element N (counting from 0) are:
855
856 byte1 = N/D + min_byte1
857 byte2 = N\D + min_char_or_byte2
858
859 where:
860
861 D = max_char_or_byte2 - min_char_or_byte2 + 1
862 / = integer division
863 \ = integer modulus */
864 if (char2b->byte1 >= font->min_byte1
865 && char2b->byte1 <= font->max_byte1
866 && char2b->byte2 >= font->min_char_or_byte2
867 && char2b->byte2 <= font->max_char_or_byte2)
868 {
869 pcm = (font->per_char
870 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
871 * (char2b->byte1 - font->min_byte1))
872 + (char2b->byte2 - font->min_char_or_byte2));
873 }
dc6f92b8 874 }
06a2c219
GM
875 }
876 else
877 {
878 /* If the per_char pointer is null, all glyphs between the first
879 and last character indexes inclusive have the same
880 information, as given by both min_bounds and max_bounds. */
881 if (char2b->byte2 >= font->min_char_or_byte2
882 && char2b->byte2 <= font->max_char_or_byte2)
883 pcm = &font->max_bounds;
884 }
dc6f92b8 885
ee569018 886 return ((pcm == NULL
3e71d8f2 887 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 888 ? NULL : pcm);
06a2c219 889}
b73b6aaf 890
57b03282 891
06a2c219
GM
892/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
893 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 894
5da0698e 895static int
8f924df7 896x_encode_char (c, char2b, font_info, charset, two_byte_p)
06a2c219
GM
897 int c;
898 XChar2b *char2b;
899 struct font_info *font_info;
8a78c965 900 struct charset *charset;
5da0698e 901 int *two_byte_p;
06a2c219 902{
06a2c219
GM
903 XFontStruct *font = font_info->font;
904
905 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
906 This may be either a program in a special encoder language or a
907 fixed encoding. */
908 if (font_info->font_encoder)
909 {
910 /* It's a program. */
911 struct ccl_program *ccl = font_info->font_encoder;
912
d8752c9e 913 check_ccl_update (ccl);
06a2c219
GM
914 if (CHARSET_DIMENSION (charset) == 1)
915 {
8a78c965 916 ccl->reg[0] = CHARSET_ID (charset);
06a2c219 917 ccl->reg[1] = char2b->byte2;
6e666629 918 ccl->reg[2] = -1;
06a2c219
GM
919 }
920 else
921 {
8a78c965 922 ccl->reg[0] = CHARSET_ID (charset);
06a2c219
GM
923 ccl->reg[1] = char2b->byte1;
924 ccl->reg[2] = char2b->byte2;
925 }
7d0393cf 926
d8d032b8 927 ccl_driver (ccl, NULL, NULL, 0, 0, Qnil);
7d0393cf 928
06a2c219
GM
929 /* We assume that MSBs are appropriately set/reset by CCL
930 program. */
931 if (font->max_byte1 == 0) /* 1-byte font */
8f924df7 932 STORE_XCHAR2B (char2b, 0, ccl->reg[1]);
06a2c219 933 else
8f924df7 934 STORE_XCHAR2B (char2b, ccl->reg[1], ccl->reg[2]);
06a2c219 935 }
8a78c965 936 else if (font_info->encoding_type)
06a2c219
GM
937 {
938 /* Fixed encoding scheme. See fontset.h for the meaning of the
939 encoding numbers. */
8a78c965 940 unsigned char enc = font_info->encoding_type;
7d0393cf 941
06a2c219
GM
942 if ((enc == 1 || enc == 2)
943 && CHARSET_DIMENSION (charset) == 2)
944 char2b->byte1 |= 0x80;
7d0393cf 945
06a2c219
GM
946 if (enc == 1 || enc == 3)
947 char2b->byte2 |= 0x80;
948 }
06a2c219 949
ee569018 950 if (two_byte_p)
5da0698e 951 *two_byte_p = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
b4192550 952
5da0698e 953 return FONT_TYPE_UNKNOWN;
06a2c219
GM
954}
955
956
06a2c219
GM
957\f
958/***********************************************************************
959 Glyph display
960 ***********************************************************************/
961
06a2c219 962
06a2c219 963
06a2c219
GM
964static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
965static void x_set_glyph_string_gc P_ ((struct glyph_string *));
966static void x_draw_glyph_string_background P_ ((struct glyph_string *,
967 int));
968static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 969static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
970static void x_draw_glyph_string_box P_ ((struct glyph_string *));
971static void x_draw_glyph_string P_ ((struct glyph_string *));
972static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
973static void x_set_cursor_gc P_ ((struct glyph_string *));
974static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
975static void x_set_mouse_face_gc P_ ((struct glyph_string *));
06a2c219 976static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 977 unsigned long *, double, int));
06a2c219 978static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 979 double, int, unsigned long));
06a2c219
GM
980static void x_setup_relief_colors P_ ((struct glyph_string *));
981static void x_draw_image_glyph_string P_ ((struct glyph_string *));
982static void x_draw_image_relief P_ ((struct glyph_string *));
983static void x_draw_image_foreground P_ ((struct glyph_string *));
984static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
06a2c219
GM
985static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
986 int, int, int));
987static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
57326d99
KS
988 int, int, int, int, int, int,
989 XRectangle *));
06a2c219
GM
990static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
991 int, int, int, XRectangle *));
5da0698e
KS
992
993#if GLYPH_DEBUG
994static void x_check_font P_ ((struct frame *, XFontStruct *));
995#endif
06a2c219
GM
996
997
998/* Set S->gc to a suitable GC for drawing glyph string S in cursor
999 face. */
1000
1001static void
1002x_set_cursor_gc (s)
1003 struct glyph_string *s;
1004{
1005 if (s->font == FRAME_FONT (s->f)
1006 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
1007 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 1008 && !s->cmp)
06a2c219
GM
1009 s->gc = s->f->output_data.x->cursor_gc;
1010 else
1011 {
1012 /* Cursor on non-default face: must merge. */
1013 XGCValues xgcv;
1014 unsigned long mask;
1015
1016 xgcv.background = s->f->output_data.x->cursor_pixel;
1017 xgcv.foreground = s->face->background;
1018
1019 /* If the glyph would be invisible, try a different foreground. */
1020 if (xgcv.foreground == xgcv.background)
1021 xgcv.foreground = s->face->foreground;
1022 if (xgcv.foreground == xgcv.background)
1023 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
1024 if (xgcv.foreground == xgcv.background)
1025 xgcv.foreground = s->face->foreground;
1026
1027 /* Make sure the cursor is distinct from text in this face. */
1028 if (xgcv.background == s->face->background
1029 && xgcv.foreground == s->face->foreground)
1030 {
1031 xgcv.background = s->face->foreground;
1032 xgcv.foreground = s->face->background;
1033 }
1034
1035 IF_DEBUG (x_check_font (s->f, s->font));
1036 xgcv.font = s->font->fid;
1037 xgcv.graphics_exposures = False;
1038 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
1039
1040 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1041 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1042 mask, &xgcv);
1043 else
1044 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
1045 = XCreateGC (s->display, s->window, mask, &xgcv);
1046
1047 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1048 }
1049}
1050
1051
1052/* Set up S->gc of glyph string S for drawing text in mouse face. */
7d0393cf 1053
06a2c219
GM
1054static void
1055x_set_mouse_face_gc (s)
1056 struct glyph_string *s;
7d0393cf 1057{
06a2c219 1058 int face_id;
ee569018 1059 struct face *face;
06a2c219 1060
e4ded23c 1061 /* What face has to be used last for the mouse face? */
06a2c219 1062 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 1063 face = FACE_FROM_ID (s->f, face_id);
e4ded23c
GM
1064 if (face == NULL)
1065 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
7d0393cf 1066
033e3e18 1067 if (s->first_glyph->type == CHAR_GLYPH)
e3c7c6a5 1068 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
033e3e18 1069 else
e3c7c6a5 1070 face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
06a2c219
GM
1071 s->face = FACE_FROM_ID (s->f, face_id);
1072 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
1073
1074 /* If font in this face is same as S->font, use it. */
1075 if (s->font == s->face->font)
1076 s->gc = s->face->gc;
c9ff09ee
KH
1077#ifdef USE_FONT_BACKEND
1078 else if (enable_font_backend)
1079 /* No need of setting a font for s->gc. */
1080 s->gc = s->face->gc;
1081#endif /* USE_FONT_BACKEND */
06a2c219
GM
1082 else
1083 {
1084 /* Otherwise construct scratch_cursor_gc with values from FACE
1085 but font FONT. */
1086 XGCValues xgcv;
1087 unsigned long mask;
7d0393cf 1088
06a2c219
GM
1089 xgcv.background = s->face->background;
1090 xgcv.foreground = s->face->foreground;
1091 IF_DEBUG (x_check_font (s->f, s->font));
1092 xgcv.font = s->font->fid;
1093 xgcv.graphics_exposures = False;
1094 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
7d0393cf 1095
06a2c219
GM
1096 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
1097 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
1098 mask, &xgcv);
1099 else
1100 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
1101 = XCreateGC (s->display, s->window, mask, &xgcv);
7d0393cf 1102
06a2c219
GM
1103 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
1104 }
1105
1106 xassert (s->gc != 0);
1107}
1108
1109
1110/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
1111 Faces to use in the mode line have already been computed when the
1112 matrix was built, so there isn't much to do, here. */
1113
1114static INLINE void
1115x_set_mode_line_face_gc (s)
1116 struct glyph_string *s;
7d0393cf 1117{
06a2c219 1118 s->gc = s->face->gc;
06a2c219
GM
1119}
1120
1121
1122/* Set S->gc of glyph string S for drawing that glyph string. Set
1123 S->stippled_p to a non-zero value if the face of S has a stipple
1124 pattern. */
1125
1126static INLINE void
1127x_set_glyph_string_gc (s)
1128 struct glyph_string *s;
1129{
209f68d9 1130 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
7d0393cf 1131
06a2c219
GM
1132 if (s->hl == DRAW_NORMAL_TEXT)
1133 {
1134 s->gc = s->face->gc;
1135 s->stippled_p = s->face->stipple != 0;
1136 }
1137 else if (s->hl == DRAW_INVERSE_VIDEO)
1138 {
1139 x_set_mode_line_face_gc (s);
1140 s->stippled_p = s->face->stipple != 0;
1141 }
1142 else if (s->hl == DRAW_CURSOR)
1143 {
1144 x_set_cursor_gc (s);
1145 s->stippled_p = 0;
1146 }
1147 else if (s->hl == DRAW_MOUSE_FACE)
1148 {
1149 x_set_mouse_face_gc (s);
1150 s->stippled_p = s->face->stipple != 0;
1151 }
1152 else if (s->hl == DRAW_IMAGE_RAISED
1153 || s->hl == DRAW_IMAGE_SUNKEN)
1154 {
1155 s->gc = s->face->gc;
1156 s->stippled_p = s->face->stipple != 0;
1157 }
1158 else
1159 {
1160 s->gc = s->face->gc;
1161 s->stippled_p = s->face->stipple != 0;
1162 }
1163
1164 /* GC must have been set. */
1165 xassert (s->gc != 0);
1166}
1167
1168
06a2c219
GM
1169/* Set clipping for output of glyph string S. S may be part of a mode
1170 line or menu if we don't have X toolkit support. */
1171
1172static INLINE void
1173x_set_glyph_string_clipping (s)
1174 struct glyph_string *s;
1175{
1176 XRectangle r;
442a09ea 1177 get_glyph_string_clip_rect (s, &r);
06a2c219 1178 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
c9ff09ee
KH
1179#ifdef USE_FONT_BACKEND
1180 s->clip_x = r.x, s->clip_y = r.y;
1181 s->clip_width = r.width, s->clip_height = r.height;
1182#endif /* USE_FONT_BACKEND */
06a2c219
GM
1183}
1184
1185
1dd71645
KH
1186/* Set SRC's clipping for output of glyph string DST. This is called
1187 when we are drawing DST's left_overhang or right_overhang only in
1188 the area of SRC. */
1189
1190static void
1191x_set_glyph_string_clipping_exactly (src, dst)
1192 struct glyph_string *src, *dst;
1193{
1194 XRectangle r;
c9ff09ee
KH
1195
1196#ifdef USE_FONT_BACKEND
1197 if (enable_font_backend)
1198 {
1199 r.x = dst->clip_x = src->x;
1b4fe7ab
KH
1200 r.width = dst->clip_width = src->width;
1201 r.y = dst->clip_y = src->y;
1202 r.height = dst->clip_height = src->height;
c9ff09ee
KH
1203 }
1204 else
1205 {
1206#endif /* USE_FONT_BACKEND */
b32d320e
KH
1207 struct glyph_string *clip_head = src->clip_head;
1208 struct glyph_string *clip_tail = src->clip_tail;
1dd71645 1209
b32d320e
KH
1210 /* This foces clipping just this glyph string. */
1211 src->clip_head = src->clip_tail = src;
1dd71645 1212 get_glyph_string_clip_rect (src, &r);
b32d320e 1213 src->clip_head = clip_head, src->clip_tail = clip_tail;
c9ff09ee
KH
1214#ifdef USE_FONT_BACKEND
1215 }
1216#endif /* USE_FONT_BACKEND */
1dd71645
KH
1217 XSetClipRectangles (dst->display, dst->gc, 0, 0, &r, 1, Unsorted);
1218}
1219
1220
5da0698e 1221/* RIF:
980a8c09 1222 Compute left and right overhang of glyph string S. */
06a2c219 1223
5da0698e 1224static void
06a2c219
GM
1225x_compute_glyph_string_overhangs (s)
1226 struct glyph_string *s;
1227{
b4192550 1228 if (s->cmp == NULL
06a2c219
GM
1229 && s->first_glyph->type == CHAR_GLYPH)
1230 {
1231 XCharStruct cs;
1232 int direction, font_ascent, font_descent;
c9ff09ee
KH
1233
1234#ifdef USE_FONT_BACKEND
1235 if (enable_font_backend)
1236 {
1237 unsigned *code = alloca (sizeof (unsigned) * s->nchars);
1238 struct font *font = (struct font *) s->font_info;
1239 struct font_metrics metrics;
1240 int i;
1241
1242 for (i = 0; i < s->nchars; i++)
1243 code[i] = (s->char2b[i].byte1 << 8) | s->char2b[i].byte2;
1244 font->driver->text_extents (font, code, s->nchars, &metrics);
1245 cs.rbearing = metrics.rbearing;
1246 cs.lbearing = metrics.lbearing;
1247 cs.width = metrics.width;
1248 }
1249 else
1250#endif /* USE_FONT_BACKEND */
06a2c219
GM
1251 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
1252 &font_ascent, &font_descent, &cs);
1253 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
1254 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
1255 }
980a8c09
KH
1256 else if (s->cmp)
1257 {
1258 s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
1259 s->left_overhang = - s->cmp->lbearing;
1260 }
06a2c219
GM
1261}
1262
1263
06a2c219
GM
1264/* Fill rectangle X, Y, W, H with background color of glyph string S. */
1265
1266static INLINE void
1267x_clear_glyph_string_rect (s, x, y, w, h)
1268 struct glyph_string *s;
1269 int x, y, w, h;
1270{
1271 XGCValues xgcv;
1272 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
1273 XSetForeground (s->display, s->gc, xgcv.background);
1274 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
1275 XSetForeground (s->display, s->gc, xgcv.foreground);
1276}
1277
1278
1279/* Draw the background of glyph_string S. If S->background_filled_p
1280 is non-zero don't draw it. FORCE_P non-zero means draw the
1281 background even if it wouldn't be drawn normally. This is used
b4192550
KH
1282 when a string preceding S draws into the background of S, or S
1283 contains the first component of a composition. */
06a2c219
GM
1284
1285static void
1286x_draw_glyph_string_background (s, force_p)
1287 struct glyph_string *s;
1288 int force_p;
1289{
1290 /* Nothing to do if background has already been drawn or if it
1291 shouldn't be drawn in the first place. */
1292 if (!s->background_filled_p)
1293 {
ea2ba0d4
KH
1294 int box_line_width = max (s->face->box_line_width, 0);
1295
b4192550 1296 if (s->stippled_p)
06a2c219
GM
1297 {
1298 /* Fill background with a stipple pattern. */
1299 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
1300 XFillRectangle (s->display, s->window, s->gc, s->x,
ea2ba0d4 1301 s->y + box_line_width,
06a2c219 1302 s->background_width,
ea2ba0d4 1303 s->height - 2 * box_line_width);
06a2c219
GM
1304 XSetFillStyle (s->display, s->gc, FillSolid);
1305 s->background_filled_p = 1;
1306 }
ea2ba0d4 1307 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
06a2c219
GM
1308 || s->font_not_found_p
1309 || s->extends_to_end_of_line_p
06a2c219
GM
1310 || force_p)
1311 {
ea2ba0d4 1312 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
06a2c219 1313 s->background_width,
ea2ba0d4 1314 s->height - 2 * box_line_width);
06a2c219
GM
1315 s->background_filled_p = 1;
1316 }
1317 }
1318}
1319
1320
1321/* Draw the foreground of glyph string S. */
1322
1323static void
1324x_draw_glyph_string_foreground (s)
1325 struct glyph_string *s;
1326{
1327 int i, x;
1328
1329 /* If first glyph of S has a left box line, start drawing the text
1330 of S to the right of that box line. */
1331 if (s->face->box != FACE_NO_BOX
1332 && s->first_glyph->left_box_line_p)
ea2ba0d4 1333 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
1334 else
1335 x = s->x;
1336
b4192550
KH
1337 /* Draw characters of S as rectangles if S's font could not be
1338 loaded. */
1339 if (s->font_not_found_p)
06a2c219 1340 {
b4192550 1341 for (i = 0; i < s->nchars; ++i)
06a2c219 1342 {
b4192550
KH
1343 struct glyph *g = s->first_glyph + i;
1344 XDrawRectangle (s->display, s->window,
1345 s->gc, x, s->y, g->pixel_width - 1,
1346 s->height - 1);
1347 x += g->pixel_width;
06a2c219
GM
1348 }
1349 }
c9ff09ee
KH
1350#ifdef USE_FONT_BACKEND
1351 else if (enable_font_backend)
1352 {
1353 unsigned *code = alloca (sizeof (unsigned) * s->nchars);
1354 int boff = s->font_info->baseline_offset;
1355 struct font *font = (struct font *) s->font_info;
1356 int y;
1357
1358 for (i = 0; i < s->nchars; i++)
1359 code[i] = (s->char2b[i].byte1 << 8) | s->char2b[i].byte2;
1360
1361 if (s->font_info->vertical_centering)
1362 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
1363
1364 y = s->ybase - boff;
1365 if (s->for_overlaps
1366 || (s->background_filled_p && s->hl != DRAW_CURSOR))
1367 font->driver->draw (s, 0, s->nchars, x, y, 0);
1368 else
1369 font->driver->draw (s, 0, s->nchars, x, y, 1);
1370 if (s->face->overstrike)
1371 font->driver->draw (s, 0, s->nchars, x + 1, y, 0);
1372 }
1373#endif /* USE_FONT_BACKEND */
06a2c219
GM
1374 else
1375 {
b4192550
KH
1376 char *char1b = (char *) s->char2b;
1377 int boff = s->font_info->baseline_offset;
06a2c219 1378
b4192550
KH
1379 if (s->font_info->vertical_centering)
1380 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
1381
1382 /* If we can use 8-bit functions, condense S->char2b. */
1383 if (!s->two_byte_p)
1384 for (i = 0; i < s->nchars; ++i)
1385 char1b[i] = s->char2b[i].byte2;
1386
1387 /* Draw text with XDrawString if background has already been
1388 filled. Otherwise, use XDrawImageString. (Note that
1389 XDrawImageString is usually faster than XDrawString.) Always
1390 use XDrawImageString when drawing the cursor so that there is
1391 no chance that characters under a box cursor are invisible. */
c2ded1b7 1392 if (s->for_overlaps
b4192550
KH
1393 || (s->background_filled_p && s->hl != DRAW_CURSOR))
1394 {
1395 /* Draw characters with 16-bit or 8-bit functions. */
1396 if (s->two_byte_p)
1397 XDrawString16 (s->display, s->window, s->gc, x,
1398 s->ybase - boff, s->char2b, s->nchars);
1399 else
1400 XDrawString (s->display, s->window, s->gc, x,
1401 s->ybase - boff, char1b, s->nchars);
1402 }
06a2c219
GM
1403 else
1404 {
b4192550
KH
1405 if (s->two_byte_p)
1406 XDrawImageString16 (s->display, s->window, s->gc, x,
1407 s->ybase - boff, s->char2b, s->nchars);
06a2c219 1408 else
b4192550
KH
1409 XDrawImageString (s->display, s->window, s->gc, x,
1410 s->ybase - boff, char1b, s->nchars);
1411 }
fce13449
MB
1412
1413 if (s->face->overstrike)
1414 {
1415 /* For overstriking (to simulate bold-face), draw the
1416 characters again shifted to the right by one pixel. */
1417 if (s->two_byte_p)
1418 XDrawString16 (s->display, s->window, s->gc, x + 1,
1419 s->ybase - boff, s->char2b, s->nchars);
1420 else
1421 XDrawString (s->display, s->window, s->gc, x + 1,
1422 s->ybase - boff, char1b, s->nchars);
1423 }
b4192550
KH
1424 }
1425}
06a2c219 1426
b4192550 1427/* Draw the foreground of composite glyph string S. */
06a2c219 1428
b4192550
KH
1429static void
1430x_draw_composite_glyph_string_foreground (s)
1431 struct glyph_string *s;
1432{
1433 int i, x;
06a2c219 1434
b4192550
KH
1435 /* If first glyph of S has a left box line, start drawing the text
1436 of S to the right of that box line. */
3eb44178 1437 if (s->face && s->face->box != FACE_NO_BOX
b4192550 1438 && s->first_glyph->left_box_line_p)
ea2ba0d4 1439 x = s->x + abs (s->face->box_line_width);
b4192550
KH
1440 else
1441 x = s->x;
06a2c219 1442
b4192550
KH
1443 /* S is a glyph string for a composition. S->gidx is the index of
1444 the first character drawn for glyphs of this composition.
1445 S->gidx == 0 means we are drawing the very first character of
1446 this composition. */
06a2c219 1447
b4192550
KH
1448 /* Draw a rectangle for the composition if the font for the very
1449 first character of the composition could not be loaded. */
1450 if (s->font_not_found_p)
1451 {
1452 if (s->gidx == 0)
1453 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
1454 s->width - 1, s->height - 1);
1455 }
c9ff09ee
KH
1456#ifdef USE_FONT_BACKEND
1457 else if (enable_font_backend)
1458 {
1459 struct font *font = (struct font *) s->font_info;
1460 int y = s->ybase;
1461 int width = 0;
1462
1463 if (s->cmp->method == COMPOSITION_WITH_GLYPH_STRING)
1464 {
1465 Lisp_Object gstring = AREF (XHASH_TABLE (composition_hash_table)
1466 ->key_and_value,
1467 s->cmp->hash_index * 2);
1468 int from;
1469
1470 for (i = from = 0; i < s->nchars; i++)
1471 {
1472 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
9de04ace
KH
1473 Lisp_Object adjustment = LGLYPH_ADJUSTMENT (g);
1474 int xoff, yoff, wadjust;
c9ff09ee 1475
878a939b 1476 if (! VECTORP (adjustment))
c9ff09ee
KH
1477 {
1478 width += XINT (LGLYPH_WIDTH (g));
1479 continue;
1480 }
1481 if (from < i)
1482 {
1483 font->driver->draw (s, from, i, x, y, 0);
1484 x += width;
1485 }
9de04ace
KH
1486 xoff = XINT (AREF (adjustment, 0));
1487 yoff = XINT (AREF (adjustment, 1));
1488 wadjust = XINT (AREF (adjustment, 2));
1489
1490 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, 0);
1491 x += XINT (LGLYPH_WIDTH (g)) + wadjust;
c9ff09ee
KH
1492 from = i + 1;
1493 width = 0;
1494 }
1495 if (from < i)
1496 font->driver->draw (s, from, i, x, y, 0);
1497 }
1498 else
1499 {
1500 for (i = 0; i < s->nchars; i++, ++s->gidx)
1501 {
1502 int xx = x + s->cmp->offsets[s->gidx * 2];
1503 int yy = y - s->cmp->offsets[s->gidx * 2 + 1];
1504
1505 font->driver->draw (s, i, i + 1, xx, yy, 0);
1506 if (s->face->overstrike)
1507 font->driver->draw (s, i, i + 1, xx + 1, yy, 0);
1508 }
1509 }
1510 }
1511#endif /* USE_FONT_BACKEND */
b4192550
KH
1512 else
1513 {
1514 for (i = 0; i < s->nchars; i++, ++s->gidx)
3eb44178
KH
1515 if (s->face)
1516 {
fce13449 1517 XDrawString16 (s->display, s->window, s->gc,
3eb44178 1518 x + s->cmp->offsets[s->gidx * 2],
fce13449
MB
1519 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
1520 s->char2b + i, 1);
3eb44178
KH
1521 if (s->face->overstrike)
1522 XDrawString16 (s->display, s->window, s->gc,
1523 x + s->cmp->offsets[s->gidx * 2] + 1,
1524 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
1525 s->char2b + i, 1);
1526 }
06a2c219
GM
1527 }
1528}
1529
1530
80c32bcc
GM
1531#ifdef USE_X_TOOLKIT
1532
3e71d8f2 1533static struct frame *x_frame_of_widget P_ ((Widget));
651f03b6
GM
1534static Boolean cvt_string_to_pixel P_ ((Display *, XrmValue *, Cardinal *,
1535 XrmValue *, XrmValue *, XtPointer *));
1536static void cvt_pixel_dtor P_ ((XtAppContext, XrmValue *, XtPointer,
1537 XrmValue *, Cardinal *));
80c32bcc 1538
3e71d8f2
GM
1539
1540/* Return the frame on which widget WIDGET is used.. Abort if frame
1541 cannot be determined. */
1542
e851c833 1543static struct frame *
3e71d8f2 1544x_frame_of_widget (widget)
80c32bcc 1545 Widget widget;
80c32bcc 1546{
80c32bcc 1547 struct x_display_info *dpyinfo;
5c187dee 1548 Lisp_Object tail;
3e71d8f2 1549 struct frame *f;
7d0393cf 1550
80c32bcc 1551 dpyinfo = x_display_info_for_display (XtDisplay (widget));
7d0393cf 1552
80c32bcc
GM
1553 /* Find the top-level shell of the widget. Note that this function
1554 can be called when the widget is not yet realized, so XtWindow
1555 (widget) == 0. That's the reason we can't simply use
1556 x_any_window_to_frame. */
1557 while (!XtIsTopLevelShell (widget))
1558 widget = XtParent (widget);
1559
1560 /* Look for a frame with that top-level widget. Allocate the color
1561 on that frame to get the right gamma correction value. */
1562 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
1563 if (GC_FRAMEP (XCAR (tail))
1564 && (f = XFRAME (XCAR (tail)),
1565 (f->output_data.nothing != 1
1566 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
1567 && f->output_data.x->widget == widget)
3e71d8f2 1568 return f;
80c32bcc
GM
1569
1570 abort ();
1571}
1572
3e71d8f2
GM
1573
1574/* Allocate the color COLOR->pixel on the screen and display of
1575 widget WIDGET in colormap CMAP. If an exact match cannot be
1576 allocated, try the nearest color available. Value is non-zero
1577 if successful. This is called from lwlib. */
1578
1579int
1580x_alloc_nearest_color_for_widget (widget, cmap, color)
1581 Widget widget;
1582 Colormap cmap;
1583 XColor *color;
1584{
1585 struct frame *f = x_frame_of_widget (widget);
1586 return x_alloc_nearest_color (f, cmap, color);
1587}
1588
1589
46d516e5
MB
1590/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
1591 or DELTA. Try a color with RGB values multiplied by FACTOR first.
1592 If this produces the same color as PIXEL, try a color where all RGB
1593 values have DELTA added. Return the allocated color in *PIXEL.
1594 DISPLAY is the X display, CMAP is the colormap to operate on.
1595 Value is non-zero if successful. */
1596
1597int
1598x_alloc_lighter_color_for_widget (widget, display, cmap, pixel, factor, delta)
1599 Widget widget;
1600 Display *display;
1601 Colormap cmap;
1602 unsigned long *pixel;
1603 double factor;
1604 int delta;
1605{
1606 struct frame *f = x_frame_of_widget (widget);
1607 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
1608}
1609
1610
651f03b6
GM
1611/* Structure specifying which arguments should be passed by Xt to
1612 cvt_string_to_pixel. We want the widget's screen and colormap. */
1613
1614static XtConvertArgRec cvt_string_to_pixel_args[] =
1615 {
1616 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.screen),
1617 sizeof (Screen *)},
1618 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.colormap),
1619 sizeof (Colormap)}
1620 };
1621
1622
1623/* The address of this variable is returned by
1624 cvt_string_to_pixel. */
1625
1626static Pixel cvt_string_to_pixel_value;
1627
1628
1629/* Convert a color name to a pixel color.
1630
1631 DPY is the display we are working on.
1632
1633 ARGS is an array of *NARGS XrmValue structures holding additional
1634 information about the widget for which the conversion takes place.
1635 The contents of this array are determined by the specification
1636 in cvt_string_to_pixel_args.
1637
1638 FROM is a pointer to an XrmValue which points to the color name to
1639 convert. TO is an XrmValue in which to return the pixel color.
1640
1641 CLOSURE_RET is a pointer to user-data, in which we record if
1642 we allocated the color or not.
1643
1644 Value is True if successful, False otherwise. */
1645
1646static Boolean
1647cvt_string_to_pixel (dpy, args, nargs, from, to, closure_ret)
1648 Display *dpy;
1649 XrmValue *args;
1650 Cardinal *nargs;
1651 XrmValue *from, *to;
1652 XtPointer *closure_ret;
1653{
1654 Screen *screen;
1655 Colormap cmap;
1656 Pixel pixel;
1657 String color_name;
1658 XColor color;
1659
1660 if (*nargs != 2)
1661 {
1662 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
1663 "wrongParameters", "cvt_string_to_pixel",
1664 "XtToolkitError",
1665 "Screen and colormap args required", NULL, NULL);
1666 return False;
1667 }
1668
1669 screen = *(Screen **) args[0].addr;
1670 cmap = *(Colormap *) args[1].addr;
1671 color_name = (String) from->addr;
1672
1673 if (strcmp (color_name, XtDefaultBackground) == 0)
1674 {
1675 *closure_ret = (XtPointer) False;
1676 pixel = WhitePixelOfScreen (screen);
1677 }
1678 else if (strcmp (color_name, XtDefaultForeground) == 0)
1679 {
1680 *closure_ret = (XtPointer) False;
1681 pixel = BlackPixelOfScreen (screen);
1682 }
1683 else if (XParseColor (dpy, cmap, color_name, &color)
1684 && x_alloc_nearest_color_1 (dpy, cmap, &color))
1685 {
1686 pixel = color.pixel;
1687 *closure_ret = (XtPointer) True;
1688 }
1689 else
1690 {
1691 String params[1];
1692 Cardinal nparams = 1;
7d0393cf 1693
651f03b6
GM
1694 params[0] = color_name;
1695 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
1696 "badValue", "cvt_string_to_pixel",
1697 "XtToolkitError", "Invalid color `%s'",
1698 params, &nparams);
1699 return False;
1700 }
1701
1702 if (to->addr != NULL)
1703 {
1704 if (to->size < sizeof (Pixel))
1705 {
1706 to->size = sizeof (Pixel);
1707 return False;
1708 }
7d0393cf 1709
651f03b6
GM
1710 *(Pixel *) to->addr = pixel;
1711 }
1712 else
1713 {
1714 cvt_string_to_pixel_value = pixel;
1715 to->addr = (XtPointer) &cvt_string_to_pixel_value;
1716 }
7d0393cf 1717
651f03b6
GM
1718 to->size = sizeof (Pixel);
1719 return True;
1720}
1721
1722
1723/* Free a pixel color which was previously allocated via
1724 cvt_string_to_pixel. This is registered as the destructor
1725 for this type of resource via XtSetTypeConverter.
1726
1727 APP is the application context in which we work.
1728
1729 TO is a pointer to an XrmValue holding the color to free.
1730 CLOSURE is the value we stored in CLOSURE_RET for this color
1731 in cvt_string_to_pixel.
1732
1733 ARGS and NARGS are like for cvt_string_to_pixel. */
1734
1735static void
1736cvt_pixel_dtor (app, to, closure, args, nargs)
1737 XtAppContext app;
1738 XrmValuePtr to;
1739 XtPointer closure;
1740 XrmValuePtr args;
1741 Cardinal *nargs;
1742{
1743 if (*nargs != 2)
1744 {
1745 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
1746 "XtToolkitError",
1747 "Screen and colormap arguments required",
1748 NULL, NULL);
1749 }
1750 else if (closure != NULL)
1751 {
1752 /* We did allocate the pixel, so free it. */
1753 Screen *screen = *(Screen **) args[0].addr;
1754 Colormap cmap = *(Colormap *) args[1].addr;
1755 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
97762eb7 1756 (Pixel *) to->addr, 1);
651f03b6
GM
1757 }
1758}
1759
1760
80c32bcc
GM
1761#endif /* USE_X_TOOLKIT */
1762
1763
f04e1297 1764/* Value is an array of XColor structures for the contents of the
651f03b6 1765 color map of display DPY. Set *NCELLS to the size of the array.
f04e1297
GM
1766 Note that this probably shouldn't be called for large color maps,
1767 say a 24-bit TrueColor map. */
1768
1769static const XColor *
651f03b6
GM
1770x_color_cells (dpy, ncells)
1771 Display *dpy;
f04e1297
GM
1772 int *ncells;
1773{
651f03b6 1774 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
f04e1297
GM
1775
1776 if (dpyinfo->color_cells == NULL)
1777 {
651f03b6 1778 Screen *screen = dpyinfo->screen;
f04e1297 1779 int i;
7d0393cf 1780
f04e1297 1781 dpyinfo->ncolor_cells
651f03b6 1782 = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
f04e1297
GM
1783 dpyinfo->color_cells
1784 = (XColor *) xmalloc (dpyinfo->ncolor_cells
1785 * sizeof *dpyinfo->color_cells);
7d0393cf 1786
f04e1297
GM
1787 for (i = 0; i < dpyinfo->ncolor_cells; ++i)
1788 dpyinfo->color_cells[i].pixel = i;
7d0393cf 1789
651f03b6 1790 XQueryColors (dpy, dpyinfo->cmap,
f04e1297
GM
1791 dpyinfo->color_cells, dpyinfo->ncolor_cells);
1792 }
1793
1794 *ncells = dpyinfo->ncolor_cells;
1795 return dpyinfo->color_cells;
1796}
1797
1798
1799/* On frame F, translate pixel colors to RGB values for the NCOLORS
1800 colors in COLORS. Use cached information, if available. */
1801
1802void
1803x_query_colors (f, colors, ncolors)
1804 struct frame *f;
1805 XColor *colors;
1806 int ncolors;
1807{
1808 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
1809
1810 if (dpyinfo->color_cells)
1811 {
1812 int i;
1813 for (i = 0; i < ncolors; ++i)
1814 {
1815 unsigned long pixel = colors[i].pixel;
1816 xassert (pixel < dpyinfo->ncolor_cells);
1817 xassert (dpyinfo->color_cells[pixel].pixel == pixel);
1818 colors[i] = dpyinfo->color_cells[pixel];
1819 }
1820 }
1821 else
1822 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
1823}
1824
1825
1826/* On frame F, translate pixel color to RGB values for the color in
1827 COLOR. Use cached information, if available. */
1828
1829void
1830x_query_color (f, color)
1831 struct frame *f;
1832 XColor *color;
1833{
1834 x_query_colors (f, color, 1);
1835}
7d0393cf 1836
f04e1297 1837
651f03b6
GM
1838/* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
1839 exact match can't be allocated, try the nearest color available.
1840 Value is non-zero if successful. Set *COLOR to the color
1841 allocated. */
06a2c219 1842
651f03b6
GM
1843static int
1844x_alloc_nearest_color_1 (dpy, cmap, color)
1845 Display *dpy;
06a2c219
GM
1846 Colormap cmap;
1847 XColor *color;
1848{
80c32bcc
GM
1849 int rc;
1850
651f03b6 1851 rc = XAllocColor (dpy, cmap, color);
06a2c219
GM
1852 if (rc == 0)
1853 {
1854 /* If we got to this point, the colormap is full, so we're going
1855 to try to get the next closest color. The algorithm used is
1856 a least-squares matching, which is what X uses for closest
1857 color matching with StaticColor visuals. */
1858 int nearest, i;
1859 unsigned long nearest_delta = ~0;
f04e1297 1860 int ncells;
651f03b6 1861 const XColor *cells = x_color_cells (dpy, &ncells);
06a2c219
GM
1862
1863 for (nearest = i = 0; i < ncells; ++i)
1864 {
1865 long dred = (color->red >> 8) - (cells[i].red >> 8);
1866 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
1867 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
1868 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
1869
1870 if (delta < nearest_delta)
1871 {
1872 nearest = i;
1873 nearest_delta = delta;
1874 }
1875 }
7d0393cf 1876
06a2c219
GM
1877 color->red = cells[nearest].red;
1878 color->green = cells[nearest].green;
1879 color->blue = cells[nearest].blue;
651f03b6 1880 rc = XAllocColor (dpy, cmap, color);
06a2c219 1881 }
35efe0a1
GM
1882 else
1883 {
1884 /* If allocation succeeded, and the allocated pixel color is not
1885 equal to a cached pixel color recorded earlier, there was a
1886 change in the colormap, so clear the color cache. */
651f03b6 1887 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
35efe0a1 1888 XColor *cached_color;
7d0393cf 1889
35efe0a1
GM
1890 if (dpyinfo->color_cells
1891 && (cached_color = &dpyinfo->color_cells[color->pixel],
cae71efe
GM
1892 (cached_color->red != color->red
1893 || cached_color->blue != color->blue
1894 || cached_color->green != color->green)))
35efe0a1
GM
1895 {
1896 xfree (dpyinfo->color_cells);
1897 dpyinfo->color_cells = NULL;
1898 dpyinfo->ncolor_cells = 0;
1899 }
1900 }
06a2c219 1901
d9c545da
GM
1902#ifdef DEBUG_X_COLORS
1903 if (rc)
1904 register_color (color->pixel);
1905#endif /* DEBUG_X_COLORS */
7d0393cf 1906
06a2c219
GM
1907 return rc;
1908}
1909
1910
651f03b6
GM
1911/* Allocate the color COLOR->pixel on frame F, colormap CMAP. If an
1912 exact match can't be allocated, try the nearest color available.
1913 Value is non-zero if successful. Set *COLOR to the color
1914 allocated. */
1915
1916int
1917x_alloc_nearest_color (f, cmap, color)
1918 struct frame *f;
1919 Colormap cmap;
1920 XColor *color;
1921{
1922 gamma_correct (f, color);
1923 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
1924}
1925
1926
d9c545da
GM
1927/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
1928 It's necessary to do this instead of just using PIXEL directly to
1929 get color reference counts right. */
1930
1931unsigned long
1932x_copy_color (f, pixel)
1933 struct frame *f;
1934 unsigned long pixel;
1935{
1936 XColor color;
1937
1938 color.pixel = pixel;
1939 BLOCK_INPUT;
f04e1297 1940 x_query_color (f, &color);
d9c545da
GM
1941 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
1942 UNBLOCK_INPUT;
1943#ifdef DEBUG_X_COLORS
1944 register_color (pixel);
1945#endif
1946 return color.pixel;
1947}
1948
1949
3e71d8f2
GM
1950/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
1951 It's necessary to do this instead of just using PIXEL directly to
1952 get color reference counts right. */
1953
1954unsigned long
1955x_copy_dpy_color (dpy, cmap, pixel)
1956 Display *dpy;
1957 Colormap cmap;
1958 unsigned long pixel;
1959{
1960 XColor color;
1961
1962 color.pixel = pixel;
1963 BLOCK_INPUT;
1964 XQueryColor (dpy, cmap, &color);
1965 XAllocColor (dpy, cmap, &color);
1966 UNBLOCK_INPUT;
1967#ifdef DEBUG_X_COLORS
1968 register_color (pixel);
1969#endif
1970 return color.pixel;
1971}
1972
1973
6d8b0acd 1974/* Brightness beyond which a color won't have its highlight brightness
d7361edf 1975 boosted.
6d8b0acd 1976
d7361edf
MB
1977 Nominally, highlight colors for `3d' faces are calculated by
1978 brightening an object's color by a constant scale factor, but this
1979 doesn't yield good results for dark colors, so for colors who's
1980 brightness is less than this value (on a scale of 0-65535) have an
1981 use an additional additive factor.
6d8b0acd
MB
1982
1983 The value here is set so that the default menu-bar/mode-line color
1984 (grey75) will not have its highlights changed at all. */
1985#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
1986
1987
06a2c219
GM
1988/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
1989 or DELTA. Try a color with RGB values multiplied by FACTOR first.
1990 If this produces the same color as PIXEL, try a color where all RGB
1991 values have DELTA added. Return the allocated color in *PIXEL.
1992 DISPLAY is the X display, CMAP is the colormap to operate on.
1993 Value is non-zero if successful. */
1994
1995static int
1996x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
1997 struct frame *f;
1998 Display *display;
1999 Colormap cmap;
2000 unsigned long *pixel;
68c45bf0 2001 double factor;
06a2c219
GM
2002 int delta;
2003{
2004 XColor color, new;
6d8b0acd 2005 long bright;
06a2c219
GM
2006 int success_p;
2007
2008 /* Get RGB color values. */
2009 color.pixel = *pixel;
f04e1297 2010 x_query_color (f, &color);
06a2c219
GM
2011
2012 /* Change RGB values by specified FACTOR. Avoid overflow! */
2013 xassert (factor >= 0);
2014 new.red = min (0xffff, factor * color.red);
2015 new.green = min (0xffff, factor * color.green);
2016 new.blue = min (0xffff, factor * color.blue);
2017
d7361edf
MB
2018 /* Calculate brightness of COLOR. */
2019 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
6d8b0acd
MB
2020
2021 /* We only boost colors that are darker than
2022 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
2023 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
2024 /* Make an additive adjustment to NEW, because it's dark enough so
2025 that scaling by FACTOR alone isn't enough. */
2026 {
2027 /* How far below the limit this color is (0 - 1, 1 being darker). */
2028 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
2029 /* The additive adjustment. */
d7361edf 2030 int min_delta = delta * dimness * factor / 2;
6d8b0acd
MB
2031
2032 if (factor < 1)
2033 {
6d8b0acd
MB
2034 new.red = max (0, new.red - min_delta);
2035 new.green = max (0, new.green - min_delta);
2036 new.blue = max (0, new.blue - min_delta);
2037 }
2038 else
2039 {
2040 new.red = min (0xffff, min_delta + new.red);
2041 new.green = min (0xffff, min_delta + new.green);
2042 new.blue = min (0xffff, min_delta + new.blue);
2043 }
2044 }
2045
06a2c219 2046 /* Try to allocate the color. */
80c32bcc 2047 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
2048 if (success_p)
2049 {
2050 if (new.pixel == *pixel)
2051 {
2052 /* If we end up with the same color as before, try adding
2053 delta to the RGB values. */
0d605c67 2054 x_free_colors (f, &new.pixel, 1);
7d0393cf 2055
06a2c219
GM
2056 new.red = min (0xffff, delta + color.red);
2057 new.green = min (0xffff, delta + color.green);
2058 new.blue = min (0xffff, delta + color.blue);
80c32bcc 2059 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
2060 }
2061 else
2062 success_p = 1;
2063 *pixel = new.pixel;
2064 }
7d0393cf 2065
06a2c219
GM
2066 return success_p;
2067}
2068
2069
2070/* Set up the foreground color for drawing relief lines of glyph
2071 string S. RELIEF is a pointer to a struct relief containing the GC
2072 with which lines will be drawn. Use a color that is FACTOR or
2073 DELTA lighter or darker than the relief's background which is found
2074 in S->f->output_data.x->relief_background. If such a color cannot
2075 be allocated, use DEFAULT_PIXEL, instead. */
7d0393cf 2076
06a2c219
GM
2077static void
2078x_setup_relief_color (f, relief, factor, delta, default_pixel)
2079 struct frame *f;
2080 struct relief *relief;
68c45bf0 2081 double factor;
06a2c219
GM
2082 int delta;
2083 unsigned long default_pixel;
2084{
2085 XGCValues xgcv;
2086 struct x_output *di = f->output_data.x;
2087 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
2088 unsigned long pixel;
2089 unsigned long background = di->relief_background;
43bd1b2b 2090 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
2091 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
2092 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
2093
2094 xgcv.graphics_exposures = False;
2095 xgcv.line_width = 1;
2096
2097 /* Free previously allocated color. The color cell will be reused
2098 when it has been freed as many times as it was allocated, so this
2099 doesn't affect faces using the same colors. */
2100 if (relief->gc
2101 && relief->allocated_p)
2102 {
0d605c67 2103 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
2104 relief->allocated_p = 0;
2105 }
2106
2107 /* Allocate new color. */
2108 xgcv.foreground = default_pixel;
2109 pixel = background;
dcd08bfb
GM
2110 if (dpyinfo->n_planes != 1
2111 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
2112 {
2113 relief->allocated_p = 1;
2114 xgcv.foreground = relief->pixel = pixel;
2115 }
7d0393cf 2116
06a2c219
GM
2117 if (relief->gc == 0)
2118 {
dcd08bfb 2119 xgcv.stipple = dpyinfo->gray;
06a2c219 2120 mask |= GCStipple;
dcd08bfb 2121 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
2122 }
2123 else
dcd08bfb 2124 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
2125}
2126
2127
2128/* Set up colors for the relief lines around glyph string S. */
2129
2130static void
2131x_setup_relief_colors (s)
2132 struct glyph_string *s;
2133{
2134 struct x_output *di = s->f->output_data.x;
2135 unsigned long color;
2136
2137 if (s->face->use_box_color_for_shadows_p)
2138 color = s->face->box_color;
e2a57b34 2139 else if (s->first_glyph->type == IMAGE_GLYPH
0cb8bb48 2140 && s->img->pixmap
e2a57b34
MB
2141 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2142 color = IMAGE_BACKGROUND (s->img, s->f, 0);
06a2c219
GM
2143 else
2144 {
2145 XGCValues xgcv;
7d0393cf 2146
06a2c219
GM
2147 /* Get the background color of the face. */
2148 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
2149 color = xgcv.background;
2150 }
2151
2152 if (di->white_relief.gc == 0
2153 || color != di->relief_background)
2154 {
2155 di->relief_background = color;
2156 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
2157 WHITE_PIX_DEFAULT (s->f));
2158 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
2159 BLACK_PIX_DEFAULT (s->f));
2160 }
2161}
2162
2163
2164/* Draw a relief on frame F inside the rectangle given by LEFT_X,
2165 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
2166 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
2167 relief. LEFT_P non-zero means draw a relief on the left side of
2168 the rectangle. RIGHT_P non-zero means draw a relief on the right
2169 side of the rectangle. CLIP_RECT is the clipping rectangle to use
2170 when drawing. */
2171
2172static void
2173x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
57326d99 2174 raised_p, top_p, bot_p, left_p, right_p, clip_rect)
06a2c219 2175 struct frame *f;
57326d99
KS
2176 int left_x, top_y, right_x, bottom_y, width;
2177 int top_p, bot_p, left_p, right_p, raised_p;
06a2c219
GM
2178 XRectangle *clip_rect;
2179{
de507556
GM
2180 Display *dpy = FRAME_X_DISPLAY (f);
2181 Window window = FRAME_X_WINDOW (f);
06a2c219
GM
2182 int i;
2183 GC gc;
7d0393cf 2184
06a2c219
GM
2185 if (raised_p)
2186 gc = f->output_data.x->white_relief.gc;
2187 else
2188 gc = f->output_data.x->black_relief.gc;
de507556 2189 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
2190
2191 /* Top. */
57326d99
KS
2192 if (top_p)
2193 for (i = 0; i < width; ++i)
2194 XDrawLine (dpy, window, gc,
2195 left_x + i * left_p, top_y + i,
2196 right_x + 1 - i * right_p, top_y + i);
06a2c219
GM
2197
2198 /* Left. */
2199 if (left_p)
2200 for (i = 0; i < width; ++i)
de507556 2201 XDrawLine (dpy, window, gc,
44655e77 2202 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
06a2c219 2203
de507556 2204 XSetClipMask (dpy, gc, None);
06a2c219
GM
2205 if (raised_p)
2206 gc = f->output_data.x->black_relief.gc;
2207 else
2208 gc = f->output_data.x->white_relief.gc;
de507556 2209 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
7d0393cf 2210
06a2c219 2211 /* Bottom. */
57326d99
KS
2212 if (bot_p)
2213 for (i = 0; i < width; ++i)
2214 XDrawLine (dpy, window, gc,
2215 left_x + i * left_p, bottom_y - i,
2216 right_x + 1 - i * right_p, bottom_y - i);
7d0393cf 2217
06a2c219
GM
2218 /* Right. */
2219 if (right_p)
2220 for (i = 0; i < width; ++i)
de507556 2221 XDrawLine (dpy, window, gc,
06a2c219
GM
2222 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
2223
de507556 2224 XSetClipMask (dpy, gc, None);
06a2c219
GM
2225}
2226
2227
2228/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
2229 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
2230 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
2231 left side of the rectangle. RIGHT_P non-zero means draw a line
2232 on the right side of the rectangle. CLIP_RECT is the clipping
2233 rectangle to use when drawing. */
2234
2235static void
2236x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
2237 left_p, right_p, clip_rect)
2238 struct glyph_string *s;
0971e730 2239 int left_x, top_y, right_x, bottom_y, width, left_p, right_p;
06a2c219
GM
2240 XRectangle *clip_rect;
2241{
2242 XGCValues xgcv;
7d0393cf 2243
06a2c219
GM
2244 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
2245 XSetForeground (s->display, s->gc, s->face->box_color);
2246 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
7d0393cf 2247
06a2c219
GM
2248 /* Top. */
2249 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 2250 left_x, top_y, right_x - left_x + 1, width);
06a2c219
GM
2251
2252 /* Left. */
2253 if (left_p)
2254 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 2255 left_x, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
2256
2257 /* Bottom. */
2258 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 2259 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
7d0393cf 2260
06a2c219
GM
2261 /* Right. */
2262 if (right_p)
2263 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 2264 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
2265
2266 XSetForeground (s->display, s->gc, xgcv.foreground);
2267 XSetClipMask (s->display, s->gc, None);
2268}
2269
2270
2271/* Draw a box around glyph string S. */
2272
2273static void
2274x_draw_glyph_string_box (s)
2275 struct glyph_string *s;
2276{
2277 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
2278 int left_p, right_p;
2279 struct glyph *last_glyph;
2280 XRectangle clip_rect;
2281
82ead4b1
KS
2282 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2283 ? WINDOW_RIGHT_EDGE_X (s->w)
2284 : window_box_right (s->w, s->area));
7d0393cf 2285
06a2c219 2286 /* The glyph that may have a right box line. */
b4192550 2287 last_glyph = (s->cmp || s->img
06a2c219
GM
2288 ? s->first_glyph
2289 : s->first_glyph + s->nchars - 1);
2290
ea2ba0d4 2291 width = abs (s->face->box_line_width);
06a2c219
GM
2292 raised_p = s->face->box == FACE_RAISED_BOX;
2293 left_x = s->x;
57ac7c81
GM
2294 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
2295 ? last_x - 1
2296 : min (last_x, s->x + s->background_width) - 1);
06a2c219
GM
2297 top_y = s->y;
2298 bottom_y = top_y + s->height - 1;
2299
2300 left_p = (s->first_glyph->left_box_line_p
2301 || (s->hl == DRAW_MOUSE_FACE
2302 && (s->prev == NULL
2303 || s->prev->hl != s->hl)));
2304 right_p = (last_glyph->right_box_line_p
2305 || (s->hl == DRAW_MOUSE_FACE
2306 && (s->next == NULL
2307 || s->next->hl != s->hl)));
327f42ee 2308
442a09ea 2309 get_glyph_string_clip_rect (s, &clip_rect);
06a2c219
GM
2310
2311 if (s->face->box == FACE_SIMPLE_BOX)
2312 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
2313 left_p, right_p, &clip_rect);
2314 else
2315 {
2316 x_setup_relief_colors (s);
2317 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
57326d99 2318 width, raised_p, 1, 1, left_p, right_p, &clip_rect);
06a2c219
GM
2319 }
2320}
2321
2322
2323/* Draw foreground of image glyph string S. */
2324
2325static void
2326x_draw_image_foreground (s)
2327 struct glyph_string *s;
2328{
57326d99
KS
2329 int x = s->x;
2330 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
06a2c219
GM
2331
2332 /* If first glyph of S has a left box line, start drawing it to the
2333 right of that line. */
2334 if (s->face->box != FACE_NO_BOX
57326d99
KS
2335 && s->first_glyph->left_box_line_p
2336 && s->slice.x == 0)
2337 x += abs (s->face->box_line_width);
06a2c219
GM
2338
2339 /* If there is a margin around the image, adjust x- and y-position
2340 by that margin. */
57326d99
KS
2341 if (s->slice.x == 0)
2342 x += s->img->hmargin;
2343 if (s->slice.y == 0)
2344 y += s->img->vmargin;
06a2c219
GM
2345
2346 if (s->img->pixmap)
2347 {
2348 if (s->img->mask)
2349 {
2350 /* We can't set both a clip mask and use XSetClipRectangles
2351 because the latter also sets a clip mask. We also can't
2352 trust on the shape extension to be available
2353 (XShapeCombineRegion). So, compute the rectangle to draw
2354 manually. */
2355 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
2356 | GCFunction);
2357 XGCValues xgcv;
2358 XRectangle clip_rect, image_rect, r;
2359
2360 xgcv.clip_mask = s->img->mask;
2361 xgcv.clip_x_origin = x;
2362 xgcv.clip_y_origin = y;
2363 xgcv.function = GXcopy;
2364 XChangeGC (s->display, s->gc, mask, &xgcv);
7d0393cf 2365
442a09ea 2366 get_glyph_string_clip_rect (s, &clip_rect);
06a2c219
GM
2367 image_rect.x = x;
2368 image_rect.y = y;
57326d99
KS
2369 image_rect.width = s->slice.width;
2370 image_rect.height = s->slice.height;
06a2c219
GM
2371 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
2372 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
57326d99
KS
2373 s->slice.x + r.x - x, s->slice.y + r.y - y,
2374 r.width, r.height, r.x, r.y);
06a2c219
GM
2375 }
2376 else
2377 {
49ad1d99
GM
2378 XRectangle clip_rect, image_rect, r;
2379
442a09ea 2380 get_glyph_string_clip_rect (s, &clip_rect);
49ad1d99
GM
2381 image_rect.x = x;
2382 image_rect.y = y;
57326d99
KS
2383 image_rect.width = s->slice.width;
2384 image_rect.height = s->slice.height;
49ad1d99
GM
2385 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
2386 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
57326d99
KS
2387 s->slice.x + r.x - x, s->slice.y + r.y - y,
2388 r.width, r.height, r.x, r.y);
7d0393cf 2389
06a2c219
GM
2390 /* When the image has a mask, we can expect that at
2391 least part of a mouse highlight or a block cursor will
2392 be visible. If the image doesn't have a mask, make
2393 a block cursor visible by drawing a rectangle around
2394 the image. I believe it's looking better if we do
2395 nothing here for mouse-face. */
2396 if (s->hl == DRAW_CURSOR)
534c20b2
KS
2397 {
2398 int r = s->img->relief;
2399 if (r < 0) r = -r;
57326d99
KS
2400 XDrawRectangle (s->display, s->window, s->gc,
2401 x - r, y - r,
2402 s->slice.width + r*2 - 1,
2403 s->slice.height + r*2 - 1);
534c20b2 2404 }
06a2c219
GM
2405 }
2406 }
2407 else
2408 /* Draw a rectangle if image could not be loaded. */
2409 XDrawRectangle (s->display, s->window, s->gc, x, y,
57326d99 2410 s->slice.width - 1, s->slice.height - 1);
06a2c219
GM
2411}
2412
2413
2414/* Draw a relief around the image glyph string S. */
2415
2416static void
2417x_draw_image_relief (s)
2418 struct glyph_string *s;
2419{
2420 int x0, y0, x1, y1, thick, raised_p;
2421 XRectangle r;
57326d99
KS
2422 int x = s->x;
2423 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
7d0393cf 2424
06a2c219
GM
2425 /* If first glyph of S has a left box line, start drawing it to the
2426 right of that line. */
2427 if (s->face->box != FACE_NO_BOX
57326d99
KS
2428 && s->first_glyph->left_box_line_p
2429 && s->slice.x == 0)
2430 x += abs (s->face->box_line_width);
7d0393cf 2431
06a2c219
GM
2432 /* If there is a margin around the image, adjust x- and y-position
2433 by that margin. */
57326d99
KS
2434 if (s->slice.x == 0)
2435 x += s->img->hmargin;
2436 if (s->slice.y == 0)
2437 y += s->img->vmargin;
7d0393cf 2438
06a2c219
GM
2439 if (s->hl == DRAW_IMAGE_SUNKEN
2440 || s->hl == DRAW_IMAGE_RAISED)
2441 {
62854fe2 2442 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
06a2c219
GM
2443 raised_p = s->hl == DRAW_IMAGE_RAISED;
2444 }
2445 else
2446 {
2447 thick = abs (s->img->relief);
2448 raised_p = s->img->relief > 0;
2449 }
7d0393cf 2450
06a2c219
GM
2451 x0 = x - thick;
2452 y0 = y - thick;
57326d99
KS
2453 x1 = x + s->slice.width + thick - 1;
2454 y1 = y + s->slice.height + thick - 1;
7d0393cf 2455
06a2c219 2456 x_setup_relief_colors (s);
442a09ea 2457 get_glyph_string_clip_rect (s, &r);
57326d99
KS
2458 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p,
2459 s->slice.y == 0,
2460 s->slice.y + s->slice.height == s->img->height,
2461 s->slice.x == 0,
2462 s->slice.x + s->slice.width == s->img->width,
2463 &r);
06a2c219
GM
2464}
2465
2466
2467/* Draw the foreground of image glyph string S to PIXMAP. */
2468
2469static void
2470x_draw_image_foreground_1 (s, pixmap)
2471 struct glyph_string *s;
2472 Pixmap pixmap;
2473{
57326d99
KS
2474 int x = 0;
2475 int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice);
06a2c219
GM
2476
2477 /* If first glyph of S has a left box line, start drawing it to the
2478 right of that line. */
2479 if (s->face->box != FACE_NO_BOX
57326d99
KS
2480 && s->first_glyph->left_box_line_p
2481 && s->slice.x == 0)
2482 x += abs (s->face->box_line_width);
06a2c219
GM
2483
2484 /* If there is a margin around the image, adjust x- and y-position
2485 by that margin. */
57326d99
KS
2486 if (s->slice.x == 0)
2487 x += s->img->hmargin;
2488 if (s->slice.y == 0)
2489 y += s->img->vmargin;
dc43ef94 2490
06a2c219
GM
2491 if (s->img->pixmap)
2492 {
2493 if (s->img->mask)
2494 {
2495 /* We can't set both a clip mask and use XSetClipRectangles
2496 because the latter also sets a clip mask. We also can't
2497 trust on the shape extension to be available
2498 (XShapeCombineRegion). So, compute the rectangle to draw
2499 manually. */
2500 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
2501 | GCFunction);
2502 XGCValues xgcv;
2503
2504 xgcv.clip_mask = s->img->mask;
95911c74
JD
2505 xgcv.clip_x_origin = x - s->slice.x;
2506 xgcv.clip_y_origin = y - s->slice.y;
06a2c219
GM
2507 xgcv.function = GXcopy;
2508 XChangeGC (s->display, s->gc, mask, &xgcv);
2509
2510 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
57326d99
KS
2511 s->slice.x, s->slice.y,
2512 s->slice.width, s->slice.height, x, y);
06a2c219
GM
2513 XSetClipMask (s->display, s->gc, None);
2514 }
2515 else
2516 {
2517 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
57326d99
KS
2518 s->slice.x, s->slice.y,
2519 s->slice.width, s->slice.height, x, y);
7d0393cf 2520
06a2c219
GM
2521 /* When the image has a mask, we can expect that at
2522 least part of a mouse highlight or a block cursor will
2523 be visible. If the image doesn't have a mask, make
2524 a block cursor visible by drawing a rectangle around
2525 the image. I believe it's looking better if we do
2526 nothing here for mouse-face. */
2527 if (s->hl == DRAW_CURSOR)
534c20b2
KS
2528 {
2529 int r = s->img->relief;
2530 if (r < 0) r = -r;
2531 XDrawRectangle (s->display, s->window, s->gc, x - r, y - r,
57326d99
KS
2532 s->slice.width + r*2 - 1,
2533 s->slice.height + r*2 - 1);
534c20b2 2534 }
06a2c219
GM
2535 }
2536 }
2537 else
2538 /* Draw a rectangle if image could not be loaded. */
2539 XDrawRectangle (s->display, pixmap, s->gc, x, y,
57326d99 2540 s->slice.width - 1, s->slice.height - 1);
06a2c219 2541}
dc43ef94 2542
990ba854 2543
06a2c219
GM
2544/* Draw part of the background of glyph string S. X, Y, W, and H
2545 give the rectangle to draw. */
a9a5b0a5 2546
06a2c219
GM
2547static void
2548x_draw_glyph_string_bg_rect (s, x, y, w, h)
2549 struct glyph_string *s;
2550 int x, y, w, h;
2551{
2552 if (s->stippled_p)
2553 {
2554 /* Fill background with a stipple pattern. */
2555 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
2556 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
2557 XSetFillStyle (s->display, s->gc, FillSolid);
2558 }
2559 else
2560 x_clear_glyph_string_rect (s, x, y, w, h);
2561}
07e34cb0 2562
b5210ea7 2563
7d0393cf 2564/* Draw image glyph string S.
dc43ef94 2565
06a2c219
GM
2566 s->y
2567 s->x +-------------------------
2568 | s->face->box
2569 |
2570 | +-------------------------
2571 | | s->img->margin
2572 | |
2573 | | +-------------------
2574 | | | the image
dc43ef94 2575
06a2c219 2576 */
dc43ef94 2577
06a2c219
GM
2578static void
2579x_draw_image_glyph_string (s)
2580 struct glyph_string *s;
2581{
ea2ba0d4
KH
2582 int box_line_hwidth = abs (s->face->box_line_width);
2583 int box_line_vwidth = max (s->face->box_line_width, 0);
06a2c219
GM
2584 int height;
2585 Pixmap pixmap = None;
2586
57326d99
KS
2587 height = s->height;
2588 if (s->slice.y == 0)
2589 height -= box_line_vwidth;
2590 if (s->slice.y + s->slice.height >= s->img->height)
2591 height -= box_line_vwidth;
488dd4c4 2592
06a2c219
GM
2593 /* Fill background with face under the image. Do it only if row is
2594 taller than image or if image has a clip mask to reduce
2595 flickering. */
2596 s->stippled_p = s->face->stipple != 0;
57326d99 2597 if (height > s->slice.height
22d650b8
GM
2598 || s->img->hmargin
2599 || s->img->vmargin
06a2c219
GM
2600 || s->img->mask
2601 || s->img->pixmap == 0
2602 || s->width != s->background_width)
2603 {
06a2c219
GM
2604 if (s->img->mask)
2605 {
f9b5db02
GM
2606 /* Create a pixmap as large as the glyph string. Fill it
2607 with the background color. Copy the image to it, using
2608 its mask. Copy the temporary pixmap to the display. */
06a2c219
GM
2609 Screen *screen = FRAME_X_SCREEN (s->f);
2610 int depth = DefaultDepthOfScreen (screen);
2611
2612 /* Create a pixmap as large as the glyph string. */
2613 pixmap = XCreatePixmap (s->display, s->window,
2614 s->background_width,
2615 s->height, depth);
7d0393cf 2616
06a2c219
GM
2617 /* Don't clip in the following because we're working on the
2618 pixmap. */
2619 XSetClipMask (s->display, s->gc, None);
2620
2621 /* Fill the pixmap with the background color/stipple. */
2622 if (s->stippled_p)
2623 {
2624 /* Fill background with a stipple pattern. */
2625 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
2626 XFillRectangle (s->display, pixmap, s->gc,
2627 0, 0, s->background_width, s->height);
2628 XSetFillStyle (s->display, s->gc, FillSolid);
2629 }
2630 else
2631 {
2632 XGCValues xgcv;
2633 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
2634 &xgcv);
2635 XSetForeground (s->display, s->gc, xgcv.background);
2636 XFillRectangle (s->display, pixmap, s->gc,
2637 0, 0, s->background_width, s->height);
2638 XSetForeground (s->display, s->gc, xgcv.foreground);
2639 }
2640 }
2641 else
57326d99
KS
2642 {
2643 int x = s->x;
2644 int y = s->y;
2645
2646 if (s->first_glyph->left_box_line_p
2647 && s->slice.x == 0)
2648 x += box_line_hwidth;
2649
2650 if (s->slice.y == 0)
2651 y += box_line_vwidth;
2652
2653 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
2654 }
7d0393cf 2655
06a2c219
GM
2656 s->background_filled_p = 1;
2657 }
dc43ef94 2658
06a2c219
GM
2659 /* Draw the foreground. */
2660 if (pixmap != None)
2661 {
2662 x_draw_image_foreground_1 (s, pixmap);
2663 x_set_glyph_string_clipping (s);
2664 XCopyArea (s->display, pixmap, s->window, s->gc,
2665 0, 0, s->background_width, s->height, s->x, s->y);
2666 XFreePixmap (s->display, pixmap);
2667 }
2668 else
2669 x_draw_image_foreground (s);
b5210ea7 2670
06a2c219
GM
2671 /* If we must draw a relief around the image, do it. */
2672 if (s->img->relief
2673 || s->hl == DRAW_IMAGE_RAISED
2674 || s->hl == DRAW_IMAGE_SUNKEN)
2675 x_draw_image_relief (s);
2676}
8c1a6a84 2677
990ba854 2678
06a2c219 2679/* Draw stretch glyph string S. */
dc43ef94 2680
06a2c219
GM
2681static void
2682x_draw_stretch_glyph_string (s)
2683 struct glyph_string *s;
2684{
2685 xassert (s->first_glyph->type == STRETCH_GLYPH);
2686 s->stippled_p = s->face->stipple != 0;
990ba854 2687
06a2c219
GM
2688 if (s->hl == DRAW_CURSOR
2689 && !x_stretch_cursor_p)
2690 {
2691 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
2692 as wide as the stretch glyph. */
e8f6b0db
KS
2693 int width, background_width = s->background_width;
2694 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
2695
2696 if (x < left_x)
2697 {
2698 background_width -= left_x - x;
2699 x = left_x;
2700 }
2701 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
990ba854 2702
06a2c219 2703 /* Draw cursor. */
e8f6b0db 2704 x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
0cdd0c9f 2705
06a2c219 2706 /* Clear rest using the GC of the original non-cursor face. */
e8f6b0db 2707 if (width < background_width)
06a2c219 2708 {
e8f6b0db
KS
2709 int y = s->y;
2710 int w = background_width - width, h = s->height;
06a2c219 2711 XRectangle r;
b7f83f9e 2712 GC gc;
dc43ef94 2713
e8f6b0db 2714 x += width;
b7f83f9e
GM
2715 if (s->row->mouse_face_p
2716 && cursor_in_mouse_face_p (s->w))
2717 {
2718 x_set_mouse_face_gc (s);
2719 gc = s->gc;
2720 }
2721 else
2722 gc = s->face->gc;
7d0393cf 2723
442a09ea 2724 get_glyph_string_clip_rect (s, &r);
06a2c219 2725 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
7d0393cf 2726
06a2c219
GM
2727 if (s->face->stipple)
2728 {
2729 /* Fill background with a stipple pattern. */
2730 XSetFillStyle (s->display, gc, FillOpaqueStippled);
2731 XFillRectangle (s->display, s->window, gc, x, y, w, h);
2732 XSetFillStyle (s->display, gc, FillSolid);
2733 }
2734 else
2735 {
2736 XGCValues xgcv;
2737 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
2738 XSetForeground (s->display, gc, xgcv.background);
2739 XFillRectangle (s->display, s->window, gc, x, y, w, h);
2740 XSetForeground (s->display, gc, xgcv.foreground);
2741 }
2742 }
2743 }
61e9f9f3 2744 else if (!s->background_filled_p)
e8f6b0db
KS
2745 {
2746 int background_width = s->background_width;
2747 int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
2748
6c693929
KS
2749 /* Don't draw into left margin, fringe or scrollbar area
2750 except for header line and mode line. */
2751 if (x < left_x && !s->row->mode_line_p)
e8f6b0db
KS
2752 {
2753 background_width -= left_x - x;
2754 x = left_x;
2755 }
2756 if (background_width > 0)
2757 x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
2758 }
7d0393cf 2759
06a2c219
GM
2760 s->background_filled_p = 1;
2761}
2762
2763
2764/* Draw glyph string S. */
2765
2766static void
2767x_draw_glyph_string (s)
2768 struct glyph_string *s;
2769{
4458cf11
KH
2770 int relief_drawn_p = 0;
2771
1dc6c31b
KH
2772 /* If S draws into the background of its successors, draw the
2773 background of the successors first so that S can draw into it.
06a2c219 2774 This makes S->next use XDrawString instead of XDrawImageString. */
c2ded1b7 2775 if (s->next && s->right_overhang && !s->for_overlaps)
06a2c219 2776 {
1dc6c31b
KH
2777 int width;
2778 struct glyph_string *next;
2779
2780 for (width = 0, next = s->next; next;
2781 width += next->width, next = next->next)
2782 if (next->first_glyph->type != IMAGE_GLYPH)
2783 {
2784 x_set_glyph_string_gc (next);
2785 x_set_glyph_string_clipping (next);
2786 x_draw_glyph_string_background (next, 1);
c9ff09ee
KH
2787#ifdef USE_FONT_BACKEND
2788 next->clip_width = 0;
2789#endif /* USE_FONT_BACKEND */
1dc6c31b 2790 }
06a2c219 2791 }
97210f4e 2792
06a2c219
GM
2793 /* Set up S->gc, set clipping and draw S. */
2794 x_set_glyph_string_gc (s);
06a2c219 2795
4458cf11
KH
2796 /* Draw relief (if any) in advance for char/composition so that the
2797 glyph string can be drawn over it. */
c2ded1b7 2798 if (!s->for_overlaps
4458cf11
KH
2799 && s->face->box != FACE_NO_BOX
2800 && (s->first_glyph->type == CHAR_GLYPH
2801 || s->first_glyph->type == COMPOSITE_GLYPH))
2802
2803 {
e6269cbb 2804 x_set_glyph_string_clipping (s);
4458cf11
KH
2805 x_draw_glyph_string_background (s, 1);
2806 x_draw_glyph_string_box (s);
e6269cbb 2807 x_set_glyph_string_clipping (s);
4458cf11
KH
2808 relief_drawn_p = 1;
2809 }
1dd71645
KH
2810 else if ((s->prev && s->prev->hl != s->hl && s->left_overhang)
2811 || (s->next && s->next->hl != s->hl && s->right_overhang))
2812 /* We must clip just this glyph. left_overhang part has already
2813 drawn when s->prev was drawn, and right_overhang part will be
2814 drawn later when s->next is drawn. */
2815 x_set_glyph_string_clipping_exactly (s, s);
e6269cbb
GM
2816 else
2817 x_set_glyph_string_clipping (s);
4458cf11 2818
06a2c219
GM
2819 switch (s->first_glyph->type)
2820 {
2821 case IMAGE_GLYPH:
2822 x_draw_image_glyph_string (s);
2823 break;
2824
2825 case STRETCH_GLYPH:
2826 x_draw_stretch_glyph_string (s);
2827 break;
2828
2829 case CHAR_GLYPH:
c2ded1b7 2830 if (s->for_overlaps)
66ac4b0e
GM
2831 s->background_filled_p = 1;
2832 else
2833 x_draw_glyph_string_background (s, 0);
06a2c219
GM
2834 x_draw_glyph_string_foreground (s);
2835 break;
2836
b4192550 2837 case COMPOSITE_GLYPH:
c2ded1b7 2838 if (s->for_overlaps || s->gidx > 0)
b4192550
KH
2839 s->background_filled_p = 1;
2840 else
2841 x_draw_glyph_string_background (s, 1);
2842 x_draw_composite_glyph_string_foreground (s);
2843 break;
2844
06a2c219
GM
2845 default:
2846 abort ();
2847 }
2848
c2ded1b7 2849 if (!s->for_overlaps)
06a2c219 2850 {
66ac4b0e
GM
2851 /* Draw underline. */
2852 if (s->face->underline_p)
2853 {
e24e84cc
GM
2854 unsigned long tem, h;
2855 int y;
06a2c219 2856
e24e84cc 2857 /* Get the underline thickness. Default is 1 pixel. */
c9ff09ee
KH
2858#ifdef USE_FONT_BACKEND
2859 if (enable_font_backend)
2860 /* In the future, we must use information of font. */
2861 h = 1;
2862 else
2863#endif /* USE_FONT_BACKEND */
66ac4b0e
GM
2864 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
2865 h = 1;
e24e84cc 2866
c9ff09ee
KH
2867#ifdef USE_FONT_BACKEND
2868 if (enable_font_backend)
c8c8ff66
KH
2869 {
2870 if (s->face->font)
2871 /* In the future, we must use information of font. */
2872 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
2873 else
2874 y = s->y + s->height - h;
2875 }
c9ff09ee
KH
2876 else
2877#endif
30f27523 2878 if (x_underline_at_descent_line)
a02f1be0 2879 y = s->y + s->height - h;
30f27523
KS
2880 else
2881 {
2882 /* Get the underline position. This is the recommended
2883 vertical offset in pixels from the baseline to the top of
2884 the underline. This is a signed value according to the
2885 specs, and its default is
2886
2887 ROUND ((maximum descent) / 2), with
2888 ROUND(x) = floor (x + 0.5) */
2889
2890 if (x_use_underline_position_properties
2891 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
2892 y = s->ybase + (long) tem;
2893 else if (s->face->font)
2894 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
2895 }
7d0393cf 2896
66ac4b0e 2897 if (s->face->underline_defaulted_p)
e24e84cc 2898 XFillRectangle (s->display, s->window, s->gc,
30f27523 2899 s->x, y, s->background_width, h);
66ac4b0e
GM
2900 else
2901 {
2902 XGCValues xgcv;
2903 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
2904 XSetForeground (s->display, s->gc, s->face->underline_color);
e24e84cc 2905 XFillRectangle (s->display, s->window, s->gc,
30f27523 2906 s->x, y, s->background_width, h);
66ac4b0e
GM
2907 XSetForeground (s->display, s->gc, xgcv.foreground);
2908 }
dc6f92b8 2909 }
07e34cb0 2910
66ac4b0e
GM
2911 /* Draw overline. */
2912 if (s->face->overline_p)
06a2c219 2913 {
66ac4b0e
GM
2914 unsigned long dy = 0, h = 1;
2915
2916 if (s->face->overline_color_defaulted_p)
2917 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
30f27523 2918 s->background_width, h);
66ac4b0e
GM
2919 else
2920 {
2921 XGCValues xgcv;
2922 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
2923 XSetForeground (s->display, s->gc, s->face->overline_color);
2924 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
30f27523 2925 s->background_width, h);
66ac4b0e
GM
2926 XSetForeground (s->display, s->gc, xgcv.foreground);
2927 }
06a2c219 2928 }
7d0393cf 2929
66ac4b0e
GM
2930 /* Draw strike-through. */
2931 if (s->face->strike_through_p)
06a2c219 2932 {
66ac4b0e
GM
2933 unsigned long h = 1;
2934 unsigned long dy = (s->height - h) / 2;
2935
2936 if (s->face->strike_through_color_defaulted_p)
2937 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
2938 s->width, h);
2939 else
2940 {
2941 XGCValues xgcv;
2942 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
2943 XSetForeground (s->display, s->gc, s->face->strike_through_color);
2944 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
2945 s->width, h);
2946 XSetForeground (s->display, s->gc, xgcv.foreground);
2947 }
06a2c219 2948 }
7d0393cf 2949
4458cf11
KH
2950 /* Draw relief if not yet drawn. */
2951 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
66ac4b0e 2952 x_draw_glyph_string_box (s);
1dd71645 2953
1dc6c31b 2954 if (s->prev)
1dd71645 2955 {
1dc6c31b
KH
2956 struct glyph_string *prev;
2957
2958 for (prev = s->prev; prev; prev = prev->prev)
2959 if (prev->hl != s->hl
2960 && prev->x + prev->width + prev->right_overhang > s->x)
2961 {
2962 /* As prev was drawn while clipped to its own area, we
2963 must draw the right_overhang part using s->hl now. */
2964 enum draw_glyphs_face save = prev->hl;
2965
2966 prev->hl = s->hl;
2967 x_set_glyph_string_gc (prev);
2968 x_set_glyph_string_clipping_exactly (s, prev);
c9ff09ee
KH
2969 if (prev->first_glyph->type == CHAR_GLYPH)
2970 x_draw_glyph_string_foreground (prev);
2971 else
2972 x_draw_composite_glyph_string_foreground (prev);
1dc6c31b
KH
2973 XSetClipMask (prev->display, prev->gc, None);
2974 prev->hl = save;
c9ff09ee
KH
2975#ifdef USE_FONT_BACKEND
2976 prev->clip_width = 0;
2977#endif /* USE_FONT_BACKEND */
1dc6c31b 2978 }
1dd71645
KH
2979 }
2980
1dc6c31b 2981 if (s->next)
1dd71645 2982 {
1dc6c31b
KH
2983 struct glyph_string *next;
2984
2985 for (next = s->next; next; next = next->next)
2986 if (next->hl != s->hl
c9ff09ee 2987 && next->x - next->left_overhang < s->x + s->width)
1dc6c31b
KH
2988 {
2989 /* As next will be drawn while clipped to its own area,
2990 we must draw the left_overhang part using s->hl now. */
2991 enum draw_glyphs_face save = next->hl;
2992
2993 next->hl = s->hl;
2994 x_set_glyph_string_gc (next);
2995 x_set_glyph_string_clipping_exactly (s, next);
c9ff09ee
KH
2996 if (next->first_glyph->type == CHAR_GLYPH)
2997 x_draw_glyph_string_foreground (next);
2998 else
2999 x_draw_composite_glyph_string_foreground (next);
1dc6c31b
KH
3000 XSetClipMask (next->display, next->gc, None);
3001 next->hl = save;
c9ff09ee
KH
3002#ifdef USE_FONT_BACKEND
3003 next->clip_width = 0;
3004#endif /* USE_FONT_BACKEND */
1dc6c31b 3005 }
1dd71645 3006 }
66ac4b0e 3007 }
7d0393cf 3008
06a2c219
GM
3009 /* Reset clipping. */
3010 XSetClipMask (s->display, s->gc, None);
c9ff09ee
KH
3011#ifdef USE_FONT_BACKEND
3012 s->clip_width = 0;
3013#endif /* USE_FONT_BACKEND */
dc6f92b8 3014}
07e34cb0 3015
442a09ea 3016/* Shift display to make room for inserted glyphs. */
06a2c219 3017
442a09ea
KS
3018void
3019x_shift_glyphs_for_insert (f, x, y, width, height, shift_by)
3020 struct frame *f;
3021 int x, y, width, height, shift_by;
06a2c219 3022{
06a2c219
GM
3023 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
3024 f->output_data.x->normal_gc,
442a09ea
KS
3025 x, y, width, height,
3026 x + shift_by, y);
0cdd0c9f 3027}
0cdd0c9f 3028
06a2c219
GM
3029/* Delete N glyphs at the nominal cursor position. Not implemented
3030 for X frames. */
c83febd7
RS
3031
3032static void
06a2c219
GM
3033x_delete_glyphs (n)
3034 register int n;
c83febd7 3035{
06a2c219 3036 abort ();
c83febd7
RS
3037}
3038
0cdd0c9f 3039
c5e6e06b
GM
3040/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
3041 If they are <= 0, this is probably an error. */
3042
3043void
3044x_clear_area (dpy, window, x, y, width, height, exposures)
3045 Display *dpy;
3046 Window window;
3047 int x, y;
3048 int width, height;
3049 int exposures;
3050{
3051 xassert (width > 0 && height > 0);
3052 XClearArea (dpy, window, x, y, width, height, exposures);
3053}
3054
3055
06a2c219 3056/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 3057 frame. Otherwise clear the selected frame. */
06a2c219
GM
3058
3059static void
3060x_clear_frame ()
0cdd0c9f 3061{
06a2c219 3062 struct frame *f;
0cdd0c9f 3063
06a2c219
GM
3064 if (updating_frame)
3065 f = updating_frame;
0cdd0c9f 3066 else
b86bd3dd 3067 f = SELECTED_FRAME ();
58769bee 3068
06a2c219
GM
3069 /* Clearing the frame will erase any cursor, so mark them all as no
3070 longer visible. */
3071 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
3072 output_cursor.hpos = output_cursor.vpos = 0;
3073 output_cursor.x = -1;
3074
3075 /* We don't set the output cursor here because there will always
3076 follow an explicit cursor_to. */
3077 BLOCK_INPUT;
3078 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3079
3080 /* We have to clear the scroll bars, too. If we have changed
3081 colors or something like that, then they should be notified. */
3082 x_scroll_bar_clear (f);
0cdd0c9f 3083
06a2c219 3084 XFlush (FRAME_X_DISPLAY (f));
0cb35f4e 3085
06a2c219 3086 UNBLOCK_INPUT;
dc6f92b8 3087}
06a2c219
GM
3088
3089
dc6f92b8 3090\f
dbc4e1c1
JB
3091/* Invert the middle quarter of the frame for .15 sec. */
3092
06a2c219
GM
3093/* We use the select system call to do the waiting, so we have to make
3094 sure it's available. If it isn't, we just won't do visual bells. */
3095
dbc4e1c1
JB
3096#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
3097
06a2c219
GM
3098
3099/* Subtract the `struct timeval' values X and Y, storing the result in
3100 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
3101
3102static int
3103timeval_subtract (result, x, y)
3104 struct timeval *result, x, y;
3105{
06a2c219
GM
3106 /* Perform the carry for the later subtraction by updating y. This
3107 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
3108 if (x.tv_usec < y.tv_usec)
3109 {
3110 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
3111 y.tv_usec -= 1000000 * nsec;
3112 y.tv_sec += nsec;
3113 }
7d0393cf 3114
dbc4e1c1
JB
3115 if (x.tv_usec - y.tv_usec > 1000000)
3116 {
3117 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
3118 y.tv_usec += 1000000 * nsec;
3119 y.tv_sec -= nsec;
3120 }
3121
06a2c219
GM
3122 /* Compute the time remaining to wait. tv_usec is certainly
3123 positive. */
dbc4e1c1
JB
3124 result->tv_sec = x.tv_sec - y.tv_sec;
3125 result->tv_usec = x.tv_usec - y.tv_usec;
3126
06a2c219
GM
3127 /* Return indication of whether the result should be considered
3128 negative. */
dbc4e1c1
JB
3129 return x.tv_sec < y.tv_sec;
3130}
dc6f92b8 3131
dfcf069d 3132void
f676886a
JB
3133XTflash (f)
3134 struct frame *f;
dc6f92b8 3135{
dbc4e1c1 3136 BLOCK_INPUT;
dc6f92b8 3137
dbc4e1c1
JB
3138 {
3139 GC gc;
dc6f92b8 3140
06a2c219
GM
3141 /* Create a GC that will use the GXxor function to flip foreground
3142 pixels into background pixels. */
dbc4e1c1
JB
3143 {
3144 XGCValues values;
dc6f92b8 3145
dbc4e1c1 3146 values.function = GXxor;
7556890b
RS
3147 values.foreground = (f->output_data.x->foreground_pixel
3148 ^ f->output_data.x->background_pixel);
58769bee 3149
334208b7 3150 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
3151 GCFunction | GCForeground, &values);
3152 }
dc6f92b8 3153
dbc4e1c1 3154 {
e84e14c3 3155 /* Get the height not including a menu bar widget. */
0899d58c 3156 int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
e84e14c3
RS
3157 /* Height of each line to flash. */
3158 int flash_height = FRAME_LINE_HEIGHT (f);
3159 /* These will be the left and right margins of the rectangles. */
3160 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
0899d58c 3161 int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
e84e14c3
RS
3162
3163 int width;
3164
3165 /* Don't flash the area between a scroll bar and the frame
3166 edge it is next to. */
3167 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
3168 {
3169 case vertical_scroll_bar_left:
3170 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
3171 break;
3172
3173 case vertical_scroll_bar_right:
3174 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
3175 break;
06a2c219
GM
3176
3177 default:
3178 break;
e84e14c3
RS
3179 }
3180
3181 width = flash_right - flash_left;
3182
3183 /* If window is tall, flash top and bottom line. */
3184 if (height > 3 * FRAME_LINE_HEIGHT (f))
3185 {
3186 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
3187 flash_left,
3188 (FRAME_INTERNAL_BORDER_WIDTH (f)
0899d58c 3189 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
e84e14c3
RS
3190 width, flash_height);
3191 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3192 flash_left,
3193 (height - flash_height
3194 - FRAME_INTERNAL_BORDER_WIDTH (f)),
3195 width, flash_height);
3196 }
3197 else
7d0393cf 3198 /* If it is short, flash it all. */
e84e14c3
RS
3199 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3200 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
3201 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 3202
06a2c219 3203 x_flush (f);
dc6f92b8 3204
dbc4e1c1 3205 {
06a2c219 3206 struct timeval wakeup;
dc6f92b8 3207
66c30ea1 3208 EMACS_GET_TIME (wakeup);
dc6f92b8 3209
dbc4e1c1
JB
3210 /* Compute time to wait until, propagating carry from usecs. */
3211 wakeup.tv_usec += 150000;
3212 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
3213 wakeup.tv_usec %= 1000000;
3214
101922c3
GM
3215 /* Keep waiting until past the time wakeup or any input gets
3216 available. */
3217 while (! detect_input_pending ())
dbc4e1c1 3218 {
101922c3 3219 struct timeval current;
dbc4e1c1
JB
3220 struct timeval timeout;
3221
101922c3 3222 EMACS_GET_TIME (current);
dbc4e1c1 3223
101922c3
GM
3224 /* Break if result would be negative. */
3225 if (timeval_subtract (&current, wakeup, current))
dbc4e1c1
JB
3226 break;
3227
101922c3
GM
3228 /* How long `select' should wait. */
3229 timeout.tv_sec = 0;
3230 timeout.tv_usec = 10000;
3231
dbc4e1c1 3232 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 3233 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
3234 }
3235 }
58769bee 3236
e84e14c3
RS
3237 /* If window is tall, flash top and bottom line. */
3238 if (height > 3 * FRAME_LINE_HEIGHT (f))
3239 {
3240 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
3241 flash_left,
3242 (FRAME_INTERNAL_BORDER_WIDTH (f)
0899d58c 3243 + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
e84e14c3
RS
3244 width, flash_height);
3245 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3246 flash_left,
3247 (height - flash_height
3248 - FRAME_INTERNAL_BORDER_WIDTH (f)),
3249 width, flash_height);
3250 }
3251 else
7d0393cf 3252 /* If it is short, flash it all. */
e84e14c3
RS
3253 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3254 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
3255 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
3256
334208b7 3257 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 3258 x_flush (f);
dc6f92b8 3259 }
dbc4e1c1
JB
3260 }
3261
3262 UNBLOCK_INPUT;
dc6f92b8
JB
3263}
3264
06a2c219 3265#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
3266
3267
dc6f92b8
JB
3268/* Make audible bell. */
3269
dfcf069d 3270void
dc6f92b8
JB
3271XTring_bell ()
3272{
b86bd3dd 3273 struct frame *f = SELECTED_FRAME ();
7d0393cf 3274
b86bd3dd
GM
3275 if (FRAME_X_DISPLAY (f))
3276 {
dbc4e1c1 3277#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
3278 if (visible_bell)
3279 XTflash (f);
3280 else
dbc4e1c1 3281#endif
b86bd3dd
GM
3282 {
3283 BLOCK_INPUT;
3284 XBell (FRAME_X_DISPLAY (f), 0);
3285 XFlush (FRAME_X_DISPLAY (f));
3286 UNBLOCK_INPUT;
3287 }
dc6f92b8
JB
3288 }
3289}
06a2c219 3290
dc6f92b8 3291\f
06a2c219
GM
3292/* Specify how many text lines, from the top of the window,
3293 should be affected by insert-lines and delete-lines operations.
3294 This, and those operations, are used only within an update
3295 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 3296
dfcf069d 3297static void
06a2c219
GM
3298XTset_terminal_window (n)
3299 register int n;
dc6f92b8 3300{
06a2c219 3301 /* This function intentionally left blank. */
dc6f92b8
JB
3302}
3303
06a2c219
GM
3304
3305\f
3306/***********************************************************************
3307 Line Dance
3308 ***********************************************************************/
3309
3310/* Perform an insert-lines or delete-lines operation, inserting N
3311 lines or deleting -N lines at vertical position VPOS. */
3312
dfcf069d 3313static void
06a2c219
GM
3314x_ins_del_lines (vpos, n)
3315 int vpos, n;
dc6f92b8
JB
3316{
3317 abort ();
3318}
06a2c219
GM
3319
3320
3321/* Scroll part of the display as described by RUN. */
dc6f92b8 3322
dfcf069d 3323static void
06a2c219
GM
3324x_scroll_run (w, run)
3325 struct window *w;
3326 struct run *run;
dc6f92b8 3327{
06a2c219
GM
3328 struct frame *f = XFRAME (w->frame);
3329 int x, y, width, height, from_y, to_y, bottom_y;
3330
3331 /* Get frame-relative bounding box of the text display area of W,
3f332ef3
KS
3332 without mode lines. Include in this box the left and right
3333 fringe of W. */
06a2c219 3334 window_box (w, -1, &x, &y, &width, &height);
06a2c219
GM
3335
3336 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
3337 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
3338 bottom_y = y + height;
dc6f92b8 3339
06a2c219
GM
3340 if (to_y < from_y)
3341 {
3342 /* Scrolling up. Make sure we don't copy part of the mode
3343 line at the bottom. */
3344 if (from_y + run->height > bottom_y)
3345 height = bottom_y - from_y;
3346 else
3347 height = run->height;
3348 }
dc6f92b8 3349 else
06a2c219
GM
3350 {
3351 /* Scolling down. Make sure we don't copy over the mode line.
3352 at the bottom. */
3353 if (to_y + run->height > bottom_y)
3354 height = bottom_y - to_y;
3355 else
3356 height = run->height;
3357 }
7a13e894 3358
06a2c219 3359 BLOCK_INPUT;
7d0393cf 3360
06a2c219
GM
3361 /* Cursor off. Will be switched on again in x_update_window_end. */
3362 updated_window = w;
3363 x_clear_cursor (w);
3364
3365 XCopyArea (FRAME_X_DISPLAY (f),
3366 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
3367 f->output_data.x->normal_gc,
3368 x, from_y,
3369 width, height,
3370 x, to_y);
7d0393cf 3371
06a2c219
GM
3372 UNBLOCK_INPUT;
3373}
dc6f92b8 3374
dc6f92b8 3375
06a2c219
GM
3376\f
3377/***********************************************************************
3378 Exposure Events
3379 ***********************************************************************/
7d0393cf 3380
442a09ea 3381\f
06a2c219 3382static void
442a09ea 3383frame_highlight (f)
06a2c219 3384 struct frame *f;
dc6f92b8 3385{
442a09ea
KS
3386 /* We used to only do this if Vx_no_window_manager was non-nil, but
3387 the ICCCM (section 4.1.6) says that the window's border pixmap
3388 and border pixel are window attributes which are "private to the
3389 client", so we can always change it to whatever we want. */
3390 BLOCK_INPUT;
3391 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3392 f->output_data.x->border_pixel);
3393 UNBLOCK_INPUT;
3394 x_update_cursor (f, 1);
3395}
dc6f92b8 3396
442a09ea
KS
3397static void
3398frame_unhighlight (f)
3399 struct frame *f;
3400{
3401 /* We used to only do this if Vx_no_window_manager was non-nil, but
3402 the ICCCM (section 4.1.6) says that the window's border pixmap
3403 and border pixel are window attributes which are "private to the
3404 client", so we can always change it to whatever we want. */
3405 BLOCK_INPUT;
3406 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
3407 f->output_data.x->border_tile);
3408 UNBLOCK_INPUT;
3409 x_update_cursor (f, 1);
3410}
dc6f92b8 3411
442a09ea
KS
3412/* The focus has changed. Update the frames as necessary to reflect
3413 the new situation. Note that we can't change the selected frame
3414 here, because the Lisp code we are interrupting might become confused.
3415 Each event gets marked with the frame in which it occurred, so the
3416 Lisp code can tell when the switch took place by examining the events. */
06a2c219 3417
442a09ea
KS
3418static void
3419x_new_focus_frame (dpyinfo, frame)
3420 struct x_display_info *dpyinfo;
3421 struct frame *frame;
3422{
3423 struct frame *old_focus = dpyinfo->x_focus_frame;
06a2c219 3424
442a09ea 3425 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 3426 {
442a09ea
KS
3427 /* Set this before calling other routines, so that they see
3428 the correct value of x_focus_frame. */
3429 dpyinfo->x_focus_frame = frame;
06a2c219 3430
442a09ea
KS
3431 if (old_focus && old_focus->auto_lower)
3432 x_lower_frame (old_focus);
06a2c219 3433
442a09ea
KS
3434#if 0
3435 selected_frame = frame;
3436 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
3437 selected_frame);
f1321dc3 3438 Fselect_window (selected_frame->selected_window, Qnil);
442a09ea
KS
3439 choose_minibuf_frame ();
3440#endif /* ! 0 */
82f053ab 3441
442a09ea
KS
3442 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
3443 pending_autoraise_frame = dpyinfo->x_focus_frame;
3444 else
3445 pending_autoraise_frame = 0;
82f053ab 3446 }
dc6f92b8 3447
442a09ea
KS
3448 x_frame_rehighlight (dpyinfo);
3449}
06a2c219 3450
442a09ea
KS
3451/* Handle FocusIn and FocusOut state changes for FRAME.
3452 If FRAME has focus and there exists more than one frame, puts
6b61353c 3453 a FOCUS_IN_EVENT into *BUFP. */
cab34f50 3454
6b61353c
KH
3455static void
3456x_focus_changed (type, state, dpyinfo, frame, bufp)
cab34f50
JD
3457 int type;
3458 int state;
3459 struct x_display_info *dpyinfo;
3460 struct frame *frame;
3461 struct input_event *bufp;
cab34f50 3462{
cab34f50
JD
3463 if (type == FocusIn)
3464 {
3465 if (dpyinfo->x_focus_event_frame != frame)
3466 {
3467 x_new_focus_frame (dpyinfo, frame);
3468 dpyinfo->x_focus_event_frame = frame;
7d0393cf 3469
cab34f50
JD
3470 /* Don't stop displaying the initial startup message
3471 for a switch-frame event we don't need. */
6b61353c 3472 if (GC_NILP (Vterminal_frame)
cab34f50
JD
3473 && GC_CONSP (Vframe_list)
3474 && !GC_NILP (XCDR (Vframe_list)))
3475 {
3476 bufp->kind = FOCUS_IN_EVENT;
3477 XSETFRAME (bufp->frame_or_window, frame);
cab34f50
JD
3478 }
3479 }
3480
3481 frame->output_data.x->focus_state |= state;
3482
3483#ifdef HAVE_X_I18N
3484 if (FRAME_XIC (frame))
3485 XSetICFocus (FRAME_XIC (frame));
3486#endif
3487 }
3488 else if (type == FocusOut)
3489 {
3490 frame->output_data.x->focus_state &= ~state;
7d0393cf 3491
cab34f50
JD
3492 if (dpyinfo->x_focus_event_frame == frame)
3493 {
3494 dpyinfo->x_focus_event_frame = 0;
3495 x_new_focus_frame (dpyinfo, 0);
3496 }
3497
3498#ifdef HAVE_X_I18N
3499 if (FRAME_XIC (frame))
3500 XUnsetICFocus (FRAME_XIC (frame));
3501#endif
3502 }
cab34f50
JD
3503}
3504
3505/* The focus may have changed. Figure out if it is a real focus change,
3506 by checking both FocusIn/Out and Enter/LeaveNotify events.
3507
6b61353c 3508 Returns FOCUS_IN_EVENT event in *BUFP. */
cab34f50 3509
6b61353c
KH
3510static void
3511x_detect_focus_change (dpyinfo, event, bufp)
cab34f50
JD
3512 struct x_display_info *dpyinfo;
3513 XEvent *event;
3514 struct input_event *bufp;
cab34f50
JD
3515{
3516 struct frame *frame;
7d0393cf 3517
9d00001f 3518 frame = x_any_window_to_frame (dpyinfo, event->xany.window);
6b61353c
KH
3519 if (! frame)
3520 return;
7d0393cf 3521
cab34f50
JD
3522 switch (event->type)
3523 {
3524 case EnterNotify:
3525 case LeaveNotify:
6b61353c
KH
3526 {
3527 struct frame *focus_frame = dpyinfo->x_focus_event_frame;
3528 int focus_state
3529 = focus_frame ? focus_frame->output_data.x->focus_state : 0;
3530
3531 if (event->xcrossing.detail != NotifyInferior
3532 && event->xcrossing.focus
3533 && ! (focus_state & FOCUS_EXPLICIT))
3534 x_focus_changed ((event->type == EnterNotify ? FocusIn : FocusOut),
3535 FOCUS_IMPLICIT,
3536 dpyinfo, frame, bufp);
3537 }
cab34f50
JD
3538 break;
3539
3540 case FocusIn:
3541 case FocusOut:
6b61353c
KH
3542 x_focus_changed (event->type,
3543 (event->xfocus.detail == NotifyPointer ?
3544 FOCUS_IMPLICIT : FOCUS_EXPLICIT),
3545 dpyinfo, frame, bufp);
cab34f50
JD
3546 break;
3547 }
cab34f50
JD
3548}
3549
3550
37c2c98b
RS
3551/* Handle an event saying the mouse has moved out of an Emacs frame. */
3552
3553void
0f941935
KH
3554x_mouse_leave (dpyinfo)
3555 struct x_display_info *dpyinfo;
37c2c98b 3556{
0f941935 3557 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 3558}
6d4238f3 3559
f451eb13
JB
3560/* The focus has changed, or we have redirected a frame's focus to
3561 another frame (this happens when a frame uses a surrogate
06a2c219 3562 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
3563
3564 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 3565 frame is being highlighted or un-highlighted; we only use it to find
0f941935 3566 the appropriate X display info. */
06a2c219 3567
6d4238f3 3568static void
0f941935
KH
3569XTframe_rehighlight (frame)
3570 struct frame *frame;
6d4238f3 3571{
0f941935
KH
3572 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
3573}
6d4238f3 3574
0f941935
KH
3575static void
3576x_frame_rehighlight (dpyinfo)
3577 struct x_display_info *dpyinfo;
3578{
3579 struct frame *old_highlight = dpyinfo->x_highlight_frame;
3580
3581 if (dpyinfo->x_focus_frame)
6d4238f3 3582 {
0f941935
KH
3583 dpyinfo->x_highlight_frame
3584 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
3585 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
3586 : dpyinfo->x_focus_frame);
3587 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 3588 {
0f941935
KH
3589 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
3590 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 3591 }
dc6f92b8 3592 }
6d4238f3 3593 else
0f941935 3594 dpyinfo->x_highlight_frame = 0;
dc6f92b8 3595
0f941935 3596 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
3597 {
3598 if (old_highlight)
f676886a 3599 frame_unhighlight (old_highlight);
0f941935
KH
3600 if (dpyinfo->x_highlight_frame)
3601 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 3602 }
dc6f92b8 3603}
06a2c219
GM
3604
3605
dc6f92b8 3606\f
06a2c219 3607/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 3608
28430d3c
JB
3609/* Initialize mode_switch_bit and modifier_meaning. */
3610static void
334208b7
RS
3611x_find_modifier_meanings (dpyinfo)
3612 struct x_display_info *dpyinfo;
28430d3c 3613{
f689eb05 3614 int min_code, max_code;
28430d3c
JB
3615 KeySym *syms;
3616 int syms_per_code;
3617 XModifierKeymap *mods;
3618
334208b7
RS
3619 dpyinfo->meta_mod_mask = 0;
3620 dpyinfo->shift_lock_mask = 0;
3621 dpyinfo->alt_mod_mask = 0;
3622 dpyinfo->super_mod_mask = 0;
3623 dpyinfo->hyper_mod_mask = 0;
58769bee 3624
9658a521 3625#ifdef HAVE_X11R4
334208b7 3626 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 3627#else
4a60f8c5
RS
3628 min_code = dpyinfo->display->min_keycode;
3629 max_code = dpyinfo->display->max_keycode;
9658a521
JB
3630#endif
3631
334208b7 3632 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
3633 min_code, max_code - min_code + 1,
3634 &syms_per_code);
334208b7 3635 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 3636
58769bee 3637 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 3638 Alt keysyms are on. */
28430d3c 3639 {
06a2c219 3640 int row, col; /* The row and column in the modifier table. */
b90ee8b5 3641 int found_alt_or_meta;
28430d3c
JB
3642
3643 for (row = 3; row < 8; row++)
b90ee8b5
JD
3644 {
3645 found_alt_or_meta = 0;
28430d3c
JB
3646 for (col = 0; col < mods->max_keypermod; col++)
3647 {
b90ee8b5 3648 KeyCode code = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 3649
af92970c
KH
3650 /* Zeroes are used for filler. Skip them. */
3651 if (code == 0)
3652 continue;
3653
28430d3c
JB
3654 /* Are any of this keycode's keysyms a meta key? */
3655 {
3656 int code_col;
3657
3658 for (code_col = 0; code_col < syms_per_code; code_col++)
3659 {
f689eb05 3660 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 3661
f689eb05 3662 switch (sym)
28430d3c 3663 {
f689eb05
JB
3664 case XK_Meta_L:
3665 case XK_Meta_R:
b90ee8b5 3666 found_alt_or_meta = 1;
334208b7 3667 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 3668 break;
f689eb05
JB
3669
3670 case XK_Alt_L:
3671 case XK_Alt_R:
b90ee8b5 3672 found_alt_or_meta = 1;
334208b7 3673 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
3674 break;
3675
3676 case XK_Hyper_L:
3677 case XK_Hyper_R:
b90ee8b5
JD
3678 if (!found_alt_or_meta)
3679 dpyinfo->hyper_mod_mask |= (1 << row);
3680 code_col = syms_per_code;
3681 col = mods->max_keypermod;
a3c44b14
RS
3682 break;
3683
3684 case XK_Super_L:
3685 case XK_Super_R:
b90ee8b5
JD
3686 if (!found_alt_or_meta)
3687 dpyinfo->super_mod_mask |= (1 << row);
3688 code_col = syms_per_code;
3689 col = mods->max_keypermod;
f689eb05 3690 break;
11edeb03
JB
3691
3692 case XK_Shift_Lock:
3693 /* Ignore this if it's not on the lock modifier. */
b90ee8b5 3694 if (!found_alt_or_meta && ((1 << row) == LockMask))
334208b7 3695 dpyinfo->shift_lock_mask = LockMask;
b90ee8b5
JD
3696 code_col = syms_per_code;
3697 col = mods->max_keypermod;
11edeb03 3698 break;
28430d3c
JB
3699 }
3700 }
3701 }
3702 }
b90ee8b5 3703 }
28430d3c
JB
3704 }
3705
f689eb05 3706 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 3707 if (! dpyinfo->meta_mod_mask)
a3c44b14 3708 {
334208b7
RS
3709 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
3710 dpyinfo->alt_mod_mask = 0;
a3c44b14 3711 }
f689eb05 3712
148c4b70
RS
3713 /* If some keys are both alt and meta,
3714 make them just meta, not alt. */
334208b7 3715 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 3716 {
334208b7 3717 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 3718 }
58769bee 3719
28430d3c 3720 XFree ((char *) syms);
f689eb05 3721 XFreeModifiermap (mods);
28430d3c
JB
3722}
3723
dfeccd2d
JB
3724/* Convert between the modifier bits X uses and the modifier bits
3725 Emacs uses. */
06a2c219 3726
e92928a7 3727unsigned int
334208b7
RS
3728x_x_to_emacs_modifiers (dpyinfo, state)
3729 struct x_display_info *dpyinfo;
dc6f92b8
JB
3730 unsigned int state;
3731{
98659da6
KG
3732 EMACS_UINT mod_meta = meta_modifier;
3733 EMACS_UINT mod_alt = alt_modifier;
3734 EMACS_UINT mod_hyper = hyper_modifier;
3735 EMACS_UINT mod_super = super_modifier;
3736 Lisp_Object tem;
7d0393cf 3737
98659da6
KG
3738 tem = Fget (Vx_alt_keysym, Qmodifier_value);
3739 if (! EQ (tem, Qnil)) mod_alt = XUINT (tem);
3740 tem = Fget (Vx_meta_keysym, Qmodifier_value);
3741 if (! EQ (tem, Qnil)) mod_meta = XUINT (tem);
3742 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
3743 if (! EQ (tem, Qnil)) mod_hyper = XUINT (tem);
3744 tem = Fget (Vx_super_keysym, Qmodifier_value);
3745 if (! EQ (tem, Qnil)) mod_super = XUINT (tem);
7d0393cf 3746
98659da6 3747
334208b7 3748 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
98659da6
KG
3749 | ((state & ControlMask) ? ctrl_modifier : 0)
3750 | ((state & dpyinfo->meta_mod_mask) ? mod_meta : 0)
3751 | ((state & dpyinfo->alt_mod_mask) ? mod_alt : 0)
3752 | ((state & dpyinfo->super_mod_mask) ? mod_super : 0)
3753 | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0));
dc6f92b8
JB
3754}
3755
dfeccd2d 3756static unsigned int
334208b7
RS
3757x_emacs_to_x_modifiers (dpyinfo, state)
3758 struct x_display_info *dpyinfo;
dfeccd2d
JB
3759 unsigned int state;
3760{
98659da6
KG
3761 EMACS_UINT mod_meta = meta_modifier;
3762 EMACS_UINT mod_alt = alt_modifier;
3763 EMACS_UINT mod_hyper = hyper_modifier;
3764 EMACS_UINT mod_super = super_modifier;
7d0393cf 3765
98659da6 3766 Lisp_Object tem;
7d0393cf 3767
98659da6
KG
3768 tem = Fget (Vx_alt_keysym, Qmodifier_value);
3769 if (! EQ (tem, Qnil)) mod_alt = XUINT (tem);
3770 tem = Fget (Vx_meta_keysym, Qmodifier_value);
3771 if (! EQ (tem, Qnil)) mod_meta = XUINT (tem);
3772 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
3773 if (! EQ (tem, Qnil)) mod_hyper = XUINT (tem);
3774 tem = Fget (Vx_super_keysym, Qmodifier_value);
3775 if (! EQ (tem, Qnil)) mod_super = XUINT (tem);
7d0393cf
JB
3776
3777
98659da6
KG
3778 return ( ((state & mod_alt) ? dpyinfo->alt_mod_mask : 0)
3779 | ((state & mod_super) ? dpyinfo->super_mod_mask : 0)
3780 | ((state & mod_hyper) ? dpyinfo->hyper_mod_mask : 0)
3781 | ((state & shift_modifier) ? ShiftMask : 0)
3782 | ((state & ctrl_modifier) ? ControlMask : 0)
3783 | ((state & mod_meta) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 3784}
d047c4eb
KH
3785
3786/* Convert a keysym to its name. */
3787
3788char *
3789x_get_keysym_name (keysym)
3790 KeySym keysym;
3791{
3792 char *value;
3793
3794 BLOCK_INPUT;
3795 value = XKeysymToString (keysym);
3796 UNBLOCK_INPUT;
3797
3798 return value;
3799}
06a2c219
GM
3800
3801
e4571a43
JB
3802\f
3803/* Mouse clicks and mouse movement. Rah. */
e4571a43 3804
442a09ea 3805/* Prepare a mouse-event in *RESULT for placement in the input queue.
71b8321e 3806
442a09ea
KS
3807 If the event is a button press, then note that we have grabbed
3808 the mouse. */
3809
3810static Lisp_Object
3811construct_mouse_click (result, event, f)
3812 struct input_event *result;
3813 XButtonEvent *event;
3814 struct frame *f;
71b8321e 3815{
442a09ea
KS
3816 /* Make the event type NO_EVENT; we'll change that when we decide
3817 otherwise. */
3818 result->kind = MOUSE_CLICK_EVENT;
3819 result->code = event->button - Button1;
3820 result->timestamp = event->time;
3821 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
3822 event->state)
3823 | (event->type == ButtonRelease
3824 ? up_modifier
3825 : down_modifier));
71b8321e 3826
442a09ea
KS
3827 XSETINT (result->x, event->x);
3828 XSETINT (result->y, event->y);
3829 XSETFRAME (result->frame_or_window, f);
3830 result->arg = Qnil;
3831 return Qnil;
71b8321e
GM
3832}
3833
442a09ea
KS
3834\f
3835/* Function to report a mouse movement to the mainstream Emacs code.
3836 The input handler calls this.
71b8321e 3837
442a09ea
KS
3838 We have received a mouse movement event, which is given in *event.
3839 If the mouse is over a different glyph than it was last time, tell
3840 the mainstream emacs code by setting mouse_moved. If not, ask for
3841 another motion event, so we can check again the next time it moves. */
e687d06e 3842
442a09ea
KS
3843static XMotionEvent last_mouse_motion_event;
3844static Lisp_Object last_mouse_motion_frame;
3845
bb339c57 3846static int
442a09ea
KS
3847note_mouse_movement (frame, event)
3848 FRAME_PTR frame;
3849 XMotionEvent *event;
e687d06e 3850{
442a09ea
KS
3851 last_mouse_movement_time = event->time;
3852 last_mouse_motion_event = *event;
3853 XSETFRAME (last_mouse_motion_frame, frame);
e687d06e 3854
555ffb46
RS
3855 if (!FRAME_X_OUTPUT (frame))
3856 return 0;
0c0351b5 3857
442a09ea 3858 if (event->window != FRAME_X_WINDOW (frame))
e687d06e 3859 {
442a09ea
KS
3860 frame->mouse_moved = 1;
3861 last_mouse_scroll_bar = Qnil;
3862 note_mouse_highlight (frame, -1, -1);
0a3fde9d 3863 last_mouse_glyph_frame = 0;
bb339c57 3864 return 1;
442a09ea
KS
3865 }
3866
a4b0e228 3867
442a09ea 3868 /* Has the mouse moved off the glyph it was on at the last sighting? */
0a3fde9d
KS
3869 if (frame != last_mouse_glyph_frame
3870 || event->x < last_mouse_glyph.x
a4b0e228
JD
3871 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
3872 || event->y < last_mouse_glyph.y
3873 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
442a09ea
KS
3874 {
3875 frame->mouse_moved = 1;
3876 last_mouse_scroll_bar = Qnil;
3877 note_mouse_highlight (frame, event->x, event->y);
9b909870 3878 /* Remember which glyph we're now on. */
cc9e7d91 3879 remember_mouse_glyph (frame, event->x, event->y, &last_mouse_glyph);
0a3fde9d 3880 last_mouse_glyph_frame = frame;
bb339c57 3881 return 1;
e687d06e 3882 }
bb339c57
KS
3883
3884 return 0;
e687d06e 3885}
b52b65bd 3886
b8009dd1 3887\f
442a09ea
KS
3888/************************************************************************
3889 Mouse Face
3890 ************************************************************************/
3891
3892static void
3893redo_mouse_highlight ()
3894{
3895 if (!NILP (last_mouse_motion_frame)
3896 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
3897 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
3898 last_mouse_motion_event.x,
3899 last_mouse_motion_event.y);
3900}
3901
3902
12ba150f 3903
90e65f07 3904/* Return the current position of the mouse.
b52b65bd 3905 *FP should be a frame which indicates which display to ask about.
90e65f07 3906
b52b65bd
GM
3907 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
3908 and *PART to the frame, window, and scroll bar part that the mouse
3909 is over. Set *X and *Y to the portion and whole of the mouse's
ab648270 3910 position on the scroll bar.
12ba150f 3911
b52b65bd
GM
3912 If the mouse movement started elsewhere, set *FP to the frame the
3913 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
12ba150f
JB
3914 the mouse is over.
3915
b52b65bd 3916 Set *TIME to the server time-stamp for the time at which the mouse
12ba150f
JB
3917 was at this position.
3918
a135645a
RS
3919 Don't store anything if we don't have a valid set of values to report.
3920
90e65f07 3921 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 3922 movement. */
90e65f07
JB
3923
3924static void
1cf412ec 3925XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 3926 FRAME_PTR *fp;
1cf412ec 3927 int insist;
12ba150f 3928 Lisp_Object *bar_window;
ab648270 3929 enum scroll_bar_part *part;
90e65f07 3930 Lisp_Object *x, *y;
e5d77022 3931 unsigned long *time;
90e65f07 3932{
a135645a
RS
3933 FRAME_PTR f1;
3934
90e65f07
JB
3935 BLOCK_INPUT;
3936
8bcee03e 3937 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 3938 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
3939 else
3940 {
12ba150f
JB
3941 Window root;
3942 int root_x, root_y;
90e65f07 3943
12ba150f
JB
3944 Window dummy_window;
3945 int dummy;
3946
39d8bb4d
KH
3947 Lisp_Object frame, tail;
3948
3949 /* Clear the mouse-moved flag for every frame on this display. */
3950 FOR_EACH_FRAME (tail, frame)
3951 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
3952 XFRAME (frame)->mouse_moved = 0;
3953
ab648270 3954 last_mouse_scroll_bar = Qnil;
12ba150f
JB
3955
3956 /* Figure out which root window we're on. */
334208b7
RS
3957 XQueryPointer (FRAME_X_DISPLAY (*fp),
3958 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
3959
3960 /* The root window which contains the pointer. */
3961 &root,
3962
3963 /* Trash which we can't trust if the pointer is on
3964 a different screen. */
3965 &dummy_window,
3966
3967 /* The position on that root window. */
58769bee 3968 &root_x, &root_y,
12ba150f
JB
3969
3970 /* More trash we can't trust. */
3971 &dummy, &dummy,
3972
3973 /* Modifier keys and pointer buttons, about which
3974 we don't care. */
3975 (unsigned int *) &dummy);
3976
3977 /* Now we have a position on the root; find the innermost window
3978 containing the pointer. */
3979 {
3980 Window win, child;
3981 int win_x, win_y;
06a2c219 3982 int parent_x = 0, parent_y = 0;
12ba150f
JB
3983
3984 win = root;
69388238 3985
2d7fc7e8
RS
3986 /* XTranslateCoordinates can get errors if the window
3987 structure is changing at the same time this function
3988 is running. So at least we must not crash from them. */
3989
9ba8e10d 3990 x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 3991
334208b7 3992 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 3993 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 3994 {
69388238
RS
3995 /* If mouse was grabbed on a frame, give coords for that frame
3996 even if the mouse is now outside it. */
334208b7 3997 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 3998
12ba150f 3999 /* From-window, to-window. */
69388238 4000 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
4001
4002 /* From-position, to-position. */
4003 root_x, root_y, &win_x, &win_y,
4004
4005 /* Child of win. */
4006 &child);
69388238
RS
4007 f1 = last_mouse_frame;
4008 }
4009 else
4010 {
4011 while (1)
4012 {
334208b7 4013 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 4014
69388238
RS
4015 /* From-window, to-window. */
4016 root, win,
12ba150f 4017
69388238
RS
4018 /* From-position, to-position. */
4019 root_x, root_y, &win_x, &win_y,
4020
4021 /* Child of win. */
4022 &child);
4023
9af3143a 4024 if (child == None || child == win)
69388238
RS
4025 break;
4026
4027 win = child;
4028 parent_x = win_x;
4029 parent_y = win_y;
4030 }
12ba150f 4031
69388238
RS
4032 /* Now we know that:
4033 win is the innermost window containing the pointer
4034 (XTC says it has no child containing the pointer),
4035 win_x and win_y are the pointer's position in it
4036 (XTC did this the last time through), and
4037 parent_x and parent_y are the pointer's position in win's parent.
4038 (They are what win_x and win_y were when win was child.
4039 If win is the root window, it has no parent, and
4040 parent_{x,y} are invalid, but that's okay, because we'll
4041 never use them in that case.) */
4042
4043 /* Is win one of our frames? */
19126e11 4044 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
aad0f6ab
GM
4045
4046#ifdef USE_X_TOOLKIT
4047 /* If we end up with the menu bar window, say it's not
4048 on the frame. */
4049 if (f1 != NULL
4050 && f1->output_data.x->menubar_widget
4051 && win == XtWindow (f1->output_data.x->menubar_widget))
4052 f1 = NULL;
4053#endif /* USE_X_TOOLKIT */
69388238 4054 }
58769bee 4055
2d7fc7e8
RS
4056 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
4057 f1 = 0;
4058
4545fa20 4059 x_uncatch_errors ();
2d7fc7e8 4060
ab648270 4061 /* If not, is it one of our scroll bars? */
a135645a 4062 if (! f1)
12ba150f 4063 {
6b61353c
KH
4064 struct scroll_bar *bar;
4065
4066 bar = x_window_to_scroll_bar (FRAME_X_DISPLAY (*fp), win);
12ba150f
JB
4067
4068 if (bar)
4069 {
a135645a 4070 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
4071 win_x = parent_x;
4072 win_y = parent_y;
4073 }
4074 }
90e65f07 4075
8bcee03e 4076 if (f1 == 0 && insist > 0)
b86bd3dd 4077 f1 = SELECTED_FRAME ();
1cf412ec 4078
a135645a 4079 if (f1)
12ba150f 4080 {
06a2c219
GM
4081 /* Ok, we found a frame. Store all the values.
4082 last_mouse_glyph is a rectangle used to reduce the
4083 generation of mouse events. To not miss any motion
4084 events, we must divide the frame into rectangles of the
4085 size of the smallest character that could be displayed
4086 on it, i.e. into the same rectangles that matrices on
4087 the frame are divided into. */
4088
cc9e7d91 4089 remember_mouse_glyph (f1, win_x, win_y, &last_mouse_glyph);
0a3fde9d 4090 last_mouse_glyph_frame = f1;
12ba150f
JB
4091
4092 *bar_window = Qnil;
4093 *part = 0;
334208b7 4094 *fp = f1;
e0c1aef2
KH
4095 XSETINT (*x, win_x);
4096 XSETINT (*y, win_y);
12ba150f
JB
4097 *time = last_mouse_movement_time;
4098 }
4099 }
4100 }
90e65f07
JB
4101
4102 UNBLOCK_INPUT;
4103}
f451eb13 4104
06a2c219 4105
06a2c219 4106\f
442a09ea
KS
4107/***********************************************************************
4108 Scroll bars
4109 ***********************************************************************/
4110
06a2c219
GM
4111/* Scroll bar support. */
4112
6b61353c
KH
4113/* Given an X window ID and a DISPLAY, find the struct scroll_bar which
4114 manages it.
06a2c219
GM
4115 This can be called in GC, so we have to make sure to strip off mark
4116 bits. */
bffcfca9 4117
06a2c219 4118static struct scroll_bar *
6b61353c
KH
4119x_window_to_scroll_bar (display, window_id)
4120 Display *display;
06a2c219
GM
4121 Window window_id;
4122{
4123 Lisp_Object tail;
4124
a11e1dce 4125#if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS)
6b61353c 4126 window_id = (Window) xg_get_scroll_id_for_window (display, window_id);
a11e1dce 4127#endif /* USE_GTK && USE_TOOLKIT_SCROLL_BARS */
257f40f2 4128
06a2c219
GM
4129 for (tail = Vframe_list;
4130 XGCTYPE (tail) == Lisp_Cons;
8e713be6 4131 tail = XCDR (tail))
06a2c219
GM
4132 {
4133 Lisp_Object frame, bar, condemned;
4134
8e713be6 4135 frame = XCAR (tail);
06a2c219
GM
4136 /* All elements of Vframe_list should be frames. */
4137 if (! GC_FRAMEP (frame))
4138 abort ();
4139
4140 /* Scan this frame's scroll bar list for a scroll bar with the
4141 right window ID. */
4142 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
4143 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
4144 /* This trick allows us to search both the ordinary and
4145 condemned scroll bar lists with one loop. */
4146 ! GC_NILP (bar) || (bar = condemned,
4147 condemned = Qnil,
4148 ! GC_NILP (bar));
4149 bar = XSCROLL_BAR (bar)->next)
6b61353c
KH
4150 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id &&
4151 FRAME_X_DISPLAY (XFRAME (frame)) == display)
06a2c219
GM
4152 return XSCROLL_BAR (bar);
4153 }
4154
4155 return 0;
4156}
4157
4158
01f67d2c 4159#if defined USE_LUCID
c95fc5f1
GM
4160
4161/* Return the Lucid menu bar WINDOW is part of. Return null
4162 if WINDOW is not part of a menu bar. */
4163
4164static Widget
4165x_window_to_menu_bar (window)
4166 Window window;
4167{
4168 Lisp_Object tail;
7d0393cf 4169
c95fc5f1
GM
4170 for (tail = Vframe_list;
4171 XGCTYPE (tail) == Lisp_Cons;
4172 tail = XCDR (tail))
4173 {
4174 Lisp_Object frame = XCAR (tail);
4175 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
7d0393cf 4176
c95fc5f1
GM
4177 if (menu_bar && xlwmenu_window_p (menu_bar, window))
4178 return menu_bar;
4179 }
4180
4181 return NULL;
4182}
4183
01f67d2c 4184#endif /* USE_LUCID */
c95fc5f1 4185
06a2c219
GM
4186\f
4187/************************************************************************
4188 Toolkit scroll bars
4189 ************************************************************************/
4190
eccc05db 4191#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
4192
4193static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
4194static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
4195static void x_create_toolkit_scroll_bar P_ ((struct frame *,
4196 struct scroll_bar *));
4197static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
4198 int, int, int));
4199
4200
06a2c219
GM
4201/* Lisp window being scrolled. Set when starting to interact with
4202 a toolkit scroll bar, reset to nil when ending the interaction. */
4203
4204static Lisp_Object window_being_scrolled;
4205
4206/* Last scroll bar part sent in xm_scroll_callback. */
4207
4208static int last_scroll_bar_part;
4209
ec18280f
SM
4210/* Whether this is an Xaw with arrow-scrollbars. This should imply
4211 that movements of 1/20 of the screen size are mapped to up/down. */
4212
488dd4c4
JD
4213#ifndef USE_GTK
4214/* Id of action hook installed for scroll bars. */
4215
4216static XtActionHookId action_hook_id;
4217
ec18280f
SM
4218static Boolean xaw3d_arrow_scroll;
4219
4220/* Whether the drag scrolling maintains the mouse at the top of the
4221 thumb. If not, resizing the thumb needs to be done more carefully
4222 to avoid jerkyness. */
4223
4224static Boolean xaw3d_pick_top;
4225
06a2c219 4226/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 4227 bars are used.. The hook is responsible for detecting when
06a2c219 4228 the user ends an interaction with the scroll bar, and generates
3b8f9651 4229 a `end-scroll' SCROLL_BAR_CLICK_EVENT' event if so. */
06a2c219
GM
4230
4231static void
4232xt_action_hook (widget, client_data, action_name, event, params,
4233 num_params)
4234 Widget widget;
4235 XtPointer client_data;
4236 String action_name;
4237 XEvent *event;
4238 String *params;
4239 Cardinal *num_params;
4240{
4241 int scroll_bar_p;
4242 char *end_action;
7d0393cf 4243
06a2c219
GM
4244#ifdef USE_MOTIF
4245 scroll_bar_p = XmIsScrollBar (widget);
4246 end_action = "Release";
ec18280f 4247#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
4248 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
4249 end_action = "EndScroll";
ec18280f 4250#endif /* USE_MOTIF */
06a2c219 4251
06a2c219
GM
4252 if (scroll_bar_p
4253 && strcmp (action_name, end_action) == 0
4254 && WINDOWP (window_being_scrolled))
4255 {
4256 struct window *w;
7d0393cf 4257
06a2c219
GM
4258 x_send_scroll_bar_event (window_being_scrolled,
4259 scroll_bar_end_scroll, 0, 0);
4260 w = XWINDOW (window_being_scrolled);
62fe13a4 4261
3c671a56 4262 if (!NILP (XSCROLL_BAR (w->vertical_scroll_bar)->dragging))
95a39dc5
SM
4263 {
4264 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
4265 /* The thumb size is incorrect while dragging: fix it. */
4266 set_vertical_scroll_bar (w);
4267 }
06a2c219
GM
4268 window_being_scrolled = Qnil;
4269 last_scroll_bar_part = -1;
bffcfca9
GM
4270
4271 /* Xt timeouts no longer needed. */
4272 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
4273 }
4274}
488dd4c4 4275#endif /* not USE_GTK */
06a2c219 4276
07b3d16e
GM
4277/* A vector of windows used for communication between
4278 x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
4279
4280static struct window **scroll_bar_windows;
4281static int scroll_bar_windows_size;
4282
06a2c219
GM
4283
4284/* Send a client message with message type Xatom_Scrollbar for a
4285 scroll action to the frame of WINDOW. PART is a value identifying
4286 the part of the scroll bar that was clicked on. PORTION is the
4287 amount to scroll of a whole of WHOLE. */
4288
4289static void
4290x_send_scroll_bar_event (window, part, portion, whole)
4291 Lisp_Object window;
4292 int part, portion, whole;
4293{
4294 XEvent event;
4295 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
07b3d16e
GM
4296 struct window *w = XWINDOW (window);
4297 struct frame *f = XFRAME (w->frame);
4298 int i;
06a2c219 4299
07b3d16e 4300 BLOCK_INPUT;
7d0393cf 4301
06a2c219
GM
4302 /* Construct a ClientMessage event to send to the frame. */
4303 ev->type = ClientMessage;
4304 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
4305 ev->display = FRAME_X_DISPLAY (f);
4306 ev->window = FRAME_X_WINDOW (f);
4307 ev->format = 32;
07b3d16e
GM
4308
4309 /* We can only transfer 32 bits in the XClientMessageEvent, which is
4310 not enough to store a pointer or Lisp_Object on a 64 bit system.
4311 So, store the window in scroll_bar_windows and pass the index
4312 into that array in the event. */
4313 for (i = 0; i < scroll_bar_windows_size; ++i)
4314 if (scroll_bar_windows[i] == NULL)
4315 break;
4316
4317 if (i == scroll_bar_windows_size)
4318 {
4319 int new_size = max (10, 2 * scroll_bar_windows_size);
4320 size_t nbytes = new_size * sizeof *scroll_bar_windows;
4321 size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows;
7d0393cf 4322
07b3d16e
GM
4323 scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
4324 nbytes);
4325 bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
4326 scroll_bar_windows_size = new_size;
4327 }
4328
4329 scroll_bar_windows[i] = w;
4330 ev->data.l[0] = (long) i;
06a2c219
GM
4331 ev->data.l[1] = (long) part;
4332 ev->data.l[2] = (long) 0;
4333 ev->data.l[3] = (long) portion;
4334 ev->data.l[4] = (long) whole;
4335
bffcfca9
GM
4336 /* Make Xt timeouts work while the scroll bar is active. */
4337 toolkit_scroll_bar_interaction = 1;
4338
06a2c219
GM
4339 /* Setting the event mask to zero means that the message will
4340 be sent to the client that created the window, and if that
4341 window no longer exists, no event will be sent. */
06a2c219
GM
4342 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
4343 UNBLOCK_INPUT;
4344}
4345
4346
4347/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
4348 in *IEVENT. */
4349
4350static void
4351x_scroll_bar_to_input_event (event, ievent)
4352 XEvent *event;
4353 struct input_event *ievent;
4354{
4355 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
4356 Lisp_Object window;
4357 struct frame *f;
07b3d16e 4358 struct window *w;
7d0393cf 4359
07b3d16e
GM
4360 w = scroll_bar_windows[ev->data.l[0]];
4361 scroll_bar_windows[ev->data.l[0]] = NULL;
52e386c2 4362
07b3d16e
GM
4363 XSETWINDOW (window, w);
4364 f = XFRAME (w->frame);
7d0393cf 4365
3b8f9651 4366 ievent->kind = SCROLL_BAR_CLICK_EVENT;
06a2c219 4367 ievent->frame_or_window = window;
0f8aabe9 4368 ievent->arg = Qnil;
488dd4c4
JD
4369#ifdef USE_GTK
4370 ievent->timestamp = CurrentTime;
4371#else
06a2c219 4372 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
488dd4c4 4373#endif
06a2c219
GM
4374 ievent->part = ev->data.l[1];
4375 ievent->code = ev->data.l[2];
4376 ievent->x = make_number ((int) ev->data.l[3]);
4377 ievent->y = make_number ((int) ev->data.l[4]);
4378 ievent->modifiers = 0;
4379}
4380
4381
4382#ifdef USE_MOTIF
4383
4384/* Minimum and maximum values used for Motif scroll bars. */
4385
06a2c219 4386#define XM_SB_MAX 10000000
06a2c219
GM
4387
4388
4389/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
4390 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
4696802b 4391 CALL_DATA is a pointer to a XmScrollBarCallbackStruct. */
06a2c219
GM
4392
4393static void
4394xm_scroll_callback (widget, client_data, call_data)
4395 Widget widget;
4396 XtPointer client_data, call_data;
4397{
4398 struct scroll_bar *bar = (struct scroll_bar *) client_data;
4399 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
06a2c219
GM
4400 int part = -1, whole = 0, portion = 0;
4401
4402 switch (cs->reason)
4403 {
4404 case XmCR_DECREMENT:
4405 bar->dragging = Qnil;
4406 part = scroll_bar_up_arrow;
4407 break;
4408
4409 case XmCR_INCREMENT:
4410 bar->dragging = Qnil;
4411 part = scroll_bar_down_arrow;
4412 break;
4413
4414 case XmCR_PAGE_DECREMENT:
4415 bar->dragging = Qnil;
4416 part = scroll_bar_above_handle;
4417 break;
4418
4419 case XmCR_PAGE_INCREMENT:
4420 bar->dragging = Qnil;
4421 part = scroll_bar_below_handle;
4422 break;
4423
4424 case XmCR_TO_TOP:
4425 bar->dragging = Qnil;
4426 part = scroll_bar_to_top;
4427 break;
7d0393cf 4428
06a2c219
GM
4429 case XmCR_TO_BOTTOM:
4430 bar->dragging = Qnil;
4431 part = scroll_bar_to_bottom;
4432 break;
4433
4434 case XmCR_DRAG:
4435 {
4436 int slider_size;
06a2c219
GM
4437
4438 /* Get the slider size. */
4439 BLOCK_INPUT;
4440 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
4441 UNBLOCK_INPUT;
4442
baa21c48 4443 whole = XM_SB_MAX - slider_size;
3c671a56 4444 portion = min (cs->value, whole);
6f2a7a68
SM
4445 part = scroll_bar_handle;
4446 bar->dragging = make_number (cs->value);
06a2c219
GM
4447 }
4448 break;
7d0393cf 4449
06a2c219
GM
4450 case XmCR_VALUE_CHANGED:
4451 break;
4452 };
4453
4454 if (part >= 0)
4455 {
4456 window_being_scrolled = bar->window;
4457 last_scroll_bar_part = part;
4458 x_send_scroll_bar_event (bar->window, part, portion, whole);
4459 }
4460}
4461
4462
488dd4c4
JD
4463#else /* !USE_MOTIF, i.e. Xaw or GTK */
4464#ifdef USE_GTK
17097258 4465/* Scroll bar callback for GTK scroll bars. WIDGET is the scroll
f979dc05 4466 bar widget. DATA is a pointer to the scroll_bar structure. */
488dd4c4
JD
4467
4468static void
4469xg_scroll_callback (widget, data)
f979dc05 4470 GtkRange *widget;
488dd4c4
JD
4471 gpointer data;
4472{
4473 struct scroll_bar *bar = (struct scroll_bar *) data;
4474 gdouble previous;
4475 gdouble position;
4476 gdouble *p;
4477 int diff;
177c0ea7 4478
488dd4c4 4479 int part = -1, whole = 0, portion = 0;
f979dc05 4480 GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (widget));
177c0ea7 4481
488dd4c4
JD
4482 position = gtk_adjustment_get_value (adj);
4483
4484 p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA);
4485 if (! p)
4486 {
4487 p = (gdouble*) xmalloc (sizeof (gdouble));
4488 *p = XG_SB_MIN;
4489 g_object_set_data (G_OBJECT (widget), XG_LAST_SB_DATA, p);
4490 }
4491
4492 previous = *p;
4493 *p = position;
4494
fecad3f6
JD
4495 if (xg_ignore_gtk_scrollbar) return;
4496
488dd4c4 4497 diff = (int) (position - previous);
177c0ea7 4498
488dd4c4
JD
4499 if (diff == (int) adj->step_increment)
4500 {
4501 part = scroll_bar_down_arrow;
4502 bar->dragging = Qnil;
4503 }
4504 else if (-diff == (int) adj->step_increment)
4505 {
4506 part = scroll_bar_up_arrow;
4507 bar->dragging = Qnil;
4508 }
4509 else if (diff == (int) adj->page_increment)
4510 {
4511 part = scroll_bar_below_handle;
4512 bar->dragging = Qnil;
4513 }
4514 else if (-diff == (int) adj->page_increment)
4515 {
4516 part = scroll_bar_above_handle;
4517 bar->dragging = Qnil;
4518 }
4519 else
4520 {
4521 part = scroll_bar_handle;
4522 whole = adj->upper - adj->page_size;
17097258
JD
4523 portion = min ((int)position, whole);
4524 bar->dragging = make_number ((int)portion);
488dd4c4 4525 }
177c0ea7 4526
488dd4c4 4527 if (part >= 0)
82ead4b1 4528 {
488dd4c4
JD
4529 window_being_scrolled = bar->window;
4530 last_scroll_bar_part = part;
4531 x_send_scroll_bar_event (bar->window, part, portion, whole);
4532 }
4533}
06a2c219 4534
488dd4c4 4535#else /* not USE_GTK */
06a2c219 4536
ec18280f 4537/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
4538 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
4539 scroll bar struct. CALL_DATA is a pointer to a float saying where
4540 the thumb is. */
4541
4542static void
ec18280f 4543xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
4544 Widget widget;
4545 XtPointer client_data, call_data;
4546{
4547 struct scroll_bar *bar = (struct scroll_bar *) client_data;
4548 float top = *(float *) call_data;
4549 float shown;
ec18280f
SM
4550 int whole, portion, height;
4551 int part;
06a2c219
GM
4552
4553 /* Get the size of the thumb, a value between 0 and 1. */
4554 BLOCK_INPUT;
ec18280f 4555 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
4556 UNBLOCK_INPUT;
4557
4558 whole = 10000000;
4559 portion = shown < 1 ? top * whole : 0;
06a2c219 4560
ec18280f
SM
4561 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
4562 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
4563 the bottom, so we force the scrolling whenever we see that we're
4564 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
4565 we try to ensure that we always stay two pixels away from the
4566 bottom). */
06a2c219
GM
4567 part = scroll_bar_down_arrow;
4568 else
4569 part = scroll_bar_handle;
4570
4571 window_being_scrolled = bar->window;
4572 bar->dragging = make_number (portion);
4573 last_scroll_bar_part = part;
4574 x_send_scroll_bar_event (bar->window, part, portion, whole);
4575}
4576
4577
ec18280f
SM
4578/* Xaw scroll bar callback. Invoked for incremental scrolling.,
4579 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
4580 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
4581 the scroll bar. CALL_DATA is an integer specifying the action that
dbd4b028 4582 has taken place. Its magnitude is in the range 0..height of the
06a2c219
GM
4583 scroll bar. Negative values mean scroll towards buffer start.
4584 Values < height of scroll bar mean line-wise movement. */
4585
4586static void
ec18280f 4587xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
4588 Widget widget;
4589 XtPointer client_data, call_data;
4590{
4591 struct scroll_bar *bar = (struct scroll_bar *) client_data;
560d7ceb
DL
4592 /* The position really is stored cast to a pointer. */
4593 int position = (long) call_data;
06a2c219
GM
4594 Dimension height;
4595 int part;
4596
4597 /* Get the height of the scroll bar. */
4598 BLOCK_INPUT;
4599 XtVaGetValues (widget, XtNheight, &height, NULL);
4600 UNBLOCK_INPUT;
4601
ec18280f
SM
4602 if (abs (position) >= height)
4603 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
4604
4605 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
4606 it maps line-movement to call_data = max(5, height/20). */
4607 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
4608 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 4609 else
ec18280f 4610 part = scroll_bar_move_ratio;
06a2c219
GM
4611
4612 window_being_scrolled = bar->window;
4613 bar->dragging = Qnil;
4614 last_scroll_bar_part = part;
ec18280f 4615 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
4616}
4617
488dd4c4 4618#endif /* not USE_GTK */
06a2c219
GM
4619#endif /* not USE_MOTIF */
4620
488dd4c4 4621#define SCROLL_BAR_NAME "verticalScrollBar"
06a2c219
GM
4622
4623/* Create the widget for scroll bar BAR on frame F. Record the widget
4624 and X window of the scroll bar in BAR. */
4625
488dd4c4
JD
4626#ifdef USE_GTK
4627static void
4628x_create_toolkit_scroll_bar (f, bar)
4629 struct frame *f;
4630 struct scroll_bar *bar;
4631{
4632 char *scroll_bar_name = SCROLL_BAR_NAME;
4633
4634 BLOCK_INPUT;
4635 xg_create_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
4636 scroll_bar_name);
4637 UNBLOCK_INPUT;
4638}
4639
4640#else /* not USE_GTK */
4641
06a2c219
GM
4642static void
4643x_create_toolkit_scroll_bar (f, bar)
4644 struct frame *f;
4645 struct scroll_bar *bar;
4646{
4647 Window xwindow;
4648 Widget widget;
4649 Arg av[20];
4650 int ac = 0;
488dd4c4 4651 char *scroll_bar_name = SCROLL_BAR_NAME;
06a2c219
GM
4652 unsigned long pixel;
4653
4654 BLOCK_INPUT;
4655
4656#ifdef USE_MOTIF
06a2c219
GM
4657 /* Set resources. Create the widget. */
4658 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
3c671a56 4659 XtSetArg (av[ac], XmNminimum, 0); ++ac;
06a2c219
GM
4660 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
4661 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
4662 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
4663 XtSetArg (av[ac], XmNincrement, 1); ++ac;
4664 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
4665
4666 pixel = f->output_data.x->scroll_bar_foreground_pixel;
4667 if (pixel != -1)
4668 {
4669 XtSetArg (av[ac], XmNforeground, pixel);
4670 ++ac;
4671 }
7d0393cf 4672
06a2c219
GM
4673 pixel = f->output_data.x->scroll_bar_background_pixel;
4674 if (pixel != -1)
4675 {
4676 XtSetArg (av[ac], XmNbackground, pixel);
4677 ++ac;
4678 }
7d0393cf 4679
06a2c219
GM
4680 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
4681 scroll_bar_name, av, ac);
4682
4683 /* Add one callback for everything that can happen. */
4684 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
4685 (XtPointer) bar);
4686 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
4687 (XtPointer) bar);
4688 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
4689 (XtPointer) bar);
4690 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
4691 (XtPointer) bar);
4692 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
4693 (XtPointer) bar);
4694 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
4695 (XtPointer) bar);
4696 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
4697 (XtPointer) bar);
7d0393cf 4698
06a2c219
GM
4699 /* Realize the widget. Only after that is the X window created. */
4700 XtRealizeWidget (widget);
4701
4702 /* Set the cursor to an arrow. I didn't find a resource to do that.
4703 And I'm wondering why it hasn't an arrow cursor by default. */
4704 XDefineCursor (XtDisplay (widget), XtWindow (widget),
4705 f->output_data.x->nontext_cursor);
7d0393cf 4706
ec18280f 4707#else /* !USE_MOTIF i.e. use Xaw */
7d0393cf 4708
06a2c219
GM
4709 /* Set resources. Create the widget. The background of the
4710 Xaw3d scroll bar widget is a little bit light for my taste.
4711 We don't alter it here to let users change it according
4712 to their taste with `emacs*verticalScrollBar.background: xxx'. */
4713 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
4714 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
4715 /* For smoother scrolling with Xaw3d -sm */
4716 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
7d0393cf 4717
06a2c219
GM
4718 pixel = f->output_data.x->scroll_bar_foreground_pixel;
4719 if (pixel != -1)
4720 {
4721 XtSetArg (av[ac], XtNforeground, pixel);
4722 ++ac;
4723 }
7d0393cf 4724
06a2c219
GM
4725 pixel = f->output_data.x->scroll_bar_background_pixel;
4726 if (pixel != -1)
4727 {
4728 XtSetArg (av[ac], XtNbackground, pixel);
4729 ++ac;
4730 }
7c1bef7a
MB
4731
4732 /* Top/bottom shadow colors. */
4733
4734 /* Allocate them, if necessary. */
4735 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
4736 {
4737 pixel = f->output_data.x->scroll_bar_background_pixel;
4738 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
4739 &pixel, 1.2, 0x8000))
4740 pixel = -1;
4741 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
4742 }
4743 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
4744 {
4745 pixel = f->output_data.x->scroll_bar_background_pixel;
4746 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
4747 &pixel, 0.6, 0x4000))
4748 pixel = -1;
4749 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
4750 }
4751
6ca53601 4752#ifdef XtNbeNiceToColormap
7c1bef7a
MB
4753 /* Tell the toolkit about them. */
4754 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
4755 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
4756 /* We tried to allocate a color for the top/bottom shadow, and
4757 failed, so tell Xaw3d to use dithering instead. */
4758 {
4759 XtSetArg (av[ac], XtNbeNiceToColormap, True);
4760 ++ac;
4761 }
4762 else
4763 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
4764 be more consistent with other emacs 3d colors, and since Xaw3d is
4765 not good at dealing with allocation failure. */
4766 {
4767 /* This tells Xaw3d to use real colors instead of dithering for
4768 the shadows. */
4769 XtSetArg (av[ac], XtNbeNiceToColormap, False);
4770 ++ac;
4771
4772 /* Specify the colors. */
4773 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
4774 if (pixel != -1)
4775 {
6ca53601 4776 XtSetArg (av[ac], XtNtopShadowPixel, pixel);
7c1bef7a
MB
4777 ++ac;
4778 }
4779 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
4780 if (pixel != -1)
4781 {
6ca53601 4782 XtSetArg (av[ac], XtNbottomShadowPixel, pixel);
7c1bef7a
MB
4783 ++ac;
4784 }
4785 }
6ca53601 4786#endif
7c1bef7a 4787
06a2c219
GM
4788 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
4789 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
4790
4791 {
4792 char *initial = "";
4793 char *val = initial;
4794 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
9cfc7da4
SM
4795#ifdef XtNarrowScrollbars
4796 XtNarrowScrollbars, (XtPointer) &xaw3d_arrow_scroll,
4797#endif
ec18280f 4798 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
9cfc7da4 4799 if (xaw3d_arrow_scroll || val == initial)
ec18280f
SM
4800 { /* ARROW_SCROLL */
4801 xaw3d_arrow_scroll = True;
9cfc7da4 4802 /* Isn't that just a personal preference ? --Stef */
ec18280f
SM
4803 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
4804 }
4805 }
7d0393cf 4806
06a2c219 4807 /* Define callbacks. */
ec18280f
SM
4808 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
4809 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219 4810 (XtPointer) bar);
7d0393cf 4811
06a2c219
GM
4812 /* Realize the widget. Only after that is the X window created. */
4813 XtRealizeWidget (widget);
7d0393cf 4814
ec18280f 4815#endif /* !USE_MOTIF */
06a2c219 4816
2a51c026 4817 /* Install an action hook that lets us detect when the user
06a2c219
GM
4818 finishes interacting with a scroll bar. */
4819 if (action_hook_id == 0)
4820 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
7d0393cf 4821
06a2c219
GM
4822 /* Remember X window and widget in the scroll bar vector. */
4823 SET_SCROLL_BAR_X_WIDGET (bar, widget);
4824 xwindow = XtWindow (widget);
4825 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
4826
4827 UNBLOCK_INPUT;
4828}
488dd4c4 4829#endif /* not USE_GTK */
06a2c219
GM
4830
4831
4832/* Set the thumb size and position of scroll bar BAR. We are currently
4833 displaying PORTION out of a whole WHOLE, and our position POSITION. */
4834
488dd4c4
JD
4835#ifdef USE_GTK
4836static void
4837x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
4838 struct scroll_bar *bar;
4839 int portion, position, whole;
4840{
4841 xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
4842}
4843
4844#else /* not USE_GTK */
06a2c219
GM
4845static void
4846x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
4847 struct scroll_bar *bar;
4848 int portion, position, whole;
f451eb13 4849{
e83dc917
GM
4850 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
4851 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
06a2c219 4852 float top, shown;
f451eb13 4853
6f2a7a68
SM
4854 BLOCK_INPUT;
4855
4856#ifdef USE_MOTIF
4857
4858 /* We use an estimate of 30 chars per line rather than the real
4859 `portion' value. This has the disadvantage that the thumb size
4860 is not very representative, but it makes our life a lot easier.
4861 Otherwise, we have to constantly adjust the thumb size, which
4862 we can't always do quickly enough: while dragging, the size of
4863 the thumb might prevent the user from dragging the thumb all the
4864 way to the end. but Motif and some versions of Xaw3d don't allow
4865 updating the thumb size while dragging. Also, even if we can update
4866 its size, the update will often happen too late.
4867 If you don't believe it, check out revision 1.650 of xterm.c to see
4868 what hoops we were going through and the still poor behavior we got. */
0899d58c 4869 portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
6f2a7a68
SM
4870 /* When the thumb is at the bottom, position == whole.
4871 So we need to increase `whole' to make space for the thumb. */
4872 whole += portion;
4873
4874 if (whole <= 0)
06a2c219
GM
4875 top = 0, shown = 1;
4876 else
f451eb13 4877 {
06a2c219
GM
4878 top = (float) position / whole;
4879 shown = (float) portion / whole;
4880 }
f451eb13 4881
6f2a7a68
SM
4882 if (NILP (bar->dragging))
4883 {
4884 int size, value;
06a2c219 4885
6f2a7a68
SM
4886 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
4887 is the scroll bar's maximum and MIN is the scroll bar's minimum
4888 value. */
3c671a56
SM
4889 size = shown * XM_SB_MAX;
4890 size = min (size, XM_SB_MAX);
6f2a7a68 4891 size = max (size, 1);
06a2c219 4892
6f2a7a68 4893 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
3c671a56 4894 value = top * XM_SB_MAX;
6f2a7a68 4895 value = min (value, XM_SB_MAX - size);
7d0393cf 4896
06a2c219 4897 XmScrollBarSetValues (widget, value, size, 0, 0, False);
6f2a7a68 4898 }
ec18280f 4899#else /* !USE_MOTIF i.e. use Xaw */
6f2a7a68
SM
4900
4901 if (whole == 0)
4902 top = 0, shown = 1;
4903 else
4904 {
4905 top = (float) position / whole;
4906 shown = (float) portion / whole;
4907 }
4908
06a2c219 4909 {
ec18280f
SM
4910 float old_top, old_shown;
4911 Dimension height;
4912 XtVaGetValues (widget,
4913 XtNtopOfThumb, &old_top,
4914 XtNshown, &old_shown,
4915 XtNheight, &height,
4916 NULL);
4917
4918 /* Massage the top+shown values. */
4919 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
4920 top = max (0, min (1, top));
4921 else
4922 top = old_top;
4923 /* Keep two pixels available for moving the thumb down. */
4924 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
4925
4926 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
4927 check that your system's configuration file contains a define
4928 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 4929 if (top != old_top || shown != old_shown)
eb393530 4930 {
ec18280f 4931 if (NILP (bar->dragging))
eb393530 4932 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
4933 else
4934 {
ec18280f
SM
4935 /* Try to make the scrolling a tad smoother. */
4936 if (!xaw3d_pick_top)
4937 shown = min (shown, old_shown);
7d0393cf 4938
ec18280f 4939 XawScrollbarSetThumb (widget, top, shown);
06a2c219 4940 }
06a2c219
GM
4941 }
4942 }
ec18280f 4943#endif /* !USE_MOTIF */
06a2c219
GM
4944
4945 UNBLOCK_INPUT;
f451eb13 4946}
488dd4c4 4947#endif /* not USE_GTK */
f451eb13 4948
06a2c219
GM
4949#endif /* USE_TOOLKIT_SCROLL_BARS */
4950
4951
4952\f
4953/************************************************************************
4954 Scroll bars, general
4955 ************************************************************************/
7d0393cf 4956
06a2c219
GM
4957/* Create a scroll bar and return the scroll bar vector for it. W is
4958 the Emacs window on which to create the scroll bar. TOP, LEFT,
f7ccf929 4959 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
06a2c219
GM
4960 scroll bar. */
4961
ab648270 4962static struct scroll_bar *
06a2c219
GM
4963x_scroll_bar_create (w, top, left, width, height)
4964 struct window *w;
f451eb13
JB
4965 int top, left, width, height;
4966{
06a2c219 4967 struct frame *f = XFRAME (w->frame);
334208b7
RS
4968 struct scroll_bar *bar
4969 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
4970
4971 BLOCK_INPUT;
4972
eccc05db 4973#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
4974 x_create_toolkit_scroll_bar (f, bar);
4975#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
4976 {
4977 XSetWindowAttributes a;
4978 unsigned long mask;
5c187dee 4979 Window window;
06a2c219
GM
4980
4981 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
4982 if (a.background_pixel == -1)
4983 a.background_pixel = f->output_data.x->background_pixel;
7d0393cf 4984
12ba150f 4985 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 4986 | ButtonMotionMask | PointerMotionHintMask
12ba150f 4987 | ExposureMask);
7a13e894 4988 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 4989
dbc4e1c1 4990 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 4991
06a2c219
GM
4992 /* Clear the area of W that will serve as a scroll bar. This is
4993 for the case that a window has been split horizontally. In
4994 this case, no clear_frame is generated to reduce flickering. */
7b49b9d2
GM
4995 if (width > 0 && height > 0)
4996 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4997 left, top, width,
4998 window_box_height (w), False);
06a2c219
GM
4999
5000 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5001 /* Position and size of scroll bar. */
5002 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
5003 top,
5004 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
5005 height,
5006 /* Border width, depth, class, and visual. */
5007 0,
5008 CopyFromParent,
5009 CopyFromParent,
5010 CopyFromParent,
5011 /* Attributes. */
5012 mask, &a);
5013 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 5014 }
06a2c219 5015#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 5016
06a2c219 5017 XSETWINDOW (bar->window, w);
e0c1aef2
KH
5018 XSETINT (bar->top, top);
5019 XSETINT (bar->left, left);
5020 XSETINT (bar->width, width);
5021 XSETINT (bar->height, height);
5022 XSETINT (bar->start, 0);
5023 XSETINT (bar->end, 0);
12ba150f 5024 bar->dragging = Qnil;
f451eb13
JB
5025
5026 /* Add bar to its frame's list of scroll bars. */
334208b7 5027 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 5028 bar->prev = Qnil;
334208b7 5029 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 5030 if (!NILP (bar->next))
e0c1aef2 5031 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 5032
06a2c219 5033 /* Map the window/widget. */
eccc05db 5034#ifdef USE_TOOLKIT_SCROLL_BARS
f964b4d7 5035 {
488dd4c4
JD
5036#ifdef USE_GTK
5037 xg_update_scrollbar_pos (f,
5038 SCROLL_BAR_X_WINDOW (bar),
5039 top,
5040 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
5041 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
6bd8015d 5042 max (height, 1));
488dd4c4
JD
5043 xg_show_scroll_bar (SCROLL_BAR_X_WINDOW (bar));
5044#else /* not USE_GTK */
f964b4d7
GM
5045 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
5046 XtConfigureWidget (scroll_bar,
5047 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
5048 top,
5049 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
5050 max (height, 1), 0);
5051 XtMapWidget (scroll_bar);
488dd4c4 5052#endif /* not USE_GTK */
f964b4d7 5053 }
06a2c219 5054#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 5055 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 5056#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
5057
5058 UNBLOCK_INPUT;
12ba150f 5059 return bar;
f451eb13
JB
5060}
5061
06a2c219 5062
12ba150f 5063/* Draw BAR's handle in the proper position.
7d0393cf 5064
12ba150f
JB
5065 If the handle is already drawn from START to END, don't bother
5066 redrawing it, unless REBUILD is non-zero; in that case, always
5067 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 5068 events.)
12ba150f
JB
5069
5070 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
5071 fit inside its rectangle, but if the user is dragging the scroll
5072 bar handle, we want to let them drag it down all the way, so that
5073 the bar's top is as far down as it goes; otherwise, there's no way
5074 to move to the very end of the buffer. */
5075
5c187dee
GM
5076#ifndef USE_TOOLKIT_SCROLL_BARS
5077
f451eb13 5078static void
ab648270
JB
5079x_scroll_bar_set_handle (bar, start, end, rebuild)
5080 struct scroll_bar *bar;
f451eb13 5081 int start, end;
12ba150f 5082 int rebuild;
f451eb13 5083{
12ba150f 5084 int dragging = ! NILP (bar->dragging);
ab648270 5085 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 5086 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 5087 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
5088
5089 /* If the display is already accurate, do nothing. */
5090 if (! rebuild
5091 && start == XINT (bar->start)
5092 && end == XINT (bar->end))
5093 return;
5094
f451eb13
JB
5095 BLOCK_INPUT;
5096
5097 {
d9cdbb3d
RS
5098 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
5099 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
5100 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
5101
5102 /* Make sure the values are reasonable, and try to preserve
5103 the distance between start and end. */
12ba150f
JB
5104 {
5105 int length = end - start;
5106
5107 if (start < 0)
5108 start = 0;
5109 else if (start > top_range)
5110 start = top_range;
5111 end = start + length;
5112
5113 if (end < start)
5114 end = start;
5115 else if (end > top_range && ! dragging)
5116 end = top_range;
5117 }
f451eb13 5118
ab648270 5119 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
5120 XSETINT (bar->start, start);
5121 XSETINT (bar->end, end);
f451eb13 5122
12ba150f
JB
5123 /* Clip the end position, just for display. */
5124 if (end > top_range)
5125 end = top_range;
f451eb13 5126
ab648270 5127 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
5128 below top positions, to make sure the handle is always at least
5129 that many pixels tall. */
ab648270 5130 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 5131
12ba150f
JB
5132 /* Draw the empty space above the handle. Note that we can't clear
5133 zero-height areas; that means "clear to end of window." */
5134 if (0 < start)
c5e6e06b
GM
5135 x_clear_area (FRAME_X_DISPLAY (f), w,
5136 /* x, y, width, height, and exposures. */
5137 VERTICAL_SCROLL_BAR_LEFT_BORDER,
5138 VERTICAL_SCROLL_BAR_TOP_BORDER,
5139 inside_width, start,
5140 False);
f451eb13 5141
06a2c219
GM
5142 /* Change to proper foreground color if one is specified. */
5143 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
5144 XSetForeground (FRAME_X_DISPLAY (f), gc,
5145 f->output_data.x->scroll_bar_foreground_pixel);
5146
12ba150f 5147 /* Draw the handle itself. */
334208b7 5148 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
12ba150f 5149 /* x, y, width, height */
ab648270
JB
5150 VERTICAL_SCROLL_BAR_LEFT_BORDER,
5151 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 5152 inside_width, end - start);
f451eb13 5153
06a2c219
GM
5154 /* Restore the foreground color of the GC if we changed it above. */
5155 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
5156 XSetForeground (FRAME_X_DISPLAY (f), gc,
5157 f->output_data.x->foreground_pixel);
f451eb13 5158
12ba150f
JB
5159 /* Draw the empty space below the handle. Note that we can't
5160 clear zero-height areas; that means "clear to end of window." */
5161 if (end < inside_height)
c5e6e06b
GM
5162 x_clear_area (FRAME_X_DISPLAY (f), w,
5163 /* x, y, width, height, and exposures. */
5164 VERTICAL_SCROLL_BAR_LEFT_BORDER,
5165 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
5166 inside_width, inside_height - end,
5167 False);
f451eb13 5168
f451eb13
JB
5169 }
5170
f451eb13
JB
5171 UNBLOCK_INPUT;
5172}
5173
5c187dee 5174#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 5175
06a2c219
GM
5176/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
5177 nil. */
58769bee 5178
12ba150f 5179static void
ab648270
JB
5180x_scroll_bar_remove (bar)
5181 struct scroll_bar *bar;
12ba150f 5182{
e83dc917 5183 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
5184 BLOCK_INPUT;
5185
eccc05db 5186#ifdef USE_TOOLKIT_SCROLL_BARS
488dd4c4
JD
5187#ifdef USE_GTK
5188 xg_remove_scroll_bar (f, SCROLL_BAR_X_WINDOW (bar));
5189#else /* not USE_GTK */
e83dc917 5190 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
488dd4c4 5191#endif /* not USE_GTK */
e83dc917
GM
5192#else
5193 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
5194#endif
7d0393cf 5195
ab648270
JB
5196 /* Disassociate this scroll bar from its window. */
5197 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
5198
5199 UNBLOCK_INPUT;
5200}
5201
06a2c219 5202
12ba150f
JB
5203/* Set the handle of the vertical scroll bar for WINDOW to indicate
5204 that we are displaying PORTION characters out of a total of WHOLE
ab648270 5205 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 5206 create one. */
06a2c219 5207
12ba150f 5208static void
06a2c219
GM
5209XTset_vertical_scroll_bar (w, portion, whole, position)
5210 struct window *w;
f451eb13
JB
5211 int portion, whole, position;
5212{
06a2c219 5213 struct frame *f = XFRAME (w->frame);
ab648270 5214 struct scroll_bar *bar;
3c6ede7b 5215 int top, height, left, sb_left, width, sb_width;
0899d58c 5216 int window_y, window_height;
06a2c219 5217
3c6ede7b 5218 /* Get window dimensions. */
0899d58c 5219 window_box (w, -1, 0, &window_y, 0, &window_height);
3c6ede7b 5220 top = window_y;
0899d58c 5221 width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
3c6ede7b 5222 height = window_height;
06a2c219 5223
3c6ede7b 5224 /* Compute the left edge of the scroll bar area. */
0899d58c 5225 left = WINDOW_SCROLL_BAR_AREA_X (w);
3c6ede7b
GM
5226
5227 /* Compute the width of the scroll bar which might be less than
5228 the width of the area reserved for the scroll bar. */
0899d58c
KS
5229 if (WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) > 0)
5230 sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
06a2c219 5231 else
3c6ede7b 5232 sb_width = width;
12ba150f 5233
3c6ede7b
GM
5234 /* Compute the left edge of the scroll bar. */
5235#ifdef USE_TOOLKIT_SCROLL_BARS
0899d58c 5236 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
13fcb889
KS
5237 sb_left = (left +
5238 (WINDOW_RIGHTMOST_P (w)
5239 ? width - sb_width - (width - sb_width) / 2
5240 : 0));
3c6ede7b 5241 else
13fcb889
KS
5242 sb_left = (left +
5243 (WINDOW_LEFTMOST_P (w)
5244 ? (width - sb_width) / 2
5245 : width - sb_width));
3c6ede7b 5246#else
0899d58c 5247 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
7d0393cf 5248 sb_left = left + width - sb_width;
3c6ede7b
GM
5249 else
5250 sb_left = left;
5251#endif
7d0393cf 5252
ab648270 5253 /* Does the scroll bar exist yet? */
06a2c219 5254 if (NILP (w->vertical_scroll_bar))
3c6ede7b 5255 {
7b49b9d2 5256 if (width > 0 && height > 0)
b547b6e8
GM
5257 {
5258 BLOCK_INPUT;
5259 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5260 left, top, width, height, False);
5261 UNBLOCK_INPUT;
5262 }
7d0393cf 5263
3c6ede7b
GM
5264 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
5265 }
f451eb13 5266 else
12ba150f
JB
5267 {
5268 /* It may just need to be moved and resized. */
06a2c219 5269 unsigned int mask = 0;
7d0393cf 5270
06a2c219
GM
5271 bar = XSCROLL_BAR (w->vertical_scroll_bar);
5272
5273 BLOCK_INPUT;
5274
3c6ede7b 5275 if (sb_left != XINT (bar->left))
06a2c219 5276 mask |= CWX;
3c6ede7b 5277 if (top != XINT (bar->top))
06a2c219 5278 mask |= CWY;
3c6ede7b 5279 if (sb_width != XINT (bar->width))
06a2c219 5280 mask |= CWWidth;
7d0393cf 5281 if (height != XINT (bar->height))
06a2c219 5282 mask |= CWHeight;
7d0393cf 5283
06a2c219 5284#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9 5285
06a2c219
GM
5286 /* Move/size the scroll bar widget. */
5287 if (mask)
13fcb889
KS
5288 {
5289 /* Since toolkit scroll bars are smaller than the space reserved
5290 for them on the frame, we have to clear "under" them. */
5291 if (width > 0 && height > 0)
5292 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5293 left, top, width, height, False);
6bd8015d
JD
5294#ifdef USE_GTK
5295 xg_update_scrollbar_pos (f,
5296 SCROLL_BAR_X_WINDOW (bar),
5297 top,
5298 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
5299 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM *2,
5300 max (height, 1));
5301#else /* not USE_GTK */
488dd4c4
JD
5302 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
5303 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
5304 top,
5305 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
5306 max (height, 1), 0);
488dd4c4 5307#endif /* not USE_GTK */
6bd8015d 5308 }
06a2c219 5309#else /* not USE_TOOLKIT_SCROLL_BARS */
7d0393cf 5310
357e7376
GM
5311 /* Clear areas not covered by the scroll bar because of
5312 VERTICAL_SCROLL_BAR_WIDTH_TRIM. */
e1f6572f
RS
5313 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
5314 {
c5e6e06b
GM
5315 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5316 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
5317 height, False);
5318 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5319 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
5320 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
5321 height, False);
e1f6572f 5322 }
357e7376
GM
5323
5324 /* Clear areas not covered by the scroll bar because it's not as
f7ccf929 5325 wide as the area reserved for it. This makes sure a
357e7376
GM
5326 previous mode line display is cleared after C-x 2 C-x 1, for
5327 example. */
5328 {
0899d58c 5329 int area_width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
357e7376 5330 int rest = area_width - sb_width;
38d2af0c
GM
5331 if (rest > 0 && height > 0)
5332 {
0899d58c 5333 if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
38d2af0c
GM
5334 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5335 left + area_width - rest, top,
5336 rest, height, False);
5337 else
5338 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5339 left, top, rest, height, False);
5340 }
357e7376 5341 }
7d0393cf 5342
06a2c219
GM
5343 /* Move/size the scroll bar window. */
5344 if (mask)
5345 {
5346 XWindowChanges wc;
7d0393cf 5347
3c6ede7b
GM
5348 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5349 wc.y = top;
5350 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
5351 wc.height = height;
06a2c219
GM
5352 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
5353 mask, &wc);
5354 }
7d0393cf 5355
06a2c219
GM
5356#endif /* not USE_TOOLKIT_SCROLL_BARS */
5357
5358 /* Remember new settings. */
3c6ede7b
GM
5359 XSETINT (bar->left, sb_left);
5360 XSETINT (bar->top, top);
5361 XSETINT (bar->width, sb_width);
5362 XSETINT (bar->height, height);
7d0393cf 5363
06a2c219 5364 UNBLOCK_INPUT;
12ba150f 5365 }
f451eb13 5366
eccc05db 5367#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
5368 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
5369#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 5370 /* Set the scroll bar's current state, unless we're currently being
f451eb13 5371 dragged. */
12ba150f 5372 if (NILP (bar->dragging))
f451eb13 5373 {
92857db0 5374 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 5375
12ba150f 5376 if (whole == 0)
ab648270 5377 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
5378 else
5379 {
43f868f5
JB
5380 int start = ((double) position * top_range) / whole;
5381 int end = ((double) (position + portion) * top_range) / whole;
ab648270 5382 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 5383 }
f451eb13 5384 }
06a2c219 5385#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 5386
06a2c219 5387 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
5388}
5389
12ba150f 5390
f451eb13 5391/* The following three hooks are used when we're doing a thorough
ab648270 5392 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 5393 are going to be deleted, because keeping track of when windows go
12ba150f
JB
5394 away is a real pain - "Can you say set-window-configuration, boys
5395 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 5396 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 5397 from the fiery pit when we actually redisplay its window. */
f451eb13 5398
ab648270
JB
5399/* Arrange for all scroll bars on FRAME to be removed at the next call
5400 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
5401 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
5402
58769bee 5403static void
ab648270 5404XTcondemn_scroll_bars (frame)
f451eb13
JB
5405 FRAME_PTR frame;
5406{
f9e24cb9
RS
5407 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
5408 while (! NILP (FRAME_SCROLL_BARS (frame)))
5409 {
5410 Lisp_Object bar;
5411 bar = FRAME_SCROLL_BARS (frame);
5412 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
5413 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
5414 XSCROLL_BAR (bar)->prev = Qnil;
5415 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
5416 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
5417 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
5418 }
f451eb13
JB
5419}
5420
fa2dfc30 5421
06a2c219 5422/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 5423 Note that WINDOW isn't necessarily condemned at all. */
fa2dfc30 5424
f451eb13 5425static void
ab648270 5426XTredeem_scroll_bar (window)
12ba150f 5427 struct window *window;
f451eb13 5428{
ab648270 5429 struct scroll_bar *bar;
fa2dfc30 5430 struct frame *f;
12ba150f 5431
ab648270
JB
5432 /* We can't redeem this window's scroll bar if it doesn't have one. */
5433 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
5434 abort ();
5435
ab648270 5436 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
5437
5438 /* Unlink it from the condemned list. */
fa2dfc30
GM
5439 f = XFRAME (WINDOW_FRAME (window));
5440 if (NILP (bar->prev))
5441 {
5442 /* If the prev pointer is nil, it must be the first in one of
5443 the lists. */
5444 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
5445 /* It's not condemned. Everything's fine. */
5446 return;
5447 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
5448 window->vertical_scroll_bar))
5449 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
5450 else
5451 /* If its prev pointer is nil, it must be at the front of
5452 one or the other! */
5453 abort ();
5454 }
5455 else
5456 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f 5457
fa2dfc30
GM
5458 if (! NILP (bar->next))
5459 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 5460
fa2dfc30
GM
5461 bar->next = FRAME_SCROLL_BARS (f);
5462 bar->prev = Qnil;
5463 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
5464 if (! NILP (bar->next))
5465 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13
JB
5466}
5467
ab648270
JB
5468/* Remove all scroll bars on FRAME that haven't been saved since the
5469 last call to `*condemn_scroll_bars_hook'. */
06a2c219 5470
f451eb13 5471static void
ab648270 5472XTjudge_scroll_bars (f)
12ba150f 5473 FRAME_PTR f;
f451eb13 5474{
12ba150f 5475 Lisp_Object bar, next;
f451eb13 5476
ab648270 5477 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
5478
5479 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
5480 more events on the hapless scroll bars. */
5481 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
5482
5483 for (; ! NILP (bar); bar = next)
f451eb13 5484 {
ab648270 5485 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 5486
ab648270 5487 x_scroll_bar_remove (b);
12ba150f
JB
5488
5489 next = b->next;
5490 b->next = b->prev = Qnil;
f451eb13 5491 }
12ba150f 5492
ab648270 5493 /* Now there should be no references to the condemned scroll bars,
12ba150f 5494 and they should get garbage-collected. */
f451eb13
JB
5495}
5496
5497
3c671a56 5498#ifndef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
5499/* Handle an Expose or GraphicsExpose event on a scroll bar. This
5500 is a no-op when using toolkit scroll bars.
ab648270
JB
5501
5502 This may be called from a signal handler, so we have to ignore GC
5503 mark bits. */
06a2c219 5504
f451eb13 5505static void
ab648270
JB
5506x_scroll_bar_expose (bar, event)
5507 struct scroll_bar *bar;
f451eb13
JB
5508 XEvent *event;
5509{
ab648270 5510 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 5511 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 5512 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 5513 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 5514
f451eb13
JB
5515 BLOCK_INPUT;
5516
ab648270 5517 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 5518
06a2c219 5519 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 5520 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
5521
5522 /* x, y, width, height */
d9cdbb3d 5523 0, 0,
3cbd2e0b 5524 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d 5525 XINT (bar->height) - 1);
7d0393cf 5526
f451eb13 5527 UNBLOCK_INPUT;
06a2c219 5528
f451eb13 5529}
3c671a56 5530#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 5531
ab648270 5532/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
3b8f9651 5533 is set to something other than NO_EVENT, it is enqueued.
ab648270
JB
5534
5535 This may be called from a signal handler, so we have to ignore GC
5536 mark bits. */
06a2c219 5537
5c187dee 5538
f451eb13 5539static void
ab648270
JB
5540x_scroll_bar_handle_click (bar, event, emacs_event)
5541 struct scroll_bar *bar;
f451eb13
JB
5542 XEvent *event;
5543 struct input_event *emacs_event;
5544{
0299d313 5545 if (! GC_WINDOWP (bar->window))
12ba150f
JB
5546 abort ();
5547
3b8f9651 5548 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
69388238 5549 emacs_event->code = event->xbutton.button - Button1;
0299d313 5550 emacs_event->modifiers
7d0393cf 5551 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
0299d313
RS
5552 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
5553 event->xbutton.state)
5554 | (event->type == ButtonRelease
5555 ? up_modifier
5556 : down_modifier));
12ba150f 5557 emacs_event->frame_or_window = bar->window;
0f8aabe9 5558 emacs_event->arg = Qnil;
f451eb13 5559 emacs_event->timestamp = event->xbutton.time;
12ba150f 5560 {
06a2c219 5561#if 0
d9cdbb3d 5562 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 5563 int internal_height
d9cdbb3d 5564 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 5565#endif
0299d313 5566 int top_range
d9cdbb3d 5567 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 5568 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
5569
5570 if (y < 0) y = 0;
5571 if (y > top_range) y = top_range;
5572
5573 if (y < XINT (bar->start))
ab648270
JB
5574 emacs_event->part = scroll_bar_above_handle;
5575 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
5576 emacs_event->part = scroll_bar_handle;
12ba150f 5577 else
ab648270 5578 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
5579
5580 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
5581 they want to drag it. Lisp code needs to be able to decide
5582 whether or not we're dragging. */
929787e1 5583#if 0
12ba150f
JB
5584 /* If the user has just clicked on the handle, record where they're
5585 holding it. */
5586 if (event->type == ButtonPress
ab648270 5587 && emacs_event->part == scroll_bar_handle)
e0c1aef2 5588 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 5589#endif
12ba150f 5590
257f40f2 5591#ifndef USE_TOOLKIT_SCROLL_BARS
12ba150f
JB
5592 /* If the user has released the handle, set it to its final position. */
5593 if (event->type == ButtonRelease
5594 && ! NILP (bar->dragging))
5595 {
5596 int new_start = y - XINT (bar->dragging);
5597 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 5598
ab648270 5599 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
5600 bar->dragging = Qnil;
5601 }
257f40f2 5602#endif
f451eb13 5603
5116f055
JB
5604 /* Same deal here as the other #if 0. */
5605#if 0
58769bee 5606 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 5607 the handle. */
ab648270 5608 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
5609 emacs_event->x = bar->start;
5610 else
e0c1aef2 5611 XSETINT (emacs_event->x, y);
5116f055 5612#else
e0c1aef2 5613 XSETINT (emacs_event->x, y);
5116f055 5614#endif
f451eb13 5615
e0c1aef2 5616 XSETINT (emacs_event->y, top_range);
12ba150f
JB
5617 }
5618}
f451eb13 5619
257f40f2
JD
5620#ifndef USE_TOOLKIT_SCROLL_BARS
5621
ab648270
JB
5622/* Handle some mouse motion while someone is dragging the scroll bar.
5623
5624 This may be called from a signal handler, so we have to ignore GC
5625 mark bits. */
06a2c219 5626
f451eb13 5627static void
ab648270
JB
5628x_scroll_bar_note_movement (bar, event)
5629 struct scroll_bar *bar;
f451eb13
JB
5630 XEvent *event;
5631{
39d8bb4d
KH
5632 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
5633
f451eb13
JB
5634 last_mouse_movement_time = event->xmotion.time;
5635
39d8bb4d 5636 f->mouse_moved = 1;
e0c1aef2 5637 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
5638
5639 /* If we're dragging the bar, display it. */
ab648270 5640 if (! GC_NILP (bar->dragging))
f451eb13
JB
5641 {
5642 /* Where should the handle be now? */
12ba150f 5643 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 5644
12ba150f 5645 if (new_start != XINT (bar->start))
f451eb13 5646 {
12ba150f 5647 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 5648
ab648270 5649 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
5650 }
5651 }
f451eb13
JB
5652}
5653
5c187dee
GM
5654#endif /* !USE_TOOLKIT_SCROLL_BARS */
5655
12ba150f 5656/* Return information to the user about the current position of the mouse
ab648270 5657 on the scroll bar. */
06a2c219 5658
12ba150f 5659static void
334208b7
RS
5660x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
5661 FRAME_PTR *fp;
12ba150f 5662 Lisp_Object *bar_window;
ab648270 5663 enum scroll_bar_part *part;
12ba150f
JB
5664 Lisp_Object *x, *y;
5665 unsigned long *time;
5666{
ab648270 5667 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
5668 Window w = SCROLL_BAR_X_WINDOW (bar);
5669 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 5670 int win_x, win_y;
559cb2fb
JB
5671 Window dummy_window;
5672 int dummy_coord;
5673 unsigned int dummy_mask;
12ba150f 5674
cf7cb199
JB
5675 BLOCK_INPUT;
5676
ab648270 5677 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 5678 report that. */
334208b7 5679 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 5680
559cb2fb
JB
5681 /* Root, child, root x and root y. */
5682 &dummy_window, &dummy_window,
5683 &dummy_coord, &dummy_coord,
12ba150f 5684
559cb2fb
JB
5685 /* Position relative to scroll bar. */
5686 &win_x, &win_y,
12ba150f 5687
559cb2fb
JB
5688 /* Mouse buttons and modifier keys. */
5689 &dummy_mask))
7a13e894 5690 ;
559cb2fb
JB
5691 else
5692 {
06a2c219 5693#if 0
559cb2fb 5694 int inside_height
d9cdbb3d 5695 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 5696#endif
559cb2fb 5697 int top_range
d9cdbb3d 5698 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
5699
5700 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
5701
5702 if (! NILP (bar->dragging))
5703 win_y -= XINT (bar->dragging);
5704
5705 if (win_y < 0)
5706 win_y = 0;
5707 if (win_y > top_range)
5708 win_y = top_range;
5709
334208b7 5710 *fp = f;
7a13e894 5711 *bar_window = bar->window;
559cb2fb
JB
5712
5713 if (! NILP (bar->dragging))
5714 *part = scroll_bar_handle;
5715 else if (win_y < XINT (bar->start))
5716 *part = scroll_bar_above_handle;
5717 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
5718 *part = scroll_bar_handle;
5719 else
5720 *part = scroll_bar_below_handle;
12ba150f 5721
e0c1aef2
KH
5722 XSETINT (*x, win_y);
5723 XSETINT (*y, top_range);
12ba150f 5724
39d8bb4d 5725 f->mouse_moved = 0;
559cb2fb
JB
5726 last_mouse_scroll_bar = Qnil;
5727 }
12ba150f 5728
559cb2fb 5729 *time = last_mouse_movement_time;
cf7cb199 5730
cf7cb199 5731 UNBLOCK_INPUT;
12ba150f
JB
5732}
5733
f451eb13 5734
dbc4e1c1 5735/* The screen has been cleared so we may have changed foreground or
ab648270
JB
5736 background colors, and the scroll bars may need to be redrawn.
5737 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
5738 redraw them. */
5739
dfcf069d 5740void
ab648270 5741x_scroll_bar_clear (f)
dbc4e1c1
JB
5742 FRAME_PTR f;
5743{
06a2c219 5744#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
5745 Lisp_Object bar;
5746
b80c363e
RS
5747 /* We can have scroll bars even if this is 0,
5748 if we just turned off scroll bar mode.
5749 But in that case we should not clear them. */
5750 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5751 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
5752 bar = XSCROLL_BAR (bar)->next)
c5e6e06b
GM
5753 XClearArea (FRAME_X_DISPLAY (f),
5754 SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
b80c363e 5755 0, 0, 0, 0, True);
06a2c219 5756#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
5757}
5758
09756a85 5759\f
f451eb13 5760/* The main X event-reading loop - XTread_socket. */
dc6f92b8 5761
042c33d3 5762#if 0
06a2c219 5763/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
5764 but we have to put it out here, since static variables within functions
5765 sometimes don't work. */
06a2c219 5766
dc6f92b8 5767static Time enter_timestamp;
042c33d3 5768#endif
dc6f92b8 5769
11edeb03 5770/* This holds the state XLookupString needs to implement dead keys
58769bee 5771 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
5772 says that a portable program can't use this, but Stephen Gildea assures
5773 me that letting the compiler initialize it to zeros will work okay.
5774
5775 This must be defined outside of XTread_socket, for the same reasons
f7d40b3b 5776 given for enter_timestamp, above. */
06a2c219 5777
11edeb03
JB
5778static XComposeStatus compose_status;
5779
10e6549c
RS
5780/* Record the last 100 characters stored
5781 to help debug the loss-of-chars-during-GC problem. */
06a2c219 5782
2224b905
RS
5783static int temp_index;
5784static short temp_buffer[100];
10e6549c 5785
6b61353c
KH
5786#define STORE_KEYSYM_FOR_DEBUG(keysym) \
5787 if (temp_index == sizeof temp_buffer / sizeof (short)) \
5788 temp_index = 0; \
5789 temp_buffer[temp_index++] = (keysym)
5790
7a13e894
RS
5791/* Set this to nonzero to fake an "X I/O error"
5792 on a particular display. */
06a2c219 5793
7a13e894
RS
5794struct x_display_info *XTread_socket_fake_io_error;
5795
2224b905
RS
5796/* When we find no input here, we occasionally do a no-op command
5797 to verify that the X server is still running and we can still talk with it.
5798 We try all the open displays, one by one.
5799 This variable is used for cycling thru the displays. */
06a2c219 5800
2224b905
RS
5801static struct x_display_info *next_noop_dpyinfo;
5802
06a2c219
GM
5803#define SET_SAVED_MENU_EVENT(size) \
5804 do \
5805 { \
5806 if (f->output_data.x->saved_menu_event == 0) \
5807 f->output_data.x->saved_menu_event \
5808 = (XEvent *) xmalloc (sizeof (XEvent)); \
5809 bcopy (&event, f->output_data.x->saved_menu_event, size); \
9b516537
AS
5810 inev.ie.kind = MENU_BAR_ACTIVATE_EVENT; \
5811 XSETFRAME (inev.ie.frame_or_window, f); \
06a2c219
GM
5812 } \
5813 while (0)
5814
8805890a 5815#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 5816#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 5817
dc6f92b8 5818
bf338245
JD
5819enum
5820{
5821 X_EVENT_NORMAL,
5822 X_EVENT_GOTO_OUT,
5823 X_EVENT_DROP
5824};
dc6f92b8 5825
1fcfb866
JD
5826/* Filter events for the current X input method.
5827 DPYINFO is the display this event is for.
5828 EVENT is the X event to filter.
5829
5830 Returns non-zero if the event was filtered, caller shall not process
5831 this event further.
5832 Returns zero if event is wasn't filtered. */
177c0ea7 5833
1fcfb866
JD
5834#ifdef HAVE_X_I18N
5835static int
5836x_filter_event (dpyinfo, event)
5837 struct x_display_info *dpyinfo;
5838 XEvent *event;
5839{
5840 /* XFilterEvent returns non-zero if the input method has
5841 consumed the event. We pass the frame's X window to
5842 XFilterEvent because that's the one for which the IC
5843 was created. */
5844
5845 struct frame *f1 = x_any_window_to_frame (dpyinfo,
5846 event->xclient.window);
5847
5848 return XFilterEvent (event, f1 ? FRAME_X_WINDOW (f1) : None);
5849}
5850#endif
5851
488dd4c4 5852#ifdef USE_GTK
488dd4c4
JD
5853static int current_count;
5854static int current_finish;
6b61353c 5855static struct input_event *current_hold_quit;
488dd4c4
JD
5856
5857/* This is the filter function invoked by the GTK event loop.
5858 It is invoked before the XEvent is translated to a GdkEvent,
6b61353c 5859 so we have a chance to act on the event before GTK. */
488dd4c4
JD
5860static GdkFilterReturn
5861event_handler_gdk (gxev, ev, data)
5862 GdkXEvent *gxev;
5863 GdkEvent *ev;
5864 gpointer data;
5865{
6b61353c 5866 XEvent *xev = (XEvent *) gxev;
488dd4c4 5867
6b61353c 5868 if (current_count >= 0)
1fcfb866 5869 {
6b61353c
KH
5870 struct x_display_info *dpyinfo;
5871
5872 dpyinfo = x_display_info_for_display (xev->xany.display);
5873
1fcfb866
JD
5874#ifdef HAVE_X_I18N
5875 /* Filter events for the current X input method.
5876 GTK calls XFilterEvent but not for key press and release,
5877 so we do it here. */
5878 if (xev->type == KeyPress || xev->type == KeyRelease)
6b61353c 5879 if (dpyinfo && x_filter_event (dpyinfo, xev))
1fcfb866
JD
5880 return GDK_FILTER_REMOVE;
5881#endif
6b61353c
KH
5882
5883 if (! dpyinfo)
5884 current_finish = X_EVENT_NORMAL;
5885 else
5886 {
5887 current_count +=
5888 handle_one_xevent (dpyinfo, xev, &current_finish,
5889 current_hold_quit);
5890 }
1fcfb866 5891 }
488dd4c4 5892 else
6b61353c 5893 current_finish = x_dispatch_event (xev, xev->xany.display);
488dd4c4
JD
5894
5895 if (current_finish == X_EVENT_GOTO_OUT || current_finish == X_EVENT_DROP)
5896 return GDK_FILTER_REMOVE;
5897
5898 return GDK_FILTER_CONTINUE;
5899}
5900#endif /* USE_GTK */
5901
5902
bf338245 5903/* Handles the XEvent EVENT on display DPYINFO.
177c0ea7 5904
bf338245
JD
5905 *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events.
5906 *FINISH is zero if caller should continue reading events.
5907 *FINISH is X_EVENT_DROP if event should not be passed to the toolkit.
5908
bf338245 5909 We return the number of characters stored into the buffer. */
177c0ea7 5910
6f2a7a68 5911static int
6b61353c 5912handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
bf338245
JD
5913 struct x_display_info *dpyinfo;
5914 XEvent *eventp;
bf338245 5915 int *finish;
6b61353c 5916 struct input_event *hold_quit;
dc6f92b8 5917{
9b516537
AS
5918 union {
5919 struct input_event ie;
5920 struct selection_input_event sie;
5921 } inev;
dc6f92b8 5922 int count = 0;
6b61353c 5923 int do_help = 0;
dc6f92b8 5924 int nbytes = 0;
f676886a 5925 struct frame *f;
379b5ac0 5926 struct coding_system coding;
bf338245 5927 XEvent event = *eventp;
dc6f92b8 5928
bf338245 5929 *finish = X_EVENT_NORMAL;
177c0ea7 5930
9b516537
AS
5931 EVENT_INIT (inev.ie);
5932 inev.ie.kind = NO_EVENT;
5933 inev.ie.arg = Qnil;
6b61353c 5934
bf338245 5935 switch (event.type)
7a13e894 5936 {
bf338245
JD
5937 case ClientMessage:
5938 {
5939 if (event.xclient.message_type
5940 == dpyinfo->Xatom_wm_protocols
5941 && event.xclient.format == 32)
5942 {
5943 if (event.xclient.data.l[0]
5944 == dpyinfo->Xatom_wm_take_focus)
5945 {
5946 /* Use x_any_window_to_frame because this
5947 could be the shell widget window
5948 if the frame has no title bar. */
5949 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5 5950#ifdef HAVE_X_I18N
bf338245
JD
5951 /* Not quite sure this is needed -pd */
5952 if (f && FRAME_XIC (f))
5953 XSetICFocus (FRAME_XIC (f));
6c183ba5 5954#endif
f1da8f06
GM
5955#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
5956 instructs the WM to set the input focus automatically for
5957 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
5958 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
5959 it has set the focus. So, XSetInputFocus below is not
5960 needed.
5961
5962 The call to XSetInputFocus below has also caused trouble. In
5963 cases where the XSetInputFocus done by the WM and the one
5964 below are temporally close (on a fast machine), the call
5965 below can generate additional FocusIn events which confuse
5966 Emacs. */
7d0393cf 5967
bf338245
JD
5968 /* Since we set WM_TAKE_FOCUS, we must call
5969 XSetInputFocus explicitly. But not if f is null,
5970 since that might be an event for a deleted frame. */
5971 if (f)
5972 {
5973 Display *d = event.xclient.display;
5974 /* Catch and ignore errors, in case window has been
5975 iconified by a window manager such as GWM. */
9ba8e10d 5976 x_catch_errors (d);
bf338245
JD
5977 XSetInputFocus (d, event.xclient.window,
5978 /* The ICCCM says this is
5979 the only valid choice. */
5980 RevertToParent,
5981 event.xclient.data.l[1]);
5982 /* This is needed to detect the error
5983 if there is an error. */
5984 XSync (d, False);
4545fa20 5985 x_uncatch_errors ();
bf338245
JD
5986 }
5987 /* Not certain about handling scroll bars here */
f1da8f06 5988#endif /* 0 */
6b61353c 5989 goto done;
bf338245 5990 }
6b61353c
KH
5991
5992 if (event.xclient.data.l[0]
bf338245
JD
5993 == dpyinfo->Xatom_wm_save_yourself)
5994 {
5995 /* Save state modify the WM_COMMAND property to
5996 something which can reinstate us. This notifies
5997 the session manager, who's looking for such a
5998 PropertyNotify. Can restart processing when
5999 a keyboard or mouse event arrives. */
6000 /* If we have a session manager, don't set this.
6001 KDE will then start two Emacsen, one for the
6002 session manager and one for this. */
5f30b957 6003#ifdef HAVE_X_SM
6b61353c 6004 if (! x_session_have_connection ())
5f30b957 6005#endif
bf338245
JD
6006 {
6007 f = x_top_window_to_frame (dpyinfo,
6008 event.xclient.window);
6009 /* This is just so we only give real data once
6010 for a single Emacs process. */
6011 if (f == SELECTED_FRAME ())
6012 XSetCommand (FRAME_X_DISPLAY (f),
6013 event.xclient.window,
6014 initial_argv, initial_argc);
6015 else if (f)
6016 XSetCommand (FRAME_X_DISPLAY (f),
6017 event.xclient.window,
6018 0, 0);
6019 }
6b61353c 6020 goto done;
bf338245 6021 }
6b61353c
KH
6022
6023 if (event.xclient.data.l[0]
6024 == dpyinfo->Xatom_wm_delete_window)
bf338245 6025 {
6b61353c 6026 f = x_any_window_to_frame (dpyinfo,
bf338245 6027 event.xclient.window);
6b61353c
KH
6028 if (!f)
6029 goto OTHER; /* May be a dialog that is to be removed */
7a13e894 6030
9b516537
AS
6031 inev.ie.kind = DELETE_WINDOW_EVENT;
6032 XSETFRAME (inev.ie.frame_or_window, f);
6b61353c 6033 goto done;
bf338245 6034 }
6b61353c
KH
6035
6036 goto done;
bf338245 6037 }
6b61353c
KH
6038
6039 if (event.xclient.message_type
bf338245
JD
6040 == dpyinfo->Xatom_wm_configure_denied)
6041 {
6b61353c 6042 goto done;
bf338245 6043 }
6b61353c
KH
6044
6045 if (event.xclient.message_type
6046 == dpyinfo->Xatom_wm_window_moved)
bf338245
JD
6047 {
6048 int new_x, new_y;
6b61353c 6049 f = x_window_to_frame (dpyinfo, event.xclient.window);
bf338245
JD
6050
6051 new_x = event.xclient.data.s[0];
6052 new_y = event.xclient.data.s[1];
6053
6054 if (f)
6055 {
0899d58c
KS
6056 f->left_pos = new_x;
6057 f->top_pos = new_y;
bf338245 6058 }
6b61353c 6059 goto done;
bf338245 6060 }
6b61353c 6061
0fdff6bb 6062#ifdef HACK_EDITRES
6b61353c
KH
6063 if (event.xclient.message_type
6064 == dpyinfo->Xatom_editres)
bf338245 6065 {
6b61353c 6066 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
79fb0ab7
JD
6067 if (f)
6068 _XEditResCheckMessages (f->output_data.x->widget, NULL,
6069 &event, NULL);
6b61353c 6070 goto done;
bf338245 6071 }
0fdff6bb 6072#endif /* HACK_EDITRES */
6b61353c
KH
6073
6074 if ((event.xclient.message_type
6075 == dpyinfo->Xatom_DONE)
6076 || (event.xclient.message_type
6077 == dpyinfo->Xatom_PAGE))
bf338245
JD
6078 {
6079 /* Ghostview job completed. Kill it. We could
6080 reply with "Next" if we received "Page", but we
6081 currently never do because we are interested in
6082 images, only, which should have 1 page. */
6083 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
6b61353c 6084 f = x_window_to_frame (dpyinfo, event.xclient.window);
fb6341e7
KS
6085 if (!f)
6086 goto OTHER;
bf338245
JD
6087 x_kill_gs_process (pixmap, f);
6088 expose_frame (f, 0, 0, 0, 0);
6b61353c 6089 goto done;
bf338245 6090 }
6b61353c 6091
06a2c219 6092#ifdef USE_TOOLKIT_SCROLL_BARS
bf338245
JD
6093 /* Scroll bar callbacks send a ClientMessage from which
6094 we construct an input_event. */
6b61353c
KH
6095 if (event.xclient.message_type
6096 == dpyinfo->Xatom_Scrollbar)
bf338245 6097 {
9b516537 6098 x_scroll_bar_to_input_event (&event, &inev.ie);
6b61353c
KH
6099 *finish = X_EVENT_GOTO_OUT;
6100 goto done;
bf338245 6101 }
06a2c219 6102#endif /* USE_TOOLKIT_SCROLL_BARS */
6b61353c
KH
6103
6104 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6b61353c
KH
6105 if (!f)
6106 goto OTHER;
9b516537 6107 if (x_handle_dnd_message (f, &event.xclient, dpyinfo, &inev.ie))
6b61353c 6108 *finish = X_EVENT_DROP;
bf338245
JD
6109 }
6110 break;
dc6f92b8 6111
bf338245 6112 case SelectionNotify:
3afe33e7 6113#ifdef USE_X_TOOLKIT
bf338245
JD
6114 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
6115 goto OTHER;
3afe33e7 6116#endif /* not USE_X_TOOLKIT */
bf338245
JD
6117 x_handle_selection_notify (&event.xselection);
6118 break;
d56a553a 6119
bf338245 6120 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 6121#ifdef USE_X_TOOLKIT
bf338245
JD
6122 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
6123 goto OTHER;
3afe33e7 6124#endif /* USE_X_TOOLKIT */
bf338245
JD
6125 {
6126 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 6127
9b516537
AS
6128 inev.ie.kind = SELECTION_CLEAR_EVENT;
6129 SELECTION_EVENT_DISPLAY (&inev.sie) = eventp->display;
6130 SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
6131 SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
6132 inev.ie.frame_or_window = Qnil;
bf338245
JD
6133 }
6134 break;
dc6f92b8 6135
bf338245 6136 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 6137#ifdef USE_X_TOOLKIT
bf338245
JD
6138 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
6139 goto OTHER;
3afe33e7 6140#endif /* USE_X_TOOLKIT */
958f04e8 6141 {
bf338245
JD
6142 XSelectionRequestEvent *eventp
6143 = (XSelectionRequestEvent *) &event;
6144
9b516537
AS
6145 inev.ie.kind = SELECTION_REQUEST_EVENT;
6146 SELECTION_EVENT_DISPLAY (&inev.sie) = eventp->display;
6147 SELECTION_EVENT_REQUESTOR (&inev.sie) = eventp->requestor;
6148 SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
6149 SELECTION_EVENT_TARGET (&inev.sie) = eventp->target;
6150 SELECTION_EVENT_PROPERTY (&inev.sie) = eventp->property;
6151 SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
6152 inev.ie.frame_or_window = Qnil;
958f04e8 6153 }
bf338245 6154 break;
7a13e894 6155
bf338245 6156 case PropertyNotify:
1d2b2268
GM
6157#if 0 /* This is plain wrong. In the case that we are waiting for a
6158 PropertyNotify used as an ACK in incremental selection
6159 transfer, the property will be on the receiver's window. */
6160#if defined USE_X_TOOLKIT
bf338245
JD
6161 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
6162 goto OTHER;
1d2b2268
GM
6163#endif
6164#endif
bf338245
JD
6165 x_handle_property_notify (&event.xproperty);
6166 goto OTHER;
dc6f92b8 6167
bf338245
JD
6168 case ReparentNotify:
6169 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
6170 if (f)
6171 {
6172 int x, y;
6173 f->output_data.x->parent_desc = event.xreparent.parent;
6174 x_real_positions (f, &x, &y);
0899d58c
KS
6175 f->left_pos = x;
6176 f->top_pos = y;
6b61353c
KH
6177
6178 /* Perhaps reparented due to a WM restart. Reset this. */
6179 FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN;
bf338245 6180 }
15213141 6181 goto OTHER;
3bd330d4 6182
bf338245
JD
6183 case Expose:
6184 f = x_window_to_frame (dpyinfo, event.xexpose.window);
6185 if (f)
6186 {
6187 x_check_fullscreen (f);
d0fa3e56 6188
42d02da0
JD
6189#ifdef USE_GTK
6190 /* This seems to be needed for GTK 2.6. */
6191 x_clear_area (event.xexpose.display,
6192 event.xexpose.window,
6193 event.xexpose.x, event.xexpose.y,
6194 event.xexpose.width, event.xexpose.height,
6195 FALSE);
6196#endif
bf338245
JD
6197 if (f->async_visible == 0)
6198 {
6199 f->async_visible = 1;
6200 f->async_iconified = 0;
6201 f->output_data.x->has_been_visible = 1;
6202 SET_FRAME_GARBAGED (f);
6203 }
6204 else
0899d58c
KS
6205 expose_frame (f,
6206 event.xexpose.x, event.xexpose.y,
bf338245
JD
6207 event.xexpose.width, event.xexpose.height);
6208 }
6209 else
6210 {
12949a7f 6211#ifndef USE_TOOLKIT_SCROLL_BARS
bf338245 6212 struct scroll_bar *bar;
12949a7f 6213#endif
01f67d2c 6214#if defined USE_LUCID
bf338245
JD
6215 /* Submenus of the Lucid menu bar aren't widgets
6216 themselves, so there's no way to dispatch events
6217 to them. Recognize this case separately. */
6218 {
6219 Widget widget
6220 = x_window_to_menu_bar (event.xexpose.window);
6221 if (widget)
6222 xlwmenu_redisplay (widget);
6223 }
01f67d2c
PJ
6224#endif /* USE_LUCID */
6225
06a2c219 6226#ifdef USE_TOOLKIT_SCROLL_BARS
bf338245
JD
6227 /* Dispatch event to the widget. */
6228 goto OTHER;
06a2c219 6229#else /* not USE_TOOLKIT_SCROLL_BARS */
6b61353c
KH
6230 bar = x_window_to_scroll_bar (event.xexpose.display,
6231 event.xexpose.window);
58769bee 6232
bf338245
JD
6233 if (bar)
6234 x_scroll_bar_expose (bar, &event);
3afe33e7 6235#ifdef USE_X_TOOLKIT
bf338245
JD
6236 else
6237 goto OTHER;
3afe33e7 6238#endif /* USE_X_TOOLKIT */
06a2c219 6239#endif /* not USE_TOOLKIT_SCROLL_BARS */
bf338245
JD
6240 }
6241 break;
dc6f92b8 6242
bf338245
JD
6243 case GraphicsExpose: /* This occurs when an XCopyArea's
6244 source area was obscured or not
6245 available. */
6246 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
6247 if (f)
6248 {
6249 expose_frame (f,
6250 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
6251 event.xgraphicsexpose.width,
6252 event.xgraphicsexpose.height);
6253 }
3afe33e7 6254#ifdef USE_X_TOOLKIT
bf338245
JD
6255 else
6256 goto OTHER;
3afe33e7 6257#endif /* USE_X_TOOLKIT */
bf338245 6258 break;
7d0393cf 6259
bf338245
JD
6260 case NoExpose: /* This occurs when an XCopyArea's
6261 source area was completely
6262 available. */
6263 break;
dc6f92b8 6264
bf338245
JD
6265 case UnmapNotify:
6266 /* Redo the mouse-highlight after the tooltip has gone. */
6267 if (event.xmap.window == tip_window)
6268 {
6269 tip_window = 0;
6270 redo_mouse_highlight ();
6271 }
bddd097c 6272
bf338245
JD
6273 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
6274 if (f) /* F may no longer exist if
6275 the frame was deleted. */
6276 {
6277 /* While a frame is unmapped, display generation is
6278 disabled; you don't want to spend time updating a
6279 display that won't ever be seen. */
6280 f->async_visible = 0;
6281 /* We can't distinguish, from the event, whether the window
6282 has become iconified or invisible. So assume, if it
6283 was previously visible, than now it is iconified.
6284 But x_make_frame_invisible clears both
6285 the visible flag and the iconified flag;
6286 and that way, we know the window is not iconified now. */
6287 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
6288 {
6289 f->async_iconified = 1;
dc6f92b8 6290
9b516537
AS
6291 inev.ie.kind = ICONIFY_EVENT;
6292 XSETFRAME (inev.ie.frame_or_window, f);
bf338245
JD
6293 }
6294 }
6295 goto OTHER;
6296
6297 case MapNotify:
6298 if (event.xmap.window == tip_window)
6299 /* The tooltip has been drawn already. Avoid
6300 the SET_FRAME_GARBAGED below. */
6301 goto OTHER;
6302
6303 /* We use x_top_window_to_frame because map events can
6304 come for sub-windows and they don't mean that the
6305 frame is visible. */
6306 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
6307 if (f)
6308 {
d64b707c 6309 /* wait_reading_process_output will notice this and update
bf338245
JD
6310 the frame's display structures.
6311 If we where iconified, we should not set garbaged,
6312 because that stops redrawing on Expose events. This looks
6313 bad if we are called from a recursive event loop
6314 (x_dispatch_event), for example when a dialog is up. */
6315 if (! f->async_iconified)
6316 SET_FRAME_GARBAGED (f);
6317
6318 f->async_visible = 1;
6319 f->async_iconified = 0;
6320 f->output_data.x->has_been_visible = 1;
6321
6322 if (f->iconified)
6323 {
9b516537
AS
6324 inev.ie.kind = DEICONIFY_EVENT;
6325 XSETFRAME (inev.ie.frame_or_window, f);
bf338245
JD
6326 }
6327 else if (! NILP (Vframe_list)
6328 && ! NILP (XCDR (Vframe_list)))
6329 /* Force a redisplay sooner or later
6330 to update the frame titles
6331 in case this is the second frame. */
6332 record_asynch_buffer_change ();
6333 }
6334 goto OTHER;
2a793c0c 6335
bf338245 6336 case KeyPress:
2a793c0c 6337
6b61353c
KH
6338 ignore_next_mouse_click_timeout = 0;
6339
22174d10 6340#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
bf338245 6341 /* Dispatch KeyPress events when in menu. */
488dd4c4 6342 if (popup_activated ())
bf338245 6343 goto OTHER;
22174d10 6344#endif
488dd4c4 6345
bf338245 6346 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 6347
92daa848
RS
6348 /* If mouse-highlight is an integer, input clears out
6349 mouse highlighting. */
99c60e86 6350 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
295fa1d4
KS
6351 && (f == 0
6352 || !EQ (f->tool_bar_window, dpyinfo->mouse_face_window)))
bf338245 6353 {
bf338245 6354 clear_mouse_face (dpyinfo);
6b61353c 6355 dpyinfo->mouse_face_hidden = 1;
bf338245 6356 }
66301061 6357
eccc05db 6358#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
bf338245
JD
6359 if (f == 0)
6360 {
6361 /* Scroll bars consume key events, but we want
6362 the keys to go to the scroll bar's frame. */
6363 Widget widget = XtWindowToWidget (dpyinfo->display,
6364 event.xkey.window);
6365 if (widget && XmIsScrollBar (widget))
6366 {
6367 widget = XtParent (widget);
6368 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
6369 }
6370 }
eccc05db 6371#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
06a2c219 6372
bf338245
JD
6373 if (f != 0)
6374 {
6375 KeySym keysym, orig_keysym;
6376 /* al%imercury@uunet.uu.net says that making this 81
6377 instead of 80 fixed a bug whereby meta chars made
6378 his Emacs hang.
6379
6380 It seems that some version of XmbLookupString has
6381 a bug of not returning XBufferOverflow in
6382 status_return even if the input is too long to
6383 fit in 81 bytes. So, we must prepare sufficient
6384 bytes for copy_buffer. 513 bytes (256 chars for
6385 two-byte character set) seems to be a fairly good
6386 approximation. -- 2000.8.10 handa@etl.go.jp */
6387 unsigned char copy_buffer[513];
6388 unsigned char *copy_bufptr = copy_buffer;
6389 int copy_bufsiz = sizeof (copy_buffer);
6390 int modifiers;
6391 Lisp_Object coding_system = Qlatin_1;
6b61353c
KH
6392 Lisp_Object c;
6393
6394#ifdef USE_GTK
6395 /* Don't pass keys to GTK. A Tab will shift focus to the
6396 tool bar in GTK 2.4. Keys will still go to menus and
6397 dialogs because in that case popup_activated is TRUE
6398 (see above). */
6399 *finish = X_EVENT_DROP;
6400#endif
bf338245
JD
6401
6402 event.xkey.state
6403 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
6404 extra_keyboard_modifiers);
6405 modifiers = event.xkey.state;
6406
6407 /* This will have to go some day... */
6408
6409 /* make_lispy_event turns chars into control chars.
6410 Don't do it here because XLookupString is too eager. */
6411 event.xkey.state &= ~ControlMask;
6412 event.xkey.state &= ~(dpyinfo->meta_mod_mask
6413 | dpyinfo->super_mod_mask
6414 | dpyinfo->hyper_mod_mask
6415 | dpyinfo->alt_mod_mask);
6416
6417 /* In case Meta is ComposeCharacter,
6418 clear its status. According to Markus Ehrnsperger
6419 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
6420 this enables ComposeCharacter to work whether or
6421 not it is combined with Meta. */
6422 if (modifiers & dpyinfo->meta_mod_mask)
6423 bzero (&compose_status, sizeof (compose_status));
1cf4a0d1 6424
6c183ba5 6425#ifdef HAVE_X_I18N
bf338245
JD
6426 if (FRAME_XIC (f))
6427 {
6428 Status status_return;
6429
6430 coding_system = Vlocale_coding_system;
6431 nbytes = XmbLookupString (FRAME_XIC (f),
6432 &event.xkey, copy_bufptr,
6433 copy_bufsiz, &keysym,
6434 &status_return);
6435 if (status_return == XBufferOverflow)
6436 {
6437 copy_bufsiz = nbytes + 1;
fa8459a3 6438 copy_bufptr = (unsigned char *) alloca (copy_bufsiz);
bf338245
JD
6439 nbytes = XmbLookupString (FRAME_XIC (f),
6440 &event.xkey, copy_bufptr,
6441 copy_bufsiz, &keysym,
6442 &status_return);
6443 }
6444 /* Xutf8LookupString is a new but already deprecated interface. -stef */
96035dca 6445#if 0 && defined X_HAVE_UTF8_STRING
bf338245
JD
6446 else if (status_return == XLookupKeySym)
6447 { /* Try again but with utf-8. */
6448 coding_system = Qutf_8;
6449 nbytes = Xutf8LookupString (FRAME_XIC (f),
6450 &event.xkey, copy_bufptr,
6451 copy_bufsiz, &keysym,
6452 &status_return);
6453 if (status_return == XBufferOverflow)
6454 {
6455 copy_bufsiz = nbytes + 1;
fa8459a3 6456 copy_bufptr = (unsigned char *) alloca (copy_bufsiz);
bf338245
JD
6457 nbytes = Xutf8LookupString (FRAME_XIC (f),
6458 &event.xkey,
6459 copy_bufptr,
6460 copy_bufsiz, &keysym,
6461 &status_return);
6462 }
6463 }
c997eae5 6464#endif
f5d11644 6465
bf338245
JD
6466 if (status_return == XLookupNone)
6467 break;
6468 else if (status_return == XLookupChars)
6469 {
6470 keysym = NoSymbol;
6471 modifiers = 0;
6472 }
6473 else if (status_return != XLookupKeySym
6474 && status_return != XLookupBoth)
6475 abort ();
6476 }
6477 else
6478 nbytes = XLookupString (&event.xkey, copy_bufptr,
6479 copy_bufsiz, &keysym,
6480 &compose_status);
6c183ba5 6481#else
bf338245
JD
6482 nbytes = XLookupString (&event.xkey, copy_bufptr,
6483 copy_bufsiz, &keysym,
6484 &compose_status);
6c183ba5 6485#endif
dc6f92b8 6486
6b61353c
KH
6487 /* If not using XIM/XIC, and a compose sequence is in progress,
6488 we break here. Otherwise, chars_matched is always 0. */
6489 if (compose_status.chars_matched > 0 && nbytes == 0)
6490 break;
6491
a6d0ae55 6492 bzero (&compose_status, sizeof (compose_status));
bf338245 6493 orig_keysym = keysym;
55123275 6494
6b61353c 6495 /* Common for all keysym input events. */
9b516537
AS
6496 XSETFRAME (inev.ie.frame_or_window, f);
6497 inev.ie.modifiers
6b61353c 6498 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), modifiers);
9b516537 6499 inev.ie.timestamp = event.xkey.time;
bf338245 6500
6b61353c
KH
6501 /* First deal with keysyms which have defined
6502 translations to characters. */
6503 if (keysym >= 32 && keysym < 128)
6504 /* Avoid explicitly decoding each ASCII character. */
6505 {
9b516537
AS
6506 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
6507 inev.ie.code = keysym;
6b61353c
KH
6508 goto done_keysym;
6509 }
6510
e5e40bff 6511 /* Keysyms directly mapped to Unicode characters. */
05e9a052 6512 if (keysym >= 0x01000000 && keysym <= 0x0110FFFF)
e5e40bff 6513 {
05e9a052
KH
6514 if (keysym < 0x01000080)
6515 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
6516 else
6517 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
e5e40bff
KH
6518 inev.ie.code = keysym & 0xFFFFFF;
6519 goto done_keysym;
6520 }
6521
6b61353c
KH
6522 /* Now non-ASCII. */
6523 if (HASH_TABLE_P (Vx_keysym_table)
6524 && (NATNUMP (c = Fgethash (make_number (keysym),
6525 Vx_keysym_table,
6526 Qnil))))
6527 {
9b516537
AS
6528 inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c))
6529 ? ASCII_KEYSTROKE_EVENT
6530 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
6531 inev.ie.code = XFASTINT (c);
6b61353c
KH
6532 goto done_keysym;
6533 }
6534
6535 /* Random non-modifier sorts of keysyms. */
6536 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
bf338245 6537 || keysym == XK_Delete
1097aea0 6538#ifdef XK_ISO_Left_Tab
bf338245
JD
6539 || (keysym >= XK_ISO_Left_Tab
6540 && keysym <= XK_ISO_Enter)
1097aea0 6541#endif
bf338245
JD
6542 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
6543 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 6544#ifdef HPUX
bf338245
JD
6545 /* This recognizes the "extended function
6546 keys". It seems there's no cleaner way.
6547 Test IsModifierKey to avoid handling
6548 mode_switch incorrectly. */
6549 || ((unsigned) (keysym) >= XK_Select
6550 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
6551#endif
6552#ifdef XK_dead_circumflex
bf338245 6553 || orig_keysym == XK_dead_circumflex
69388238
RS
6554#endif
6555#ifdef XK_dead_grave
bf338245 6556 || orig_keysym == XK_dead_grave
69388238
RS
6557#endif
6558#ifdef XK_dead_tilde
bf338245 6559 || orig_keysym == XK_dead_tilde
69388238
RS
6560#endif
6561#ifdef XK_dead_diaeresis
bf338245 6562 || orig_keysym == XK_dead_diaeresis
69388238
RS
6563#endif
6564#ifdef XK_dead_macron
bf338245 6565 || orig_keysym == XK_dead_macron
69388238
RS
6566#endif
6567#ifdef XK_dead_degree
bf338245 6568 || orig_keysym == XK_dead_degree
69388238
RS
6569#endif
6570#ifdef XK_dead_acute
bf338245 6571 || orig_keysym == XK_dead_acute
69388238
RS
6572#endif
6573#ifdef XK_dead_cedilla
bf338245 6574 || orig_keysym == XK_dead_cedilla
69388238
RS
6575#endif
6576#ifdef XK_dead_breve
bf338245 6577 || orig_keysym == XK_dead_breve
69388238
RS
6578#endif
6579#ifdef XK_dead_ogonek
bf338245 6580 || orig_keysym == XK_dead_ogonek
69388238
RS
6581#endif
6582#ifdef XK_dead_caron
bf338245 6583 || orig_keysym == XK_dead_caron
69388238
RS
6584#endif
6585#ifdef XK_dead_doubleacute
bf338245 6586 || orig_keysym == XK_dead_doubleacute
69388238
RS
6587#endif
6588#ifdef XK_dead_abovedot
bf338245 6589 || orig_keysym == XK_dead_abovedot
c34790e0 6590#endif
bf338245
JD
6591 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
6592 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
6593 /* Any "vendor-specific" key is ok. */
6594 || (orig_keysym & (1 << 28))
6595 || (keysym != NoSymbol && nbytes == 0))
6596 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
6597#ifndef HAVE_X11R5
6598#ifdef XK_Mode_switch
bf338245 6599 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
6600#endif
6601#ifdef XK_Num_Lock
bf338245 6602 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
6603#endif
6604#endif /* not HAVE_X11R5 */
bf338245
JD
6605 /* The symbols from XK_ISO_Lock
6606 to XK_ISO_Last_Group_Lock
6607 don't have real modifiers but
6608 should be treated similarly to
6609 Mode_switch by Emacs. */
7ef18d79 6610#if defined XK_ISO_Lock && defined XK_ISO_Last_Group_Lock
bf338245
JD
6611 || ((unsigned)(orig_keysym)
6612 >= XK_ISO_Lock
6613 && (unsigned)(orig_keysym)
6614 <= XK_ISO_Last_Group_Lock)
7ef18d79 6615#endif
bf338245 6616 ))
6b61353c
KH
6617 {
6618 STORE_KEYSYM_FOR_DEBUG (keysym);
6619 /* make_lispy_event will convert this to a symbolic
6620 key. */
9b516537
AS
6621 inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
6622 inev.ie.code = keysym;
6b61353c
KH
6623 goto done_keysym;
6624 }
379b5ac0 6625
6b61353c
KH
6626 { /* Raw bytes, not keysym. */
6627 register int i;
6628 register int c;
6629 int nchars, len;
379b5ac0 6630
6b61353c
KH
6631 for (i = 0, nchars = 0; i < nbytes; i++)
6632 {
6633 if (ASCII_BYTE_P (copy_bufptr[i]))
6634 nchars++;
6635 STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]);
6636 }
bf338245 6637
6b61353c
KH
6638 if (nchars < nbytes)
6639 {
6640 /* Decode the input data. */
6641 int require;
6642 unsigned char *p;
6643
6644 /* The input should be decoded with `coding_system'
6645 which depends on which X*LookupString function
6646 we used just above and the locale. */
6647 setup_coding_system (coding_system, &coding);
6648 coding.src_multibyte = 0;
6649 coding.dst_multibyte = 1;
6650 /* The input is converted to events, thus we can't
6651 handle composition. Anyway, there's no XIM that
6652 gives us composition information. */
6653 coding.common_flags &= ~CODING_ANNOTATION_MASK;
6654
6655 require = MAX_MULTIBYTE_LENGTH * nbytes;
6656 coding.destination = alloca (require);
6657 coding.dst_bytes = require;
6658 coding.mode |= CODING_MODE_LAST_BLOCK;
6659 decode_coding_c_string (&coding, copy_bufptr, nbytes, Qnil);
6660 nbytes = coding.produced;
6661 nchars = coding.produced_char;
6662 copy_bufptr = coding.destination;
6663 }
bf338245 6664
6b61353c
KH
6665 /* Convert the input data to a sequence of
6666 character events. */
6667 for (i = 0; i < nbytes; i += len)
6668 {
6669 if (nchars == nbytes)
6670 c = copy_bufptr[i], len = 1;
6671 else
6672 c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
6673 nbytes - i, len);
9b516537 6674 inev.ie.kind = (SINGLE_BYTE_CHAR_P (c)
6b61353c
KH
6675 ? ASCII_KEYSTROKE_EVENT
6676 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
9b516537
AS
6677 inev.ie.code = c;
6678 kbd_buffer_store_event_hold (&inev.ie, hold_quit);
6b61353c
KH
6679 }
6680
6681 /* Previous code updated count by nchars rather than nbytes,
6682 but that seems bogus to me. ++kfs */
6683 count += nbytes;
6684
9b516537 6685 inev.ie.kind = NO_EVENT; /* Already stored above. */
6b61353c
KH
6686
6687 if (keysym == NoSymbol)
6688 break;
6689 }
bf338245 6690 }
6b61353c 6691 done_keysym:
59ddecde 6692#ifdef HAVE_X_I18N
bf338245
JD
6693 /* Don't dispatch this event since XtDispatchEvent calls
6694 XFilterEvent, and two calls in a row may freeze the
6695 client. */
6696 break;
59ddecde 6697#else
bf338245 6698 goto OTHER;
59ddecde 6699#endif
f451eb13 6700
bf338245 6701 case KeyRelease:
59ddecde 6702#ifdef HAVE_X_I18N
bf338245
JD
6703 /* Don't dispatch this event since XtDispatchEvent calls
6704 XFilterEvent, and two calls in a row may freeze the
6705 client. */
6706 break;
59ddecde 6707#else
bf338245 6708 goto OTHER;
59ddecde 6709#endif
f5d11644 6710
bf338245 6711 case EnterNotify:
9b516537 6712 x_detect_focus_change (dpyinfo, &event, &inev.ie);
cab34f50 6713
6b61353c 6714 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
7d0393cf 6715
6b61353c
KH
6716 if (f && x_mouse_click_focus_ignore_position)
6717 ignore_next_mouse_click_timeout = event.xmotion.time + 200;
06a2c219 6718
2c850e26 6719#if 0
6b61353c
KH
6720 if (event.xcrossing.focus)
6721 {
6722 /* Avoid nasty pop/raise loops. */
6723 if (f && (!(f->auto_raise)
6724 || !(f->auto_lower)
6725 || (event.xcrossing.time - enter_timestamp) > 500))
6726 {
6727 x_new_focus_frame (dpyinfo, f);
6728 enter_timestamp = event.xcrossing.time;
6729 }
6730 }
6731 else if (f == dpyinfo->x_focus_frame)
6732 x_new_focus_frame (dpyinfo, 0);
bf338245 6733#endif
f9e24cb9 6734
6b61353c
KH
6735 /* EnterNotify counts as mouse movement,
6736 so update things that depend on mouse position. */
6737 if (f && !f->output_data.x->hourglass_p)
6738 note_mouse_movement (f, &event.xmotion);
a8f116e7
JD
6739#ifdef USE_GTK
6740 /* We may get an EnterNotify on the buttons in the toolbar. In that
6741 case we moved out of any highlighted area and need to note this. */
6742 if (!f && last_mouse_glyph_frame)
6743 note_mouse_movement (last_mouse_glyph_frame, &event);
6744#endif
6b61353c 6745 goto OTHER;
cab34f50 6746
bf338245 6747 case FocusIn:
9b516537 6748 x_detect_focus_change (dpyinfo, &event, &inev.ie);
bf338245 6749 goto OTHER;
7a13e894 6750
bf338245 6751 case LeaveNotify:
9b516537 6752 x_detect_focus_change (dpyinfo, &event, &inev.ie);
cab34f50 6753
bf338245
JD
6754 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
6755 if (f)
6756 {
6757 if (f == dpyinfo->mouse_face_mouse_frame)
6758 {
6759 /* If we move outside the frame, then we're
6760 certainly no longer on any text in the frame. */
6761 clear_mouse_face (dpyinfo);
6762 dpyinfo->mouse_face_mouse_frame = 0;
6763 }
6c183ba5 6764
bf338245
JD
6765 /* Generate a nil HELP_EVENT to cancel a help-echo.
6766 Do it only if there's something to cancel.
6767 Otherwise, the startup message is cleared when
6768 the mouse leaves the frame. */
6769 if (any_help_event_p)
6b61353c 6770 do_help = -1;
bf338245 6771 }
a8f116e7
JD
6772#ifdef USE_GTK
6773 /* See comment in EnterNotify above */
6774 else if (last_mouse_glyph_frame)
6775 note_mouse_movement (last_mouse_glyph_frame, &event);
6776#endif
bf338245 6777 goto OTHER;
7d0393cf 6778
bf338245 6779 case FocusOut:
9b516537 6780 x_detect_focus_change (dpyinfo, &event, &inev.ie);
bf338245 6781 goto OTHER;
5bc62483 6782
bf338245
JD
6783 case MotionNotify:
6784 {
442a09ea 6785 previous_help_echo_string = help_echo_string;
bb339c57 6786 help_echo_string = Qnil;
bf338245
JD
6787
6788 if (dpyinfo->grabbed && last_mouse_frame
6789 && FRAME_LIVE_P (last_mouse_frame))
6790 f = last_mouse_frame;
6791 else
6792 f = x_window_to_frame (dpyinfo, event.xmotion.window);
6793
6794 if (dpyinfo->mouse_face_hidden)
6795 {
6796 dpyinfo->mouse_face_hidden = 0;
6797 clear_mouse_face (dpyinfo);
6798 }
6799
6800 if (f)
6801 {
6802
6803 /* Generate SELECT_WINDOW_EVENTs when needed. */
6804 if (mouse_autoselect_window)
6805 {
6806 Lisp_Object window;
bf338245
JD
6807
6808 window = window_from_coordinates (f,
6809 event.xmotion.x, event.xmotion.y,
0899d58c 6810 0, 0, 0, 0);
bf338245
JD
6811
6812 /* Window will be selected only when it is not selected now and
6813 last mouse movement event was not in it. Minibuffer window
6814 will be selected iff it is active. */
6b61353c 6815 if (WINDOWP (window)
bf338245 6816 && !EQ (window, last_window)
6b61353c 6817 && !EQ (window, selected_window))
bf338245 6818 {
9b516537
AS
6819 inev.ie.kind = SELECT_WINDOW_EVENT;
6820 inev.ie.frame_or_window = window;
bf338245 6821 }
5bc62483 6822
bf338245
JD
6823 last_window=window;
6824 }
bb339c57
KS
6825 if (!note_mouse_movement (f, &event.xmotion))
6826 help_echo_string = previous_help_echo_string;
bf338245
JD
6827 }
6828 else
6829 {
e88b3c50 6830#ifndef USE_TOOLKIT_SCROLL_BARS
bf338245 6831 struct scroll_bar *bar
6b61353c
KH
6832 = x_window_to_scroll_bar (event.xmotion.display,
6833 event.xmotion.window);
f451eb13 6834
bf338245
JD
6835 if (bar)
6836 x_scroll_bar_note_movement (bar, &event);
e88b3c50 6837#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 6838
bf338245
JD
6839 /* If we move outside the frame, then we're
6840 certainly no longer on any text in the frame. */
6841 clear_mouse_face (dpyinfo);
6842 }
6843
442a09ea 6844 /* If the contents of the global variable help_echo_string
bf338245 6845 has changed, generate a HELP_EVENT. */
442a09ea
KS
6846 if (!NILP (help_echo_string)
6847 || !NILP (previous_help_echo_string))
6b61353c 6848 do_help = 1;
bf338245
JD
6849 goto OTHER;
6850 }
dc6f92b8 6851
bf338245
JD
6852 case ConfigureNotify:
6853 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
6854 if (f)
6855 {
7a4bce14 6856#ifndef USE_X_TOOLKIT
488dd4c4
JD
6857#ifdef USE_GTK
6858 xg_resize_widgets (f, event.xconfigure.width,
6859 event.xconfigure.height);
6860#else /* not USE_GTK */
bf338245
JD
6861 /* If there is a pending resize for fullscreen, don't
6862 do this one, the right one will come later.
6863 The toolkit version doesn't seem to need this, but we
6864 need to reset it below. */
62fe13a4 6865 int dont_resize
0899d58c
KS
6866 = ((f->want_fullscreen & FULLSCREEN_WAIT)
6867 && f->new_text_cols != 0);
6868 int rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, event.xconfigure.height);
6869 int columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, event.xconfigure.width);
6870
bf338245
JD
6871 if (dont_resize)
6872 goto OTHER;
6873
6874 /* In the toolkit version, change_frame_size
6875 is called by the code that handles resizing
6876 of the EmacsFrame widget. */
6877
6878 /* Even if the number of character rows and columns has
6879 not changed, the font size may have changed, so we need
6880 to check the pixel dimensions as well. */
0899d58c
KS
6881 if (columns != FRAME_COLS (f)
6882 || rows != FRAME_LINES (f)
6883 || event.xconfigure.width != FRAME_PIXEL_WIDTH (f)
6884 || event.xconfigure.height != FRAME_PIXEL_HEIGHT (f))
bf338245
JD
6885 {
6886 change_frame_size (f, rows, columns, 0, 1, 0);
6887 SET_FRAME_GARBAGED (f);
6888 cancel_mouse_face (f);
6889 }
488dd4c4 6890#endif /* not USE_GTK */
2d7fc7e8 6891#endif
af395ec1 6892
0899d58c
KS
6893 FRAME_PIXEL_WIDTH (f) = event.xconfigure.width;
6894 FRAME_PIXEL_HEIGHT (f) = event.xconfigure.height;
7a13e894 6895
488dd4c4
JD
6896#ifdef USE_GTK
6897 /* GTK creates windows but doesn't map them.
6898 Only get real positions and check fullscreen when mapped. */
6899 if (FRAME_GTK_OUTER_WIDGET (f)
6900 && GTK_WIDGET_MAPPED (FRAME_GTK_OUTER_WIDGET (f)))
488dd4c4 6901#endif
0899d58c 6902 {
0899d58c
KS
6903 x_real_positions (f, &f->left_pos, &f->top_pos);
6904
0899d58c
KS
6905 if (f->want_fullscreen & FULLSCREEN_WAIT)
6906 f->want_fullscreen &= ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH);
488dd4c4 6907 }
0899d58c 6908
f5d11644 6909#ifdef HAVE_X_I18N
bf338245
JD
6910 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
6911 xic_set_statusarea (f);
f5d11644
GM
6912#endif
6913
bf338245
JD
6914 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6915 {
6916 /* Since the WM decorations come below top_pos now,
6917 we must put them below top_pos in the future. */
0899d58c 6918 f->win_gravity = NorthWestGravity;
bf338245
JD
6919 x_wm_set_size_hint (f, (long) 0, 0);
6920 }
6921 }
6922 goto OTHER;
dc6f92b8 6923
bf338245 6924 case ButtonRelease:
488dd4c4 6925 case ButtonPress:
bf338245
JD
6926 {
6927 /* If we decide we want to generate an event to be seen
6928 by the rest of Emacs, we put it here. */
bf338245
JD
6929 int tool_bar_p = 0;
6930
bf338245 6931 bzero (&compose_status, sizeof (compose_status));
0a3fde9d 6932 last_mouse_glyph_frame = 0;
bf338245
JD
6933
6934 if (dpyinfo->grabbed
6935 && last_mouse_frame
6936 && FRAME_LIVE_P (last_mouse_frame))
6937 f = last_mouse_frame;
6938 else
6939 f = x_window_to_frame (dpyinfo, event.xbutton.window);
6940
6941 if (f)
6942 {
6943 /* Is this in the tool-bar? */
6944 if (WINDOWP (f->tool_bar_window)
0899d58c 6945 && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
bf338245
JD
6946 {
6947 Lisp_Object window;
442a09ea
KS
6948 int x = event.xbutton.x;
6949 int y = event.xbutton.y;
06a2c219 6950
0899d58c 6951 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
bf338245
JD
6952 if (EQ (window, f->tool_bar_window))
6953 {
442a09ea
KS
6954 if (event.xbutton.type == ButtonPress)
6955 handle_tool_bar_click (f, x, y, 1, 0);
6956 else
6957 handle_tool_bar_click (f, x, y, 0,
6958 x_x_to_emacs_modifiers (dpyinfo,
6959 event.xbutton.state));
6960 tool_bar_p = 1;
bf338245
JD
6961 }
6962 }
06a2c219 6963
bf338245
JD
6964 if (!tool_bar_p)
6965 if (!dpyinfo->x_focus_frame
6966 || f == dpyinfo->x_focus_frame)
488dd4c4 6967 {
22174d10 6968#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
488dd4c4 6969 if (! popup_activated ())
22174d10 6970#endif
6b61353c
KH
6971 {
6972 if (ignore_next_mouse_click_timeout)
6973 {
6974 if (event.type == ButtonPress
6975 && (int)(event.xbutton.time - ignore_next_mouse_click_timeout) > 0)
6976 {
6977 ignore_next_mouse_click_timeout = 0;
6c4eb4ce 6978 construct_mouse_click (&inev.ie, &event.xbutton, f);
6b61353c
KH
6979 }
6980 if (event.type == ButtonRelease)
6981 ignore_next_mouse_click_timeout = 0;
6982 }
6983 else
6c4eb4ce 6984 construct_mouse_click (&inev.ie, &event.xbutton, f);
6b61353c 6985 }
488dd4c4 6986 }
bf338245
JD
6987 }
6988 else
6989 {
bf338245 6990 struct scroll_bar *bar
6b61353c
KH
6991 = x_window_to_scroll_bar (event.xbutton.display,
6992 event.xbutton.window);
f451eb13 6993
257f40f2
JD
6994#ifdef USE_TOOLKIT_SCROLL_BARS
6995 /* Make the "Ctrl-Mouse-2 splits window" work for toolkit
6996 scroll bars. */
6997 if (bar && event.xbutton.state & ControlMask)
6998 {
9b516537 6999 x_scroll_bar_handle_click (bar, &event, &inev.ie);
257f40f2
JD
7000 *finish = X_EVENT_DROP;
7001 }
7002#else /* not USE_TOOLKIT_SCROLL_BARS */
bf338245 7003 if (bar)
9b516537 7004 x_scroll_bar_handle_click (bar, &event, &inev.ie);
06a2c219 7005#endif /* not USE_TOOLKIT_SCROLL_BARS */
bf338245
JD
7006 }
7007
7008 if (event.type == ButtonPress)
7009 {
7010 dpyinfo->grabbed |= (1 << event.xbutton.button);
7011 last_mouse_frame = f;
bf338245
JD
7012
7013 if (!tool_bar_p)
7014 last_tool_bar_item = -1;
7015 }
7016 else
488dd4c4 7017 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
bf338245 7018
24aad441
KS
7019 /* Ignore any mouse motion that happened before this event;
7020 any subsequent mouse-movement Emacs events should reflect
7021 only motion after the ButtonPress/Release. */
7022 if (f != 0)
7023 f->mouse_moved = 0;
7024
488dd4c4 7025#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
bf338245
JD
7026 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
7027 /* For a down-event in the menu bar,
7028 don't pass it to Xt right now.
7029 Instead, save it away
7030 and we will pass it to Xt from kbd_buffer_get_event.
7031 That way, we can run some Lisp code first. */
488dd4c4
JD
7032 if (
7033#ifdef USE_GTK
7034 ! popup_activated ()
7035 &&
7036#endif
7037 f && event.type == ButtonPress
bf338245
JD
7038 /* Verify the event is really within the menu bar
7039 and not just sent to it due to grabbing. */
7040 && event.xbutton.x >= 0
0899d58c 7041 && event.xbutton.x < FRAME_PIXEL_WIDTH (f)
bf338245
JD
7042 && event.xbutton.y >= 0
7043 && event.xbutton.y < f->output_data.x->menubar_height
7044 && event.xbutton.same_screen)
7045 {
7046 SET_SAVED_BUTTON_EVENT;
7047 XSETFRAME (last_mouse_press_frame, f);
488dd4c4
JD
7048#ifdef USE_GTK
7049 *finish = X_EVENT_DROP;
7050#endif
bf338245
JD
7051 }
7052 else if (event.type == ButtonPress)
7053 {
7054 last_mouse_press_frame = Qnil;
7055 goto OTHER;
7056 }
06a2c219 7057
2237cac9
RS
7058#ifdef USE_MOTIF /* This should do not harm for Lucid,
7059 but I am trying to be cautious. */
bf338245
JD
7060 else if (event.type == ButtonRelease)
7061 {
7062 if (!NILP (last_mouse_press_frame))
7063 {
7064 f = XFRAME (last_mouse_press_frame);
7065 if (f->output_data.x)
7066 SET_SAVED_BUTTON_EVENT;
7067 }
7068 else
7069 goto OTHER;
7070 }
2237cac9 7071#endif /* USE_MOTIF */
bf338245
JD
7072 else
7073 goto OTHER;
488dd4c4 7074#endif /* USE_X_TOOLKIT || USE_GTK */
bf338245
JD
7075 }
7076 break;
dc6f92b8 7077
bf338245
JD
7078 case CirculateNotify:
7079 goto OTHER;
7d0393cf 7080
bf338245
JD
7081 case CirculateRequest:
7082 goto OTHER;
06a2c219 7083
bf338245
JD
7084 case VisibilityNotify:
7085 goto OTHER;
dc6f92b8 7086
bf338245
JD
7087 case MappingNotify:
7088 /* Someone has changed the keyboard mapping - update the
7089 local cache. */
7090 switch (event.xmapping.request)
7091 {
7092 case MappingModifier:
7093 x_find_modifier_meanings (dpyinfo);
7094 /* This is meant to fall through. */
7095 case MappingKeyboard:
7096 XRefreshKeyboardMapping (&event.xmapping);
7097 }
7098 goto OTHER;
dc6f92b8 7099
bf338245
JD
7100 default:
7101 OTHER:
717ca130 7102#ifdef USE_X_TOOLKIT
bf338245 7103 BLOCK_INPUT;
257f40f2
JD
7104 if (*finish != X_EVENT_DROP)
7105 XtDispatchEvent (&event);
bf338245 7106 UNBLOCK_INPUT;
3afe33e7 7107#endif /* USE_X_TOOLKIT */
bf338245
JD
7108 break;
7109 }
7110
6b61353c 7111 done:
9b516537 7112 if (inev.ie.kind != NO_EVENT)
6b61353c 7113 {
9b516537 7114 kbd_buffer_store_event_hold (&inev.ie, hold_quit);
6b61353c
KH
7115 count++;
7116 }
177c0ea7 7117
6b61353c
KH
7118 if (do_help
7119 && !(hold_quit && hold_quit->kind != NO_EVENT))
7120 {
7121 Lisp_Object frame;
bf338245 7122
6b61353c
KH
7123 if (f)
7124 XSETFRAME (frame, f);
7125 else
7126 frame = Qnil;
177c0ea7 7127
6b61353c
KH
7128 if (do_help > 0)
7129 {
7130 any_help_event_p = 1;
7131 gen_help_event (help_echo_string, frame, help_echo_window,
7132 help_echo_object, help_echo_pos);
7133 }
7134 else
7135 {
7136 help_echo_string = Qnil;
7137 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
7138 }
7139 count++;
7140 }
7141
7142 *eventp = event;
bf338245
JD
7143 return count;
7144}
7145
7146
7147/* Handles the XEvent EVENT on display DISPLAY.
7148 This is used for event loops outside the normal event handling,
1fcfb866
JD
7149 i.e. looping while a popup menu or a dialog is posted.
7150
7151 Returns the value handle_one_xevent sets in the finish argument. */
7152int
bf338245
JD
7153x_dispatch_event (event, display)
7154 XEvent *event;
7155 Display *display;
7156{
7157 struct x_display_info *dpyinfo;
1fcfb866 7158 int finish = X_EVENT_NORMAL;
177c0ea7 7159
6b61353c 7160 dpyinfo = x_display_info_for_display (display);
177c0ea7 7161
bf338245 7162 if (dpyinfo)
6b61353c 7163 handle_one_xevent (dpyinfo, event, &finish, 0);
1fcfb866
JD
7164
7165 return finish;
bf338245
JD
7166}
7167
7168
7169/* Read events coming from the X server.
7170 This routine is called by the SIGIO handler.
7171 We return as soon as there are no more events to be read.
7172
bf338245
JD
7173 We return the number of characters stored into the buffer,
7174 thus pretending to be `read'.
7175
7176 EXPECTED is nonzero if the caller knows input is available. */
7177
7178static int
6b61353c 7179XTread_socket (sd, expected, hold_quit)
bf338245 7180 register int sd;
bf338245 7181 int expected;
6b61353c 7182 struct input_event *hold_quit;
bf338245
JD
7183{
7184 int count = 0;
bf338245
JD
7185 XEvent event;
7186 int event_found = 0;
7187 struct x_display_info *dpyinfo;
7188
7189 if (interrupt_input_blocked)
7190 {
7191 interrupt_input_pending = 1;
7192 return -1;
7193 }
7194
7195 interrupt_input_pending = 0;
7196 BLOCK_INPUT;
7197
7198 /* So people can tell when we have read the available input. */
7199 input_signal_count++;
7200
bf338245
JD
7201 ++handling_signal;
7202
7203 /* Find the display we are supposed to read input for.
7204 It's the one communicating on descriptor SD. */
7205 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
7206 {
7207#if 0 /* This ought to be unnecessary; let's verify it. */
7208#ifdef FIOSNBIO
7209 /* If available, Xlib uses FIOSNBIO to make the socket
7210 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
7211 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
7212 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7213 fcntl (dpyinfo->connection, F_SETFL, 0);
7214#endif /* ! defined (FIOSNBIO) */
7215#endif
7216
7217#if 0 /* This code can't be made to work, with multiple displays,
7218 and appears not to be used on any system any more.
7219 Also keyboard.c doesn't turn O_NDELAY on and off
7220 for X connections. */
7221#ifndef SIGIO
7222#ifndef HAVE_SELECT
7223 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
7224 {
7225 extern int read_alarm_should_throw;
7226 read_alarm_should_throw = 1;
7227 XPeekEvent (dpyinfo->display, &event);
7228 read_alarm_should_throw = 0;
7229 }
7230#endif /* HAVE_SELECT */
7231#endif /* SIGIO */
7232#endif
7233
7234 /* For debugging, this gives a way to fake an I/O error. */
7235 if (dpyinfo == XTread_socket_fake_io_error)
7236 {
7237 XTread_socket_fake_io_error = 0;
7238 x_io_error_quitter (dpyinfo->display);
dc6f92b8 7239 }
bf338245
JD
7240
7241#ifdef HAVE_X_SM
6b61353c
KH
7242 {
7243 struct input_event inev;
7244 BLOCK_INPUT;
7245 /* We don't need to EVENT_INIT (inev) here, as
7246 x_session_check_input copies an entire input_event. */
7247 if (x_session_check_input (&inev))
7248 {
7249 kbd_buffer_store_event_hold (&inev, hold_quit);
7250 count++;
7251 }
7252 UNBLOCK_INPUT;
7253 }
bf338245
JD
7254#endif
7255
6b61353c 7256#ifndef USE_GTK
bf338245
JD
7257 while (XPending (dpyinfo->display))
7258 {
7259 int finish;
177c0ea7 7260
bf338245
JD
7261 XNextEvent (dpyinfo->display, &event);
7262
7263#ifdef HAVE_X_I18N
1fcfb866
JD
7264 /* Filter events for the current X input method. */
7265 if (x_filter_event (dpyinfo, &event))
7266 break;
bf338245
JD
7267#endif
7268 event_found = 1;
7269
6b61353c 7270 count += handle_one_xevent (dpyinfo, &event, &finish, hold_quit);
bf338245
JD
7271
7272 if (finish == X_EVENT_GOTO_OUT)
7273 goto out;
7274 }
6b61353c
KH
7275#endif /* not USE_GTK */
7276 }
7277
7278#ifdef USE_GTK
7279
7280 /* For GTK we must use the GTK event loop. But XEvents gets passed
7281 to our filter function above, and then to the big event switch.
7282 We use a bunch of globals to communicate with our filter function,
7283 that is kind of ugly, but it works.
7284
7285 There is no way to do one display at the time, GTK just does events
7286 from all displays. */
7287
7288 while (gtk_events_pending ())
7289 {
7290 current_count = count;
7291 current_hold_quit = hold_quit;
7292
7293 gtk_main_iteration ();
7294
7295 count = current_count;
7296 current_count = -1;
7297 current_hold_quit = 0;
7298
7299 if (current_finish == X_EVENT_GOTO_OUT)
7300 break;
dc6f92b8 7301 }
6b61353c 7302#endif /* USE_GTK */
dc6f92b8 7303
06a2c219
GM
7304 out:;
7305
9a5196d0
RS
7306 /* On some systems, an X bug causes Emacs to get no more events
7307 when the window is destroyed. Detect that. (1994.) */
58769bee 7308 if (! event_found)
ef2a22d0 7309 {
ef2a22d0
RS
7310 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
7311 One XNOOP in 100 loops will make Emacs terminate.
7312 B. Bretthauer, 1994 */
7313 x_noop_count++;
58769bee 7314 if (x_noop_count >= 100)
ef2a22d0
RS
7315 {
7316 x_noop_count=0;
2224b905
RS
7317
7318 if (next_noop_dpyinfo == 0)
7319 next_noop_dpyinfo = x_display_list;
7320
7321 XNoOp (next_noop_dpyinfo->display);
7322
7323 /* Each time we get here, cycle through the displays now open. */
7324 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
7325 }
7326 }
502add23 7327
06a2c219 7328 /* If the focus was just given to an auto-raising frame,
0134a210 7329 raise it now. */
7a13e894 7330 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
7331 if (pending_autoraise_frame)
7332 {
7333 x_raise_frame (pending_autoraise_frame);
7334 pending_autoraise_frame = 0;
7335 }
0134a210 7336
bde5503b 7337 --handling_signal;
6b61353c
KH
7338 UNBLOCK_INPUT;
7339
dc6f92b8
JB
7340 return count;
7341}
06a2c219
GM
7342
7343
7344
dc6f92b8 7345\f
06a2c219
GM
7346/***********************************************************************
7347 Text Cursor
7348 ***********************************************************************/
7349
06a2c219
GM
7350/* Set clipping for output in glyph row ROW. W is the window in which
7351 we operate. GC is the graphics context to set clipping in.
06a2c219
GM
7352
7353 ROW may be a text row or, e.g., a mode line. Text rows must be
7354 clipped to the interior of the window dedicated to text display,
7355 mode lines must be clipped to the whole window. */
dc6f92b8
JB
7356
7357static void
08f66682 7358x_clip_to_row (w, row, area, gc)
06a2c219
GM
7359 struct window *w;
7360 struct glyph_row *row;
08f66682 7361 int area;
06a2c219 7362 GC gc;
dc6f92b8 7363{
06a2c219
GM
7364 struct frame *f = XFRAME (WINDOW_FRAME (w));
7365 XRectangle clip_rect;
08f66682 7366 int window_x, window_y, window_width;
dc6f92b8 7367
08f66682 7368 window_box (w, area, &window_x, &window_y, &window_width, 0);
5c1aae96 7369
08f66682 7370 clip_rect.x = window_x;
dbd8ee19 7371 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
06a2c219
GM
7372 clip_rect.y = max (clip_rect.y, window_y);
7373 clip_rect.width = window_width;
7374 clip_rect.height = row->visible_height;
5c1aae96 7375
06a2c219 7376 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
7377}
7378
06a2c219
GM
7379
7380/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
7381
7382static void
06a2c219
GM
7383x_draw_hollow_cursor (w, row)
7384 struct window *w;
7385 struct glyph_row *row;
dc6f92b8 7386{
06a2c219
GM
7387 struct frame *f = XFRAME (WINDOW_FRAME (w));
7388 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7389 Display *dpy = FRAME_X_DISPLAY (f);
7390 int x, y, wd, h;
7391 XGCValues xgcv;
7392 struct glyph *cursor_glyph;
7393 GC gc;
7394
06a2c219
GM
7395 /* Get the glyph the cursor is on. If we can't tell because
7396 the current matrix is invalid or such, give up. */
7397 cursor_glyph = get_phys_cursor_glyph (w);
7398 if (cursor_glyph == NULL)
dc6f92b8
JB
7399 return;
7400
dbd8ee19 7401 /* Compute frame-relative coordinates for phys cursor. */
e8f6b0db 7402 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
dbd8ee19 7403 wd = w->phys_cursor_width;
6b61353c 7404
06a2c219
GM
7405 /* The foreground of cursor_gc is typically the same as the normal
7406 background color, which can cause the cursor box to be invisible. */
7407 xgcv.foreground = f->output_data.x->cursor_pixel;
7408 if (dpyinfo->scratch_cursor_gc)
7409 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
7410 else
7411 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
7412 GCForeground, &xgcv);
7413 gc = dpyinfo->scratch_cursor_gc;
7414
7415 /* Set clipping, draw the rectangle, and reset clipping again. */
08f66682 7416 x_clip_to_row (w, row, TEXT_AREA, gc);
005a80de 7417 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h - 1);
06a2c219 7418 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
7419}
7420
06a2c219
GM
7421
7422/* Draw a bar cursor on window W in glyph row ROW.
7423
7424 Implementation note: One would like to draw a bar cursor with an
7425 angle equal to the one given by the font property XA_ITALIC_ANGLE.
7426 Unfortunately, I didn't find a font yet that has this property set.
7427 --gerd. */
dc6f92b8
JB
7428
7429static void
65c26775 7430x_draw_bar_cursor (w, row, width, kind)
06a2c219
GM
7431 struct window *w;
7432 struct glyph_row *row;
f02d8aa0 7433 int width;
65c26775 7434 enum text_cursor_kinds kind;
dc6f92b8 7435{
92f424df
GM
7436 struct frame *f = XFRAME (w->frame);
7437 struct glyph *cursor_glyph;
7d0393cf 7438
92f424df
GM
7439 /* If cursor is out of bounds, don't draw garbage. This can happen
7440 in mini-buffer windows when switching between echo area glyphs
7441 and mini-buffer. */
7442 cursor_glyph = get_phys_cursor_glyph (w);
7443 if (cursor_glyph == NULL)
7444 return;
06a2c219 7445
92f424df
GM
7446 /* If on an image, draw like a normal cursor. That's usually better
7447 visible than drawing a bar, esp. if the image is large so that
7448 the bar might not be in the window. */
7449 if (cursor_glyph->type == IMAGE_GLYPH)
7450 {
7451 struct glyph_row *row;
7452 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
442a09ea 7453 draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
92f424df
GM
7454 }
7455 else
7456 {
34e5d0af
GM
7457 Display *dpy = FRAME_X_DISPLAY (f);
7458 Window window = FRAME_X_WINDOW (f);
7459 GC gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
7460 unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures;
7461 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
7462 XGCValues xgcv;
7463
7464 /* If the glyph's background equals the color we normally draw
7465 the bar cursor in, the bar cursor in its normal color is
7466 invisible. Use the glyph's foreground color instead in this
7467 case, on the assumption that the glyph's colors are chosen so
7468 that the glyph is legible. */
7469 if (face->background == f->output_data.x->cursor_pixel)
7470 xgcv.background = xgcv.foreground = face->foreground;
7471 else
7472 xgcv.background = xgcv.foreground = f->output_data.x->cursor_pixel;
06a2c219 7473 xgcv.graphics_exposures = 0;
7d0393cf 7474
06a2c219
GM
7475 if (gc)
7476 XChangeGC (dpy, gc, mask, &xgcv);
7477 else
7478 {
7479 gc = XCreateGC (dpy, window, mask, &xgcv);
7480 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
7481 }
7d0393cf 7482
f02d8aa0 7483 if (width < 0)
fdbe859c 7484 width = FRAME_CURSOR_WIDTH (f);
34e5d0af 7485 width = min (cursor_glyph->pixel_width, width);
7d0393cf 7486
b3738089 7487 w->phys_cursor_width = width;
08f66682 7488 x_clip_to_row (w, row, TEXT_AREA, gc);
7d0393cf 7489
65c26775
EZ
7490 if (kind == BAR_CURSOR)
7491 XFillRectangle (dpy, window, gc,
7492 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
7493 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
7494 width, row->height);
7495 else
7496 XFillRectangle (dpy, window, gc,
7497 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
7498 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
7499 row->height - width),
7500 cursor_glyph->pixel_width,
7501 width);
7502
06a2c219
GM
7503 XSetClipMask (dpy, gc, None);
7504 }
dc6f92b8
JB
7505}
7506
06a2c219 7507
442a09ea 7508/* RIF: Define cursor CURSOR on frame F. */
06a2c219 7509
dc6f92b8 7510static void
442a09ea
KS
7511x_define_frame_cursor (f, cursor)
7512 struct frame *f;
7513 Cursor cursor;
dc6f92b8 7514{
442a09ea 7515 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
06a2c219 7516}
90e65f07 7517
dbc4e1c1 7518
442a09ea 7519/* RIF: Clear area on frame F. */
dbc4e1c1 7520
06a2c219 7521static void
442a09ea
KS
7522x_clear_frame_area (f, x, y, width, height)
7523 struct frame *f;
7524 int x, y, width, height;
06a2c219 7525{
442a09ea
KS
7526 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7527 x, y, width, height, False);
06a2c219 7528}
dbc4e1c1 7529
eea6af04 7530
442a09ea 7531/* RIF: Draw cursor on window W. */
eea6af04 7532
06a2c219 7533static void
e5a3b7d9 7534x_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, active_p)
06a2c219 7535 struct window *w;
442a09ea 7536 struct glyph_row *glyph_row;
e5a3b7d9
KS
7537 int x, y;
7538 int cursor_type, cursor_width;
7539 int on_p, active_p;
dbc4e1c1 7540{
442a09ea 7541 struct frame *f = XFRAME (WINDOW_FRAME (w));
06a2c219 7542
e5a3b7d9 7543 if (on_p)
06a2c219 7544 {
e5a3b7d9 7545 w->phys_cursor_type = cursor_type;
06a2c219
GM
7546 w->phys_cursor_on_p = 1;
7547
6b61353c
KH
7548 if (glyph_row->exact_window_width_line_p
7549 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
7550 {
7551 glyph_row->cursor_in_fringe_p = 1;
7552 draw_fringe_bitmap (w, glyph_row, 0);
7553 }
7554 else
e5a3b7d9 7555 switch (cursor_type)
dc6f92b8 7556 {
06a2c219
GM
7557 case HOLLOW_BOX_CURSOR:
7558 x_draw_hollow_cursor (w, glyph_row);
7559 break;
7560
7561 case FILLED_BOX_CURSOR:
442a09ea 7562 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
06a2c219
GM
7563 break;
7564
7565 case BAR_CURSOR:
e5a3b7d9 7566 x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
65c26775
EZ
7567 break;
7568
7569 case HBAR_CURSOR:
e5a3b7d9 7570 x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
06a2c219
GM
7571 break;
7572
7573 case NO_CURSOR:
4398e673 7574 w->phys_cursor_width = 0;
06a2c219 7575 break;
dc6f92b8 7576
06a2c219
GM
7577 default:
7578 abort ();
7579 }
7d0393cf 7580
59ddecde
GM
7581#ifdef HAVE_X_I18N
7582 if (w == XWINDOW (f->selected_window))
7583 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
7584 xic_set_preeditarea (w, x, y);
7585#endif
dc6f92b8
JB
7586 }
7587
06a2c219 7588#ifndef XFlush
f676886a 7589 if (updating_frame != f)
334208b7 7590 XFlush (FRAME_X_DISPLAY (f));
06a2c219 7591#endif
dc6f92b8
JB
7592}
7593
dc6f92b8
JB
7594\f
7595/* Icons. */
7596
dbc4e1c1 7597/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
7598
7599int
990ba854 7600x_bitmap_icon (f, file)
f676886a 7601 struct frame *f;
990ba854 7602 Lisp_Object file;
dc6f92b8 7603{
06a2c219 7604 int bitmap_id;
dc6f92b8 7605
c118dd06 7606 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
7607 return 1;
7608
62fe13a4 7609 /* Free up our existing icon bitmap and mask if any. */
7556890b
RS
7610 if (f->output_data.x->icon_bitmap > 0)
7611 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
7612 f->output_data.x->icon_bitmap = 0;
990ba854
RS
7613
7614 if (STRINGP (file))
62fe13a4
JB
7615 {
7616#ifdef USE_GTK
6b61353c 7617 /* Use gtk_window_set_icon_from_file () if available,
62fe13a4 7618 It's not restricted to bitmaps */
6b61353c 7619 if (xg_set_icon (f, file))
62fe13a4
JB
7620 return 0;
7621#endif /* USE_GTK */
7622 bitmap_id = x_create_bitmap_from_file (f, file);
6b61353c 7623 x_create_bitmap_mask (f, bitmap_id);
62fe13a4 7624 }
7f2ae036
RS
7625 else
7626 {
62fe13a4 7627 /* Create the GNU bitmap and mask if necessary. */
5bf01b68 7628 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
62fe13a4 7629 {
9f7b984b
CY
7630 int rc = -1;
7631
786a43d6 7632#if defined (HAVE_XPM) && defined (HAVE_X_WINDOWS)
9f7b984b
CY
7633#ifdef USE_GTK
7634 if (xg_set_icon_from_xpm_data (f, gnu_xpm_bits))
7635 return 0;
786a43d6 7636#else
9f7b984b
CY
7637 rc = x_create_bitmap_from_xpm_data (f, gnu_xpm_bits);
7638 if (rc != -1)
7639 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id = rc;
7640#endif /* USE_GTK */
7641#endif /* defined (HAVE_XPM) && defined (HAVE_X_WINDOWS) */
7642
7643 /* If all else fails, use the (black and white) xbm image. */
7644 if (rc == -1)
7645 {
7646 rc = x_create_bitmap_from_data (f, gnu_xbm_bits,
7647 gnu_xbm_width, gnu_xbm_height);
7648 if (rc == -1)
7649 return 1;
7650
7651 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id = rc;
7652 x_create_bitmap_mask (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
7653 }
62fe13a4 7654 }
990ba854 7655
62fe13a4 7656 /* The first time we create the GNU bitmap and mask,
06a2c219 7657 this increments the ref-count one extra time.
62fe13a4 7658 As a result, the GNU bitmap and mask are never freed.
990ba854 7659 That way, we don't have to worry about allocating it again. */
334208b7 7660 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 7661
334208b7 7662 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
7663 }
7664
7665 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 7666 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
7667
7668 return 0;
7669}
7670
7671
1be2d067
KH
7672/* Make the x-window of frame F use a rectangle with text.
7673 Use ICON_NAME as the text. */
dc6f92b8
JB
7674
7675int
f676886a
JB
7676x_text_icon (f, icon_name)
7677 struct frame *f;
dc6f92b8
JB
7678 char *icon_name;
7679{
c118dd06 7680 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
7681 return 1;
7682
1be2d067
KH
7683#ifdef HAVE_X11R4
7684 {
7685 XTextProperty text;
7686 text.value = (unsigned char *) icon_name;
7687 text.encoding = XA_STRING;
7688 text.format = 8;
7689 text.nitems = strlen (icon_name);
2436a4e4 7690 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), &text);
1be2d067
KH
7691 }
7692#else /* not HAVE_X11R4 */
2436a4e4 7693 XSetIconName (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), icon_name);
1be2d067 7694#endif /* not HAVE_X11R4 */
58769bee 7695
7556890b
RS
7696 if (f->output_data.x->icon_bitmap > 0)
7697 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
7698 f->output_data.x->icon_bitmap = 0;
b1c884c3 7699 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
7700
7701 return 0;
7702}
7703\f
e99db5a1
RS
7704#define X_ERROR_MESSAGE_SIZE 200
7705
7706/* If non-nil, this should be a string.
9ba8e10d
CY
7707 It means catch X errors and store the error message in this string.
7708
7709 The reason we use a stack is that x_catch_error/x_uncatch_error can
7710 be called from a signal handler.
7711*/
e99db5a1 7712
5badc98d
SM
7713struct x_error_message_stack {
7714 char string[X_ERROR_MESSAGE_SIZE];
7715 Display *dpy;
7716 struct x_error_message_stack *prev;
7717};
7718static struct x_error_message_stack *x_error_message;
e99db5a1
RS
7719
7720/* An X error handler which stores the error message in
7721 x_error_message_string. This is called from x_error_handler if
7722 x_catch_errors is in effect. */
7723
06a2c219 7724static void
e99db5a1
RS
7725x_error_catcher (display, error)
7726 Display *display;
7727 XErrorEvent *error;
7728{
7729 XGetErrorText (display, error->error_code,
5badc98d 7730 x_error_message->string,
e99db5a1
RS
7731 X_ERROR_MESSAGE_SIZE);
7732}
7733
7734/* Begin trapping X errors for display DPY. Actually we trap X errors
7735 for all displays, but DPY should be the display you are actually
7736 operating on.
7737
7738 After calling this function, X protocol errors no longer cause
7739 Emacs to exit; instead, they are recorded in the string
7740 stored in x_error_message_string.
7741
7742 Calling x_check_errors signals an Emacs error if an X error has
7743 occurred since the last call to x_catch_errors or x_check_errors.
7744
7745 Calling x_uncatch_errors resumes the normal error handling. */
7746
7747void x_check_errors ();
e99db5a1 7748
9ba8e10d 7749void
e99db5a1
RS
7750x_catch_errors (dpy)
7751 Display *dpy;
7752{
5eeafdc9 7753 struct x_error_message_stack *data = xmalloc (sizeof (*data));
e99db5a1
RS
7754
7755 /* Make sure any errors from previous requests have been dealt with. */
7756 XSync (dpy, False);
7757
5badc98d
SM
7758 data->dpy = dpy;
7759 data->string[0] = 0;
7760 data->prev = x_error_message;
7761 x_error_message = data;
e99db5a1
RS
7762}
7763
9ba8e10d
CY
7764/* Undo the last x_catch_errors call.
7765 DPY should be the display that was passed to x_catch_errors. */
e99db5a1 7766
9ba8e10d 7767void
4545fa20 7768x_uncatch_errors ()
e99db5a1 7769{
5badc98d 7770 struct x_error_message_stack *tmp;
781d152a 7771
8a34117e
CY
7772 BLOCK_INPUT;
7773
2728b5d0
JD
7774 /* The display may have been closed before this function is called.
7775 Check if it is still open before calling XSync. */
4545fa20 7776 if (x_display_info_for_display (x_error_message->dpy) != 0)
8a34117e 7777 XSync (x_error_message->dpy, False);
781d152a 7778
5badc98d
SM
7779 tmp = x_error_message;
7780 x_error_message = x_error_message->prev;
9ba8e10d 7781 xfree (tmp);
8a34117e 7782 UNBLOCK_INPUT;
e99db5a1
RS
7783}
7784
7785/* If any X protocol errors have arrived since the last call to
7786 x_catch_errors or x_check_errors, signal an Emacs error using
7787 sprintf (a buffer, FORMAT, the x error message text) as the text. */
7788
7789void
7790x_check_errors (dpy, format)
7791 Display *dpy;
7792 char *format;
7793{
7794 /* Make sure to catch any errors incurred so far. */
7795 XSync (dpy, False);
7796
5badc98d 7797 if (x_error_message->string[0])
9ba8e10d
CY
7798 {
7799 char string[X_ERROR_MESSAGE_SIZE];
7800 bcopy (x_error_message->string, string, X_ERROR_MESSAGE_SIZE);
4545fa20 7801 x_uncatch_errors ();
9ba8e10d
CY
7802 error (format, string);
7803 }
e99db5a1
RS
7804}
7805
9829ddba
RS
7806/* Nonzero if we had any X protocol errors
7807 since we did x_catch_errors on DPY. */
e99db5a1
RS
7808
7809int
7810x_had_errors_p (dpy)
7811 Display *dpy;
7812{
7813 /* Make sure to catch any errors incurred so far. */
7814 XSync (dpy, False);
7815
5badc98d 7816 return x_error_message->string[0] != 0;
e99db5a1
RS
7817}
7818
9829ddba
RS
7819/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
7820
06a2c219 7821void
9829ddba
RS
7822x_clear_errors (dpy)
7823 Display *dpy;
7824{
5badc98d 7825 x_error_message->string[0] = 0;
e6feb692
RS
7826}
7827
7828/* Close off all unclosed x_catch_errors calls. */
7829
7830void
7831x_fully_uncatch_errors ()
7832{
7833 while (x_error_message)
7834 x_uncatch_errors ();
7835}
7836
7837/* Nonzero if x_catch_errors has been done and not yet canceled. */
7838
7839int
7840x_catching_errors ()
7841{
7842 return x_error_message != 0;
9829ddba
RS
7843}
7844
e99db5a1
RS
7845#if 0
7846static unsigned int x_wire_count;
7847x_trace_wire ()
7848{
7849 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
7850}
7851#endif /* ! 0 */
7852
7853\f
7854/* Handle SIGPIPE, which can happen when the connection to a server
7855 simply goes away. SIGPIPE is handled by x_connection_signal.
7d0393cf 7856 Don't need to do anything, because the write which caused the
e99db5a1 7857 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 7858 which will do the appropriate cleanup for us. */
7d0393cf 7859
e99db5a1
RS
7860static SIGTYPE
7861x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 7862 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
7863{
7864#ifdef USG
7865 /* USG systems forget handlers when they are used;
7866 must reestablish each time */
7867 signal (signalnum, x_connection_signal);
7868#endif /* USG */
7869}
0da1ab50 7870
e99db5a1 7871\f
0da1ab50
GM
7872/************************************************************************
7873 Handling X errors
7874 ************************************************************************/
4746118a 7875
f0e299de
GM
7876/* Error message passed to x_connection_closed. */
7877
7878static char *error_msg;
7879
a7248e4f 7880/* Function installed as fatal_error_signal_hook in
f0e299de
GM
7881 x_connection_closed. Print the X error message, and exit normally,
7882 instead of dumping core when XtCloseDisplay fails. */
7883
7884static void
7885x_fatal_error_signal ()
7886{
7887 fprintf (stderr, "%s\n", error_msg);
7888 exit (70);
7889}
7890
0da1ab50
GM
7891/* Handle the loss of connection to display DPY. ERROR_MESSAGE is
7892 the text of an error message that lead to the connection loss. */
16bd92ea 7893
4746118a 7894static SIGTYPE
5978125e
GM
7895x_connection_closed (dpy, error_message)
7896 Display *dpy;
7a13e894 7897 char *error_message;
4746118a 7898{
5978125e 7899 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
7a13e894 7900 Lisp_Object frame, tail;
7d0393cf 7901
f0e299de
GM
7902 error_msg = (char *) alloca (strlen (error_message) + 1);
7903 strcpy (error_msg, error_message);
1a532e54 7904 handling_signal = 0;
7d0393cf 7905
0da1ab50
GM
7906 /* Prevent being called recursively because of an error condition
7907 below. Otherwise, we might end up with printing ``can't find per
7908 display information'' in the recursive call instead of printing
7909 the original message here. */
9ba8e10d 7910 x_catch_errors (dpy);
7d0393cf 7911
8a4f36cc
GM
7912 /* We have to close the display to inform Xt that it doesn't
7913 exist anymore. If we don't, Xt will continue to wait for
7914 events from the display. As a consequence, a sequence of
7915
7916 M-x make-frame-on-display RET :1 RET
7917 ...kill the new frame, so that we get an IO error...
7918 M-x make-frame-on-display RET :1 RET
7919
7920 will indefinitely wait in Xt for events for display `:1', opened
7921 in the first class to make-frame-on-display.
6186a4a0 7922
8a4f36cc
GM
7923 Closing the display is reported to lead to a bus error on
7924 OpenWindows in certain situations. I suspect that is a bug
7925 in OpenWindows. I don't know how to cicumvent it here. */
7d0393cf 7926
f613a4c8 7927#ifdef USE_X_TOOLKIT
ae24cb3b
GM
7928 /* If DPYINFO is null, this means we didn't open the display
7929 in the first place, so don't try to close it. */
7930 if (dpyinfo)
f0e299de
GM
7931 {
7932 extern void (*fatal_error_signal_hook) P_ ((void));
7933 fatal_error_signal_hook = x_fatal_error_signal;
7934 XtCloseDisplay (dpy);
7935 fatal_error_signal_hook = NULL;
7936 }
f613a4c8 7937#endif
adabc3a9 7938
6b61353c
KH
7939#ifdef USE_GTK
7940 if (dpyinfo)
7941 xg_display_close (dpyinfo->display);
7942#endif
7943
8a4f36cc 7944 /* Indicate that this display is dead. */
9e80b57d
KR
7945 if (dpyinfo)
7946 dpyinfo->display = 0;
6186a4a0 7947
06a2c219 7948 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
7949 that are on the dead display. */
7950 FOR_EACH_FRAME (tail, frame)
7951 {
7952 Lisp_Object minibuf_frame;
7953 minibuf_frame
7954 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
7955 if (FRAME_X_P (XFRAME (frame))
7956 && FRAME_X_P (XFRAME (minibuf_frame))
7957 && ! EQ (frame, minibuf_frame)
7958 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
7959 Fdelete_frame (frame, Qt);
7960 }
7961
7962 /* Now delete all remaining frames on the dead display.
06a2c219 7963 We are now sure none of these is used as the mini-buffer
7a13e894
RS
7964 for another frame that we need to delete. */
7965 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
7966 if (FRAME_X_P (XFRAME (frame))
7967 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
7968 {
7969 /* Set this to t so that Fdelete_frame won't get confused
7970 trying to find a replacement. */
7971 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
7972 Fdelete_frame (frame, Qt);
7973 }
7a13e894 7974
482a1bd2
KH
7975 if (dpyinfo)
7976 x_delete_display (dpyinfo);
7a13e894 7977
4545fa20 7978 x_uncatch_errors ();
7d0393cf 7979
7a13e894
RS
7980 if (x_display_list == 0)
7981 {
f0e299de 7982 fprintf (stderr, "%s\n", error_msg);
7a13e894
RS
7983 shut_down_emacs (0, 0, Qnil);
7984 exit (70);
7985 }
12ba150f 7986
7a13e894
RS
7987 /* Ordinary stack unwind doesn't deal with these. */
7988#ifdef SIGIO
7989 sigunblock (sigmask (SIGIO));
7990#endif
7991 sigunblock (sigmask (SIGALRM));
7992 TOTALLY_UNBLOCK_INPUT;
7993
aa4d9a9e 7994 clear_waiting_for_input ();
f0e299de 7995 error ("%s", error_msg);
4746118a
JB
7996}
7997
043f7f73
SM
7998/* We specifically use it before defining it, so that gcc doesn't inline it,
7999 otherwise gdb doesn't know how to properly put a breakpoint on it. */
2381d38d 8000static void x_error_quitter P_ ((Display *, XErrorEvent *)) NO_RETURN;
043f7f73 8001
b70001a1
RS
8002/* This is the first-level handler for X protocol errors.
8003 It calls x_error_quitter or x_error_catcher. */
8004
8005static int
8006x_error_handler (display, error)
8007 Display *display;
8008 XErrorEvent *error;
8009{
5badc98d 8010 if (x_error_message)
b70001a1
RS
8011 x_error_catcher (display, error);
8012 else
8013 x_error_quitter (display, error);
8014 return 0;
8015}
0da1ab50 8016
7a13e894
RS
8017/* This is the usual handler for X protocol errors.
8018 It kills all frames on the display that we got the error for.
8019 If that was the only one, it prints an error message and kills Emacs. */
8020
799775ff 8021/* .gdbinit puts a breakpoint here, so make sure it is not inlined. */
b70001a1 8022
799775ff
RS
8023#if __GNUC__ >= 3 /* On GCC 3.0 we might get a warning. */
8024#define NO_INLINE __attribute__((noinline))
8025#else
8026#define NO_INLINE
8027#endif
8028
285a529b
RS
8029/* Some versions of GNU/Linux define noinline in their headers. */
8030
5599ac10
RS
8031#ifdef noinline
8032#undef noinline
285a529b
RS
8033#endif
8034
799775ff
RS
8035/* On older GCC versions, just putting x_error_quitter
8036 after x_error_handler prevents inlining into the former. */
8037
8038static void NO_INLINE
c118dd06
JB
8039x_error_quitter (display, error)
8040 Display *display;
8041 XErrorEvent *error;
8042{
7a13e894 8043 char buf[256], buf1[356];
dc6f92b8 8044
58769bee 8045 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 8046 original error handler. */
dc6f92b8 8047
c118dd06 8048 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 8049 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 8050 buf, error->request_code);
7a13e894 8051 x_connection_closed (display, buf1);
dc6f92b8
JB
8052}
8053
0da1ab50 8054
e99db5a1
RS
8055/* This is the handler for X IO errors, always.
8056 It kills all frames on the display that we lost touch with.
8057 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 8058
c118dd06 8059static int
e99db5a1 8060x_io_error_quitter (display)
c118dd06 8061 Display *display;
c118dd06 8062{
e99db5a1 8063 char buf[256];
dc6f92b8 8064
e99db5a1
RS
8065 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
8066 x_connection_closed (display, buf);
06a2c219 8067 return 0;
dc6f92b8 8068}
dc6f92b8 8069\f
f451eb13
JB
8070/* Changing the font of the frame. */
8071
76bcdf39
RS
8072/* Give frame F the font named FONTNAME as its default font, and
8073 return the full name of that font. FONTNAME may be a wildcard
8074 pattern; in that case, we choose some font that fits the pattern.
8075 The return value shows which font we chose. */
8076
b5cf7a0e 8077Lisp_Object
f676886a
JB
8078x_new_font (f, fontname)
8079 struct frame *f;
dc6f92b8
JB
8080 register char *fontname;
8081{
dc43ef94 8082 struct font_info *fontp
8a78c965 8083 = FS_LOAD_FONT (f, fontname);
dc6f92b8 8084
dc43ef94
KH
8085 if (!fontp)
8086 return Qnil;
2224a5fc 8087
8f924df7 8088 if (FRAME_FONT (f) == (XFontStruct *) (fontp->font))
2570e344
KH
8089 /* This font is already set in frame F. There's nothing more to
8090 do. */
8091 return build_string (fontp->full_name);
8092
0899d58c
KS
8093 FRAME_FONT (f) = (XFontStruct *) (fontp->font);
8094 FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
8095 FRAME_FONTSET (f) = -1;
8096
6875d1ae
KH
8097 FRAME_COLUMN_WIDTH (f) = fontp->average_width;
8098 FRAME_SPACE_WIDTH (f) = fontp->space_width;
0899d58c 8099 FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (FRAME_FONT (f));
976b73d7 8100
5958f265 8101 compute_fringe_widths (f, 1);
976b73d7 8102
b2cad826 8103 /* Compute the scroll bar width in character columns. */
0899d58c 8104 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
b2cad826 8105 {
0899d58c
KS
8106 int wid = FRAME_COLUMN_WIDTH (f);
8107 FRAME_CONFIG_SCROLL_BAR_COLS (f)
8108 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid-1) / wid;
b2cad826
KH
8109 }
8110 else
4e61bddf 8111 {
0899d58c
KS
8112 int wid = FRAME_COLUMN_WIDTH (f);
8113 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
4e61bddf 8114 }
b2cad826 8115
f676886a 8116 /* Now make the frame display the given font. */
c118dd06 8117 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 8118 {
7556890b 8119 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
0899d58c 8120 FRAME_FONT (f)->fid);
7556890b 8121 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
0899d58c 8122 FRAME_FONT (f)->fid);
7556890b 8123 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
0899d58c 8124 FRAME_FONT (f)->fid);
3497f73e
GM
8125
8126 /* Don't change the size of a tip frame; there's no point in
8127 doing it because it's done in Fx_show_tip, and it leads to
8128 problems because the tip frame has no widget. */
8129 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
0899d58c 8130 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
dc6f92b8
JB
8131 }
8132
dc43ef94
KH
8133 return build_string (fontp->full_name);
8134}
8135
2570e344
KH
8136/* Give frame F the fontset named FONTSETNAME as its default fontset,
8137 and return the full name of that fontset. FONTSETNAME may be a
8138 wildcard pattern; in that case, we choose some fontset that fits
8139 the pattern. FONTSETNAME may be a font name for ASCII characters;
8140 in that case, we create a fontset from that font name.
8141
8f924df7 8142 The return value shows which fontset we chose.
a92bf2cb 8143 If FONTSETNAME specifies the default fontset, return Qt.
2570e344
KH
8144 If an ASCII font in the specified fontset can't be loaded, return
8145 Qnil. */
b5cf7a0e 8146
dc43ef94
KH
8147Lisp_Object
8148x_new_fontset (f, fontsetname)
8149 struct frame *f;
77dabd3b 8150 Lisp_Object fontsetname;
dc43ef94 8151{
77dabd3b 8152 int fontset = fs_query_fontset (fontsetname, 0);
dc43ef94 8153 Lisp_Object result;
b5cf7a0e 8154
a92bf2cb 8155 if (fontset > 0 && f->output_data.x->fontset == fontset)
2da424f1
KH
8156 /* This fontset is already set in frame F. There's nothing more
8157 to do. */
ee569018 8158 return fontset_name (fontset);
a92bf2cb
KH
8159 else if (fontset == 0)
8160 /* The default fontset can't be the default font. */
8161 return Qt;
dc43ef94 8162
8f924df7
KH
8163 if (fontset > 0)
8164 result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
8093092d 8165 else
8f924df7 8166 result = x_new_font (f, SDATA (fontsetname));
dc43ef94
KH
8167
8168 if (!STRINGP (result))
8169 /* Can't load ASCII font. */
8170 return Qnil;
8171
8093092d 8172 if (fontset < 0)
77dabd3b 8173 fontset = new_fontset_from_font_name (result);
8093092d 8174
dc43ef94 8175 /* Since x_new_font doesn't update any fontset information, do it now. */
0899d58c 8176 FRAME_FONTSET (f) = fontset;
dc43ef94 8177
f5d11644
GM
8178#ifdef HAVE_X_I18N
8179 if (FRAME_XIC (f)
8180 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
d5db4077 8181 xic_set_xfontset (f, SDATA (fontset_ascii (fontset)));
f5d11644 8182#endif
7d0393cf 8183
8093092d 8184 return fontset_name (fontset);
dc6f92b8 8185}
f5d11644 8186
c9ff09ee
KH
8187#ifdef USE_FONT_BACKEND
8188Lisp_Object
8140317c 8189x_new_fontset2 (f, fontset, font_object)
c9ff09ee 8190 struct frame *f;
8140317c
KH
8191 int fontset;
8192 Lisp_Object font_object;
c9ff09ee 8193{
8140317c 8194 struct font *font = XSAVE_VALUE (font_object)->pointer;
c9ff09ee 8195
8140317c 8196 if (FRAME_FONT_OBJECT (f) == font)
c9ff09ee
KH
8197 /* This font is already set in frame F. There's nothing more to
8198 do. */
8199 return fontset_name (fontset);
8200
8201 BLOCK_INPUT;
8202
8140317c
KH
8203 FRAME_FONT_OBJECT (f) = font;
8204 FRAME_FONT (f) = font->font.font;
c9ff09ee
KH
8205 FRAME_BASELINE_OFFSET (f) = font->font.baseline_offset;
8206 FRAME_FONTSET (f) = fontset;
8207
8208 FRAME_COLUMN_WIDTH (f) = font->font.average_width;
8209 FRAME_SPACE_WIDTH (f) = font->font.space_width;
8210 FRAME_LINE_HEIGHT (f) = font->font.height;
8211
8212 compute_fringe_widths (f, 1);
8213
8214 /* Compute the scroll bar width in character columns. */
8215 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8216 {
8217 int wid = FRAME_COLUMN_WIDTH (f);
8218 FRAME_CONFIG_SCROLL_BAR_COLS (f)
8219 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8220 }
8221 else
8222 {
8223 int wid = FRAME_COLUMN_WIDTH (f);
8224 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8225 }
8226
8227 /* Now make the frame display the given font. */
8228 if (FRAME_X_WINDOW (f) != 0)
8229 {
8230 /* Don't change the size of a tip frame; there's no point in
8231 doing it because it's done in Fx_show_tip, and it leads to
8232 problems because the tip frame has no widget. */
8233 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
8234 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
8235 }
8236
8237#ifdef HAVE_X_I18N
8238 if (FRAME_XIC (f)
8239 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
8240 xic_set_xfontset (f, SDATA (fontset_ascii (fontset)));
8241#endif
8242
8243 UNBLOCK_INPUT;
8244
8245 return fontset_name (fontset);
8246}
8247#endif /* USE_FONT_BACKEND */
8248
f5d11644
GM
8249\f
8250/***********************************************************************
8251 X Input Methods
8252 ***********************************************************************/
8253
8254#ifdef HAVE_X_I18N
8255
8256#ifdef HAVE_X11R6
8257
8258/* XIM destroy callback function, which is called whenever the
8259 connection to input method XIM dies. CLIENT_DATA contains a
8260 pointer to the x_display_info structure corresponding to XIM. */
8261
8262static void
8263xim_destroy_callback (xim, client_data, call_data)
8264 XIM xim;
8265 XPointer client_data;
8266 XPointer call_data;
8267{
8268 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
8269 Lisp_Object frame, tail;
7d0393cf 8270
f5d11644 8271 BLOCK_INPUT;
7d0393cf 8272
f5d11644
GM
8273 /* No need to call XDestroyIC.. */
8274 FOR_EACH_FRAME (tail, frame)
8275 {
8276 struct frame *f = XFRAME (frame);
8277 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
8278 {
8279 FRAME_XIC (f) = NULL;
c27ed90a 8280 xic_free_xfontset (f);
f5d11644
GM
8281 }
8282 }
7d0393cf 8283
f5d11644
GM
8284 /* No need to call XCloseIM. */
8285 dpyinfo->xim = NULL;
8286 XFree (dpyinfo->xim_styles);
8287 UNBLOCK_INPUT;
8288}
8289
8290#endif /* HAVE_X11R6 */
8291
dbd4b028
DL
8292#ifdef HAVE_X11R6
8293/* This isn't prototyped in OSF 5.0 or 5.1a. */
8294extern char *XSetIMValues P_ ((XIM, ...));
8295#endif
8296
f5d11644
GM
8297/* Open the connection to the XIM server on display DPYINFO.
8298 RESOURCE_NAME is the resource name Emacs uses. */
8299
8300static void
8301xim_open_dpy (dpyinfo, resource_name)
8302 struct x_display_info *dpyinfo;
8303 char *resource_name;
8304{
8305 XIM xim;
8306
7e7ade6e 8307#ifdef HAVE_XIM
51f3cc3b 8308 if (use_xim)
f5d11644 8309 {
51f3cc3b
DL
8310 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name,
8311 EMACS_CLASS);
8312 dpyinfo->xim = xim;
8313
8314 if (xim)
8315 {
f5d11644 8316#ifdef HAVE_X11R6
51f3cc3b 8317 XIMCallback destroy;
f5d11644 8318#endif
7d0393cf 8319
51f3cc3b
DL
8320 /* Get supported styles and XIM values. */
8321 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
7d0393cf 8322
f5d11644 8323#ifdef HAVE_X11R6
51f3cc3b
DL
8324 destroy.callback = xim_destroy_callback;
8325 destroy.client_data = (XPointer)dpyinfo;
8326 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
f5d11644 8327#endif
51f3cc3b 8328 }
f5d11644 8329 }
7d0393cf 8330
51f3cc3b 8331 else
7e7ade6e 8332#endif /* HAVE_XIM */
51f3cc3b 8333 dpyinfo->xim = NULL;
f5d11644
GM
8334}
8335
8336
b9de836c 8337#ifdef HAVE_X11R6_XIM
f5d11644
GM
8338
8339struct xim_inst_t
8340{
8341 struct x_display_info *dpyinfo;
8342 char *resource_name;
8343};
8344
8345/* XIM instantiate callback function, which is called whenever an XIM
1fcfb866 8346 server is available. DISPLAY is the display of the XIM.
f5d11644
GM
8347 CLIENT_DATA contains a pointer to an xim_inst_t structure created
8348 when the callback was registered. */
8349
8350static void
8351xim_instantiate_callback (display, client_data, call_data)
8352 Display *display;
8353 XPointer client_data;
8354 XPointer call_data;
8355{
8356 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
8357 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
8358
8359 /* We don't support multiple XIM connections. */
8360 if (dpyinfo->xim)
8361 return;
7d0393cf 8362
f5d11644
GM
8363 xim_open_dpy (dpyinfo, xim_inst->resource_name);
8364
8365 /* Create XIC for the existing frames on the same display, as long
8366 as they have no XIC. */
8367 if (dpyinfo->xim && dpyinfo->reference_count > 0)
8368 {
8369 Lisp_Object tail, frame;
8370
8371 BLOCK_INPUT;
8372 FOR_EACH_FRAME (tail, frame)
8373 {
8374 struct frame *f = XFRAME (frame);
7d0393cf 8375
f5d11644
GM
8376 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
8377 if (FRAME_XIC (f) == NULL)
8378 {
8379 create_frame_xic (f);
8380 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
8381 xic_set_statusarea (f);
8382 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
8383 {
8384 struct window *w = XWINDOW (f->selected_window);
8385 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
8386 }
8387 }
8388 }
7d0393cf 8389
f5d11644
GM
8390 UNBLOCK_INPUT;
8391 }
8392}
8393
b9de836c 8394#endif /* HAVE_X11R6_XIM */
f5d11644
GM
8395
8396
8397/* Open a connection to the XIM server on display DPYINFO.
8398 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
8399 connection only at the first time. On X11R6, open the connection
8400 in the XIM instantiate callback function. */
8401
8402static void
8403xim_initialize (dpyinfo, resource_name)
8404 struct x_display_info *dpyinfo;
8405 char *resource_name;
8406{
7e7ade6e 8407#ifdef HAVE_XIM
51f3cc3b
DL
8408 if (use_xim)
8409 {
b9de836c 8410#ifdef HAVE_X11R6_XIM
51f3cc3b
DL
8411 struct xim_inst_t *xim_inst;
8412 int len;
8413
8414 dpyinfo->xim = NULL;
8415 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
8416 xim_inst->dpyinfo = dpyinfo;
8417 len = strlen (resource_name);
8418 xim_inst->resource_name = (char *) xmalloc (len + 1);
8419 bcopy (resource_name, xim_inst->resource_name, len + 1);
8420 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
8421 resource_name, EMACS_CLASS,
8422 xim_instantiate_callback,
bcea31c2
DL
8423 /* This is XPointer in XFree86
8424 but (XPointer *) on Tru64, at
8425 least, hence the configure test. */
fdc39b59 8426 (XRegisterIMInstantiateCallback_arg6) xim_inst);
b9de836c 8427#else /* not HAVE_X11R6_XIM */
51f3cc3b
DL
8428 dpyinfo->xim = NULL;
8429 xim_open_dpy (dpyinfo, resource_name);
b9de836c 8430#endif /* not HAVE_X11R6_XIM */
7d0393cf 8431
51f3cc3b
DL
8432 }
8433 else
7e7ade6e 8434#endif /* HAVE_XIM */
51f3cc3b 8435 dpyinfo->xim = NULL;
f5d11644
GM
8436}
8437
8438
8439/* Close the connection to the XIM server on display DPYINFO. */
8440
8441static void
8442xim_close_dpy (dpyinfo)
8443 struct x_display_info *dpyinfo;
8444{
7e7ade6e 8445#ifdef HAVE_XIM
51f3cc3b
DL
8446 if (use_xim)
8447 {
b9de836c 8448#ifdef HAVE_X11R6_XIM
51f3cc3b
DL
8449 if (dpyinfo->display)
8450 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
8451 NULL, EMACS_CLASS,
8452 xim_instantiate_callback, NULL);
b9de836c 8453#endif /* not HAVE_X11R6_XIM */
51f3cc3b
DL
8454 if (dpyinfo->display)
8455 XCloseIM (dpyinfo->xim);
8456 dpyinfo->xim = NULL;
8457 XFree (dpyinfo->xim_styles);
8458 }
7e7ade6e 8459#endif /* HAVE_XIM */
f5d11644
GM
8460}
8461
b9de836c 8462#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
8463
8464
dc6f92b8 8465\f
2e365682
RS
8466/* Calculate the absolute position in frame F
8467 from its current recorded position values and gravity. */
8468
dfcf069d 8469void
43bca5d5 8470x_calc_absolute_position (f)
f676886a 8471 struct frame *f;
dc6f92b8 8472{
0899d58c 8473 int flags = f->size_hint_flags;
c81412a0 8474
9829ddba
RS
8475 /* We have nothing to do if the current position
8476 is already for the top-left corner. */
8477 if (! ((flags & XNegative) || (flags & YNegative)))
8478 return;
8479
6dba1858
RS
8480 /* Treat negative positions as relative to the leftmost bottommost
8481 position that fits on the screen. */
20f55f9a 8482 if (flags & XNegative)
0899d58c 8483 f->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
c83c9f9d 8484 - FRAME_PIXEL_WIDTH (f) + f->left_pos);
dc6f92b8 8485
7708ced0 8486 {
0899d58c 8487 int height = FRAME_PIXEL_HEIGHT (f);
06a2c219 8488
7708ced0
GM
8489#if defined USE_X_TOOLKIT && defined USE_MOTIF
8490 /* Something is fishy here. When using Motif, starting Emacs with
8491 `-g -0-0', the frame appears too low by a few pixels.
8492
8493 This seems to be so because initially, while Emacs is starting,
8494 the column widget's height and the frame's pixel height are
8495 different. The column widget's height is the right one. In
8496 later invocations, when Emacs is up, the frame's pixel height
8497 is right, though.
8498
8499 It's not obvious where the initial small difference comes from.
8500 2000-12-01, gerd. */
7d0393cf 8501
7708ced0 8502 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
06a2c219 8503#endif
2e365682 8504
7708ced0 8505 if (flags & YNegative)
c83c9f9d 8506 f->top_pos = (FRAME_X_DISPLAY_INFO (f)->height - height + f->top_pos);
7708ced0 8507 }
7d0393cf 8508
3a35ab44
RS
8509 /* The left_pos and top_pos
8510 are now relative to the top and left screen edges,
8511 so the flags should correspond. */
0899d58c 8512 f->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
8513}
8514
3a35ab44
RS
8515/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
8516 to really change the position, and 0 when calling from
8517 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
8518 position values). It is -1 when calling from x_set_frame_parameters,
8519 which means, do adjust for borders but don't change the gravity. */
3a35ab44 8520
dfcf069d 8521void
dc05a16b 8522x_set_offset (f, xoff, yoff, change_gravity)
f676886a 8523 struct frame *f;
dc6f92b8 8524 register int xoff, yoff;
dc05a16b 8525 int change_gravity;
dc6f92b8 8526{
4a4cbdd5
KH
8527 int modified_top, modified_left;
8528
d692a3d5 8529 if (change_gravity != 0)
3a35ab44 8530 {
d692a3d5
JD
8531 FRAME_X_OUTPUT (f)->left_before_move = f->left_pos;
8532 FRAME_X_OUTPUT (f)->top_before_move = f->top_pos;
8533
0899d58c
KS
8534 f->top_pos = yoff;
8535 f->left_pos = xoff;
8536 f->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 8537 if (xoff < 0)
0899d58c 8538 f->size_hint_flags |= XNegative;
3a35ab44 8539 if (yoff < 0)
0899d58c
KS
8540 f->size_hint_flags |= YNegative;
8541 f->win_gravity = NorthWestGravity;
3a35ab44 8542 }
43bca5d5 8543 x_calc_absolute_position (f);
dc6f92b8
JB
8544
8545 BLOCK_INPUT;
c32cdd9a 8546 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 8547
0899d58c
KS
8548 modified_left = f->left_pos;
8549 modified_top = f->top_pos;
6b61353c 8550
d692a3d5 8551 if (change_gravity != 0 && FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A)
4a4cbdd5 8552 {
6b61353c
KH
8553 /* Some WMs (twm, wmaker at least) has an offset that is smaller
8554 than the WM decorations. So we use the calculated offset instead
8555 of the WM decoration sizes here (x/y_pixels_outer_diff). */
8556 modified_left += FRAME_X_OUTPUT (f)->move_offset_left;
8557 modified_top += FRAME_X_OUTPUT (f)->move_offset_top;
4a4cbdd5
KH
8558 }
8559
488dd4c4
JD
8560 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
8561 modified_left, modified_top);
6b61353c 8562
d692a3d5
JD
8563 x_sync_with_move (f, f->left_pos, f->top_pos,
8564 FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
8565 ? 1 : 0);
8566
8567 /* change_gravity is non-zero when this function is called from Lisp to
8568 programmatically move a frame. In that case, we call
8569 x_check_expected_move to discover if we have a "Type A" or "Type B"
8570 window manager, and, for a "Type A" window manager, adjust the position
8571 of the frame.
8572
8573 We call x_check_expected_move if a programmatic move occurred, and
8574 either the window manager type (A/B) is unknown or it is Type A but we
8575 need to compute the top/left offset adjustment for this frame. */
8576
8577 if (change_gravity != 0 &&
8578 (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
8579 || (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
8580 && (FRAME_X_OUTPUT (f)->move_offset_left == 0
8581 && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
8582 x_check_expected_move (f, modified_left, modified_top);
6b61353c 8583
dc6f92b8
JB
8584 UNBLOCK_INPUT;
8585}
8586
d0fa3e56
EZ
8587/* Check if we need to resize the frame due to a fullscreen request.
8588 If so needed, resize the frame. */
8589static void
8590x_check_fullscreen (f)
8591 struct frame *f;
8592{
0899d58c 8593 if (f->want_fullscreen & FULLSCREEN_BOTH)
d0fa3e56
EZ
8594 {
8595 int width, height, ign;
7d0393cf 8596
0899d58c 8597 x_real_positions (f, &f->left_pos, &f->top_pos);
d0fa3e56
EZ
8598
8599 x_fullscreen_adjust (f, &width, &height, &ign, &ign);
7d0393cf 8600
d0fa3e56
EZ
8601 /* We do not need to move the window, it shall be taken care of
8602 when setting WM manager hints.
8603 If the frame is visible already, the position is checked by
6b61353c 8604 x_check_expected_move. */
0899d58c 8605 if (FRAME_COLS (f) != width || FRAME_LINES (f) != height)
d0fa3e56
EZ
8606 {
8607 change_frame_size (f, height, width, 0, 1, 0);
8608 SET_FRAME_GARBAGED (f);
8609 cancel_mouse_face (f);
8610
8611 /* Wait for the change of frame size to occur */
0899d58c 8612 f->want_fullscreen |= FULLSCREEN_WAIT;
d0fa3e56
EZ
8613 }
8614 }
8615}
8616
d692a3d5
JD
8617/* This function is called by x_set_offset to determine whether the window
8618 manager interfered with the positioning of the frame. Type A window
8619 managers position the surrounding window manager decorations a small
8620 amount above and left of the user-supplied position. Type B window
8621 managers position the surrounding window manager decorations at the
8622 user-specified position. If we detect a Type A window manager, we
8623 compensate by moving the window right and down by the proper amount. */
8624
d0fa3e56 8625static void
d692a3d5 8626x_check_expected_move (f, expected_left, expected_top)
d0fa3e56 8627 struct frame *f;
d692a3d5
JD
8628 int expected_left;
8629 int expected_top;
d0fa3e56 8630{
d692a3d5
JD
8631 int count = 0, current_left = 0, current_top = 0;
8632
8633 /* x_real_positions returns the left and top offsets of the outermost
8634 window manager window around the frame. */
7d0393cf 8635
d692a3d5
JD
8636 x_real_positions (f, &current_left, &current_top);
8637
8638 if (current_left != expected_left || current_top != expected_top)
6b61353c 8639 {
d692a3d5
JD
8640 /* It's a "Type A" window manager. */
8641
8642 int adjusted_left;
8643 int adjusted_top;
8644
6b61353c 8645 FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_A;
d692a3d5
JD
8646 FRAME_X_OUTPUT (f)->move_offset_left = expected_left - current_left;
8647 FRAME_X_OUTPUT (f)->move_offset_top = expected_top - current_top;
8648
8649 /* Now fix the mispositioned frame's location. */
6b61353c 8650
d692a3d5
JD
8651 adjusted_left = expected_left + FRAME_X_OUTPUT (f)->move_offset_left;
8652 adjusted_top = expected_top + FRAME_X_OUTPUT (f)->move_offset_top;
8653
8654 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
8655 adjusted_left, adjusted_top);
8656
8657 x_sync_with_move (f, expected_left, expected_top, 0);
6b61353c 8658 }
d692a3d5
JD
8659 else
8660 /* It's a "Type B" window manager. We don't have to adjust the
8661 frame's position. */
8662
6b61353c 8663 FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_B;
d692a3d5
JD
8664}
8665
8666
8667/* Wait for XGetGeometry to return up-to-date position information for a
8668 recently-moved frame. Call this immediately after calling XMoveWindow.
8669 If FUZZY is non-zero, then LEFT and TOP are just estimates of where the
8670 frame has been moved to, so we use a fuzzy position comparison instead
8671 of an exact comparison. */
8672
8673static void
8674x_sync_with_move (f, left, top, fuzzy)
8675 struct frame *f;
8676 int left, top, fuzzy;
8677{
8678 int count = 0;
8679
8680 while (count++ < 50)
8681 {
8682 int current_left = 0, current_top = 0;
8683
8684 /* In theory, this call to XSync only needs to happen once, but in
8685 practice, it doesn't seem to work, hence the need for the surrounding
8686 loop. */
8687
8688 XSync (FRAME_X_DISPLAY (f), False);
8689 x_real_positions (f, &current_left, &current_top);
8690
8691 if (fuzzy)
8692 {
8693 /* The left fuzz-factor is 10 pixels. The top fuzz-factor is 40
8694 pixels. */
d0fa3e56 8695
d692a3d5
JD
8696 if (abs (current_left - left) <= 10 && abs (current_top - top) <= 40)
8697 return;
d0fa3e56 8698 }
d692a3d5
JD
8699 else if (current_left == left && current_top == top)
8700 return;
8701 }
8702
8703 /* As a last resort, just wait 0.5 seconds and hope that XGetGeometry
8704 will then return up-to-date position info. */
8705
8706 wait_reading_process_output (0, 500000, 0, 0, Qnil, NULL, 0);
d0fa3e56
EZ
8707}
8708
8709
499b1844
GM
8710/* Change the size of frame F's X window to COLS/ROWS in the case F
8711 doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
8712 top-left-corner window gravity for this size change and subsequent
8713 size changes. Otherwise we leave the window gravity unchanged. */
8714
8715static void
8716x_set_window_size_1 (f, change_gravity, cols, rows)
f676886a 8717 struct frame *f;
bc20ebbf 8718 int change_gravity;
b1c884c3 8719 int cols, rows;
dc6f92b8
JB
8720{
8721 int pixelwidth, pixelheight;
80fd1fe2 8722
b1c884c3 8723 check_frame_size (f, &rows, &cols);
0899d58c 8724 f->scroll_bar_actual_width
b2cad826
KH
8725 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
8726 ? 0
0899d58c
KS
8727 : FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0
8728 ? FRAME_CONFIG_SCROLL_BAR_WIDTH (f)
8729 : (FRAME_CONFIG_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)));
976b73d7 8730
5958f265 8731 compute_fringe_widths (f, 0);
976b73d7 8732
0899d58c
KS
8733 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
8734 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 8735
0899d58c 8736 f->win_gravity = NorthWestGravity;
c32cdd9a 8737 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 8738
334208b7
RS
8739 XSync (FRAME_X_DISPLAY (f), False);
8740 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8741 pixelwidth, pixelheight);
b1c884c3
JB
8742
8743 /* Now, strictly speaking, we can't be sure that this is accurate,
8744 but the window manager will get around to dealing with the size
8745 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
8746 ConfigureNotify event gets here.
8747
8748 We could just not bother storing any of this information here,
8749 and let the ConfigureNotify event set everything up, but that
fddd5ceb 8750 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 8751 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
8752 point in the future when the ConfigureNotify event arrives.
8753
8754 We pass 1 for DELAY since we can't run Lisp code inside of
8755 a BLOCK_INPUT. */
7d1e984f 8756 change_frame_size (f, rows, cols, 0, 1, 0);
0899d58c
KS
8757 FRAME_PIXEL_WIDTH (f) = pixelwidth;
8758 FRAME_PIXEL_HEIGHT (f) = pixelheight;
b1c884c3 8759
aee9a898
RS
8760 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
8761 receive in the ConfigureNotify event; if we get what we asked
8762 for, then the event won't cause the screen to become garbaged, so
8763 we have to make sure to do it here. */
8764 SET_FRAME_GARBAGED (f);
8765
8766 XFlush (FRAME_X_DISPLAY (f));
499b1844
GM
8767}
8768
8769
8770/* Call this to change the size of frame F's x-window.
8771 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
8772 for this size change and subsequent size changes.
8773 Otherwise we leave the window gravity unchanged. */
aee9a898 8774
499b1844
GM
8775void
8776x_set_window_size (f, change_gravity, cols, rows)
8777 struct frame *f;
8778 int change_gravity;
8779 int cols, rows;
8780{
8781 BLOCK_INPUT;
8782
488dd4c4
JD
8783#ifdef USE_GTK
8784 if (FRAME_GTK_WIDGET (f))
8785 xg_frame_set_char_size (f, cols, rows);
8786 else
8787 x_set_window_size_1 (f, change_gravity, cols, rows);
8788#elif USE_X_TOOLKIT
7d0393cf 8789
f1f4d345 8790 if (f->output_data.x->widget != NULL)
499b1844
GM
8791 {
8792 /* The x and y position of the widget is clobbered by the
8793 call to XtSetValues within EmacsFrameSetCharSize.
8794 This is a real kludge, but I don't understand Xt so I can't
8795 figure out a correct fix. Can anyone else tell me? -- rms. */
8796 int xpos = f->output_data.x->widget->core.x;
8797 int ypos = f->output_data.x->widget->core.y;
8798 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
8799 f->output_data.x->widget->core.x = xpos;
8800 f->output_data.x->widget->core.y = ypos;
8801 }
8802 else
8803 x_set_window_size_1 (f, change_gravity, cols, rows);
7d0393cf 8804
499b1844 8805#else /* not USE_X_TOOLKIT */
7d0393cf 8806
499b1844 8807 x_set_window_size_1 (f, change_gravity, cols, rows);
7d0393cf 8808
aee9a898
RS
8809#endif /* not USE_X_TOOLKIT */
8810
4d73d038 8811 /* If cursor was outside the new size, mark it as off. */
06a2c219 8812 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 8813
aee9a898 8814 /* Clear out any recollection of where the mouse highlighting was,
7d0393cf 8815 since it might be in a place that's outside the new frame size.
aee9a898
RS
8816 Actually checking whether it is outside is a pain in the neck,
8817 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 8818 cancel_mouse_face (f);
dbc4e1c1 8819
dc6f92b8
JB
8820 UNBLOCK_INPUT;
8821}
dc6f92b8 8822\f
d047c4eb 8823/* Mouse warping. */
dc6f92b8 8824
9b378208 8825void
f676886a
JB
8826x_set_mouse_position (f, x, y)
8827 struct frame *f;
dc6f92b8
JB
8828 int x, y;
8829{
8830 int pix_x, pix_y;
8831
0899d58c
KS
8832 pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
8833 pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
f451eb13
JB
8834
8835 if (pix_x < 0) pix_x = 0;
0899d58c 8836 if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
f451eb13
JB
8837
8838 if (pix_y < 0) pix_y = 0;
0899d58c 8839 if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
dc6f92b8
JB
8840
8841 BLOCK_INPUT;
dc6f92b8 8842
334208b7
RS
8843 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
8844 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
8845 UNBLOCK_INPUT;
8846}
8847
9b378208
RS
8848/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
8849
8850void
8851x_set_mouse_pixel_position (f, pix_x, pix_y)
8852 struct frame *f;
8853 int pix_x, pix_y;
8854{
8855 BLOCK_INPUT;
8856
334208b7
RS
8857 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
8858 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
8859 UNBLOCK_INPUT;
8860}
d047c4eb
KH
8861\f
8862/* focus shifting, raising and lowering. */
9b378208 8863
dfcf069d 8864void
f676886a
JB
8865x_focus_on_frame (f)
8866 struct frame *f;
dc6f92b8 8867{
1fb20991 8868#if 0 /* This proves to be unpleasant. */
f676886a 8869 x_raise_frame (f);
1fb20991 8870#endif
6d4238f3
JB
8871#if 0
8872 /* I don't think that the ICCCM allows programs to do things like this
8873 without the interaction of the window manager. Whatever you end up
f676886a 8874 doing with this code, do it to x_unfocus_frame too. */
334208b7 8875 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 8876 RevertToPointerRoot, CurrentTime);
c118dd06 8877#endif /* ! 0 */
dc6f92b8
JB
8878}
8879
dfcf069d 8880void
f676886a
JB
8881x_unfocus_frame (f)
8882 struct frame *f;
dc6f92b8 8883{
6d4238f3 8884#if 0
f676886a 8885 /* Look at the remarks in x_focus_on_frame. */
0f941935 8886 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 8887 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 8888 RevertToPointerRoot, CurrentTime);
c118dd06 8889#endif /* ! 0 */
dc6f92b8
JB
8890}
8891
f676886a 8892/* Raise frame F. */
dc6f92b8 8893
dfcf069d 8894void
f676886a
JB
8895x_raise_frame (f)
8896 struct frame *f;
dc6f92b8 8897{
3a88c238 8898 if (f->async_visible)
dc6f92b8
JB
8899 {
8900 BLOCK_INPUT;
2436a4e4 8901 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
334208b7 8902 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
8903 UNBLOCK_INPUT;
8904 }
8905}
8906
f676886a 8907/* Lower frame F. */
dc6f92b8 8908
dfcf069d 8909void
f676886a
JB
8910x_lower_frame (f)
8911 struct frame *f;
dc6f92b8 8912{
3a88c238 8913 if (f->async_visible)
dc6f92b8
JB
8914 {
8915 BLOCK_INPUT;
2436a4e4 8916 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
334208b7 8917 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
8918 UNBLOCK_INPUT;
8919 }
8920}
8921
dbc4e1c1 8922static void
6b0442dc 8923XTframe_raise_lower (f, raise_flag)
dbc4e1c1 8924 FRAME_PTR f;
6b0442dc 8925 int raise_flag;
dbc4e1c1 8926{
6b0442dc 8927 if (raise_flag)
dbc4e1c1
JB
8928 x_raise_frame (f);
8929 else
8930 x_lower_frame (f);
8931}
d047c4eb
KH
8932\f
8933/* Change of visibility. */
dc6f92b8 8934
9382638d
KH
8935/* This tries to wait until the frame is really visible.
8936 However, if the window manager asks the user where to position
8937 the frame, this will return before the user finishes doing that.
8938 The frame will not actually be visible at that time,
8939 but it will become visible later when the window manager
8940 finishes with it. */
8941
dfcf069d 8942void
f676886a
JB
8943x_make_frame_visible (f)
8944 struct frame *f;
dc6f92b8 8945{
990ba854 8946 Lisp_Object type;
1aa6072f 8947 int original_top, original_left;
31be9251
GM
8948 int retry_count = 2;
8949
8950 retry:
dc6f92b8 8951
dc6f92b8 8952 BLOCK_INPUT;
dc6f92b8 8953
990ba854
RS
8954 type = x_icon_type (f);
8955 if (!NILP (type))
8956 x_bitmap_icon (f, type);
bdcd49ba 8957
f676886a 8958 if (! FRAME_VISIBLE_P (f))
90e65f07 8959 {
1aa6072f
RS
8960 /* We test FRAME_GARBAGED_P here to make sure we don't
8961 call x_set_offset a second time
8962 if we get to x_make_frame_visible a second time
8963 before the window gets really visible. */
8964 if (! FRAME_ICONIFIED_P (f)
8965 && ! f->output_data.x->asked_for_visible)
0899d58c 8966 x_set_offset (f, f->left_pos, f->top_pos, 0);
1aa6072f
RS
8967
8968 f->output_data.x->asked_for_visible = 1;
8969
90e65f07 8970 if (! EQ (Vx_no_window_manager, Qt))
f676886a 8971 x_wm_set_window_state (f, NormalState);
3afe33e7 8972#ifdef USE_X_TOOLKIT
d7a38a2e 8973 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 8974 XtMapWidget (f->output_data.x->widget);
3afe33e7 8975#else /* not USE_X_TOOLKIT */
488dd4c4
JD
8976#ifdef USE_GTK
8977 gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
7b76ca1c 8978 gtk_window_deiconify (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
488dd4c4 8979#else
7f9c7f94 8980 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
488dd4c4 8981#endif /* not USE_GTK */
3afe33e7 8982#endif /* not USE_X_TOOLKIT */
0134a210
RS
8983#if 0 /* This seems to bring back scroll bars in the wrong places
8984 if the window configuration has changed. They seem
8985 to come back ok without this. */
ab648270 8986 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 8987 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 8988#endif
90e65f07 8989 }
dc6f92b8 8990
334208b7 8991 XFlush (FRAME_X_DISPLAY (f));
90e65f07 8992
0dacf791
RS
8993 /* Synchronize to ensure Emacs knows the frame is visible
8994 before we do anything else. We do this loop with input not blocked
8995 so that incoming events are handled. */
8996 {
8997 Lisp_Object frame;
12ce2351 8998 int count;
28c01ffe
RS
8999 /* This must be before UNBLOCK_INPUT
9000 since events that arrive in response to the actions above
9001 will set it when they are handled. */
9002 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f 9003
0899d58c
KS
9004 original_left = f->left_pos;
9005 original_top = f->top_pos;
c0a04927
RS
9006
9007 /* This must come after we set COUNT. */
9008 UNBLOCK_INPUT;
9009
2745e6c4 9010 /* We unblock here so that arriving X events are processed. */
1aa6072f 9011
dcb07ae9
RS
9012 /* Now move the window back to where it was "supposed to be".
9013 But don't do it if the gravity is negative.
9014 When the gravity is negative, this uses a position
28c01ffe
RS
9015 that is 3 pixels too low. Perhaps that's really the border width.
9016
9017 Don't do this if the window has never been visible before,
9018 because the window manager may choose the position
9019 and we don't want to override it. */
1aa6072f 9020
4d3f5d9a 9021 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
0899d58c 9022 && f->win_gravity == NorthWestGravity
28c01ffe 9023 && previously_visible)
1aa6072f 9024 {
2745e6c4
RS
9025 Drawable rootw;
9026 int x, y;
9027 unsigned int width, height, border, depth;
7d0393cf 9028
1aa6072f 9029 BLOCK_INPUT;
9829ddba 9030
06a2c219
GM
9031 /* On some window managers (such as FVWM) moving an existing
9032 window, even to the same place, causes the window manager
9033 to introduce an offset. This can cause the window to move
9034 to an unexpected location. Check the geometry (a little
9035 slow here) and then verify that the window is in the right
9036 place. If the window is not in the right place, move it
9037 there, and take the potential window manager hit. */
2745e6c4
RS
9038 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
9039 &rootw, &x, &y, &width, &height, &border, &depth);
9040
9041 if (original_left != x || original_top != y)
9042 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
9043 original_left, original_top);
9044
1aa6072f
RS
9045 UNBLOCK_INPUT;
9046 }
9829ddba 9047
e0c1aef2 9048 XSETFRAME (frame, f);
c0a04927 9049
12ce2351
GM
9050 /* Wait until the frame is visible. Process X events until a
9051 MapNotify event has been seen, or until we think we won't get a
9052 MapNotify at all.. */
9053 for (count = input_signal_count + 10;
9054 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 9055 {
12ce2351 9056 /* Force processing of queued events. */
334208b7 9057 x_sync (f);
12ce2351
GM
9058
9059 /* Machines that do polling rather than SIGIO have been
9060 observed to go into a busy-wait here. So we'll fake an
9061 alarm signal to let the handler know that there's something
9062 to be read. We used to raise a real alarm, but it seems
9063 that the handler isn't always enabled here. This is
9064 probably a bug. */
8b2f8d4e 9065 if (input_polling_used ())
3b2fa4e6 9066 {
12ce2351
GM
9067 /* It could be confusing if a real alarm arrives while
9068 processing the fake one. Turn it off and let the
9069 handler reset it. */
3e71d8f2 9070 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
9071 int old_poll_suppress_count = poll_suppress_count;
9072 poll_suppress_count = 1;
9073 poll_for_input_1 ();
9074 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 9075 }
12ce2351
GM
9076
9077 /* See if a MapNotify event has been processed. */
9078 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 9079 }
31be9251
GM
9080
9081 /* 2000-09-28: In
9082
9083 (let ((f (selected-frame)))
9084 (iconify-frame f)
9085 (raise-frame f))
9086
9087 the frame is not raised with various window managers on
554061d8 9088 FreeBSD, GNU/Linux and Solaris. It turns out that, for some
31be9251
GM
9089 unknown reason, the call to XtMapWidget is completely ignored.
9090 Mapping the widget a second time works. */
7d0393cf 9091
31be9251
GM
9092 if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
9093 goto retry;
0dacf791 9094 }
dc6f92b8
JB
9095}
9096
06a2c219 9097/* Change from mapped state to withdrawn state. */
dc6f92b8 9098
d047c4eb
KH
9099/* Make the frame visible (mapped and not iconified). */
9100
dfcf069d 9101void
f676886a
JB
9102x_make_frame_invisible (f)
9103 struct frame *f;
dc6f92b8 9104{
546e6d5b
RS
9105 Window window;
9106
546e6d5b 9107 /* Use the frame's outermost window, not the one we normally draw on. */
2436a4e4 9108 window = FRAME_OUTER_WINDOW (f);
dc6f92b8 9109
9319ae23 9110 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
9111 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
9112 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 9113
5627c40e 9114#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 9115 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 9116 return;
5627c40e 9117#endif
dc6f92b8
JB
9118
9119 BLOCK_INPUT;
c118dd06 9120
af31d76f
RS
9121 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
9122 that the current position of the window is user-specified, rather than
9123 program-specified, so that when the window is mapped again, it will be
9124 placed at the same location, without forcing the user to position it
9125 by hand again (they have already done that once for this window.) */
c32cdd9a 9126 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 9127
488dd4c4
JD
9128#ifdef USE_GTK
9129 if (FRAME_GTK_OUTER_WIDGET (f))
3c671a56
SM
9130 gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f));
9131 else
488dd4c4 9132#endif
3c671a56 9133 {
c118dd06
JB
9134#ifdef HAVE_X11R4
9135
334208b7
RS
9136 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
9137 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
9138 {
9139 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 9140 error ("Can't notify window manager of window withdrawal");
c118dd06 9141 }
c118dd06 9142#else /* ! defined (HAVE_X11R4) */
16bd92ea 9143
c118dd06 9144 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
9145 if (! EQ (Vx_no_window_manager, Qt))
9146 {
16bd92ea 9147 XEvent unmap;
dc6f92b8 9148
16bd92ea 9149 unmap.xunmap.type = UnmapNotify;
546e6d5b 9150 unmap.xunmap.window = window;
334208b7 9151 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 9152 unmap.xunmap.from_configure = False;
334208b7
RS
9153 if (! XSendEvent (FRAME_X_DISPLAY (f),
9154 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 9155 False,
06a2c219 9156 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
9157 &unmap))
9158 {
9159 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 9160 error ("Can't notify window manager of withdrawal");
16bd92ea 9161 }
dc6f92b8
JB
9162 }
9163
16bd92ea 9164 /* Unmap the window ourselves. Cheeky! */
334208b7 9165 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 9166#endif /* ! defined (HAVE_X11R4) */
3c671a56 9167 }
dc6f92b8 9168
5627c40e
RS
9169 /* We can't distinguish this from iconification
9170 just by the event that we get from the server.
9171 So we can't win using the usual strategy of letting
9172 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
9173 and synchronize with the server to make sure we agree. */
9174 f->visible = 0;
9175 FRAME_ICONIFIED_P (f) = 0;
9176 f->async_visible = 0;
9177 f->async_iconified = 0;
9178
334208b7 9179 x_sync (f);
5627c40e 9180
dc6f92b8
JB
9181 UNBLOCK_INPUT;
9182}
9183
06a2c219 9184/* Change window state from mapped to iconified. */
dc6f92b8 9185
dfcf069d 9186void
f676886a
JB
9187x_iconify_frame (f)
9188 struct frame *f;
dc6f92b8 9189{
3afe33e7 9190 int result;
990ba854 9191 Lisp_Object type;
dc6f92b8 9192
9319ae23 9193 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
9194 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
9195 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 9196
3a88c238 9197 if (f->async_iconified)
dc6f92b8
JB
9198 return;
9199
3afe33e7 9200 BLOCK_INPUT;
546e6d5b 9201
9af3143a
RS
9202 FRAME_SAMPLE_VISIBILITY (f);
9203
990ba854
RS
9204 type = x_icon_type (f);
9205 if (!NILP (type))
9206 x_bitmap_icon (f, type);
bdcd49ba 9207
488dd4c4
JD
9208#ifdef USE_GTK
9209 if (FRAME_GTK_OUTER_WIDGET (f))
9210 {
9211 if (! FRAME_VISIBLE_P (f))
9212 gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
9213
9214 gtk_window_iconify (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
9215 f->iconified = 1;
9216 f->visible = 1;
9217 f->async_iconified = 1;
9218 f->async_visible = 0;
9219 UNBLOCK_INPUT;
9220 return;
9221 }
9222#endif
9223
bdcd49ba
RS
9224#ifdef USE_X_TOOLKIT
9225
546e6d5b
RS
9226 if (! FRAME_VISIBLE_P (f))
9227 {
9228 if (! EQ (Vx_no_window_manager, Qt))
9229 x_wm_set_window_state (f, IconicState);
9230 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 9231 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
9232 /* The server won't give us any event to indicate
9233 that an invisible frame was changed to an icon,
9234 so we have to record it here. */
9235 f->iconified = 1;
1e6bc770 9236 f->visible = 1;
9cf30a30 9237 f->async_iconified = 1;
1e6bc770 9238 f->async_visible = 0;
546e6d5b
RS
9239 UNBLOCK_INPUT;
9240 return;
9241 }
9242
334208b7 9243 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 9244 XtWindow (f->output_data.x->widget),
334208b7 9245 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
9246 UNBLOCK_INPUT;
9247
9248 if (!result)
546e6d5b 9249 error ("Can't notify window manager of iconification");
3afe33e7
RS
9250
9251 f->async_iconified = 1;
1e6bc770
RS
9252 f->async_visible = 0;
9253
8c002a25
KH
9254
9255 BLOCK_INPUT;
334208b7 9256 XFlush (FRAME_X_DISPLAY (f));
8c002a25 9257 UNBLOCK_INPUT;
3afe33e7
RS
9258#else /* not USE_X_TOOLKIT */
9259
fd13dbb2
RS
9260 /* Make sure the X server knows where the window should be positioned,
9261 in case the user deiconifies with the window manager. */
9262 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
0899d58c 9263 x_set_offset (f, f->left_pos, f->top_pos, 0);
fd13dbb2 9264
16bd92ea
JB
9265 /* Since we don't know which revision of X we're running, we'll use both
9266 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
9267
9268 /* X11R4: send a ClientMessage to the window manager using the
9269 WM_CHANGE_STATE type. */
9270 {
9271 XEvent message;
58769bee 9272
c118dd06 9273 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 9274 message.xclient.type = ClientMessage;
334208b7 9275 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
9276 message.xclient.format = 32;
9277 message.xclient.data.l[0] = IconicState;
9278
334208b7
RS
9279 if (! XSendEvent (FRAME_X_DISPLAY (f),
9280 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
9281 False,
9282 SubstructureRedirectMask | SubstructureNotifyMask,
9283 &message))
dc6f92b8
JB
9284 {
9285 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 9286 error ("Can't notify window manager of iconification");
dc6f92b8 9287 }
16bd92ea 9288 }
dc6f92b8 9289
58769bee 9290 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
9291 IconicState. */
9292 x_wm_set_window_state (f, IconicState);
dc6f92b8 9293
a9c00105
RS
9294 if (!FRAME_VISIBLE_P (f))
9295 {
9296 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 9297 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
9298 }
9299
3a88c238 9300 f->async_iconified = 1;
1e6bc770 9301 f->async_visible = 0;
dc6f92b8 9302
334208b7 9303 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 9304 UNBLOCK_INPUT;
8c002a25 9305#endif /* not USE_X_TOOLKIT */
dc6f92b8 9306}
19f71add 9307
d047c4eb 9308\f
19f71add 9309/* Free X resources of frame F. */
dc6f92b8 9310
dfcf069d 9311void
19f71add 9312x_free_frame_resources (f)
f676886a 9313 struct frame *f;
dc6f92b8 9314{
7f9c7f94 9315 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
c6ea2775
EZ
9316 Lisp_Object bar;
9317 struct scroll_bar *b;
7f9c7f94 9318
dc6f92b8 9319 BLOCK_INPUT;
c0ff3fab 9320
6186a4a0
RS
9321 /* If a display connection is dead, don't try sending more
9322 commands to the X server. */
19f71add 9323 if (dpyinfo->display)
6186a4a0 9324 {
c9ff09ee
KH
9325#ifdef USE_FONT_BACKEND
9326 /* We must free faces before destroying windows because some
9327 font-driver (e.g. xft) access a window while finishing a
9328 face. */
9329 if (enable_font_backend
9330 && FRAME_FACE_CACHE (f))
9331 free_frame_faces (f);
9332#endif /* USE_FONT_BACKEND */
9333
19f71add 9334 if (f->output_data.x->icon_desc)
6186a4a0 9335 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
c6ea2775
EZ
9336
9337#ifdef USE_X_TOOLKIT
9338 /* Explicitly destroy the scroll bars of the frame. Without
9339 this, we get "BadDrawable" errors from the toolkit later on,
9340 presumably from expose events generated for the disappearing
9341 toolkit scroll bars. */
9342 for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next)
9343 {
9344 b = XSCROLL_BAR (bar);
9345 x_scroll_bar_remove (b);
9346 }
9347#endif
9348
31f41daf 9349#ifdef HAVE_X_I18N
f5d11644
GM
9350 if (FRAME_XIC (f))
9351 free_frame_xic (f);
31f41daf 9352#endif
c6ea2775 9353
3afe33e7 9354#ifdef USE_X_TOOLKIT
06a2c219 9355 if (f->output_data.x->widget)
30ca89f5
GM
9356 {
9357 XtDestroyWidget (f->output_data.x->widget);
9358 f->output_data.x->widget = NULL;
9359 }
c6ea2775
EZ
9360 /* Tooltips don't have widgets, only a simple X window, even if
9361 we are using a toolkit. */
9362 else if (FRAME_X_WINDOW (f))
9363 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
9364
6186a4a0 9365 free_frame_menubar (f);
c6ea2775 9366#else /* !USE_X_TOOLKIT */
488dd4c4
JD
9367
9368#ifdef USE_GTK
9369 /* In the GTK version, tooltips are normal X
9370 frames. We must check and free both types. */
9371 if (FRAME_GTK_OUTER_WIDGET (f))
9372 {
9373 gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f));
9374 FRAME_X_WINDOW (f) = 0; /* Set to avoid XDestroyWindow below */
9375 FRAME_GTK_OUTER_WIDGET (f) = 0;
9376 }
9377#endif /* USE_GTK */
177c0ea7 9378
c6ea2775
EZ
9379 if (FRAME_X_WINDOW (f))
9380 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
9381#endif /* !USE_X_TOOLKIT */
3afe33e7 9382
3e71d8f2
GM
9383 unload_color (f, f->output_data.x->foreground_pixel);
9384 unload_color (f, f->output_data.x->background_pixel);
9385 unload_color (f, f->output_data.x->cursor_pixel);
9386 unload_color (f, f->output_data.x->cursor_foreground_pixel);
9387 unload_color (f, f->output_data.x->border_pixel);
9388 unload_color (f, f->output_data.x->mouse_pixel);
c6ea2775 9389
3e71d8f2
GM
9390 if (f->output_data.x->scroll_bar_background_pixel != -1)
9391 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
9392 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9393 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
7c1bef7a
MB
9394#ifdef USE_TOOLKIT_SCROLL_BARS
9395 /* Scrollbar shadow colors. */
9396 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
9397 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
9398 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
9399 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
9400#endif /* USE_TOOLKIT_SCROLL_BARS */
3e71d8f2
GM
9401 if (f->output_data.x->white_relief.allocated_p)
9402 unload_color (f, f->output_data.x->white_relief.pixel);
9403 if (f->output_data.x->black_relief.allocated_p)
9404 unload_color (f, f->output_data.x->black_relief.pixel);
4ca78676 9405
19f71add
GM
9406 if (FRAME_FACE_CACHE (f))
9407 free_frame_faces (f);
7d0393cf 9408
4ca78676 9409 x_free_gcs (f);
6186a4a0
RS
9410 XFlush (FRAME_X_DISPLAY (f));
9411 }
dc6f92b8 9412
df89d8a4 9413 if (f->output_data.x->saved_menu_event)
06a2c219 9414 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 9415
7556890b 9416 xfree (f->output_data.x);
19f71add 9417 f->output_data.x = NULL;
7d0393cf 9418
0f941935
KH
9419 if (f == dpyinfo->x_focus_frame)
9420 dpyinfo->x_focus_frame = 0;
9421 if (f == dpyinfo->x_focus_event_frame)
9422 dpyinfo->x_focus_event_frame = 0;
9423 if (f == dpyinfo->x_highlight_frame)
9424 dpyinfo->x_highlight_frame = 0;
c0ff3fab 9425
7f9c7f94 9426 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 9427 {
7f9c7f94
RS
9428 dpyinfo->mouse_face_beg_row
9429 = dpyinfo->mouse_face_beg_col = -1;
9430 dpyinfo->mouse_face_end_row
9431 = dpyinfo->mouse_face_end_col = -1;
9432 dpyinfo->mouse_face_window = Qnil;
21323706
RS
9433 dpyinfo->mouse_face_deferred_gc = 0;
9434 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 9435 }
0134a210 9436
c0ff3fab 9437 UNBLOCK_INPUT;
dc6f92b8 9438}
19f71add
GM
9439
9440
9441/* Destroy the X window of frame F. */
9442
9443void
9444x_destroy_window (f)
9445 struct frame *f;
9446{
9447 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9448
9449 /* If a display connection is dead, don't try sending more
9450 commands to the X server. */
9451 if (dpyinfo->display != 0)
9452 x_free_frame_resources (f);
9453
9454 dpyinfo->reference_count--;
9455}
9456
dc6f92b8 9457\f
f451eb13
JB
9458/* Setting window manager hints. */
9459
af31d76f
RS
9460/* Set the normal size hints for the window manager, for frame F.
9461 FLAGS is the flags word to use--or 0 meaning preserve the flags
9462 that the window now has.
9463 If USER_POSITION is nonzero, we set the USPosition
488dd4c4
JD
9464 flag (this is useful when FLAGS is 0).
9465 The GTK version is in gtkutils.c */
6dba1858 9466
488dd4c4 9467#ifndef USE_GTK
dfcf069d 9468void
af31d76f 9469x_wm_set_size_hint (f, flags, user_position)
f676886a 9470 struct frame *f;
af31d76f
RS
9471 long flags;
9472 int user_position;
dc6f92b8
JB
9473{
9474 XSizeHints size_hints;
3afe33e7
RS
9475
9476#ifdef USE_X_TOOLKIT
7e4f2521
FP
9477 Arg al[2];
9478 int ac = 0;
9479 Dimension widget_width, widget_height;
488dd4c4 9480#endif
177c0ea7 9481
488dd4c4 9482 Window window = FRAME_OUTER_WINDOW (f);
dc6f92b8 9483
b72a58fd
RS
9484 /* Setting PMaxSize caused various problems. */
9485 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 9486
0899d58c
KS
9487 size_hints.x = f->left_pos;
9488 size_hints.y = f->top_pos;
7553a6b7 9489
7e4f2521
FP
9490#ifdef USE_X_TOOLKIT
9491 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
9492 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 9493 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
9494 size_hints.height = widget_height;
9495 size_hints.width = widget_width;
9496#else /* not USE_X_TOOLKIT */
0899d58c
KS
9497 size_hints.height = FRAME_PIXEL_HEIGHT (f);
9498 size_hints.width = FRAME_PIXEL_WIDTH (f);
7e4f2521 9499#endif /* not USE_X_TOOLKIT */
7553a6b7 9500
0899d58c
KS
9501 size_hints.width_inc = FRAME_COLUMN_WIDTH (f);
9502 size_hints.height_inc = FRAME_LINE_HEIGHT (f);
334208b7 9503 size_hints.max_width
0899d58c 9504 = FRAME_X_DISPLAY_INFO (f)->width - FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
334208b7 9505 size_hints.max_height
0899d58c 9506 = FRAME_X_DISPLAY_INFO (f)->height - FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
0134a210 9507
d067ea8b
KH
9508 /* Calculate the base and minimum sizes.
9509
9510 (When we use the X toolkit, we don't do it here.
9511 Instead we copy the values that the widgets are using, below.) */
9512#ifndef USE_X_TOOLKIT
b1c884c3 9513 {
b0342f17 9514 int base_width, base_height;
0134a210 9515 int min_rows = 0, min_cols = 0;
b0342f17 9516
0899d58c
KS
9517 base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
9518 base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
b0342f17 9519
0134a210 9520 check_frame_size (f, &min_rows, &min_cols);
b0342f17 9521
0134a210
RS
9522 /* The window manager uses the base width hints to calculate the
9523 current number of rows and columns in the frame while
9524 resizing; min_width and min_height aren't useful for this
9525 purpose, since they might not give the dimensions for a
9526 zero-row, zero-column frame.
58769bee 9527
0134a210
RS
9528 We use the base_width and base_height members if we have
9529 them; otherwise, we set the min_width and min_height members
9530 to the size for a zero x zero frame. */
b0342f17
JB
9531
9532#ifdef HAVE_X11R4
0134a210
RS
9533 size_hints.flags |= PBaseSize;
9534 size_hints.base_width = base_width;
9535 size_hints.base_height = base_height;
9536 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
9537 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 9538#else
0134a210
RS
9539 size_hints.min_width = base_width;
9540 size_hints.min_height = base_height;
b0342f17 9541#endif
b1c884c3 9542 }
dc6f92b8 9543
d067ea8b 9544 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 9545 if (flags)
dc6f92b8 9546 {
d067ea8b
KH
9547 size_hints.flags |= flags;
9548 goto no_read;
9549 }
9550#endif /* not USE_X_TOOLKIT */
9551
9552 {
9553 XSizeHints hints; /* Sometimes I hate X Windows... */
9554 long supplied_return;
9555 int value;
af31d76f
RS
9556
9557#ifdef HAVE_X11R4
d067ea8b
KH
9558 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
9559 &supplied_return);
af31d76f 9560#else
d067ea8b 9561 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 9562#endif
58769bee 9563
d067ea8b
KH
9564#ifdef USE_X_TOOLKIT
9565 size_hints.base_height = hints.base_height;
9566 size_hints.base_width = hints.base_width;
9567 size_hints.min_height = hints.min_height;
9568 size_hints.min_width = hints.min_width;
9569#endif
9570
9571 if (flags)
9572 size_hints.flags |= flags;
9573 else
9574 {
9575 if (value == 0)
9576 hints.flags = 0;
9577 if (hints.flags & PSize)
9578 size_hints.flags |= PSize;
9579 if (hints.flags & PPosition)
9580 size_hints.flags |= PPosition;
9581 if (hints.flags & USPosition)
9582 size_hints.flags |= USPosition;
9583 if (hints.flags & USSize)
9584 size_hints.flags |= USSize;
9585 }
9586 }
9587
06a2c219 9588#ifndef USE_X_TOOLKIT
d067ea8b 9589 no_read:
06a2c219 9590#endif
0134a210 9591
af31d76f 9592#ifdef PWinGravity
0899d58c 9593 size_hints.win_gravity = f->win_gravity;
af31d76f 9594 size_hints.flags |= PWinGravity;
dc05a16b 9595
af31d76f 9596 if (user_position)
6dba1858 9597 {
af31d76f
RS
9598 size_hints.flags &= ~ PPosition;
9599 size_hints.flags |= USPosition;
6dba1858 9600 }
2554751d 9601#endif /* PWinGravity */
6dba1858 9602
b0342f17 9603#ifdef HAVE_X11R4
334208b7 9604 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 9605#else
334208b7 9606 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 9607#endif
dc6f92b8 9608}
488dd4c4 9609#endif /* not USE_GTK */
dc6f92b8
JB
9610
9611/* Used for IconicState or NormalState */
06a2c219 9612
dfcf069d 9613void
f676886a
JB
9614x_wm_set_window_state (f, state)
9615 struct frame *f;
dc6f92b8
JB
9616 int state;
9617{
3afe33e7 9618#ifdef USE_X_TOOLKIT
546e6d5b
RS
9619 Arg al[1];
9620
9621 XtSetArg (al[0], XtNinitialState, state);
7556890b 9622 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 9623#else /* not USE_X_TOOLKIT */
c118dd06 9624 Window window = FRAME_X_WINDOW (f);
dc6f92b8 9625
7556890b
RS
9626 f->output_data.x->wm_hints.flags |= StateHint;
9627 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 9628
7556890b 9629 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 9630#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
9631}
9632
dfcf069d 9633void
7f2ae036 9634x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 9635 struct frame *f;
7f2ae036 9636 int pixmap_id;
dc6f92b8 9637{
62fe13a4 9638 Pixmap icon_pixmap, icon_mask;
d2bd6bc4 9639
06a2c219 9640#ifndef USE_X_TOOLKIT
488dd4c4 9641 Window window = FRAME_OUTER_WINDOW (f);
75231bad 9642#endif
dc6f92b8 9643
7f2ae036 9644 if (pixmap_id > 0)
dbc4e1c1 9645 {
d2bd6bc4 9646 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 9647 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
62fe13a4
JB
9648 icon_mask = x_bitmap_mask (f, pixmap_id);
9649 f->output_data.x->wm_hints.icon_mask = icon_mask;
dbc4e1c1
JB
9650 }
9651 else
68568555
RS
9652 {
9653 /* It seems there is no way to turn off use of an icon pixmap.
9654 The following line does it, only if no icon has yet been created,
9655 for some window managers. But with mwm it crashes.
9656 Some people say it should clear the IconPixmapHint bit in this case,
9657 but that doesn't work, and the X consortium said it isn't the
9658 right thing at all. Since there is no way to win,
9659 best to explicitly give up. */
9660#if 0
9661 f->output_data.x->wm_hints.icon_pixmap = None;
62fe13a4 9662 f->output_data.x->wm_hints.icon_mask = None;
68568555
RS
9663#else
9664 return;
9665#endif
9666 }
b1c884c3 9667
cb515a21
JD
9668
9669#ifdef USE_GTK
9670 {
e76738f9 9671 xg_set_frame_icon (f, icon_pixmap, icon_mask);
cb515a21
JD
9672 return;
9673 }
9674
9675#elif defined (USE_X_TOOLKIT) /* same as in x_wm_set_window_state. */
d2bd6bc4
RS
9676
9677 {
9678 Arg al[1];
9679 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
9680 XtSetValues (f->output_data.x->widget, al, 1);
62fe13a4
JB
9681 XtSetArg (al[0], XtNiconMask, icon_mask);
9682 XtSetValues (f->output_data.x->widget, al, 1);
d2bd6bc4
RS
9683 }
9684
cb515a21 9685#else /* not USE_X_TOOLKIT && not USE_GTK */
7d0393cf 9686
62fe13a4 9687 f->output_data.x->wm_hints.flags |= (IconPixmapHint | IconMaskHint);
7556890b 9688 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4 9689
cb515a21 9690#endif /* not USE_X_TOOLKIT && not USE_GTK */
dc6f92b8
JB
9691}
9692
dfcf069d 9693void
f676886a
JB
9694x_wm_set_icon_position (f, icon_x, icon_y)
9695 struct frame *f;
dc6f92b8
JB
9696 int icon_x, icon_y;
9697{
2436a4e4 9698 Window window = FRAME_OUTER_WINDOW (f);
dc6f92b8 9699
7556890b
RS
9700 f->output_data.x->wm_hints.flags |= IconPositionHint;
9701 f->output_data.x->wm_hints.icon_x = icon_x;
9702 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 9703
7556890b 9704 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
9705}
9706
9707\f
06a2c219
GM
9708/***********************************************************************
9709 Fonts
9710 ***********************************************************************/
dc43ef94
KH
9711
9712/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 9713
dc43ef94
KH
9714struct font_info *
9715x_get_font_info (f, font_idx)
9716 FRAME_PTR f;
9717 int font_idx;
9718{
9719 return (FRAME_X_FONT_TABLE (f) + font_idx);
9720}
9721
9722
9c11f79e
GM
9723/* Return a list of names of available fonts matching PATTERN on frame F.
9724
9725 If SIZE is > 0, it is the size (maximum bounds width) of fonts
9726 to be listed.
9727
285f9304 9728 SIZE < 0 means include auto scaled fonts.
9c11f79e
GM
9729
9730 Frame F null means we have not yet created any frame on X, and
9731 consult the first display in x_display_list. MAXNAMES sets a limit
9732 on how many fonts to match. */
dc43ef94
KH
9733
9734Lisp_Object
9735x_list_fonts (f, pattern, size, maxnames)
9c11f79e 9736 struct frame *f;
dc43ef94
KH
9737 Lisp_Object pattern;
9738 int size;
9739 int maxnames;
9740{
06a2c219
GM
9741 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
9742 Lisp_Object tem, second_best;
9c11f79e
GM
9743 struct x_display_info *dpyinfo
9744 = f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
9745 Display *dpy = dpyinfo->display;
09c6077f 9746 int try_XLoadQueryFont = 0;
285f9304 9747 int allow_auto_scaled_font = 0;
9c11f79e
GM
9748
9749 if (size < 0)
9750 {
285f9304 9751 allow_auto_scaled_font = 1;
9c11f79e
GM
9752 size = 0;
9753 }
dc43ef94 9754
6b0efe73 9755 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
9756 if (NILP (patterns))
9757 patterns = Fcons (pattern, Qnil);
81ba44e5 9758
09c6077f
KH
9759 if (maxnames == 1 && !size)
9760 /* We can return any single font matching PATTERN. */
9761 try_XLoadQueryFont = 1;
9a32686f 9762
8e713be6 9763 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 9764 {
dc43ef94 9765 int num_fonts;
3e71d8f2 9766 char **names = NULL;
dc43ef94 9767
8e713be6 9768 pattern = XCAR (patterns);
536f4067
RS
9769 /* See if we cached the result for this particular query.
9770 The cache is an alist of the form:
9c11f79e
GM
9771 ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */
9772 tem = XCDR (dpyinfo->name_list_element);
9773 key = Fcons (Fcons (pattern, make_number (maxnames)),
285f9304 9774 allow_auto_scaled_font ? Qt : Qnil);
9c11f79e
GM
9775 list = Fassoc (key, tem);
9776 if (!NILP (list))
b5210ea7
KH
9777 {
9778 list = Fcdr_safe (list);
9779 /* We have a cashed list. Don't have to get the list again. */
9780 goto label_cached;
9781 }
9782
9783 /* At first, put PATTERN in the cache. */
09c6077f 9784
dc43ef94 9785 BLOCK_INPUT;
9ba8e10d 9786 x_catch_errors (dpy);
17d85edc 9787
09c6077f
KH
9788 if (try_XLoadQueryFont)
9789 {
9790 XFontStruct *font;
9791 unsigned long value;
9792
d5db4077 9793 font = XLoadQueryFont (dpy, SDATA (pattern));
17d85edc
KH
9794 if (x_had_errors_p (dpy))
9795 {
9796 /* This error is perhaps due to insufficient memory on X
9797 server. Let's just ignore it. */
9798 font = NULL;
9799 x_clear_errors (dpy);
9800 }
9801
09c6077f
KH
9802 if (font
9803 && XGetFontProperty (font, XA_FONT, &value))
9804 {
9805 char *name = (char *) XGetAtomName (dpy, (Atom) value);
9806 int len = strlen (name);
01c752b5 9807 char *tmp;
09c6077f 9808
6f6512e8
KH
9809 /* If DXPC (a Differential X Protocol Compressor)
9810 Ver.3.7 is running, XGetAtomName will return null
9811 string. We must avoid such a name. */
9812 if (len == 0)
9813 try_XLoadQueryFont = 0;
9814 else
9815 {
9816 num_fonts = 1;
9817 names = (char **) alloca (sizeof (char *));
9818 /* Some systems only allow alloca assigned to a
9819 simple var. */
9820 tmp = (char *) alloca (len + 1); names[0] = tmp;
9821 bcopy (name, names[0], len + 1);
9822 XFree (name);
9823 }
09c6077f
KH
9824 }
9825 else
9826 try_XLoadQueryFont = 0;
a083fd23
RS
9827
9828 if (font)
9829 XFreeFont (dpy, font);
09c6077f
KH
9830 }
9831
9832 if (!try_XLoadQueryFont)
17d85edc
KH
9833 {
9834 /* We try at least 10 fonts because XListFonts will return
9835 auto-scaled fonts at the head. */
ee5be7c3
JD
9836 if (maxnames < 0)
9837 {
9838 int limit;
9839
9840 for (limit = 500;;)
9841 {
9842 names = XListFonts (dpy, SDATA (pattern), limit, &num_fonts);
9843 if (num_fonts == limit)
9844 {
9845 BLOCK_INPUT;
9846 XFreeFontNames (names);
9847 UNBLOCK_INPUT;
9848 limit *= 2;
9849 }
9850 else
9851 break;
9852 }
9853 }
9854 else
9855 names = XListFonts (dpy, SDATA (pattern), max (maxnames, 10),
9856 &num_fonts);
9857
17d85edc
KH
9858 if (x_had_errors_p (dpy))
9859 {
9860 /* This error is perhaps due to insufficient memory on X
9861 server. Let's just ignore it. */
9862 names = NULL;
9863 x_clear_errors (dpy);
9864 }
9865 }
9866
4545fa20 9867 x_uncatch_errors ();
dc43ef94
KH
9868 UNBLOCK_INPUT;
9869
9870 if (names)
9871 {
9872 int i;
dc43ef94
KH
9873
9874 /* Make a list of all the fonts we got back.
9875 Store that in the font cache for the display. */
9876 for (i = 0; i < num_fonts; i++)
9877 {
06a2c219 9878 int width = 0;
dc43ef94 9879 char *p = names[i];
285f9304 9880 int average_width = -1, resx = 0, dashes = 0;
7d0393cf 9881
dc43ef94 9882 /* Count the number of dashes in NAMES[I]. If there are
6b61353c
KH
9883 14 dashes, the field value following 9th dash
9884 (RESOLUTION_X) is nonzero, and the field value
285f9304
KH
9885 following 12th dash (AVERAGE_WIDTH) is 0, this is a
9886 auto-scaled font which is usually too ugly to be used
9887 for editing. Let's ignore it. */
dc43ef94
KH
9888 while (*p)
9889 if (*p++ == '-')
9890 {
9891 dashes++;
9892 if (dashes == 7) /* PIXEL_SIZE field */
9893 width = atoi (p);
285f9304
KH
9894 else if (dashes == 9)
9895 resx = atoi (p);
dc43ef94
KH
9896 else if (dashes == 12) /* AVERAGE_WIDTH field */
9897 average_width = atoi (p);
9898 }
7d0393cf 9899
285f9304 9900 if (allow_auto_scaled_font
6b61353c 9901 || dashes < 14 || average_width != 0 || resx == 0)
dc43ef94
KH
9902 {
9903 tem = build_string (names[i]);
9904 if (NILP (Fassoc (tem, list)))
9905 {
9906 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
9907 && ((fast_c_string_match_ignore_case
9908 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
9909 >= 0))
9910 /* We can set the value of PIXEL_SIZE to the
b5210ea7 9911 width of this font. */
dc43ef94
KH
9912 list = Fcons (Fcons (tem, make_number (width)), list);
9913 else
9914 /* For the moment, width is not known. */
9915 list = Fcons (Fcons (tem, Qnil), list);
9916 }
9917 }
9918 }
7d0393cf 9919
09c6077f 9920 if (!try_XLoadQueryFont)
e38f4136
GM
9921 {
9922 BLOCK_INPUT;
9923 XFreeFontNames (names);
9924 UNBLOCK_INPUT;
9925 }
dc43ef94
KH
9926 }
9927
b5210ea7 9928 /* Now store the result in the cache. */
f3fbd155
KR
9929 XSETCDR (dpyinfo->name_list_element,
9930 Fcons (Fcons (key, list), XCDR (dpyinfo->name_list_element)));
dc43ef94 9931
b5210ea7
KH
9932 label_cached:
9933 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 9934
b5210ea7
KH
9935 newlist = second_best = Qnil;
9936 /* Make a list of the fonts that have the right width. */
8e713be6 9937 for (; CONSP (list); list = XCDR (list))
b5210ea7 9938 {
536f4067
RS
9939 int found_size;
9940
8e713be6 9941 tem = XCAR (list);
dc43ef94 9942
8e713be6 9943 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
9944 continue;
9945 if (!size)
9946 {
8e713be6 9947 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
9948 continue;
9949 }
dc43ef94 9950
8e713be6 9951 if (!INTEGERP (XCDR (tem)))
dc43ef94 9952 {
b5210ea7 9953 /* Since we have not yet known the size of this font, we
9c11f79e 9954 must try slow function call XLoadQueryFont. */
dc43ef94
KH
9955 XFontStruct *thisinfo;
9956
9957 BLOCK_INPUT;
9ba8e10d 9958 x_catch_errors (dpy);
dc43ef94 9959 thisinfo = XLoadQueryFont (dpy,
d5db4077 9960 SDATA (XCAR (tem)));
17d85edc
KH
9961 if (x_had_errors_p (dpy))
9962 {
9963 /* This error is perhaps due to insufficient memory on X
9964 server. Let's just ignore it. */
9965 thisinfo = NULL;
9966 x_clear_errors (dpy);
9967 }
4545fa20 9968 x_uncatch_errors ();
dc43ef94
KH
9969 UNBLOCK_INPUT;
9970
9971 if (thisinfo)
9972 {
f3fbd155
KR
9973 XSETCDR (tem,
9974 (thisinfo->min_bounds.width == 0
9975 ? make_number (0)
9976 : make_number (thisinfo->max_bounds.width)));
e38f4136 9977 BLOCK_INPUT;
dc43ef94 9978 XFreeFont (dpy, thisinfo);
e38f4136 9979 UNBLOCK_INPUT;
dc43ef94
KH
9980 }
9981 else
b5210ea7 9982 /* For unknown reason, the previous call of XListFont had
06a2c219 9983 returned a font which can't be opened. Record the size
b5210ea7 9984 as 0 not to try to open it again. */
f3fbd155 9985 XSETCDR (tem, make_number (0));
dc43ef94 9986 }
536f4067 9987
8e713be6 9988 found_size = XINT (XCDR (tem));
536f4067 9989 if (found_size == size)
8e713be6 9990 newlist = Fcons (XCAR (tem), newlist);
536f4067 9991 else if (found_size > 0)
b5210ea7 9992 {
536f4067 9993 if (NILP (second_best))
b5210ea7 9994 second_best = tem;
536f4067
RS
9995 else if (found_size < size)
9996 {
8e713be6
KR
9997 if (XINT (XCDR (second_best)) > size
9998 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
9999 second_best = tem;
10000 }
10001 else
10002 {
8e713be6
KR
10003 if (XINT (XCDR (second_best)) > size
10004 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
10005 second_best = tem;
10006 }
b5210ea7
KH
10007 }
10008 }
10009 if (!NILP (newlist))
10010 break;
10011 else if (!NILP (second_best))
10012 {
8e713be6 10013 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 10014 break;
dc43ef94 10015 }
dc43ef94
KH
10016 }
10017
10018 return newlist;
7d0393cf 10019}
dc43ef94 10020
06a2c219
GM
10021
10022#if GLYPH_DEBUG
10023
10024/* Check that FONT is valid on frame F. It is if it can be found in F's
10025 font table. */
10026
10027static void
10028x_check_font (f, font)
10029 struct frame *f;
10030 XFontStruct *font;
10031{
10032 int i;
10033 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10034
10035 xassert (font != NULL);
10036
10037 for (i = 0; i < dpyinfo->n_fonts; i++)
7d0393cf 10038 if (dpyinfo->font_table[i].name
06a2c219
GM
10039 && font == dpyinfo->font_table[i].font)
10040 break;
10041
10042 xassert (i < dpyinfo->n_fonts);
10043}
10044
10045#endif /* GLYPH_DEBUG != 0 */
10046
10047/* Set *W to the minimum width, *H to the minimum font height of FONT.
10048 Note: There are (broken) X fonts out there with invalid XFontStruct
10049 min_bounds contents. For example, handa@etl.go.jp reports that
10050 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
10051 have font->min_bounds.width == 0. */
10052
10053static INLINE void
10054x_font_min_bounds (font, w, h)
10055 XFontStruct *font;
10056 int *w, *h;
10057{
10058 *h = FONT_HEIGHT (font);
10059 *w = font->min_bounds.width;
10060
10061 /* Try to handle the case where FONT->min_bounds has invalid
10062 contents. Since the only font known to have invalid min_bounds
10063 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
10064 if (*w <= 0)
10065 *w = font->max_bounds.width;
10066}
10067
10068
10069/* Compute the smallest character width and smallest font height over
10070 all fonts available on frame F. Set the members smallest_char_width
10071 and smallest_font_height in F's x_display_info structure to
10072 the values computed. Value is non-zero if smallest_font_height or
10073 smallest_char_width become smaller than they were before. */
10074
10075static int
10076x_compute_min_glyph_bounds (f)
10077 struct frame *f;
10078{
10079 int i;
10080 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10081 XFontStruct *font;
10082 int old_width = dpyinfo->smallest_char_width;
10083 int old_height = dpyinfo->smallest_font_height;
7d0393cf 10084
06a2c219
GM
10085 dpyinfo->smallest_font_height = 100000;
10086 dpyinfo->smallest_char_width = 100000;
7d0393cf 10087
06a2c219
GM
10088 for (i = 0; i < dpyinfo->n_fonts; ++i)
10089 if (dpyinfo->font_table[i].name)
10090 {
10091 struct font_info *fontp = dpyinfo->font_table + i;
10092 int w, h;
7d0393cf 10093
06a2c219
GM
10094 font = (XFontStruct *) fontp->font;
10095 xassert (font != (XFontStruct *) ~0);
10096 x_font_min_bounds (font, &w, &h);
7d0393cf 10097
06a2c219
GM
10098 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
10099 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
10100 }
10101
10102 xassert (dpyinfo->smallest_char_width > 0
10103 && dpyinfo->smallest_font_height > 0);
10104
10105 return (dpyinfo->n_fonts == 1
10106 || dpyinfo->smallest_char_width < old_width
10107 || dpyinfo->smallest_font_height < old_height);
10108}
10109
10110
dc43ef94
KH
10111/* Load font named FONTNAME of the size SIZE for frame F, and return a
10112 pointer to the structure font_info while allocating it dynamically.
10113 If SIZE is 0, load any size of font.
10114 If loading is failed, return NULL. */
10115
10116struct font_info *
10117x_load_font (f, fontname, size)
10118 struct frame *f;
10119 register char *fontname;
10120 int size;
10121{
10122 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10123 Lisp_Object font_names;
10124
10125 /* Get a list of all the fonts that match this name. Once we
10126 have a list of matching fonts, we compare them against the fonts
10127 we already have by comparing names. */
09c6077f 10128 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
10129
10130 if (!NILP (font_names))
10131 {
10132 Lisp_Object tail;
10133 int i;
10134
10135 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 10136 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
10137 if (dpyinfo->font_table[i].name
10138 && (!strcmp (dpyinfo->font_table[i].name,
d5db4077 10139 SDATA (XCAR (tail)))
06a2c219 10140 || !strcmp (dpyinfo->font_table[i].full_name,
d5db4077 10141 SDATA (XCAR (tail)))))
dc43ef94
KH
10142 return (dpyinfo->font_table + i);
10143 }
10144
10145 /* Load the font and add it to the table. */
10146 {
10147 char *full_name;
10148 XFontStruct *font;
10149 struct font_info *fontp;
10150 unsigned long value;
06a2c219 10151 int i;
dc43ef94 10152
2da424f1
KH
10153 /* If we have found fonts by x_list_font, load one of them. If
10154 not, we still try to load a font by the name given as FONTNAME
10155 because XListFonts (called in x_list_font) of some X server has
10156 a bug of not finding a font even if the font surely exists and
10157 is loadable by XLoadQueryFont. */
e1d6d5b9 10158 if (size > 0 && !NILP (font_names))
d5db4077 10159 fontname = (char *) SDATA (XCAR (font_names));
dc43ef94
KH
10160
10161 BLOCK_INPUT;
9ba8e10d 10162 x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 10163 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
10164 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
10165 {
10166 /* This error is perhaps due to insufficient memory on X
10167 server. Let's just ignore it. */
10168 font = NULL;
10169 x_clear_errors (FRAME_X_DISPLAY (f));
10170 }
4545fa20 10171 x_uncatch_errors ();
dc43ef94 10172 UNBLOCK_INPUT;
b5210ea7 10173 if (!font)
dc43ef94
KH
10174 return NULL;
10175
06a2c219
GM
10176 /* Find a free slot in the font table. */
10177 for (i = 0; i < dpyinfo->n_fonts; ++i)
10178 if (dpyinfo->font_table[i].name == NULL)
10179 break;
10180
10181 /* If no free slot found, maybe enlarge the font table. */
10182 if (i == dpyinfo->n_fonts
10183 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 10184 {
06a2c219
GM
10185 int sz;
10186 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
10187 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 10188 dpyinfo->font_table
06a2c219 10189 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
10190 }
10191
06a2c219
GM
10192 fontp = dpyinfo->font_table + i;
10193 if (i == dpyinfo->n_fonts)
10194 ++dpyinfo->n_fonts;
dc43ef94
KH
10195
10196 /* Now fill in the slots of *FONTP. */
10197 BLOCK_INPUT;
6b61353c 10198 bzero (fontp, sizeof (*fontp));
dc43ef94 10199 fontp->font = font;
06a2c219 10200 fontp->font_idx = i;
d8891a0f 10201 fontp->charset = -1; /* fs_load_font sets it. */
dc43ef94
KH
10202 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
10203 bcopy (fontname, fontp->name, strlen (fontname) + 1);
10204
6875d1ae
KH
10205 if (font->min_bounds.width == font->max_bounds.width)
10206 {
10207 /* Fixed width font. */
10208 fontp->average_width = fontp->space_width = font->min_bounds.width;
10209 }
10210 else
10211 {
10212 XChar2b char2b;
10213 XCharStruct *pcm;
10214
10215 char2b.byte1 = 0x00, char2b.byte2 = 0x20;
10216 pcm = x_per_char_metric (font, &char2b, 0);
10217 if (pcm)
10218 fontp->space_width = pcm->width;
10219 else
10220 fontp->space_width = FONT_WIDTH (font);
10221
10222 fontp->average_width
10223 = (XGetFontProperty (font, dpyinfo->Xatom_AVERAGE_WIDTH, &value)
10224 ? (long) value / 10 : 0);
10225 if (fontp->average_width < 0)
10226 fontp->average_width = - fontp->average_width;
10227 if (fontp->average_width == 0)
10228 {
10229 if (pcm)
10230 {
10231 int width = pcm->width;
10232 for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
10233 if ((pcm = x_per_char_metric (font, &char2b, 0)) != NULL)
10234 width += pcm->width;
10235 fontp->average_width = width / 95;
10236 }
10237 else
10238 fontp->average_width = FONT_WIDTH (font);
10239 }
10240 }
10241
dc43ef94
KH
10242 /* Try to get the full name of FONT. Put it in FULL_NAME. */
10243 full_name = 0;
10244 if (XGetFontProperty (font, XA_FONT, &value))
10245 {
10246 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
10247 char *p = name;
10248 int dashes = 0;
10249
10250 /* Count the number of dashes in the "full name".
10251 If it is too few, this isn't really the font's full name,
10252 so don't use it.
10253 In X11R4, the fonts did not come with their canonical names
10254 stored in them. */
10255 while (*p)
10256 {
10257 if (*p == '-')
10258 dashes++;
10259 p++;
10260 }
10261
10262 if (dashes >= 13)
10263 {
10264 full_name = (char *) xmalloc (p - name + 1);
10265 bcopy (name, full_name, p - name + 1);
10266 }
10267
10268 XFree (name);
10269 }
7d0393cf 10270
dc43ef94
KH
10271 if (full_name != 0)
10272 fontp->full_name = full_name;
10273 else
10274 fontp->full_name = fontp->name;
10275
10276 fontp->size = font->max_bounds.width;
d5749adb 10277 fontp->height = FONT_HEIGHT (font);
dc43ef94 10278
2da424f1
KH
10279 if (NILP (font_names))
10280 {
10281 /* We come here because of a bug of XListFonts mentioned at
10282 the head of this block. Let's store this information in
10283 the cache for x_list_fonts. */
10284 Lisp_Object lispy_name = build_string (fontname);
10285 Lisp_Object lispy_full_name = build_string (fontp->full_name);
9c11f79e
GM
10286 Lisp_Object key = Fcons (Fcons (lispy_name, make_number (256)),
10287 Qnil);
2da424f1 10288
f3fbd155
KR
10289 XSETCDR (dpyinfo->name_list_element,
10290 Fcons (Fcons (key,
10291 Fcons (Fcons (lispy_full_name,
10292 make_number (fontp->size)),
10293 Qnil)),
10294 XCDR (dpyinfo->name_list_element)));
2da424f1 10295 if (full_name)
9c11f79e
GM
10296 {
10297 key = Fcons (Fcons (lispy_full_name, make_number (256)),
10298 Qnil);
f3fbd155
KR
10299 XSETCDR (dpyinfo->name_list_element,
10300 Fcons (Fcons (key,
10301 Fcons (Fcons (lispy_full_name,
10302 make_number (fontp->size)),
10303 Qnil)),
10304 XCDR (dpyinfo->name_list_element)));
9c11f79e 10305 }
2da424f1
KH
10306 }
10307
dc43ef94
KH
10308 /* The slot `encoding' specifies how to map a character
10309 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
10310 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
10311 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 10312 2:0xA020..0xFF7F). For the moment, we don't know which charset
8f924df7 10313 uses this font. So, we set information in fontp->encoding_type
8ff102bd
RS
10314 which is never used by any charset. If mapping can't be
10315 decided, set FONT_ENCODING_NOT_DECIDED. */
8a78c965 10316 fontp->encoding_type
dc43ef94
KH
10317 = (font->max_byte1 == 0
10318 /* 1-byte font */
10319 ? (font->min_char_or_byte2 < 0x80
10320 ? (font->max_char_or_byte2 < 0x80
10321 ? 0 /* 0x20..0x7F */
8ff102bd 10322 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
10323 : 1) /* 0xA0..0xFF */
10324 /* 2-byte font */
10325 : (font->min_byte1 < 0x80
10326 ? (font->max_byte1 < 0x80
10327 ? (font->min_char_or_byte2 < 0x80
10328 ? (font->max_char_or_byte2 < 0x80
10329 ? 0 /* 0x2020..0x7F7F */
8ff102bd 10330 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 10331 : 3) /* 0x20A0..0x7FFF */
8ff102bd 10332 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
10333 : (font->min_char_or_byte2 < 0x80
10334 ? (font->max_char_or_byte2 < 0x80
10335 ? 2 /* 0xA020..0xFF7F */
8ff102bd 10336 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
10337 : 1))); /* 0xA0A0..0xFFFF */
10338
10339 fontp->baseline_offset
10340 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
10341 ? (long) value : 0);
10342 fontp->relative_compose
10343 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
10344 ? (long) value : 0);
f78798df
KH
10345 fontp->default_ascent
10346 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
10347 ? (long) value : 0);
dc43ef94 10348
06a2c219
GM
10349 /* Set global flag fonts_changed_p to non-zero if the font loaded
10350 has a character with a smaller width than any other character
437dfb9f 10351 before, or if the font loaded has a smaller height than any
06a2c219
GM
10352 other font loaded before. If this happens, it will make a
10353 glyph matrix reallocation necessary. */
437dfb9f 10354 fonts_changed_p |= x_compute_min_glyph_bounds (f);
dc43ef94 10355 UNBLOCK_INPUT;
dc43ef94
KH
10356 return fontp;
10357 }
10358}
10359
06a2c219
GM
10360
10361/* Return a pointer to struct font_info of a font named FONTNAME for
10362 frame F. If no such font is loaded, return NULL. */
10363
dc43ef94
KH
10364struct font_info *
10365x_query_font (f, fontname)
10366 struct frame *f;
10367 register char *fontname;
10368{
10369 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10370 int i;
10371
10372 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219 10373 if (dpyinfo->font_table[i].name
dc3ca107
KH
10374 && (!strcasecmp (dpyinfo->font_table[i].name, fontname)
10375 || !strcasecmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
10376 return (dpyinfo->font_table + i);
10377 return NULL;
10378}
10379
06a2c219
GM
10380
10381/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
10382 `encoder' of the structure. */
10383
10384void
10385x_find_ccl_program (fontp)
10386 struct font_info *fontp;
10387{
a42f54e6 10388 Lisp_Object list, elt;
a6582676 10389
f9b5db02 10390 elt = Qnil;
8e713be6 10391 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 10392 {
8e713be6 10393 elt = XCAR (list);
a6582676 10394 if (CONSP (elt)
8e713be6 10395 && STRINGP (XCAR (elt))
9f2feff6
KH
10396 && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
10397 >= 0)
10398 || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
10399 >= 0)))
a42f54e6
KH
10400 break;
10401 }
7d0393cf 10402
a42f54e6
KH
10403 if (! NILP (list))
10404 {
d27f8ca7
KH
10405 struct ccl_program *ccl
10406 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 10407
8e713be6 10408 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
10409 xfree (ccl);
10410 else
10411 fontp->font_encoder = ccl;
a6582676
KH
10412 }
10413}
10414
06a2c219 10415
8093092d 10416/* Return a char-table whose elements are t if the font FONT_INFO
0e3dd87a
KH
10417 contains a glyph for the corresponding character, and nil if
10418 not. */
8093092d
KH
10419
10420Lisp_Object
10421x_get_font_repertory (f, font_info)
10422 FRAME_PTR f;
10423 struct font_info *font_info;
10424{
10425 XFontStruct *font = (XFontStruct *) font_info->font;
8093092d
KH
10426 Lisp_Object table;
10427 int min_byte1, max_byte1, min_byte2, max_byte2;
0e3dd87a 10428 int c;
cf0c289d
KH
10429 struct charset *charset = CHARSET_FROM_ID (font_info->charset);
10430 int offset = CHARSET_OFFSET (charset);
8093092d
KH
10431
10432 table = Fmake_char_table (Qnil, Qnil);
10433
10434 min_byte1 = font->min_byte1;
10435 max_byte1 = font->max_byte1;
10436 min_byte2 = font->min_char_or_byte2;
10437 max_byte2 = font->max_char_or_byte2;
10438 if (min_byte1 == 0 && max_byte1 == 0)
10439 {
10440 if (! font->per_char || font->all_chars_exist == True)
cf0c289d
KH
10441 {
10442 if (offset >= 0)
10443 char_table_set_range (table, offset + min_byte2,
10444 offset + max_byte2, Qt);
10445 else
10446 for (; min_byte2 <= max_byte2; min_byte2++)
10447 {
10448 c = DECODE_CHAR (charset, min_byte2);
10449 CHAR_TABLE_SET (table, c, Qt);
10450 }
10451 }
8093092d
KH
10452 else
10453 {
10454 XCharStruct *pcm = font->per_char;
10455 int from = -1;
10456 int i;
10457
10458 for (i = min_byte2; i <= max_byte2; i++, pcm++)
10459 {
10460 if (pcm->width == 0 && pcm->rbearing == pcm->lbearing)
10461 {
10462 if (from >= 0)
10463 {
cf0c289d
KH
10464 if (offset >= 0)
10465 char_table_set_range (table, offset + from,
10466 offset + i - 1, Qt);
0e3dd87a
KH
10467 else
10468 for (; from < i; from++)
10469 {
cf0c289d 10470 c = DECODE_CHAR (charset, from);
0e3dd87a
KH
10471 CHAR_TABLE_SET (table, c, Qt);
10472 }
8093092d
KH
10473 from = -1;
10474 }
10475 }
10476 else if (from < 0)
10477 from = i;
10478 }
10479 if (from >= 0)
0e3dd87a 10480 {
cf0c289d
KH
10481 if (offset >= 0)
10482 char_table_set_range (table, offset + from, offset + i - 1,
10483 Qt);
0e3dd87a
KH
10484 else
10485 for (; from < i; from++)
10486 {
cf0c289d 10487 c = DECODE_CHAR (charset, from);
0e3dd87a
KH
10488 CHAR_TABLE_SET (table, c, Qt);
10489 }
10490 }
8093092d
KH
10491 }
10492 }
10493 else
10494 {
10495 if (! font->per_char || font->all_chars_exist == True)
10496 {
0e3dd87a 10497 int i, j;
8093092d 10498
cf0c289d 10499 if (offset >= 0)
0e3dd87a 10500 for (i = min_byte1; i <= max_byte1; i++)
cf0c289d
KH
10501 char_table_set_range
10502 (table, offset + ((i << 8) | min_byte2),
10503 offset + ((i << 8) | max_byte2), Qt);
0e3dd87a
KH
10504 else
10505 for (i = min_byte1; i <= max_byte1; i++)
10506 for (j = min_byte2; j <= max_byte2; j++)
10507 {
10508 unsigned code = (i << 8) | j;
cf0c289d
KH
10509 c = DECODE_CHAR (charset, code);
10510 CHAR_TABLE_SET (table, c, Qt);
0e3dd87a 10511 }
8093092d
KH
10512 }
10513 else
10514 {
10515 XCharStruct *pcm = font->per_char;
10516 int i;
10517
10518 for (i = min_byte1; i <= max_byte1; i++)
10519 {
10520 int from = -1;
10521 int j;
10522
10523 for (j = min_byte2; j <= max_byte2; j++, pcm++)
10524 {
10525 if (pcm->width == 0 && pcm->rbearing == pcm->lbearing)
10526 {
10527 if (from >= 0)
10528 {
cf0c289d
KH
10529 if (offset >= 0)
10530 char_table_set_range
10531 (table, offset + ((i << 8) | from),
10532 offset + ((i << 8) | (j - 1)), Qt);
0e3dd87a
KH
10533 else
10534 {
10535 for (; from < j; from++)
10536 {
10537 unsigned code = (i << 8) | from;
10538 c = ENCODE_CHAR (charset, code);
10539 CHAR_TABLE_SET (table, c, Qt);
10540 }
10541 }
8093092d
KH
10542 from = -1;
10543 }
10544 }
10545 else if (from < 0)
10546 from = j;
10547 }
10548 if (from >= 0)
0e3dd87a 10549 {
cf0c289d
KH
10550 if (offset >= 0)
10551 char_table_set_range
10552 (table, offset + ((i << 8) | from),
10553 offset + ((i << 8) | (j - 1)), Qt);
0e3dd87a
KH
10554 else
10555 {
10556 for (; from < j; from++)
10557 {
10558 unsigned code = (i << 8) | from;
cf0c289d 10559 c = DECODE_CHAR (charset, code);
0e3dd87a
KH
10560 CHAR_TABLE_SET (table, c, Qt);
10561 }
10562 }
10563 }
8093092d
KH
10564 }
10565 }
10566 }
10567
10568 return table;
10569}
dc43ef94 10570\f
06a2c219
GM
10571/***********************************************************************
10572 Initialization
10573 ***********************************************************************/
f451eb13 10574
3afe33e7
RS
10575#ifdef USE_X_TOOLKIT
10576static XrmOptionDescRec emacs_options[] = {
10577 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
10578 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
10579
10580 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
10581 XrmoptionSepArg, NULL},
10582 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
10583
10584 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
10585 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
10586 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
10587 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
10588 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
10589 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
10590 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
10591};
10592#endif /* USE_X_TOOLKIT */
10593
7a13e894
RS
10594static int x_initialized;
10595
11e887e2
JD
10596#ifdef HAVE_X_SM
10597static int x_session_initialized;
10598#endif
10599
29b38361
KH
10600#ifdef MULTI_KBOARD
10601/* Test whether two display-name strings agree up to the dot that separates
10602 the screen number from the server number. */
10603static int
10604same_x_server (name1, name2)
59ab1dc7 10605 const char *name1, *name2;
29b38361
KH
10606{
10607 int seen_colon = 0;
59ab1dc7 10608 const unsigned char *system_name = SDATA (Vsystem_name);
cf591cc1
RS
10609 int system_name_length = strlen (system_name);
10610 int length_until_period = 0;
10611
10612 while (system_name[length_until_period] != 0
10613 && system_name[length_until_period] != '.')
10614 length_until_period++;
10615
10616 /* Treat `unix' like an empty host name. */
10617 if (! strncmp (name1, "unix:", 5))
10618 name1 += 4;
10619 if (! strncmp (name2, "unix:", 5))
10620 name2 += 4;
10621 /* Treat this host's name like an empty host name. */
10622 if (! strncmp (name1, system_name, system_name_length)
10623 && name1[system_name_length] == ':')
10624 name1 += system_name_length;
10625 if (! strncmp (name2, system_name, system_name_length)
10626 && name2[system_name_length] == ':')
10627 name2 += system_name_length;
10628 /* Treat this host's domainless name like an empty host name. */
10629 if (! strncmp (name1, system_name, length_until_period)
10630 && name1[length_until_period] == ':')
10631 name1 += length_until_period;
10632 if (! strncmp (name2, system_name, length_until_period)
10633 && name2[length_until_period] == ':')
10634 name2 += length_until_period;
10635
29b38361
KH
10636 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
10637 {
10638 if (*name1 == ':')
10639 seen_colon++;
10640 if (seen_colon && *name1 == '.')
10641 return 1;
10642 }
10643 return (seen_colon
10644 && (*name1 == '.' || *name1 == '\0')
10645 && (*name2 == '.' || *name2 == '\0'));
10646}
10647#endif
10648
6b61353c
KH
10649/* Count number of set bits in mask and number of bits to shift to
10650 get to the first bit. With MASK 0x7e0, *BITS is set to 6, and *OFFSET
10651 to 5. */
10652static void
10653get_bits_and_offset (mask, bits, offset)
10654 unsigned long mask;
10655 int *bits;
10656 int *offset;
10657{
10658 int nr = 0;
10659 int off = 0;
10660
10661 while (!(mask & 1))
10662 {
10663 off++;
10664 mask >>= 1;
10665 }
10666
10667 while (mask & 1)
10668 {
10669 nr++;
10670 mask >>= 1;
10671 }
10672
10673 *offset = off;
10674 *bits = nr;
10675}
10676
3c7b6f9f
EZ
10677int
10678x_display_ok (display)
10679 const char * display;
10680{
10681 int dpy_ok = 1;
10682 Display *dpy;
3c7b6f9f 10683
c1fc674b
AS
10684 dpy = XOpenDisplay (display);
10685 if (dpy)
3c7b6f9f
EZ
10686 XCloseDisplay (dpy);
10687 else
10688 dpy_ok = 0;
10689 return dpy_ok;
10690}
10691
334208b7 10692struct x_display_info *
1f8255f2 10693x_term_init (display_name, xrm_option, resource_name)
334208b7 10694 Lisp_Object display_name;
1f8255f2
RS
10695 char *xrm_option;
10696 char *resource_name;
dc6f92b8 10697{
334208b7 10698 int connection;
7a13e894 10699 Display *dpy;
334208b7
RS
10700 struct x_display_info *dpyinfo;
10701 XrmDatabase xrdb;
10702
60439948
KH
10703 BLOCK_INPUT;
10704
7a13e894
RS
10705 if (!x_initialized)
10706 {
10707 x_initialize ();
6b61353c 10708 ++x_initialized;
7a13e894 10709 }
dc6f92b8 10710
488dd4c4
JD
10711#ifdef USE_GTK
10712 {
10713#define NUM_ARGV 10
10714 int argc;
10715 char *argv[NUM_ARGV];
10716 char **argv2 = argv;
10717 GdkAtom atom;
10718
6b61353c
KH
10719 if (x_initialized++ > 1)
10720 {
10721 /* Opening another display. If xg_display_open returns less
10722 than zero, we are probably on GTK 2.0, which can only handle
10723 one display. GTK 2.2 or later can handle more than one. */
10724 if (xg_display_open (SDATA (display_name), &dpy) < 0)
10725 error ("Sorry, this version of GTK can only handle one display");
10726 }
10727 else
10728 {
10729 for (argc = 0; argc < NUM_ARGV; ++argc)
10730 argv[argc] = 0;
488dd4c4 10731
6b61353c
KH
10732 argc = 0;
10733 argv[argc++] = initial_argv[0];
488dd4c4 10734
6b61353c
KH
10735 if (! NILP (display_name))
10736 {
10737 argv[argc++] = "--display";
10738 argv[argc++] = SDATA (display_name);
10739 }
488dd4c4 10740
6b61353c
KH
10741 argv[argc++] = "--name";
10742 argv[argc++] = resource_name;
177c0ea7 10743
1fcfb866 10744#ifdef HAVE_X11R5
6b61353c 10745 XSetLocaleModifiers ("");
1fcfb866
JD
10746#endif
10747
6b61353c 10748 gtk_init (&argc, &argv2);
488dd4c4 10749
6b61353c
KH
10750 /* gtk_init does set_locale. We must fix locale after calling it. */
10751 fixup_locale ();
10752 xg_initialize ();
488dd4c4 10753
6b61353c 10754 dpy = GDK_DISPLAY ();
177c0ea7 10755
6b61353c
KH
10756 /* NULL window -> events for all windows go to our function */
10757 gdk_window_add_filter (NULL, event_handler_gdk, NULL);
488dd4c4 10758
6b61353c
KH
10759 /* Load our own gtkrc if it exists. */
10760 {
6b61353c
KH
10761 char *file = "~/.emacs.d/gtkrc";
10762 Lisp_Object s, abs_file;
488dd4c4 10763
6b61353c
KH
10764 s = make_string (file, strlen (file));
10765 abs_file = Fexpand_file_name (s, Qnil);
488dd4c4 10766
6b61353c
KH
10767 if (! NILP (abs_file) && !NILP (Ffile_readable_p (abs_file)))
10768 gtk_rc_parse (SDATA (abs_file));
6b61353c 10769 }
177c0ea7 10770
6b61353c
KH
10771 XSetErrorHandler (x_error_handler);
10772 XSetIOErrorHandler (x_io_error_quitter);
10773 }
488dd4c4
JD
10774 }
10775#else /* not USE_GTK */
3afe33e7 10776#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
10777 /* weiner@footloose.sps.mot.com reports that this causes
10778 errors with X11R5:
10779 X protocol error: BadAtom (invalid Atom parameter)
10780 on protocol request 18skiloaf.
10781 So let's not use it until R6. */
10782#ifdef HAVE_X11XTR6
bdcd49ba
RS
10783 XtSetLanguageProc (NULL, NULL, NULL);
10784#endif
10785
7f9c7f94
RS
10786 {
10787 int argc = 0;
10788 char *argv[3];
10789
10790 argv[0] = "";
10791 argc = 1;
10792 if (xrm_option)
10793 {
10794 argv[argc++] = "-xrm";
10795 argv[argc++] = xrm_option;
10796 }
bc4e60fc 10797 turn_on_atimers (0);
d5db4077 10798 dpy = XtOpenDisplay (Xt_app_con, SDATA (display_name),
7f9c7f94
RS
10799 resource_name, EMACS_CLASS,
10800 emacs_options, XtNumber (emacs_options),
10801 &argc, argv);
bc4e60fc 10802 turn_on_atimers (1);
39d8bb4d
KH
10803
10804#ifdef HAVE_X11XTR6
10537cb1 10805 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 10806 fixup_locale ();
39d8bb4d 10807#endif
7f9c7f94 10808 }
3afe33e7
RS
10809
10810#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
10811#ifdef HAVE_X11R5
10812 XSetLocaleModifiers ("");
10813#endif
d5db4077 10814 dpy = XOpenDisplay (SDATA (display_name));
3afe33e7 10815#endif /* not USE_X_TOOLKIT */
488dd4c4 10816#endif /* not USE_GTK*/
334208b7 10817
7a13e894
RS
10818 /* Detect failure. */
10819 if (dpy == 0)
60439948
KH
10820 {
10821 UNBLOCK_INPUT;
10822 return 0;
10823 }
7a13e894
RS
10824
10825 /* We have definitely succeeded. Record the new connection. */
10826
10827 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
f04e1297 10828 bzero (dpyinfo, sizeof *dpyinfo);
7a13e894 10829
29b38361
KH
10830#ifdef MULTI_KBOARD
10831 {
10832 struct x_display_info *share;
10833 Lisp_Object tail;
10834
10835 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6 10836 share = share->next, tail = XCDR (tail))
d5db4077
KR
10837 if (same_x_server (SDATA (XCAR (XCAR (tail))),
10838 SDATA (display_name)))
29b38361
KH
10839 break;
10840 if (share)
10841 dpyinfo->kboard = share->kboard;
10842 else
10843 {
10844 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
10845 init_kboard (dpyinfo->kboard);
59e755be
KH
10846 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
10847 {
10848 char *vendor = ServerVendor (dpy);
9b6ed9f3 10849 UNBLOCK_INPUT;
59e755be
KH
10850 dpyinfo->kboard->Vsystem_key_alist
10851 = call1 (Qvendor_specific_keysyms,
10852 build_string (vendor ? vendor : ""));
9b6ed9f3 10853 BLOCK_INPUT;
59e755be
KH
10854 }
10855
29b38361
KH
10856 dpyinfo->kboard->next_kboard = all_kboards;
10857 all_kboards = dpyinfo->kboard;
0ad5446c
KH
10858 /* Don't let the initial kboard remain current longer than necessary.
10859 That would cause problems if a file loaded on startup tries to
06a2c219 10860 prompt in the mini-buffer. */
0ad5446c
KH
10861 if (current_kboard == initial_kboard)
10862 current_kboard = dpyinfo->kboard;
29b38361
KH
10863 }
10864 dpyinfo->kboard->reference_count++;
10865 }
b9737ad3
KH
10866#endif
10867
7a13e894
RS
10868 /* Put this display on the chain. */
10869 dpyinfo->next = x_display_list;
10870 x_display_list = dpyinfo;
10871
7d0393cf 10872 /* Put it on x_display_name_list as well, to keep them parallel. */
7a13e894
RS
10873 x_display_name_list = Fcons (Fcons (display_name, Qnil),
10874 x_display_name_list);
8e713be6 10875 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
10876
10877 dpyinfo->display = dpy;
dc6f92b8 10878
dc6f92b8 10879#if 0
7a13e894 10880 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 10881#endif /* ! 0 */
7a13e894
RS
10882
10883 dpyinfo->x_id_name
d5db4077
KR
10884 = (char *) xmalloc (SBYTES (Vinvocation_name)
10885 + SBYTES (Vsystem_name)
7a13e894
RS
10886 + 2);
10887 sprintf (dpyinfo->x_id_name, "%s@%s",
d5db4077 10888 SDATA (Vinvocation_name), SDATA (Vsystem_name));
28430d3c
JB
10889
10890 /* Figure out which modifier bits mean what. */
334208b7 10891 x_find_modifier_meanings (dpyinfo);
f451eb13 10892
ab648270 10893 /* Get the scroll bar cursor. */
6b61353c
KH
10894#ifdef USE_GTK
10895 /* We must create a GTK cursor, it is required for GTK widgets. */
10896 dpyinfo->xg_cursor = xg_create_default_cursor (dpyinfo->display);
10897#endif /* USE_GTK */
10898
7a13e894 10899 dpyinfo->vertical_scroll_bar_cursor
334208b7 10900 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 10901
334208b7
RS
10902 xrdb = x_load_resources (dpyinfo->display, xrm_option,
10903 resource_name, EMACS_CLASS);
10904#ifdef HAVE_XRMSETDATABASE
10905 XrmSetDatabase (dpyinfo->display, xrdb);
10906#else
10907 dpyinfo->display->db = xrdb;
10908#endif
547d9db8 10909 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
10910 all versions. */
10911 dpyinfo->xrdb = xrdb;
334208b7
RS
10912
10913 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
10914 DefaultScreen (dpyinfo->display));
5ff67d81 10915 select_visual (dpyinfo);
43bd1b2b 10916 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
10917 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
10918 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
10919 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
6b61353c 10920 dpyinfo->client_leader_window = 0;
334208b7
RS
10921 dpyinfo->grabbed = 0;
10922 dpyinfo->reference_count = 0;
10923 dpyinfo->icon_bitmap_id = -1;
06a2c219 10924 dpyinfo->font_table = NULL;
7a13e894
RS
10925 dpyinfo->n_fonts = 0;
10926 dpyinfo->font_table_size = 0;
10927 dpyinfo->bitmaps = 0;
10928 dpyinfo->bitmaps_size = 0;
10929 dpyinfo->bitmaps_last = 0;
10930 dpyinfo->scratch_cursor_gc = 0;
10931 dpyinfo->mouse_face_mouse_frame = 0;
10932 dpyinfo->mouse_face_deferred_gc = 0;
10933 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
10934 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 10935 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894 10936 dpyinfo->mouse_face_window = Qnil;
0a61c667 10937 dpyinfo->mouse_face_overlay = Qnil;
7a13e894
RS
10938 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
10939 dpyinfo->mouse_face_defer = 0;
66301061 10940 dpyinfo->mouse_face_hidden = 0;
0f941935
KH
10941 dpyinfo->x_focus_frame = 0;
10942 dpyinfo->x_focus_event_frame = 0;
10943 dpyinfo->x_highlight_frame = 0;
06a2c219 10944 dpyinfo->image_cache = make_image_cache ();
6b61353c
KH
10945 dpyinfo->wm_type = X_WMTYPE_UNKNOWN;
10946
10947 /* See if we can construct pixel values from RGB values. */
10948 dpyinfo->red_bits = dpyinfo->blue_bits = dpyinfo->green_bits = 0;
10949 dpyinfo->red_offset = dpyinfo->blue_offset = dpyinfo->green_offset = 0;
10950
10951 if (dpyinfo->visual->class == TrueColor)
10952 {
10953 get_bits_and_offset (dpyinfo->visual->red_mask,
10954 &dpyinfo->red_bits, &dpyinfo->red_offset);
10955 get_bits_and_offset (dpyinfo->visual->blue_mask,
10956 &dpyinfo->blue_bits, &dpyinfo->blue_offset);
10957 get_bits_and_offset (dpyinfo->visual->green_mask,
10958 &dpyinfo->green_bits, &dpyinfo->green_offset);
10959 }
334208b7 10960
43bd1b2b 10961 /* See if a private colormap is requested. */
5ff67d81
GM
10962 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
10963 {
10964 if (dpyinfo->visual->class == PseudoColor)
10965 {
10966 Lisp_Object value;
10967 value = display_x_get_resource (dpyinfo,
10968 build_string ("privateColormap"),
10969 build_string ("PrivateColormap"),
10970 Qnil, Qnil);
10971 if (STRINGP (value)
d5db4077
KR
10972 && (!strcmp (SDATA (value), "true")
10973 || !strcmp (SDATA (value), "on")))
5ff67d81
GM
10974 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
10975 }
43bd1b2b 10976 }
5ff67d81
GM
10977 else
10978 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
10979 dpyinfo->visual, AllocNone);
7d0393cf 10980
06a2c219
GM
10981 {
10982 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
10983 double pixels = DisplayHeight (dpyinfo->display, screen_number);
10984 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
2c51754c
SM
10985 /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */
10986 dpyinfo->resy = (mm < 1) ? 100 : pixels * 25.4 / mm;
06a2c219 10987 pixels = DisplayWidth (dpyinfo->display, screen_number);
2c51754c 10988 /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */
06a2c219 10989 mm = DisplayWidthMM (dpyinfo->display, screen_number);
2c51754c 10990 dpyinfo->resx = (mm < 1) ? 100 : pixels * 25.4 / mm;
06a2c219 10991 }
7d0393cf 10992
334208b7
RS
10993 dpyinfo->Xatom_wm_protocols
10994 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
10995 dpyinfo->Xatom_wm_take_focus
10996 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
10997 dpyinfo->Xatom_wm_save_yourself
10998 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
10999 dpyinfo->Xatom_wm_delete_window
11000 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
11001 dpyinfo->Xatom_wm_change_state
11002 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
11003 dpyinfo->Xatom_wm_configure_denied
11004 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
11005 dpyinfo->Xatom_wm_window_moved
11006 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
6b61353c
KH
11007 dpyinfo->Xatom_wm_client_leader
11008 = XInternAtom (dpyinfo->display, "WM_CLIENT_LEADER", False);
334208b7
RS
11009 dpyinfo->Xatom_editres
11010 = XInternAtom (dpyinfo->display, "Editres", False);
11011 dpyinfo->Xatom_CLIPBOARD
11012 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
11013 dpyinfo->Xatom_TIMESTAMP
11014 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
11015 dpyinfo->Xatom_TEXT
11016 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
11017 dpyinfo->Xatom_COMPOUND_TEXT
11018 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
c62525b7
KH
11019 dpyinfo->Xatom_UTF8_STRING
11020 = XInternAtom (dpyinfo->display, "UTF8_STRING", False);
334208b7
RS
11021 dpyinfo->Xatom_DELETE
11022 = XInternAtom (dpyinfo->display, "DELETE", False);
11023 dpyinfo->Xatom_MULTIPLE
11024 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
11025 dpyinfo->Xatom_INCR
11026 = XInternAtom (dpyinfo->display, "INCR", False);
11027 dpyinfo->Xatom_EMACS_TMP
11028 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
11029 dpyinfo->Xatom_TARGETS
11030 = XInternAtom (dpyinfo->display, "TARGETS", False);
11031 dpyinfo->Xatom_NULL
11032 = XInternAtom (dpyinfo->display, "NULL", False);
11033 dpyinfo->Xatom_ATOM_PAIR
11034 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
11035 /* For properties of font. */
11036 dpyinfo->Xatom_PIXEL_SIZE
11037 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
6875d1ae
KH
11038 dpyinfo->Xatom_AVERAGE_WIDTH
11039 = XInternAtom (dpyinfo->display, "AVERAGE_WIDTH", False);
dc43ef94
KH
11040 dpyinfo->Xatom_MULE_BASELINE_OFFSET
11041 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
11042 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
11043 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
11044 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
11045 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 11046
06a2c219
GM
11047 /* Ghostscript support. */
11048 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
11049 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
7d0393cf 11050
06a2c219
GM
11051 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
11052 False);
11053
547d9db8
KH
11054 dpyinfo->cut_buffers_initialized = 0;
11055
93acf8f3
JD
11056 dpyinfo->x_dnd_atoms_size = 8;
11057 dpyinfo->x_dnd_atoms_length = 0;
11058 dpyinfo->x_dnd_atoms = xmalloc (sizeof (*dpyinfo->x_dnd_atoms)
11059 * dpyinfo->x_dnd_atoms_size);
11060
334208b7
RS
11061 connection = ConnectionNumber (dpyinfo->display);
11062 dpyinfo->connection = connection;
11063
dc43ef94 11064 {
5d7cc324
RS
11065 char null_bits[1];
11066
11067 null_bits[0] = 0x00;
dc43ef94
KH
11068
11069 dpyinfo->null_pixel
7d0393cf 11070 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
dc43ef94
KH
11071 null_bits, 1, 1, (long) 0, (long) 0,
11072 1);
11073 }
11074
06a2c219
GM
11075 {
11076 extern int gray_bitmap_width, gray_bitmap_height;
10659c77 11077 extern char *gray_bitmap_bits;
06a2c219
GM
11078 dpyinfo->gray
11079 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
11080 gray_bitmap_bits,
11081 gray_bitmap_width, gray_bitmap_height,
11082 (unsigned long) 1, (unsigned long) 0, 1);
11083 }
11084
f5d11644
GM
11085#ifdef HAVE_X_I18N
11086 xim_initialize (dpyinfo, resource_name);
11087#endif
7d0393cf 11088
87485d6f
MW
11089#ifdef subprocesses
11090 /* This is only needed for distinguishing keyboard and process input. */
334208b7 11091 if (connection != 0)
7a13e894 11092 add_keyboard_wait_descriptor (connection);
87485d6f 11093#endif
6d4238f3 11094
041b69ac 11095#ifndef F_SETOWN_BUG
dc6f92b8 11096#ifdef F_SETOWN
dc6f92b8 11097#ifdef F_SETOWN_SOCK_NEG
61c3ce62 11098 /* stdin is a socket here */
334208b7 11099 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 11100#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 11101 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
11102#endif /* ! defined (F_SETOWN_SOCK_NEG) */
11103#endif /* ! defined (F_SETOWN) */
041b69ac 11104#endif /* F_SETOWN_BUG */
dc6f92b8
JB
11105
11106#ifdef SIGIO
eee20f6a
KH
11107 if (interrupt_input)
11108 init_sigio (connection);
c118dd06 11109#endif /* ! defined (SIGIO) */
dc6f92b8 11110
51b592fb 11111#ifdef USE_LUCID
f8c39f51 11112#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
11113 /* Make sure that we have a valid font for dialog boxes
11114 so that Xt does not crash. */
11115 {
11116 Display *dpy = dpyinfo->display;
11117 XrmValue d, fr, to;
11118 Font font;
7d0393cf 11119
51b592fb
RS
11120 d.addr = (XPointer)&dpy;
11121 d.size = sizeof (Display *);
11122 fr.addr = XtDefaultFont;
11123 fr.size = sizeof (XtDefaultFont);
11124 to.size = sizeof (Font *);
11125 to.addr = (XPointer)&font;
9ba8e10d 11126 x_catch_errors (dpy);
51b592fb
RS
11127 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
11128 abort ();
11129 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
11130 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
4545fa20 11131 x_uncatch_errors ();
51b592fb
RS
11132 }
11133#endif
f8c39f51 11134#endif
51b592fb 11135
34e23e5a
GM
11136 /* See if we should run in synchronous mode. This is useful
11137 for debugging X code. */
11138 {
11139 Lisp_Object value;
11140 value = display_x_get_resource (dpyinfo,
11141 build_string ("synchronous"),
11142 build_string ("Synchronous"),
11143 Qnil, Qnil);
11144 if (STRINGP (value)
d5db4077
KR
11145 && (!strcmp (SDATA (value), "true")
11146 || !strcmp (SDATA (value), "on")))
34e23e5a
GM
11147 XSynchronize (dpyinfo->display, True);
11148 }
62fe13a4 11149
51f3cc3b
DL
11150 {
11151 Lisp_Object value;
11152 value = display_x_get_resource (dpyinfo,
11153 build_string ("useXIM"),
11154 build_string ("UseXIM"),
11155 Qnil, Qnil);
539465b3 11156#ifdef USE_XIM
51f3cc3b
DL
11157 if (STRINGP (value)
11158 && (!strcmp (XSTRING (value)->data, "false")
11159 || !strcmp (XSTRING (value)->data, "off")))
11160 use_xim = 0;
539465b3
KS
11161#else
11162 if (STRINGP (value)
11163 && (!strcmp (XSTRING (value)->data, "true")
11164 || !strcmp (XSTRING (value)->data, "on")))
11165 use_xim = 1;
11166#endif
51f3cc3b 11167 }
7d0393cf 11168
6b61353c
KH
11169#ifdef HAVE_X_SM
11170 /* Only do this for the first display. */
11e887e2 11171 if (!x_session_initialized++)
6b61353c
KH
11172 x_session_initialize (dpyinfo);
11173#endif
11174
60439948
KH
11175 UNBLOCK_INPUT;
11176
7a13e894
RS
11177 return dpyinfo;
11178}
11179\f
11180/* Get rid of display DPYINFO, assuming all frames are already gone,
11181 and without sending any more commands to the X server. */
dc6f92b8 11182
7a13e894
RS
11183void
11184x_delete_display (dpyinfo)
11185 struct x_display_info *dpyinfo;
11186{
6b61353c
KH
11187 int i;
11188
7a13e894
RS
11189 delete_keyboard_wait_descriptor (dpyinfo->connection);
11190
11191 /* Discard this display from x_display_name_list and x_display_list.
11192 We can't use Fdelq because that can quit. */
11193 if (! NILP (x_display_name_list)
8e713be6
KR
11194 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
11195 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
11196 else
11197 {
11198 Lisp_Object tail;
11199
11200 tail = x_display_name_list;
8e713be6 11201 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 11202 {
bffcfca9 11203 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 11204 {
f3fbd155 11205 XSETCDR (tail, XCDR (XCDR (tail)));
7a13e894
RS
11206 break;
11207 }
8e713be6 11208 tail = XCDR (tail);
7a13e894
RS
11209 }
11210 }
11211
9bda743f
GM
11212 if (next_noop_dpyinfo == dpyinfo)
11213 next_noop_dpyinfo = dpyinfo->next;
11214
7a13e894
RS
11215 if (x_display_list == dpyinfo)
11216 x_display_list = dpyinfo->next;
7f9c7f94
RS
11217 else
11218 {
11219 struct x_display_info *tail;
7a13e894 11220
7f9c7f94
RS
11221 for (tail = x_display_list; tail; tail = tail->next)
11222 if (tail->next == dpyinfo)
11223 tail->next = tail->next->next;
11224 }
7a13e894 11225
0d777288
RS
11226#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
11227#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
11228 XrmDestroyDatabase (dpyinfo->xrdb);
11229#endif
0d777288 11230#endif
29b38361
KH
11231#ifdef MULTI_KBOARD
11232 if (--dpyinfo->kboard->reference_count == 0)
39f79001 11233 delete_kboard (dpyinfo->kboard);
b9737ad3 11234#endif
f5d11644
GM
11235#ifdef HAVE_X_I18N
11236 if (dpyinfo->xim)
11237 xim_close_dpy (dpyinfo);
11238#endif
7d0393cf 11239
6b61353c
KH
11240 /* Free the font names in the font table. */
11241 for (i = 0; i < dpyinfo->n_fonts; i++)
11242 if (dpyinfo->font_table[i].name)
11243 {
11244 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
11245 xfree (dpyinfo->font_table[i].full_name);
11246 xfree (dpyinfo->font_table[i].name);
11247 }
11248
4fbd0f6d
KS
11249 if (dpyinfo->font_table)
11250 {
11251 if (dpyinfo->font_table->font_encoder)
11252 xfree (dpyinfo->font_table->font_encoder);
11253 xfree (dpyinfo->font_table);
11254 }
11255 if (dpyinfo->x_id_name)
11256 xfree (dpyinfo->x_id_name);
11257 if (dpyinfo->color_cells)
11258 xfree (dpyinfo->color_cells);
b9737ad3 11259 xfree (dpyinfo);
7a13e894 11260}
f04e1297 11261
442a09ea
KS
11262#ifdef USE_X_TOOLKIT
11263
11264/* Atimer callback function for TIMER. Called every 0.1s to process
11265 Xt timeouts, if needed. We must avoid calling XtAppPending as
11266 much as possible because that function does an implicit XFlush
11267 that slows us down. */
11268
11269static void
11270x_process_timeouts (timer)
11271 struct atimer *timer;
11272{
11273 if (toolkit_scroll_bar_interaction || popup_activated ())
11274 {
11275 BLOCK_INPUT;
11276 while (XtAppPending (Xt_app_con) & XtIMTimer)
11277 XtAppProcessEvent (Xt_app_con, XtIMTimer);
11278 UNBLOCK_INPUT;
11279 }
11280}
11281
11282#endif /* USE_X_TOOLKIT */
11283
7a13e894
RS
11284\f
11285/* Set up use of X before we make the first connection. */
11286
f8240bf8
KS
11287extern frame_parm_handler x_frame_parm_handlers[];
11288
06a2c219
GM
11289static struct redisplay_interface x_redisplay_interface =
11290{
f8240bf8 11291 x_frame_parm_handlers,
06a2c219
GM
11292 x_produce_glyphs,
11293 x_write_glyphs,
11294 x_insert_glyphs,
11295 x_clear_end_of_line,
11296 x_scroll_run,
11297 x_after_update_window_line,
11298 x_update_window_begin,
11299 x_update_window_end,
442a09ea
KS
11300 x_cursor_to,
11301 x_flush,
61087d3f 11302#ifdef XFlush
06a2c219 11303 x_flush,
442a09ea
KS
11304#else
11305 0, /* flush_display_optional */
11306#endif
11307 x_clear_window_mouse_face,
66ac4b0e 11308 x_get_glyph_overhangs,
5958f265 11309 x_fix_overlapping_area,
5da0698e 11310 x_draw_fringe_bitmap,
6b61353c
KH
11311 0, /* define_fringe_bitmap */
11312 0, /* destroy_fringe_bitmap */
5da0698e
KS
11313 x_per_char_metric,
11314 x_encode_char,
11315 x_compute_glyph_string_overhangs,
442a09ea
KS
11316 x_draw_glyph_string,
11317 x_define_frame_cursor,
11318 x_clear_frame_area,
11319 x_draw_window_cursor,
11320 x_draw_vertical_window_border,
11321 x_shift_glyphs_for_insert
06a2c219
GM
11322};
11323
dfcf069d 11324void
7a13e894
RS
11325x_initialize ()
11326{
06a2c219
GM
11327 rif = &x_redisplay_interface;
11328
11329 clear_frame_hook = x_clear_frame;
11330 ins_del_lines_hook = x_ins_del_lines;
06a2c219 11331 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
11332 ring_bell_hook = XTring_bell;
11333 reset_terminal_modes_hook = XTreset_terminal_modes;
11334 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
11335 update_begin_hook = x_update_begin;
11336 update_end_hook = x_update_end;
dc6f92b8
JB
11337 set_terminal_window_hook = XTset_terminal_window;
11338 read_socket_hook = XTread_socket;
b8009dd1 11339 frame_up_to_date_hook = XTframe_up_to_date;
90e65f07 11340 mouse_position_hook = XTmouse_position;
f451eb13 11341 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 11342 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
11343 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
11344 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
11345 redeem_scroll_bar_hook = XTredeem_scroll_bar;
11346 judge_scroll_bars_hook = XTjudge_scroll_bars;
58769bee 11347
f676886a 11348 scroll_region_ok = 1; /* we'll scroll partial frames */
9017309f 11349 char_ins_del_ok = 1;
dc6f92b8
JB
11350 line_ins_del_ok = 1; /* we'll just blt 'em */
11351 fast_clear_end_of_line = 1; /* X does this well */
58769bee 11352 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
11353 off the bottom */
11354 baud_rate = 19200;
11355
7a13e894 11356 x_noop_count = 0;
9ea173e8 11357 last_tool_bar_item = -1;
06a2c219 11358 any_help_event_p = 0;
6b61353c 11359 ignore_next_mouse_click_timeout = 0;
11e887e2
JD
11360#ifdef HAVE_X_SM
11361 x_session_initialized = 0;
11362#endif
6b61353c
KH
11363
11364#ifdef USE_GTK
11365 current_count = -1;
11366#endif
7d0393cf 11367
b30b24cb
RS
11368 /* Try to use interrupt input; if we can't, then start polling. */
11369 Fset_input_mode (Qt, Qnil, Qt, Qnil);
11370
7f9c7f94
RS
11371#ifdef USE_X_TOOLKIT
11372 XtToolkitInitialize ();
651f03b6 11373
7f9c7f94 11374 Xt_app_con = XtCreateApplicationContext ();
7d0393cf 11375
651f03b6
GM
11376 /* Register a converter from strings to pixels, which uses
11377 Emacs' color allocation infrastructure. */
11378 XtAppSetTypeConverter (Xt_app_con,
11379 XtRString, XtRPixel, cvt_string_to_pixel,
11380 cvt_string_to_pixel_args,
11381 XtNumber (cvt_string_to_pixel_args),
11382 XtCacheByDisplay, cvt_pixel_dtor);
11383
665881ad 11384 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
11385
11386 /* Install an asynchronous timer that processes Xt timeout events
11387 every 0.1s. This is necessary because some widget sets use
11388 timeouts internally, for example the LessTif menu bar, or the
11389 Xaw3d scroll bar. When Xt timouts aren't processed, these
11390 widgets don't behave normally. */
11391 {
11392 EMACS_TIME interval;
11393 EMACS_SET_SECS_USECS (interval, 0, 100000);
11394 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
11395 }
db74249b 11396#endif
7d0393cf 11397
eccc05db 11398#ifdef USE_TOOLKIT_SCROLL_BARS
488dd4c4 11399#ifndef USE_GTK
ec18280f
SM
11400 xaw3d_arrow_scroll = False;
11401 xaw3d_pick_top = True;
488dd4c4 11402#endif
7f9c7f94
RS
11403#endif
11404
58769bee 11405 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 11406 original error handler. */
e99db5a1 11407 XSetErrorHandler (x_error_handler);
334208b7 11408 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 11409
06a2c219 11410 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
11411#ifdef SIGWINCH
11412 signal (SIGWINCH, SIG_DFL);
a59facca 11413#endif /* SIGWINCH */
dc6f92b8 11414
92e2441b 11415 signal (SIGPIPE, x_connection_signal);
dc6f92b8 11416}
55123275 11417
06a2c219 11418
55123275
JB
11419void
11420syms_of_xterm ()
11421{
5badc98d 11422 x_error_message = NULL;
e99db5a1 11423
7a13e894
RS
11424 staticpro (&x_display_name_list);
11425 x_display_name_list = Qnil;
334208b7 11426
ab648270 11427 staticpro (&last_mouse_scroll_bar);
e53cb100 11428 last_mouse_scroll_bar = Qnil;
59e755be
KH
11429
11430 staticpro (&Qvendor_specific_keysyms);
11431 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9 11432
c997eae5
SM
11433 staticpro (&Qlatin_1);
11434 Qlatin_1 = intern ("latin-1");
11435
2237cac9
RS
11436 staticpro (&last_mouse_press_frame);
11437 last_mouse_press_frame = Qnil;
06a2c219 11438
a72d5ce5 11439 DEFVAR_BOOL ("x-use-underline-position-properties",
7ee72033
MB
11440 &x_use_underline_position_properties,
11441 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
f0529b5b 11442nil means ignore them. If you encounter fonts with bogus
228299fa
GM
11443UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
11444to 4.1, set this to nil. */);
a72d5ce5
GM
11445 x_use_underline_position_properties = 1;
11446
30f27523
KS
11447 DEFVAR_BOOL ("x-underline-at-descent-line",
11448 &x_underline_at_descent_line,
11449 doc: /* *Non-nil means to draw the underline at the same place as the descent line.
11450nil means to draw the underline according to the value of the variable
11451`x-use-underline-position-properties', which is usually at the baseline
11452level. The default value is nil. */);
11453 x_underline_at_descent_line = 0;
11454
6b61353c
KH
11455 DEFVAR_BOOL ("x-mouse-click-focus-ignore-position",
11456 &x_mouse_click_focus_ignore_position,
11457 doc: /* Non-nil means that a mouse click to focus a frame does not move point.
11458This variable is only used when the window manager requires that you
11459click on a frame to select it (give it focus). In that case, a value
11460of nil, means that the selected window and cursor position changes to
11461reflect the mouse click position, while a non-nil value means that the
11462selected window or cursor position is preserved. */);
11463 x_mouse_click_focus_ignore_position = 0;
11464
7ee72033
MB
11465 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
11466 doc: /* What X toolkit scroll bars Emacs uses.
228299fa
GM
11467A value of nil means Emacs doesn't use X toolkit scroll bars.
11468Otherwise, value is a symbol describing the X toolkit. */);
eccc05db 11469#ifdef USE_TOOLKIT_SCROLL_BARS
5bf04520
GM
11470#ifdef USE_MOTIF
11471 Vx_toolkit_scroll_bars = intern ("motif");
11472#elif defined HAVE_XAW3D
11473 Vx_toolkit_scroll_bars = intern ("xaw3d");
488dd4c4
JD
11474#elif USE_GTK
11475 Vx_toolkit_scroll_bars = intern ("gtk");
5bf04520
GM
11476#else
11477 Vx_toolkit_scroll_bars = intern ("xaw");
11478#endif
06a2c219 11479#else
5bf04520 11480 Vx_toolkit_scroll_bars = Qnil;
06a2c219
GM
11481#endif
11482
06a2c219
GM
11483 staticpro (&last_mouse_motion_frame);
11484 last_mouse_motion_frame = Qnil;
7d0393cf 11485
98659da6
KG
11486 Qmodifier_value = intern ("modifier-value");
11487 Qalt = intern ("alt");
11488 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
11489 Qhyper = intern ("hyper");
11490 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
11491 Qmeta = intern ("meta");
11492 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
11493 Qsuper = intern ("super");
11494 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7d0393cf 11495
98659da6
KG
11496 DEFVAR_LISP ("x-alt-keysym", &Vx_alt_keysym,
11497 doc: /* Which keys Emacs uses for the alt modifier.
11498This should be one of the symbols `alt', `hyper', `meta', `super'.
11499For example, `alt' means use the Alt_L and Alt_R keysyms. The default
11500is nil, which is the same as `alt'. */);
11501 Vx_alt_keysym = Qnil;
7d0393cf 11502
98659da6
KG
11503 DEFVAR_LISP ("x-hyper-keysym", &Vx_hyper_keysym,
11504 doc: /* Which keys Emacs uses for the hyper modifier.
11505This should be one of the symbols `alt', `hyper', `meta', `super'.
11506For example, `hyper' means use the Hyper_L and Hyper_R keysyms. The
11507default is nil, which is the same as `hyper'. */);
11508 Vx_hyper_keysym = Qnil;
7d0393cf 11509
98659da6
KG
11510 DEFVAR_LISP ("x-meta-keysym", &Vx_meta_keysym,
11511 doc: /* Which keys Emacs uses for the meta modifier.
11512This should be one of the symbols `alt', `hyper', `meta', `super'.
11513For example, `meta' means use the Meta_L and Meta_R keysyms. The
11514default is nil, which is the same as `meta'. */);
11515 Vx_meta_keysym = Qnil;
7d0393cf 11516
98659da6
KG
11517 DEFVAR_LISP ("x-super-keysym", &Vx_super_keysym,
11518 doc: /* Which keys Emacs uses for the super modifier.
11519This should be one of the symbols `alt', `hyper', `meta', `super'.
11520For example, `super' means use the Super_L and Super_R keysyms. The
11521default is nil, which is the same as `super'. */);
11522 Vx_super_keysym = Qnil;
11523
dbd4b028
DL
11524 DEFVAR_LISP ("x-keysym-table", &Vx_keysym_table,
11525 doc: /* Hash table of character codes indexed by X keysym codes. */);
11526 Vx_keysym_table = make_hash_table (Qeql, make_number (900),
11527 make_float (DEFAULT_REHASH_SIZE),
11528 make_float (DEFAULT_REHASH_THRESHOLD),
11529 Qnil, Qnil, Qnil);
55123275 11530}
6cf0ae86 11531
1d6c120a 11532#endif /* HAVE_X_WINDOWS */
6b61353c
KH
11533
11534/* arch-tag: 6d4e4cb7-abc1-4302-9585-d84dcfb09d0f
11535 (do not change this comment) */