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