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