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