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