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