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