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