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