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