(notice_overwritten_cursor): Don't depend on
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
edf36fe6 2 Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001
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
d624284c
PJ
100#ifdef USE_LUCID
101extern int xlwmenu_window_p (Widget w, Window window);
102extern void xlwmenu_redisplay P_ ((Widget));
103#endif
104
3afe33e7 105#ifdef USE_X_TOOLKIT
06a2c219 106
952291d9
GM
107extern void free_frame_menubar P_ ((struct frame *));
108extern struct frame *x_menubar_window_to_frame P_ ((struct x_display_info *,
109 int));
06a2c219 110
0fdff6bb
RS
111#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
112#define HACK_EDITRES
113extern void _XEditResCheckMessages ();
114#endif /* not NO_EDITRES */
06a2c219
GM
115
116/* Include toolkit specific headers for the scroll bar widget. */
117
118#ifdef USE_TOOLKIT_SCROLL_BARS
119#if defined USE_MOTIF
120#include <Xm/Xm.h> /* for LESSTIF_VERSION */
121#include <Xm/ScrollBar.h>
ec18280f
SM
122#else /* !USE_MOTIF i.e. use Xaw */
123
124#ifdef HAVE_XAW3D
06a2c219 125#include <X11/Xaw3d/Simple.h>
06a2c219
GM
126#include <X11/Xaw3d/Scrollbar.h>
127#define ARROW_SCROLLBAR
128#include <X11/Xaw3d/ScrollbarP.h>
ec18280f
SM
129#else /* !HAVE_XAW3D */
130#include <X11/Xaw/Simple.h>
131#include <X11/Xaw/Scrollbar.h>
132#endif /* !HAVE_XAW3D */
133#ifndef XtNpickTop
134#define XtNpickTop "pickTop"
135#endif /* !XtNpickTop */
136#endif /* !USE_MOTIF */
06a2c219
GM
137#endif /* USE_TOOLKIT_SCROLL_BARS */
138
3afe33e7
RS
139#endif /* USE_X_TOOLKIT */
140
b849c413
RS
141#ifndef USE_X_TOOLKIT
142#define x_any_window_to_frame x_window_to_frame
5627c40e 143#define x_top_window_to_frame x_window_to_frame
b849c413
RS
144#endif
145
546e6d5b 146#ifdef USE_X_TOOLKIT
d067ea8b 147#include "widget.h"
546e6d5b
RS
148#ifndef XtNinitialState
149#define XtNinitialState "initialState"
150#endif
151#endif
152
06a2c219
GM
153#define abs(x) ((x) < 0 ? -(x) : (x))
154
155#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
156
157\f
3f332ef3 158/* Fringe bitmaps. */
06a2c219 159
3f332ef3 160enum fringe_bitmap_type
06a2c219 161{
3f332ef3 162 NO_FRINGE_BITMAP,
06a2c219
GM
163 LEFT_TRUNCATION_BITMAP,
164 RIGHT_TRUNCATION_BITMAP,
165 OVERLAY_ARROW_BITMAP,
166 CONTINUED_LINE_BITMAP,
167 CONTINUATION_LINE_BITMAP,
168 ZV_LINE_BITMAP
169};
170
171/* Bitmap drawn to indicate lines not displaying text if
172 `indicate-empty-lines' is non-nil. */
173
174#define zv_width 8
976b73d7
KS
175#define zv_height 72
176#define zv_period 3
06a2c219 177static unsigned char zv_bits[] = {
976b73d7
KS
178 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
179 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
180 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
181 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
182 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
183 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
184 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
185 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00};
06a2c219
GM
186
187/* An arrow like this: `<-'. */
188
189#define left_width 8
190#define left_height 8
191static unsigned char left_bits[] = {
192 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
193
110859fc
GM
194/* Right truncation arrow bitmap `->'. */
195
196#define right_width 8
197#define right_height 8
198static unsigned char right_bits[] = {
199 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
200
06a2c219
GM
201/* Marker for continued lines. */
202
203#define continued_width 8
204#define continued_height 8
205static unsigned char continued_bits[] = {
110859fc
GM
206 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
207
208/* Marker for continuation lines. */
06a2c219
GM
209
210#define continuation_width 8
211#define continuation_height 8
212static unsigned char continuation_bits[] = {
110859fc 213 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
06a2c219 214
110859fc 215/* Overlay arrow bitmap. */
06a2c219 216
110859fc
GM
217#if 0
218/* A bomb. */
06a2c219
GM
219#define ov_width 8
220#define ov_height 8
221static unsigned char ov_bits[] = {
222 0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
06a2c219 223#else
110859fc 224/* A triangular arrow. */
06a2c219
GM
225#define ov_width 8
226#define ov_height 8
227static unsigned char ov_bits[] = {
110859fc
GM
228 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
229
e4b68333 230#endif
06a2c219
GM
231
232extern Lisp_Object Qhelp_echo;
233
69388238 234\f
5bf04520 235/* Non-nil means Emacs uses toolkit scroll bars. */
06a2c219 236
5bf04520 237Lisp_Object Vx_toolkit_scroll_bars;
06a2c219
GM
238
239/* If a string, XTread_socket generates an event to display that string.
240 (The display is done in read_char.) */
241
242static Lisp_Object help_echo;
7cea38bc 243static Lisp_Object help_echo_window;
be010514
GM
244static Lisp_Object help_echo_object;
245static int help_echo_pos;
06a2c219
GM
246
247/* Temporary variable for XTread_socket. */
248
249static Lisp_Object previous_help_echo;
250
251/* Non-zero means that a HELP_EVENT has been generated since Emacs
252 start. */
253
254static int any_help_event_p;
255
256/* Non-zero means draw block and hollow cursor as wide as the glyph
257 under it. For example, if a block cursor is over a tab, it will be
258 drawn as wide as that tab on the display. */
259
260int x_stretch_cursor_p;
261
a72d5ce5
GM
262/* Non-zero means make use of UNDERLINE_POSITION font properties. */
263
264int x_use_underline_position_properties;
265
06a2c219
GM
266/* This is a chain of structures for all the X displays currently in
267 use. */
268
334208b7 269struct x_display_info *x_display_list;
dc6f92b8 270
06a2c219
GM
271/* This is a list of cons cells, each of the form (NAME
272 . FONT-LIST-CACHE), one for each element of x_display_list and in
273 the same order. NAME is the name of the frame. FONT-LIST-CACHE
274 records previous values returned by x-list-fonts. */
275
7a13e894 276Lisp_Object x_display_name_list;
f451eb13 277
987d2ad1 278/* Frame being updated by update_frame. This is declared in term.c.
06a2c219
GM
279 This is set by update_begin and looked at by all the XT functions.
280 It is zero while not inside an update. In that case, the XT
281 functions assume that `selected_frame' is the frame to apply to. */
282
d0386f2a 283extern struct frame *updating_frame;
dc6f92b8 284
06a2c219
GM
285/* This is a frame waiting to be auto-raised, within XTread_socket. */
286
0134a210
RS
287struct frame *pending_autoraise_frame;
288
7f9c7f94
RS
289#ifdef USE_X_TOOLKIT
290/* The application context for Xt use. */
291XtAppContext Xt_app_con;
06a2c219
GM
292static String Xt_default_resources[] = {0};
293#endif /* USE_X_TOOLKIT */
665881ad 294
06a2c219
GM
295/* Nominal cursor position -- where to draw output.
296 HPOS and VPOS are window relative glyph matrix coordinates.
297 X and Y are window relative pixel coordinates. */
dc6f92b8 298
06a2c219 299struct cursor_pos output_cursor;
dc6f92b8 300
bffcfca9
GM
301/* Non-zero means user is interacting with a toolkit scroll bar. */
302
303static int toolkit_scroll_bar_interaction;
dc6f92b8 304
69388238
RS
305/* Mouse movement.
306
06a2c219 307 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
308 so that we would have to call XQueryPointer after each MotionNotify
309 event to ask for another such event. However, this made mouse tracking
310 slow, and there was a bug that made it eventually stop.
311
312 Simply asking for MotionNotify all the time seems to work better.
313
69388238
RS
314 In order to avoid asking for motion events and then throwing most
315 of them away or busy-polling the server for mouse positions, we ask
316 the server for pointer motion hints. This means that we get only
317 one event per group of mouse movements. "Groups" are delimited by
318 other kinds of events (focus changes and button clicks, for
319 example), or by XQueryPointer calls; when one of these happens, we
320 get another MotionNotify event the next time the mouse moves. This
321 is at least as efficient as getting motion events when mouse
322 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 323 is off. */
69388238
RS
324
325/* Where the mouse was last time we reported a mouse event. */
69388238 326
06a2c219
GM
327FRAME_PTR last_mouse_frame;
328static XRectangle last_mouse_glyph;
2237cac9
RS
329static Lisp_Object last_mouse_press_frame;
330
69388238
RS
331/* The scroll bar in which the last X motion event occurred.
332
06a2c219
GM
333 If the last X motion event occurred in a scroll bar, we set this so
334 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
335 an ordinary motion.
336
06a2c219
GM
337 If the last X motion event didn't occur in a scroll bar, we set
338 this to Qnil, to tell XTmouse_position to return an ordinary motion
339 event. */
340
69388238
RS
341static Lisp_Object last_mouse_scroll_bar;
342
69388238
RS
343/* This is a hack. We would really prefer that XTmouse_position would
344 return the time associated with the position it returns, but there
06a2c219 345 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
346 along with the position query. So, we just keep track of the time
347 of the last movement we received, and return that in hopes that
348 it's somewhat accurate. */
06a2c219 349
69388238
RS
350static Time last_mouse_movement_time;
351
06a2c219
GM
352/* Incremented by XTread_socket whenever it really tries to read
353 events. */
354
c0a04927
RS
355#ifdef __STDC__
356static int volatile input_signal_count;
357#else
358static int input_signal_count;
359#endif
360
7a13e894 361/* Used locally within XTread_socket. */
06a2c219 362
7a13e894 363static int x_noop_count;
dc6f92b8 364
7a13e894 365/* Initial values of argv and argc. */
06a2c219 366
7a13e894
RS
367extern char **initial_argv;
368extern int initial_argc;
dc6f92b8 369
7a13e894 370extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 371
06a2c219 372/* Tells if a window manager is present or not. */
7a13e894
RS
373
374extern Lisp_Object Vx_no_window_manager;
dc6f92b8 375
c2df547c 376extern Lisp_Object Qface, Qmouse_face;
b8009dd1 377
dc6f92b8
JB
378extern int errno;
379
dfeccd2d 380/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 381
64bb1782
RS
382extern int extra_keyboard_modifiers;
383
59e755be
KH
384static Lisp_Object Qvendor_specific_keysyms;
385
952291d9
GM
386extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
387extern Lisp_Object x_icon_type P_ ((struct frame *));
c32cdd9a 388
7a13e894 389
06a2c219
GM
390/* Enumeration for overriding/changing the face to use for drawing
391 glyphs in x_draw_glyphs. */
392
393enum draw_glyphs_face
394{
395 DRAW_NORMAL_TEXT,
396 DRAW_INVERSE_VIDEO,
397 DRAW_CURSOR,
398 DRAW_MOUSE_FACE,
399 DRAW_IMAGE_RAISED,
400 DRAW_IMAGE_SUNKEN
401};
402
b7f83f9e 403static int cursor_in_mouse_face_p P_ ((struct window *));
fa262c07 404static int clear_mouse_face P_ ((struct x_display_info *));
651f03b6 405static int x_alloc_nearest_color_1 P_ ((Display *, Colormap, XColor *));
499b1844 406static void x_set_window_size_1 P_ ((struct frame *, int, int, int));
651f03b6 407static const XColor *x_color_cells P_ ((Display *, int *));
71b8321e 408static void x_update_window_end P_ ((struct window *, int, int));
06a2c219
GM
409static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
410void x_delete_display P_ ((struct x_display_info *));
411static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
412 unsigned));
413static int fast_find_position P_ ((struct window *, int, int *, int *,
7e376260 414 int *, int *, Lisp_Object));
f9db2310
GM
415static int fast_find_string_pos P_ ((struct window *, int, Lisp_Object,
416 int *, int *, int *, int *, int));
06a2c219
GM
417static void set_output_cursor P_ ((struct cursor_pos *));
418static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
f9db2310 419 int *, int *, int *, int));
06a2c219 420static void note_mode_line_highlight P_ ((struct window *, int, int));
06a2c219 421static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
422static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
423static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
424static void show_mouse_face P_ ((struct x_display_info *,
425 enum draw_glyphs_face));
426static int x_io_error_quitter P_ ((Display *));
427int x_catch_errors P_ ((Display *));
428void x_uncatch_errors P_ ((Display *, int));
429void x_lower_frame P_ ((struct frame *));
430void x_scroll_bar_clear P_ ((struct frame *));
431int x_had_errors_p P_ ((Display *));
432void x_wm_set_size_hint P_ ((struct frame *, long, int));
433void x_raise_frame P_ ((struct frame *));
434void x_set_window_size P_ ((struct frame *, int, int, int));
435void x_wm_set_window_state P_ ((struct frame *, int));
436void x_wm_set_icon_pixmap P_ ((struct frame *, int));
437void x_initialize P_ ((void));
438static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
439static int x_compute_min_glyph_bounds P_ ((struct frame *));
440static void x_draw_phys_cursor_glyph P_ ((struct window *,
441 struct glyph_row *,
442 enum draw_glyphs_face));
443static void x_update_end P_ ((struct frame *));
444static void XTframe_up_to_date P_ ((struct frame *));
06a2c219
GM
445static void XTset_terminal_modes P_ ((void));
446static void XTreset_terminal_modes P_ ((void));
447static void XTcursor_to P_ ((int, int, int, int));
448static void x_write_glyphs P_ ((struct glyph *, int));
449static void x_clear_end_of_line P_ ((int));
450static void x_clear_frame P_ ((void));
451static void x_clear_cursor P_ ((struct window *));
452static void frame_highlight P_ ((struct frame *));
453static void frame_unhighlight P_ ((struct frame *));
454static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
455static void XTframe_rehighlight P_ ((struct frame *));
456static void x_frame_rehighlight P_ ((struct x_display_info *));
457static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
f02d8aa0 458static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
06a2c219
GM
459static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
460 XRectangle *));
461static void expose_frame P_ ((struct frame *, int, int, int, int));
82f053ab 462static int expose_window_tree P_ ((struct window *, XRectangle *));
a39202f6 463static int expose_window P_ ((struct window *, XRectangle *));
06a2c219
GM
464static void expose_area P_ ((struct window *, struct glyph_row *,
465 XRectangle *, enum glyph_row_area));
82f053ab 466static int expose_line P_ ((struct window *, struct glyph_row *,
06a2c219
GM
467 XRectangle *));
468static void x_update_cursor_in_window_tree P_ ((struct window *, int));
469static void x_update_window_cursor P_ ((struct window *, int));
470static void x_erase_phys_cursor P_ ((struct window *));
471void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
3f332ef3 472static void x_draw_fringe_bitmap P_ ((struct window *, struct glyph_row *,
976b73d7 473 enum fringe_bitmap_type, int left_p));
06a2c219
GM
474
475static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
476 GC, int));
477static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
3f332ef3 478static void x_draw_row_fringe_bitmaps P_ ((struct window *, struct glyph_row *));
60626bab
GM
479static void notice_overwritten_cursor P_ ((struct window *, enum glyph_row_area,
480 int, int, int, int));
06a2c219 481static void x_flush P_ ((struct frame *f));
952291d9
GM
482static void x_update_begin P_ ((struct frame *));
483static void x_update_window_begin P_ ((struct window *));
484static void x_draw_vertical_border P_ ((struct window *));
485static void x_after_update_window_line P_ ((struct glyph_row *));
486static INLINE void take_vertical_position_into_account P_ ((struct it *));
487static void x_produce_stretch_glyph P_ ((struct it *));
b52b65bd
GM
488static struct scroll_bar *x_window_to_scroll_bar P_ ((Window));
489static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
490 enum scroll_bar_part *,
491 Lisp_Object *, Lisp_Object *,
492 unsigned long *));
06a2c219
GM
493
494/* Flush display of frame F, or of all frames if F is null. */
495
496static void
497x_flush (f)
498 struct frame *f;
499{
500 BLOCK_INPUT;
501 if (f == NULL)
502 {
503 Lisp_Object rest, frame;
504 FOR_EACH_FRAME (rest, frame)
505 x_flush (XFRAME (frame));
506 }
507 else if (FRAME_X_P (f))
508 XFlush (FRAME_X_DISPLAY (f));
509 UNBLOCK_INPUT;
510}
511
dc6f92b8 512
06a2c219
GM
513/* Remove calls to XFlush by defining XFlush to an empty replacement.
514 Calls to XFlush should be unnecessary because the X output buffer
515 is flushed automatically as needed by calls to XPending,
516 XNextEvent, or XWindowEvent according to the XFlush man page.
517 XTread_socket calls XPending. Removing XFlush improves
518 performance. */
519
520#define XFlush(DISPLAY) (void) 0
b8009dd1 521
334208b7 522\f
06a2c219
GM
523/***********************************************************************
524 Debugging
525 ***********************************************************************/
526
9382638d 527#if 0
06a2c219
GM
528
529/* This is a function useful for recording debugging information about
530 the sequence of occurrences in this file. */
9382638d
KH
531
532struct record
533{
534 char *locus;
535 int type;
536};
537
538struct record event_record[100];
539
540int event_record_index;
541
542record_event (locus, type)
543 char *locus;
544 int type;
545{
546 if (event_record_index == sizeof (event_record) / sizeof (struct record))
547 event_record_index = 0;
548
549 event_record[event_record_index].locus = locus;
550 event_record[event_record_index].type = type;
551 event_record_index++;
552}
553
554#endif /* 0 */
06a2c219
GM
555
556
9382638d 557\f
334208b7
RS
558/* Return the struct x_display_info corresponding to DPY. */
559
560struct x_display_info *
561x_display_info_for_display (dpy)
562 Display *dpy;
563{
564 struct x_display_info *dpyinfo;
565
566 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
567 if (dpyinfo->display == dpy)
568 return dpyinfo;
16bd92ea 569
334208b7
RS
570 return 0;
571}
f451eb13 572
06a2c219
GM
573
574\f
575/***********************************************************************
576 Starting and ending an update
577 ***********************************************************************/
578
579/* Start an update of frame F. This function is installed as a hook
580 for update_begin, i.e. it is called when update_begin is called.
581 This function is called prior to calls to x_update_window_begin for
582 each window being updated. Currently, there is nothing to do here
583 because all interesting stuff is done on a window basis. */
dc6f92b8 584
dfcf069d 585static void
06a2c219 586x_update_begin (f)
f676886a 587 struct frame *f;
58769bee 588{
06a2c219
GM
589 /* Nothing to do. */
590}
dc6f92b8 591
dc6f92b8 592
06a2c219
GM
593/* Start update of window W. Set the global variable updated_window
594 to the window being updated and set output_cursor to the cursor
595 position of W. */
dc6f92b8 596
06a2c219
GM
597static void
598x_update_window_begin (w)
599 struct window *w;
600{
601 struct frame *f = XFRAME (WINDOW_FRAME (w));
602 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
603
604 updated_window = w;
605 set_output_cursor (&w->cursor);
b8009dd1 606
06a2c219 607 BLOCK_INPUT;
d1bc4182 608
06a2c219 609 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 610 {
514e4681 611 /* Don't do highlighting for mouse motion during the update. */
06a2c219 612 display_info->mouse_face_defer = 1;
37c2c98b 613
06a2c219
GM
614 /* If F needs to be redrawn, simply forget about any prior mouse
615 highlighting. */
9f67f20b 616 if (FRAME_GARBAGED_P (f))
06a2c219
GM
617 display_info->mouse_face_window = Qnil;
618
64f26cf5
GM
619#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
620 their mouse_face_p flag set, which means that they are always
621 unequal to rows in a desired matrix which never have that
622 flag set. So, rows containing mouse-face glyphs are never
623 scrolled, and we don't have to switch the mouse highlight off
624 here to prevent it from being scrolled. */
625
06a2c219
GM
626 /* Can we tell that this update does not affect the window
627 where the mouse highlight is? If so, no need to turn off.
628 Likewise, don't do anything if the frame is garbaged;
629 in that case, the frame's current matrix that we would use
630 is all wrong, and we will redisplay that line anyway. */
631 if (!NILP (display_info->mouse_face_window)
632 && w == XWINDOW (display_info->mouse_face_window))
514e4681 633 {
06a2c219 634 int i;
514e4681 635
06a2c219
GM
636 for (i = 0; i < w->desired_matrix->nrows; ++i)
637 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
638 break;
639
06a2c219
GM
640 if (i < w->desired_matrix->nrows)
641 clear_mouse_face (display_info);
514e4681 642 }
64f26cf5 643#endif /* 0 */
b8009dd1 644 }
6ccf47d1 645
dc6f92b8
JB
646 UNBLOCK_INPUT;
647}
648
06a2c219
GM
649
650/* Draw a vertical window border to the right of window W if W doesn't
651 have vertical scroll bars. */
652
dfcf069d 653static void
06a2c219
GM
654x_draw_vertical_border (w)
655 struct window *w;
58769bee 656{
06a2c219
GM
657 struct frame *f = XFRAME (WINDOW_FRAME (w));
658
659 /* Redraw borders between horizontally adjacent windows. Don't
660 do it for frames with vertical scroll bars because either the
661 right scroll bar of a window, or the left scroll bar of its
662 neighbor will suffice as a border. */
663 if (!WINDOW_RIGHTMOST_P (w)
664 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
665 {
666 int x0, x1, y0, y1;
dc6f92b8 667
06a2c219 668 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
3f332ef3 669 x1 += FRAME_X_RIGHT_FRINGE_WIDTH (f);
06a2c219
GM
670 y1 -= 1;
671
672 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
673 f->output_data.x->normal_gc, x1, y0, x1, y1);
674 }
675}
676
677
71b8321e
GM
678/* End update of window W (which is equal to updated_window).
679
680 Draw vertical borders between horizontally adjacent windows, and
681 display W's cursor if CURSOR_ON_P is non-zero.
682
683 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
684 glyphs in mouse-face were overwritten. In that case we have to
685 make sure that the mouse-highlight is properly redrawn.
686
687 W may be a menu bar pseudo-window in case we don't have X toolkit
688 support. Such windows don't have a cursor, so don't display it
689 here. */
06a2c219
GM
690
691static void
71b8321e 692x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 693 struct window *w;
71b8321e 694 int cursor_on_p, mouse_face_overwritten_p;
06a2c219 695{
140330de
GM
696 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
697
06a2c219
GM
698 if (!w->pseudo_window_p)
699 {
700 BLOCK_INPUT;
71b8321e 701
06a2c219
GM
702 if (cursor_on_p)
703 x_display_and_set_cursor (w, 1, output_cursor.hpos,
704 output_cursor.vpos,
705 output_cursor.x, output_cursor.y);
71b8321e 706
06a2c219
GM
707 x_draw_vertical_border (w);
708 UNBLOCK_INPUT;
709 }
710
140330de
GM
711 /* If a row with mouse-face was overwritten, arrange for
712 XTframe_up_to_date to redisplay the mouse highlight. */
713 if (mouse_face_overwritten_p)
714 {
715 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
716 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
717 dpyinfo->mouse_face_window = Qnil;
718 }
719
06a2c219
GM
720 updated_window = NULL;
721}
dc6f92b8 722
dc6f92b8 723
06a2c219
GM
724/* End update of frame F. This function is installed as a hook in
725 update_end. */
726
727static void
728x_update_end (f)
729 struct frame *f;
730{
731 /* Mouse highlight may be displayed again. */
aa8bff2e 732 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 733
06a2c219 734 BLOCK_INPUT;
334208b7 735 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
736 UNBLOCK_INPUT;
737}
b8009dd1 738
06a2c219
GM
739
740/* This function is called from various places in xdisp.c whenever a
741 complete update has been performed. The global variable
742 updated_window is not available here. */
b8009dd1 743
dfcf069d 744static void
b8009dd1 745XTframe_up_to_date (f)
06a2c219 746 struct frame *f;
b8009dd1 747{
06a2c219 748 if (FRAME_X_P (f))
514e4681 749 {
06a2c219 750 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 751
06a2c219
GM
752 if (dpyinfo->mouse_face_deferred_gc
753 || f == dpyinfo->mouse_face_mouse_frame)
754 {
755 BLOCK_INPUT;
756 if (dpyinfo->mouse_face_mouse_frame)
757 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
758 dpyinfo->mouse_face_mouse_x,
759 dpyinfo->mouse_face_mouse_y);
760 dpyinfo->mouse_face_deferred_gc = 0;
761 UNBLOCK_INPUT;
762 }
514e4681 763 }
b8009dd1 764}
06a2c219
GM
765
766
767/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
3f332ef3 768 arrow bitmaps, or clear the fringes if no bitmaps are required
06a2c219
GM
769 before DESIRED_ROW is made current. The window being updated is
770 found in updated_window. This function It is called from
771 update_window_line only if it is known that there are differences
772 between bitmaps to be drawn between current row and DESIRED_ROW. */
773
774static void
775x_after_update_window_line (desired_row)
776 struct glyph_row *desired_row;
777{
778 struct window *w = updated_window;
ef253080 779 struct frame *f;
259cf6bc 780 int width, height;
06a2c219
GM
781
782 xassert (w);
783
784 if (!desired_row->mode_line_p && !w->pseudo_window_p)
785 {
786 BLOCK_INPUT;
3f332ef3 787 x_draw_row_fringe_bitmaps (w, desired_row);
ef253080
GM
788 UNBLOCK_INPUT;
789 }
790
791 /* When a window has disappeared, make sure that no rest of
792 full-width rows stays visible in the internal border. Could
793 check here if updated_window is the leftmost/rightmost window,
794 but I guess it's not worth doing since vertically split windows
795 are almost never used, internal border is rarely set, and the
796 overhead is very small. */
797 if (windows_or_buffers_changed
798 && desired_row->full_width_p
799 && (f = XFRAME (w->frame),
800 width = FRAME_INTERNAL_BORDER_WIDTH (f),
259cf6bc
GM
801 width != 0)
802 && (height = desired_row->visible_height,
803 height > 0))
ef253080 804 {
ef253080 805 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
06a2c219 806
ef253080
GM
807 /* Internal border is drawn below the tool bar. */
808 if (WINDOWP (f->tool_bar_window)
809 && w == XWINDOW (f->tool_bar_window))
810 y -= width;
06a2c219 811
ef253080
GM
812 BLOCK_INPUT;
813 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
814 0, y, width, height, False);
815 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
816 f->output_data.x->pixel_width - width,
817 y, width, height, False);
06a2c219
GM
818 UNBLOCK_INPUT;
819 }
820}
821
822
3f332ef3 823/* Draw the bitmap WHICH in one of the left or right fringes of
06a2c219
GM
824 window W. ROW is the glyph row for which to display the bitmap; it
825 determines the vertical position at which the bitmap has to be
826 drawn. */
827
828static void
976b73d7 829x_draw_fringe_bitmap (w, row, which, left_p)
06a2c219
GM
830 struct window *w;
831 struct glyph_row *row;
3f332ef3 832 enum fringe_bitmap_type which;
976b73d7 833 int left_p;
06a2c219
GM
834{
835 struct frame *f = XFRAME (WINDOW_FRAME (w));
836 Display *display = FRAME_X_DISPLAY (f);
837 Window window = FRAME_X_WINDOW (f);
838 int x, y, wd, h, dy;
976b73d7 839 int b1, b2;
06a2c219
GM
840 unsigned char *bits;
841 Pixmap pixmap;
842 GC gc = f->output_data.x->normal_gc;
843 struct face *face;
844 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
845
846 /* Must clip because of partially visible lines. */
847 x_clip_to_row (w, row, gc, 1);
848
976b73d7
KS
849 /* Convert row to frame coordinates. */
850 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
851
06a2c219
GM
852 switch (which)
853 {
976b73d7
KS
854 case NO_FRINGE_BITMAP:
855 wd = 0;
856 h = 0;
857 break;
858
06a2c219
GM
859 case LEFT_TRUNCATION_BITMAP:
860 wd = left_width;
861 h = left_height;
862 bits = left_bits;
06a2c219
GM
863 break;
864
865 case OVERLAY_ARROW_BITMAP:
976b73d7
KS
866 wd = ov_width;
867 h = ov_height;
06a2c219 868 bits = ov_bits;
06a2c219
GM
869 break;
870
871 case RIGHT_TRUNCATION_BITMAP:
872 wd = right_width;
873 h = right_height;
874 bits = right_bits;
06a2c219
GM
875 break;
876
877 case CONTINUED_LINE_BITMAP:
976b73d7
KS
878 wd = continued_width;
879 h = continued_height;
06a2c219 880 bits = continued_bits;
06a2c219
GM
881 break;
882
883 case CONTINUATION_LINE_BITMAP:
884 wd = continuation_width;
885 h = continuation_height;
886 bits = continuation_bits;
06a2c219
GM
887 break;
888
889 case ZV_LINE_BITMAP:
890 wd = zv_width;
976b73d7
KS
891 h = zv_height - (y % zv_period);
892 bits = zv_bits + (y % zv_period);
06a2c219
GM
893 break;
894
895 default:
896 abort ();
897 }
898
976b73d7
KS
899 /* Clip bitmap if too high. */
900 if (h > row->height)
901 h = row->height;
902
903 /* Set dy to the offset in the row to start drawing the bitmap. */
06a2c219
GM
904 dy = (row->height - h) / 2;
905
976b73d7
KS
906 face = FACE_FROM_ID (f, FRINGE_FACE_ID);
907 PREPARE_FACE_FOR_DISPLAY (f, face);
908
909 /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill
910 the fringe. */
dbdc9702 911 b1 = b2 = -1;
976b73d7
KS
912 if (left_p)
913 {
914 if (wd > FRAME_X_LEFT_FRINGE_WIDTH (f))
915 wd = FRAME_X_LEFT_FRINGE_WIDTH (f);
916 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
917 - wd
918 - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2);
919 if (wd < FRAME_X_LEFT_FRINGE_WIDTH (f) || row->height > h)
920 {
921 /* If W has a vertical border to its left, don't draw over it. */
922 int border = ((XFASTINT (w->left) > 0
923 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
924 ? 1 : 0);
925 b1 = (window_box_left (w, -1)
926 - FRAME_X_LEFT_FRINGE_WIDTH (f)
927 + border);
928 b2 = (FRAME_X_LEFT_FRINGE_WIDTH (f) - border);
929 }
930 }
931 else
932 {
933 if (wd > FRAME_X_RIGHT_FRINGE_WIDTH (f))
934 wd = FRAME_X_RIGHT_FRINGE_WIDTH (f);
935 x = (window_box_right (w, -1)
936 + (FRAME_X_RIGHT_FRINGE_WIDTH (f) - wd) / 2);
937 /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill
938 the fringe. */
939 if (wd < FRAME_X_RIGHT_FRINGE_WIDTH (f) || row->height > h)
940 {
941 b1 = window_box_right (w, -1);
942 b2 = FRAME_X_RIGHT_FRINGE_WIDTH (f);
943 }
944 }
945
946 if (b1 >= 0)
947 {
948 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
949
950 /* In case the same realized face is used for fringes and
951 for something displayed in the text (e.g. face `region' on
952 mono-displays, the fill style may have been changed to
953 FillSolid in x_draw_glyph_string_background. */
954 if (face->stipple)
955 XSetFillStyle (display, face->gc, FillOpaqueStippled);
956 else
957 XSetForeground (display, face->gc, face->background);
958
959 XFillRectangle (display, window, face->gc,
960 b1,
961 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
962 row->y)),
963 b2,
964 row->visible_height);
965 if (!face->stipple)
966 XSetForeground (display, face->gc, face->foreground);
967 }
968
dbdc9702
GM
969 if (which != NO_FRINGE_BITMAP)
970 {
971 /* Draw the bitmap. I believe these small pixmaps can be cached
972 by the server. */
973 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
974 face->foreground,
975 face->background, depth);
976 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
977 XFreePixmap (display, pixmap);
978 }
979
06a2c219
GM
980 XSetClipMask (display, gc, None);
981}
982
983
3f332ef3 984/* Draw fringe bitmaps for glyph row ROW on window W. Call this
06a2c219
GM
985 function with input blocked. */
986
987static void
3f332ef3 988x_draw_row_fringe_bitmaps (w, row)
06a2c219
GM
989 struct window *w;
990 struct glyph_row *row;
991{
992 struct frame *f = XFRAME (w->frame);
3f332ef3 993 enum fringe_bitmap_type bitmap;
06a2c219
GM
994
995 xassert (interrupt_input_blocked);
996
997 /* If row is completely invisible, because of vscrolling, we
998 don't have to draw anything. */
999 if (row->visible_height <= 0)
1000 return;
1001
976b73d7
KS
1002 if (FRAME_X_LEFT_FRINGE_WIDTH (f) != 0)
1003 {
1004 /* Decide which bitmap to draw in the left fringe. */
1005 if (row->overlay_arrow_p)
1006 bitmap = OVERLAY_ARROW_BITMAP;
1007 else if (row->truncated_on_left_p)
1008 bitmap = LEFT_TRUNCATION_BITMAP;
1009 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
1010 bitmap = CONTINUATION_LINE_BITMAP;
1011 else if (row->indicate_empty_line_p)
1012 bitmap = ZV_LINE_BITMAP;
dcd08bfb 1013 else
976b73d7 1014 bitmap = NO_FRINGE_BITMAP;
06a2c219 1015
976b73d7
KS
1016 x_draw_fringe_bitmap (w, row, bitmap, 1);
1017 }
06a2c219 1018
976b73d7 1019 if (FRAME_X_RIGHT_FRINGE_WIDTH (f) != 0)
06a2c219 1020 {
976b73d7
KS
1021 /* Decide which bitmap to draw in the right fringe. */
1022 if (row->truncated_on_right_p)
1023 bitmap = RIGHT_TRUNCATION_BITMAP;
1024 else if (row->continued_p)
1025 bitmap = CONTINUED_LINE_BITMAP;
1026 else if (row->indicate_empty_line_p && FRAME_X_LEFT_FRINGE_WIDTH (f) == 0)
1027 bitmap = ZV_LINE_BITMAP;
dcd08bfb 1028 else
976b73d7 1029 bitmap = NO_FRINGE_BITMAP;
06a2c219 1030
976b73d7
KS
1031 x_draw_fringe_bitmap (w, row, bitmap, 0);
1032 }
06a2c219
GM
1033}
1034
dc6f92b8 1035\f
06a2c219
GM
1036
1037/* This is called when starting Emacs and when restarting after
1038 suspend. When starting Emacs, no X window is mapped. And nothing
1039 must be done to Emacs's own window if it is suspended (though that
1040 rarely happens). */
dc6f92b8 1041
dfcf069d 1042static void
dc6f92b8
JB
1043XTset_terminal_modes ()
1044{
1045}
1046
06a2c219
GM
1047/* This is called when exiting or suspending Emacs. Exiting will make
1048 the X-windows go away, and suspending requires no action. */
dc6f92b8 1049
dfcf069d 1050static void
dc6f92b8
JB
1051XTreset_terminal_modes ()
1052{
dc6f92b8 1053}
06a2c219
GM
1054
1055
dc6f92b8 1056\f
06a2c219
GM
1057/***********************************************************************
1058 Output Cursor
1059 ***********************************************************************/
1060
1061/* Set the global variable output_cursor to CURSOR. All cursor
1062 positions are relative to updated_window. */
dc6f92b8 1063
dfcf069d 1064static void
06a2c219
GM
1065set_output_cursor (cursor)
1066 struct cursor_pos *cursor;
dc6f92b8 1067{
06a2c219
GM
1068 output_cursor.hpos = cursor->hpos;
1069 output_cursor.vpos = cursor->vpos;
1070 output_cursor.x = cursor->x;
1071 output_cursor.y = cursor->y;
1072}
1073
1074
1075/* Set a nominal cursor position.
dc6f92b8 1076
06a2c219
GM
1077 HPOS and VPOS are column/row positions in a window glyph matrix. X
1078 and Y are window text area relative pixel positions.
1079
1080 If this is done during an update, updated_window will contain the
1081 window that is being updated and the position is the future output
1082 cursor position for that window. If updated_window is null, use
1083 selected_window and display the cursor at the given position. */
1084
1085static void
1086XTcursor_to (vpos, hpos, y, x)
1087 int vpos, hpos, y, x;
1088{
1089 struct window *w;
1090
1091 /* If updated_window is not set, work on selected_window. */
1092 if (updated_window)
1093 w = updated_window;
1094 else
1095 w = XWINDOW (selected_window);
dbcb258a 1096
06a2c219
GM
1097 /* Set the output cursor. */
1098 output_cursor.hpos = hpos;
1099 output_cursor.vpos = vpos;
1100 output_cursor.x = x;
1101 output_cursor.y = y;
dc6f92b8 1102
06a2c219
GM
1103 /* If not called as part of an update, really display the cursor.
1104 This will also set the cursor position of W. */
1105 if (updated_window == NULL)
dc6f92b8
JB
1106 {
1107 BLOCK_INPUT;
06a2c219 1108 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1109 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1110 UNBLOCK_INPUT;
1111 }
1112}
dc43ef94 1113
06a2c219
GM
1114
1115\f
1116/***********************************************************************
1117 Display Iterator
1118 ***********************************************************************/
1119
1120/* Function prototypes of this page. */
1121
1122static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1123 struct glyph *,
ee569018
KH
1124 XChar2b *,
1125 int *));
06a2c219
GM
1126static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1127 int, XChar2b *, int));
1128static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1129static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1130static void x_append_glyph P_ ((struct it *));
b4192550 1131static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1132static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1133 int, int, double));
1134static void x_produce_glyphs P_ ((struct it *));
06a2c219 1135static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1136
1137
e2ef8ee6
GM
1138/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1139 is not contained in the font. */
dc43ef94 1140
06a2c219 1141static INLINE XCharStruct *
ee569018 1142x_per_char_metric (font, char2b)
06a2c219
GM
1143 XFontStruct *font;
1144 XChar2b *char2b;
1145{
1146 /* The result metric information. */
1147 XCharStruct *pcm = NULL;
dc6f92b8 1148
06a2c219 1149 xassert (font && char2b);
dc6f92b8 1150
06a2c219 1151 if (font->per_char != NULL)
dc6f92b8 1152 {
06a2c219 1153 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1154 {
06a2c219
GM
1155 /* min_char_or_byte2 specifies the linear character index
1156 corresponding to the first element of the per_char array,
1157 max_char_or_byte2 is the index of the last character. A
1158 character with non-zero CHAR2B->byte1 is not in the font.
1159 A character with byte2 less than min_char_or_byte2 or
1160 greater max_char_or_byte2 is not in the font. */
1161 if (char2b->byte1 == 0
1162 && char2b->byte2 >= font->min_char_or_byte2
1163 && char2b->byte2 <= font->max_char_or_byte2)
1164 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1165 }
06a2c219 1166 else
dc6f92b8 1167 {
06a2c219
GM
1168 /* If either min_byte1 or max_byte1 are nonzero, both
1169 min_char_or_byte2 and max_char_or_byte2 are less than
1170 256, and the 2-byte character index values corresponding
1171 to the per_char array element N (counting from 0) are:
1172
1173 byte1 = N/D + min_byte1
1174 byte2 = N\D + min_char_or_byte2
1175
1176 where:
1177
1178 D = max_char_or_byte2 - min_char_or_byte2 + 1
1179 / = integer division
1180 \ = integer modulus */
1181 if (char2b->byte1 >= font->min_byte1
1182 && char2b->byte1 <= font->max_byte1
1183 && char2b->byte2 >= font->min_char_or_byte2
1184 && char2b->byte2 <= font->max_char_or_byte2)
1185 {
1186 pcm = (font->per_char
1187 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1188 * (char2b->byte1 - font->min_byte1))
1189 + (char2b->byte2 - font->min_char_or_byte2));
1190 }
dc6f92b8 1191 }
06a2c219
GM
1192 }
1193 else
1194 {
1195 /* If the per_char pointer is null, all glyphs between the first
1196 and last character indexes inclusive have the same
1197 information, as given by both min_bounds and max_bounds. */
1198 if (char2b->byte2 >= font->min_char_or_byte2
1199 && char2b->byte2 <= font->max_char_or_byte2)
1200 pcm = &font->max_bounds;
1201 }
dc6f92b8 1202
ee569018 1203 return ((pcm == NULL
3e71d8f2 1204 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1205 ? NULL : pcm);
06a2c219 1206}
b73b6aaf 1207
57b03282 1208
06a2c219
GM
1209/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1210 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1211
06a2c219
GM
1212static INLINE void
1213x_encode_char (c, char2b, font_info)
1214 int c;
1215 XChar2b *char2b;
1216 struct font_info *font_info;
1217{
1218 int charset = CHAR_CHARSET (c);
1219 XFontStruct *font = font_info->font;
1220
1221 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1222 This may be either a program in a special encoder language or a
1223 fixed encoding. */
1224 if (font_info->font_encoder)
1225 {
1226 /* It's a program. */
1227 struct ccl_program *ccl = font_info->font_encoder;
1228
1229 if (CHARSET_DIMENSION (charset) == 1)
1230 {
1231 ccl->reg[0] = charset;
1232 ccl->reg[1] = char2b->byte2;
1233 }
1234 else
1235 {
1236 ccl->reg[0] = charset;
1237 ccl->reg[1] = char2b->byte1;
1238 ccl->reg[2] = char2b->byte2;
1239 }
1240
1241 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1242
1243 /* We assume that MSBs are appropriately set/reset by CCL
1244 program. */
1245 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1246 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1247 else
1248 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1249 }
1250 else if (font_info->encoding[charset])
1251 {
1252 /* Fixed encoding scheme. See fontset.h for the meaning of the
1253 encoding numbers. */
1254 int enc = font_info->encoding[charset];
1255
1256 if ((enc == 1 || enc == 2)
1257 && CHARSET_DIMENSION (charset) == 2)
1258 char2b->byte1 |= 0x80;
1259
1260 if (enc == 1 || enc == 3)
1261 char2b->byte2 |= 0x80;
1262 }
1263}
1264
1265
1266/* Get face and two-byte form of character C in face FACE_ID on frame
1267 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1268 means we want to display multibyte text. Value is a pointer to a
1269 realized face that is ready for display. */
1270
1271static INLINE struct face *
1272x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1273 struct frame *f;
1274 int c, face_id;
1275 XChar2b *char2b;
1276 int multibyte_p;
1277{
1278 struct face *face = FACE_FROM_ID (f, face_id);
1279
1280 if (!multibyte_p)
1281 {
1282 /* Unibyte case. We don't have to encode, but we have to make
1283 sure to use a face suitable for unibyte. */
1284 char2b->byte1 = 0;
1285 char2b->byte2 = c;
ee569018
KH
1286 face_id = FACE_FOR_CHAR (f, face, c);
1287 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1288 }
1289 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1290 {
1291 /* Case of ASCII in a face known to fit ASCII. */
1292 char2b->byte1 = 0;
1293 char2b->byte2 = c;
1294 }
1295 else
1296 {
1297 int c1, c2, charset;
1298
1299 /* Split characters into bytes. If c2 is -1 afterwards, C is
1300 really a one-byte character so that byte1 is zero. */
1301 SPLIT_CHAR (c, charset, c1, c2);
1302 if (c2 > 0)
1303 char2b->byte1 = c1, char2b->byte2 = c2;
1304 else
1305 char2b->byte1 = 0, char2b->byte2 = c1;
1306
06a2c219 1307 /* Maybe encode the character in *CHAR2B. */
ee569018 1308 if (face->font != NULL)
06a2c219
GM
1309 {
1310 struct font_info *font_info
1311 = FONT_INFO_FROM_ID (f, face->font_info_id);
1312 if (font_info)
ee569018 1313 x_encode_char (c, char2b, font_info);
06a2c219
GM
1314 }
1315 }
1316
1317 /* Make sure X resources of the face are allocated. */
1318 xassert (face != NULL);
1319 PREPARE_FACE_FOR_DISPLAY (f, face);
1320
1321 return face;
1322}
1323
1324
1325/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1326 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1327 a pointer to a realized face that is ready for display. */
1328
1329static INLINE struct face *
ee569018 1330x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1331 struct frame *f;
1332 struct glyph *glyph;
1333 XChar2b *char2b;
ee569018 1334 int *two_byte_p;
06a2c219
GM
1335{
1336 struct face *face;
1337
1338 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1339 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1340
ee569018
KH
1341 if (two_byte_p)
1342 *two_byte_p = 0;
1343
06a2c219
GM
1344 if (!glyph->multibyte_p)
1345 {
1346 /* Unibyte case. We don't have to encode, but we have to make
1347 sure to use a face suitable for unibyte. */
1348 char2b->byte1 = 0;
43d120d8 1349 char2b->byte2 = glyph->u.ch;
06a2c219 1350 }
43d120d8
KH
1351 else if (glyph->u.ch < 128
1352 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1353 {
1354 /* Case of ASCII in a face known to fit ASCII. */
1355 char2b->byte1 = 0;
43d120d8 1356 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1357 }
1358 else
1359 {
1360 int c1, c2, charset;
1361
1362 /* Split characters into bytes. If c2 is -1 afterwards, C is
1363 really a one-byte character so that byte1 is zero. */
43d120d8 1364 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1365 if (c2 > 0)
1366 char2b->byte1 = c1, char2b->byte2 = c2;
1367 else
1368 char2b->byte1 = 0, char2b->byte2 = c1;
1369
1370 /* Maybe encode the character in *CHAR2B. */
1371 if (charset != CHARSET_ASCII)
1372 {
1373 struct font_info *font_info
1374 = FONT_INFO_FROM_ID (f, face->font_info_id);
1375 if (font_info)
1376 {
43d120d8 1377 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1378 if (two_byte_p)
1379 *two_byte_p
1380 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1381 }
1382 }
1383 }
1384
1385 /* Make sure X resources of the face are allocated. */
1386 xassert (face != NULL);
1387 PREPARE_FACE_FOR_DISPLAY (f, face);
1388 return face;
1389}
1390
1391
1392/* Store one glyph for IT->char_to_display in IT->glyph_row.
1393 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1394
1395static INLINE void
1396x_append_glyph (it)
1397 struct it *it;
1398{
1399 struct glyph *glyph;
1400 enum glyph_row_area area = it->area;
1401
1402 xassert (it->glyph_row);
1403 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1404
1405 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1406 if (glyph < it->glyph_row->glyphs[area + 1])
1407 {
06a2c219
GM
1408 glyph->charpos = CHARPOS (it->position);
1409 glyph->object = it->object;
88d75730 1410 glyph->pixel_width = it->pixel_width;
06a2c219 1411 glyph->voffset = it->voffset;
88d75730 1412 glyph->type = CHAR_GLYPH;
06a2c219 1413 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1414 glyph->left_box_line_p = it->start_of_box_run_p;
1415 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1416 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1417 || it->phys_descent > it->descent);
88d75730 1418 glyph->padding_p = 0;
ee569018 1419 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1420 glyph->face_id = it->face_id;
1421 glyph->u.ch = it->char_to_display;
06a2c219
GM
1422 ++it->glyph_row->used[area];
1423 }
1424}
1425
b4192550
KH
1426/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1427 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1428
1429static INLINE void
1430x_append_composite_glyph (it)
1431 struct it *it;
1432{
1433 struct glyph *glyph;
1434 enum glyph_row_area area = it->area;
1435
1436 xassert (it->glyph_row);
1437
1438 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1439 if (glyph < it->glyph_row->glyphs[area + 1])
1440 {
b4192550
KH
1441 glyph->charpos = CHARPOS (it->position);
1442 glyph->object = it->object;
88d75730 1443 glyph->pixel_width = it->pixel_width;
b4192550 1444 glyph->voffset = it->voffset;
88d75730 1445 glyph->type = COMPOSITE_GLYPH;
b4192550 1446 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1447 glyph->left_box_line_p = it->start_of_box_run_p;
1448 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1449 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1450 || it->phys_descent > it->descent);
88d75730
GM
1451 glyph->padding_p = 0;
1452 glyph->glyph_not_available_p = 0;
1453 glyph->face_id = it->face_id;
1454 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1455 ++it->glyph_row->used[area];
1456 }
1457}
1458
06a2c219
GM
1459
1460/* Change IT->ascent and IT->height according to the setting of
1461 IT->voffset. */
1462
1463static INLINE void
1464take_vertical_position_into_account (it)
1465 struct it *it;
1466{
1467 if (it->voffset)
1468 {
1469 if (it->voffset < 0)
1470 /* Increase the ascent so that we can display the text higher
1471 in the line. */
1472 it->ascent += abs (it->voffset);
1473 else
1474 /* Increase the descent so that we can display the text lower
1475 in the line. */
1476 it->descent += it->voffset;
1477 }
1478}
1479
1480
1481/* Produce glyphs/get display metrics for the image IT is loaded with.
1482 See the description of struct display_iterator in dispextern.h for
1483 an overview of struct display_iterator. */
1484
1485static void
1486x_produce_image_glyph (it)
1487 struct it *it;
1488{
1489 struct image *img;
1490 struct face *face;
1491
1492 xassert (it->what == IT_IMAGE);
1493
1494 face = FACE_FROM_ID (it->f, it->face_id);
1495 img = IMAGE_FROM_ID (it->f, it->image_id);
1496 xassert (img);
1497
1498 /* Make sure X resources of the face and image are loaded. */
1499 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1500 prepare_image_for_display (it->f, img);
1501
95af8492 1502 it->ascent = it->phys_ascent = image_ascent (img, face);
22d650b8
GM
1503 it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
1504 it->pixel_width = img->width + 2 * img->hmargin;
06a2c219
GM
1505
1506 it->nglyphs = 1;
1507
1508 if (face->box != FACE_NO_BOX)
1509 {
ea2ba0d4
KH
1510 if (face->box_line_width > 0)
1511 {
1512 it->ascent += face->box_line_width;
1513 it->descent += face->box_line_width;
1514 }
06a2c219
GM
1515
1516 if (it->start_of_box_run_p)
ea2ba0d4 1517 it->pixel_width += abs (face->box_line_width);
06a2c219 1518 if (it->end_of_box_run_p)
ea2ba0d4 1519 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1520 }
1521
1522 take_vertical_position_into_account (it);
1523
1524 if (it->glyph_row)
1525 {
1526 struct glyph *glyph;
1527 enum glyph_row_area area = it->area;
1528
1529 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1530 if (glyph < it->glyph_row->glyphs[area + 1])
1531 {
06a2c219
GM
1532 glyph->charpos = CHARPOS (it->position);
1533 glyph->object = it->object;
88d75730 1534 glyph->pixel_width = it->pixel_width;
06a2c219 1535 glyph->voffset = it->voffset;
88d75730 1536 glyph->type = IMAGE_GLYPH;
06a2c219 1537 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1538 glyph->left_box_line_p = it->start_of_box_run_p;
1539 glyph->right_box_line_p = it->end_of_box_run_p;
1540 glyph->overlaps_vertically_p = 0;
1541 glyph->padding_p = 0;
1542 glyph->glyph_not_available_p = 0;
1543 glyph->face_id = it->face_id;
1544 glyph->u.img_id = img->id;
06a2c219
GM
1545 ++it->glyph_row->used[area];
1546 }
1547 }
1548}
1549
1550
1551/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1552 of the glyph, WIDTH and HEIGHT are the width and height of the
1553 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1554 ascent of the glyph (0 <= ASCENT <= 1). */
1555
1556static void
1557x_append_stretch_glyph (it, object, width, height, ascent)
1558 struct it *it;
1559 Lisp_Object object;
1560 int width, height;
1561 double ascent;
1562{
1563 struct glyph *glyph;
1564 enum glyph_row_area area = it->area;
1565
1566 xassert (ascent >= 0 && ascent <= 1);
1567
1568 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1569 if (glyph < it->glyph_row->glyphs[area + 1])
1570 {
06a2c219
GM
1571 glyph->charpos = CHARPOS (it->position);
1572 glyph->object = object;
88d75730 1573 glyph->pixel_width = width;
06a2c219 1574 glyph->voffset = it->voffset;
88d75730 1575 glyph->type = STRETCH_GLYPH;
06a2c219 1576 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1577 glyph->left_box_line_p = it->start_of_box_run_p;
1578 glyph->right_box_line_p = it->end_of_box_run_p;
1579 glyph->overlaps_vertically_p = 0;
1580 glyph->padding_p = 0;
1581 glyph->glyph_not_available_p = 0;
1582 glyph->face_id = it->face_id;
1583 glyph->u.stretch.ascent = height * ascent;
1584 glyph->u.stretch.height = height;
06a2c219
GM
1585 ++it->glyph_row->used[area];
1586 }
1587}
1588
1589
1590/* Produce a stretch glyph for iterator IT. IT->object is the value
1591 of the glyph property displayed. The value must be a list
1592 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1593 being recognized:
1594
1595 1. `:width WIDTH' specifies that the space should be WIDTH *
1596 canonical char width wide. WIDTH may be an integer or floating
1597 point number.
1598
1599 2. `:relative-width FACTOR' specifies that the width of the stretch
1600 should be computed from the width of the first character having the
1601 `glyph' property, and should be FACTOR times that width.
1602
1603 3. `:align-to HPOS' specifies that the space should be wide enough
1604 to reach HPOS, a value in canonical character units.
1605
1606 Exactly one of the above pairs must be present.
1607
1608 4. `:height HEIGHT' specifies that the height of the stretch produced
1609 should be HEIGHT, measured in canonical character units.
1610
1611 5. `:relative-height FACTOR' specifies that the height of the the
1612 stretch should be FACTOR times the height of the characters having
1613 the glyph property.
1614
1615 Either none or exactly one of 4 or 5 must be present.
1616
1617 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1618 of the stretch should be used for the ascent of the stretch.
1619 ASCENT must be in the range 0 <= ASCENT <= 100. */
1620
1621#define NUMVAL(X) \
1622 ((INTEGERP (X) || FLOATP (X)) \
1623 ? XFLOATINT (X) \
1624 : - 1)
1625
1626
1627static void
1628x_produce_stretch_glyph (it)
1629 struct it *it;
1630{
1631 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1632#if GLYPH_DEBUG
1633 extern Lisp_Object Qspace;
1634#endif
1635 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1636 extern Lisp_Object QCrelative_width, QCrelative_height;
1637 extern Lisp_Object QCalign_to;
1638 Lisp_Object prop, plist;
1639 double width = 0, height = 0, ascent = 0;
1640 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1641 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1642
1643 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1644
1645 /* List should start with `space'. */
1646 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1647 plist = XCDR (it->object);
1648
1649 /* Compute the width of the stretch. */
1650 if (prop = Fplist_get (plist, QCwidth),
1651 NUMVAL (prop) > 0)
1652 /* Absolute width `:width WIDTH' specified and valid. */
1653 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1654 else if (prop = Fplist_get (plist, QCrelative_width),
1655 NUMVAL (prop) > 0)
1656 {
1657 /* Relative width `:relative-width FACTOR' specified and valid.
1658 Compute the width of the characters having the `glyph'
1659 property. */
1660 struct it it2;
1661 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1662
1663 it2 = *it;
1664 if (it->multibyte_p)
1665 {
1666 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1667 - IT_BYTEPOS (*it));
1668 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1669 }
1670 else
1671 it2.c = *p, it2.len = 1;
1672
1673 it2.glyph_row = NULL;
1674 it2.what = IT_CHARACTER;
1675 x_produce_glyphs (&it2);
1676 width = NUMVAL (prop) * it2.pixel_width;
1677 }
1678 else if (prop = Fplist_get (plist, QCalign_to),
1679 NUMVAL (prop) > 0)
1680 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1681 else
1682 /* Nothing specified -> width defaults to canonical char width. */
1683 width = CANON_X_UNIT (it->f);
1684
1685 /* Compute height. */
1686 if (prop = Fplist_get (plist, QCheight),
1687 NUMVAL (prop) > 0)
1688 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1689 else if (prop = Fplist_get (plist, QCrelative_height),
1690 NUMVAL (prop) > 0)
1691 height = FONT_HEIGHT (font) * NUMVAL (prop);
1692 else
1693 height = FONT_HEIGHT (font);
1694
1695 /* Compute percentage of height used for ascent. If
1696 `:ascent ASCENT' is present and valid, use that. Otherwise,
1697 derive the ascent from the font in use. */
1698 if (prop = Fplist_get (plist, QCascent),
1699 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1700 ascent = NUMVAL (prop) / 100.0;
1701 else
1702 ascent = (double) font->ascent / FONT_HEIGHT (font);
1703
1704 if (width <= 0)
1705 width = 1;
1706 if (height <= 0)
1707 height = 1;
1708
1709 if (it->glyph_row)
1710 {
1711 Lisp_Object object = it->stack[it->sp - 1].string;
1712 if (!STRINGP (object))
1713 object = it->w->buffer;
1714 x_append_stretch_glyph (it, object, width, height, ascent);
1715 }
1716
1717 it->pixel_width = width;
66ac4b0e
GM
1718 it->ascent = it->phys_ascent = height * ascent;
1719 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1720 it->nglyphs = 1;
1721
1722 if (face->box != FACE_NO_BOX)
1723 {
ea2ba0d4
KH
1724 if (face->box_line_width > 0)
1725 {
1726 it->ascent += face->box_line_width;
1727 it->descent += face->box_line_width;
1728 }
06a2c219
GM
1729
1730 if (it->start_of_box_run_p)
ea2ba0d4 1731 it->pixel_width += abs (face->box_line_width);
06a2c219 1732 if (it->end_of_box_run_p)
ea2ba0d4 1733 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1734 }
1735
1736 take_vertical_position_into_account (it);
1737}
1738
b4192550
KH
1739/* Return proper value to be used as baseline offset of font that has
1740 ASCENT and DESCENT to draw characters by the font at the vertical
1741 center of the line of frame F.
1742
1743 Here, out task is to find the value of BOFF in the following figure;
1744
1745 -------------------------+-----------+-
1746 -+-+---------+-+ | |
1747 | | | | | |
1748 | | | | F_ASCENT F_HEIGHT
1749 | | | ASCENT | |
1750 HEIGHT | | | | |
1751 | | |-|-+------+-----------|------- baseline
1752 | | | | BOFF | |
1753 | |---------|-+-+ | |
1754 | | | DESCENT | |
1755 -+-+---------+-+ F_DESCENT |
1756 -------------------------+-----------+-
1757
1758 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1759 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1760 DESCENT = FONT->descent
1761 HEIGHT = FONT_HEIGHT (FONT)
1762 F_DESCENT = (F->output_data.x->font->descent
1763 - F->output_data.x->baseline_offset)
1764 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1765*/
1766
458f45fa
KH
1767#define VCENTER_BASELINE_OFFSET(FONT, F) \
1768 ((FONT)->descent \
1769 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT)) \
1770 + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \
1771 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1772
1773/* Produce glyphs/get display metrics for the display element IT is
1774 loaded with. See the description of struct display_iterator in
1775 dispextern.h for an overview of struct display_iterator. */
1776
1777static void
1778x_produce_glyphs (it)
1779 struct it *it;
1780{
ee569018
KH
1781 it->glyph_not_available_p = 0;
1782
06a2c219
GM
1783 if (it->what == IT_CHARACTER)
1784 {
1785 XChar2b char2b;
1786 XFontStruct *font;
ee569018 1787 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1788 XCharStruct *pcm;
06a2c219 1789 int font_not_found_p;
b4192550
KH
1790 struct font_info *font_info;
1791 int boff; /* baseline offset */
a4249304
KH
1792 /* We may change it->multibyte_p upon unibyte<->multibyte
1793 conversion. So, save the current value now and restore it
1794 later.
1795
1796 Note: It seems that we don't have to record multibyte_p in
1797 struct glyph because the character code itself tells if or
1798 not the character is multibyte. Thus, in the future, we must
1799 consider eliminating the field `multibyte_p' in the struct
c347a1c3 1800 glyph. */
a4249304 1801 int saved_multibyte_p = it->multibyte_p;
06a2c219 1802
ee569018
KH
1803 /* Maybe translate single-byte characters to multibyte, or the
1804 other way. */
06a2c219 1805 it->char_to_display = it->c;
ee569018 1806 if (!ASCII_BYTE_P (it->c))
06a2c219 1807 {
ee569018
KH
1808 if (unibyte_display_via_language_environment
1809 && SINGLE_BYTE_CHAR_P (it->c)
1810 && (it->c >= 0240
1811 || !NILP (Vnonascii_translation_table)))
1812 {
1813 it->char_to_display = unibyte_char_to_multibyte (it->c);
a4249304 1814 it->multibyte_p = 1;
ee569018
KH
1815 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1816 face = FACE_FROM_ID (it->f, it->face_id);
1817 }
1818 else if (!SINGLE_BYTE_CHAR_P (it->c)
1819 && !it->multibyte_p)
1820 {
c347a1c3 1821 it->multibyte_p = 1;
ee569018
KH
1822 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1823 face = FACE_FROM_ID (it->f, it->face_id);
1824 }
06a2c219
GM
1825 }
1826
ee569018
KH
1827 /* Get font to use. Encode IT->char_to_display. */
1828 x_get_char_face_and_encoding (it->f, it->char_to_display,
1829 it->face_id, &char2b,
1830 it->multibyte_p);
06a2c219
GM
1831 font = face->font;
1832
1833 /* When no suitable font found, use the default font. */
1834 font_not_found_p = font == NULL;
1835 if (font_not_found_p)
b4192550
KH
1836 {
1837 font = FRAME_FONT (it->f);
1838 boff = it->f->output_data.x->baseline_offset;
1839 font_info = NULL;
1840 }
1841 else
1842 {
1843 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1844 boff = font_info->baseline_offset;
1845 if (font_info->vertical_centering)
1846 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1847 }
06a2c219
GM
1848
1849 if (it->char_to_display >= ' '
1850 && (!it->multibyte_p || it->char_to_display < 128))
1851 {
1852 /* Either unibyte or ASCII. */
1853 int stretched_p;
1854
1855 it->nglyphs = 1;
06a2c219
GM
1856
1857 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1858 it->ascent = font->ascent + boff;
1859 it->descent = font->descent - boff;
474848ac
GM
1860
1861 if (pcm)
1862 {
1863 it->phys_ascent = pcm->ascent + boff;
1864 it->phys_descent = pcm->descent - boff;
1865 it->pixel_width = pcm->width;
1866 }
1867 else
1868 {
1869 it->glyph_not_available_p = 1;
1870 it->phys_ascent = font->ascent + boff;
1871 it->phys_descent = font->descent - boff;
1872 it->pixel_width = FONT_WIDTH (font);
1873 }
06a2c219
GM
1874
1875 /* If this is a space inside a region of text with
1876 `space-width' property, change its width. */
1877 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1878 if (stretched_p)
1879 it->pixel_width *= XFLOATINT (it->space_width);
1880
1881 /* If face has a box, add the box thickness to the character
1882 height. If character has a box line to the left and/or
1883 right, add the box line width to the character's width. */
1884 if (face->box != FACE_NO_BOX)
1885 {
1886 int thick = face->box_line_width;
1887
ea2ba0d4
KH
1888 if (thick > 0)
1889 {
1890 it->ascent += thick;
1891 it->descent += thick;
1892 }
1893 else
1894 thick = -thick;
1895
06a2c219
GM
1896 if (it->start_of_box_run_p)
1897 it->pixel_width += thick;
1898 if (it->end_of_box_run_p)
1899 it->pixel_width += thick;
1900 }
1901
1902 /* If face has an overline, add the height of the overline
1903 (1 pixel) and a 1 pixel margin to the character height. */
1904 if (face->overline_p)
1905 it->ascent += 2;
1906
1907 take_vertical_position_into_account (it);
1908
1909 /* If we have to actually produce glyphs, do it. */
1910 if (it->glyph_row)
1911 {
1912 if (stretched_p)
1913 {
1914 /* Translate a space with a `space-width' property
1915 into a stretch glyph. */
1916 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1917 x_append_stretch_glyph (it, it->object, it->pixel_width,
1918 it->ascent + it->descent, ascent);
1919 }
1920 else
1921 x_append_glyph (it);
1922
1923 /* If characters with lbearing or rbearing are displayed
1924 in this line, record that fact in a flag of the
1925 glyph row. This is used to optimize X output code. */
1c7e22fd 1926 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1927 it->glyph_row->contains_overlapping_glyphs_p = 1;
1928 }
1929 }
1930 else if (it->char_to_display == '\n')
1931 {
1932 /* A newline has no width but we need the height of the line. */
1933 it->pixel_width = 0;
1934 it->nglyphs = 0;
b4192550
KH
1935 it->ascent = it->phys_ascent = font->ascent + boff;
1936 it->descent = it->phys_descent = font->descent - boff;
06a2c219 1937
ea2ba0d4
KH
1938 if (face->box != FACE_NO_BOX
1939 && face->box_line_width > 0)
06a2c219 1940 {
ea2ba0d4
KH
1941 it->ascent += face->box_line_width;
1942 it->descent += face->box_line_width;
06a2c219
GM
1943 }
1944 }
1945 else if (it->char_to_display == '\t')
1946 {
1947 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1948 int x = it->current_x + it->continuation_lines_width;
06a2c219 1949 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
2a32b5ea
GM
1950
1951 /* If the distance from the current position to the next tab
1952 stop is less than a canonical character width, use the
1953 tab stop after that. */
1954 if (next_tab_x - x < CANON_X_UNIT (it->f))
1955 next_tab_x += tab_width;
06a2c219
GM
1956
1957 it->pixel_width = next_tab_x - x;
1958 it->nglyphs = 1;
b4192550
KH
1959 it->ascent = it->phys_ascent = font->ascent + boff;
1960 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1961
1962 if (it->glyph_row)
1963 {
1964 double ascent = (double) it->ascent / (it->ascent + it->descent);
1965 x_append_stretch_glyph (it, it->object, it->pixel_width,
1966 it->ascent + it->descent, ascent);
1967 }
1968 }
1969 else
1970 {
1971 /* A multi-byte character. Assume that the display width of the
1972 character is the width of the character multiplied by the
b4192550 1973 width of the font. */
06a2c219 1974
b4192550
KH
1975 /* If we found a font, this font should give us the right
1976 metrics. If we didn't find a font, use the frame's
1977 default font and calculate the width of the character
1978 from the charset width; this is what old redisplay code
1979 did. */
1980 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
1981 if (font_not_found_p || !pcm)
1982 {
1983 int charset = CHAR_CHARSET (it->char_to_display);
1984
1985 it->glyph_not_available_p = 1;
1986 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
1987 * CHARSET_WIDTH (charset));
1988 it->phys_ascent = font->ascent + boff;
1989 it->phys_descent = font->descent - boff;
1990 }
1991 else
1992 {
1993 it->pixel_width = pcm->width;
1994 it->phys_ascent = pcm->ascent + boff;
1995 it->phys_descent = pcm->descent - boff;
1996 if (it->glyph_row
1997 && (pcm->lbearing < 0
1998 || pcm->rbearing > pcm->width))
1999 it->glyph_row->contains_overlapping_glyphs_p = 1;
2000 }
b4192550
KH
2001 it->nglyphs = 1;
2002 it->ascent = font->ascent + boff;
2003 it->descent = font->descent - boff;
06a2c219
GM
2004 if (face->box != FACE_NO_BOX)
2005 {
2006 int thick = face->box_line_width;
ea2ba0d4
KH
2007
2008 if (thick > 0)
2009 {
2010 it->ascent += thick;
2011 it->descent += thick;
2012 }
2013 else
2014 thick = - thick;
06a2c219
GM
2015
2016 if (it->start_of_box_run_p)
2017 it->pixel_width += thick;
2018 if (it->end_of_box_run_p)
2019 it->pixel_width += thick;
2020 }
2021
2022 /* If face has an overline, add the height of the overline
2023 (1 pixel) and a 1 pixel margin to the character height. */
2024 if (face->overline_p)
2025 it->ascent += 2;
2026
2027 take_vertical_position_into_account (it);
2028
2029 if (it->glyph_row)
2030 x_append_glyph (it);
2031 }
a4249304 2032 it->multibyte_p = saved_multibyte_p;
06a2c219 2033 }
b4192550
KH
2034 else if (it->what == IT_COMPOSITION)
2035 {
2036 /* Note: A composition is represented as one glyph in the
2037 glyph matrix. There are no padding glyphs. */
2038 XChar2b char2b;
2039 XFontStruct *font;
ee569018 2040 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2041 XCharStruct *pcm;
2042 int font_not_found_p;
2043 struct font_info *font_info;
2044 int boff; /* baseline offset */
2045 struct composition *cmp = composition_table[it->cmp_id];
2046
2047 /* Maybe translate single-byte characters to multibyte. */
2048 it->char_to_display = it->c;
2049 if (unibyte_display_via_language_environment
2050 && SINGLE_BYTE_CHAR_P (it->c)
2051 && (it->c >= 0240
2052 || (it->c >= 0200
2053 && !NILP (Vnonascii_translation_table))))
2054 {
2055 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2056 }
2057
2058 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2059 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2060 face = FACE_FROM_ID (it->f, it->face_id);
2061 x_get_char_face_and_encoding (it->f, it->char_to_display,
2062 it->face_id, &char2b, it->multibyte_p);
b4192550
KH
2063 font = face->font;
2064
2065 /* When no suitable font found, use the default font. */
2066 font_not_found_p = font == NULL;
2067 if (font_not_found_p)
2068 {
2069 font = FRAME_FONT (it->f);
2070 boff = it->f->output_data.x->baseline_offset;
2071 font_info = NULL;
2072 }
2073 else
2074 {
2075 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2076 boff = font_info->baseline_offset;
2077 if (font_info->vertical_centering)
2078 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2079 }
2080
2081 /* There are no padding glyphs, so there is only one glyph to
2082 produce for the composition. Important is that pixel_width,
2083 ascent and descent are the values of what is drawn by
2084 draw_glyphs (i.e. the values of the overall glyphs composed). */
2085 it->nglyphs = 1;
2086
2087 /* If we have not yet calculated pixel size data of glyphs of
2088 the composition for the current face font, calculate them
2089 now. Theoretically, we have to check all fonts for the
2090 glyphs, but that requires much time and memory space. So,
2091 here we check only the font of the first glyph. This leads
2092 to incorrect display very rarely, and C-l (recenter) can
2093 correct the display anyway. */
2094 if (cmp->font != (void *) font)
2095 {
2096 /* Ascent and descent of the font of the first character of
2097 this composition (adjusted by baseline offset). Ascent
2098 and descent of overall glyphs should not be less than
2099 them respectively. */
2100 int font_ascent = font->ascent + boff;
2101 int font_descent = font->descent - boff;
2102 /* Bounding box of the overall glyphs. */
2103 int leftmost, rightmost, lowest, highest;
329bed06 2104 int i, width, ascent, descent;
b4192550
KH
2105
2106 cmp->font = (void *) font;
2107
2108 /* Initialize the bounding box. */
1bdeec2e
KH
2109 if (font_info
2110 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2111 {
2112 width = pcm->width;
2113 ascent = pcm->ascent;
2114 descent = pcm->descent;
2115 }
2116 else
2117 {
2118 width = FONT_WIDTH (font);
2119 ascent = font->ascent;
2120 descent = font->descent;
2121 }
2122
2123 rightmost = width;
2124 lowest = - descent + boff;
2125 highest = ascent + boff;
b4192550 2126 leftmost = 0;
329bed06 2127
b4192550
KH
2128 if (font_info
2129 && font_info->default_ascent
2130 && CHAR_TABLE_P (Vuse_default_ascent)
2131 && !NILP (Faref (Vuse_default_ascent,
2132 make_number (it->char_to_display))))
2133 highest = font_info->default_ascent + boff;
2134
2135 /* Draw the first glyph at the normal position. It may be
2136 shifted to right later if some other glyphs are drawn at
2137 the left. */
2138 cmp->offsets[0] = 0;
2139 cmp->offsets[1] = boff;
2140
2141 /* Set cmp->offsets for the remaining glyphs. */
2142 for (i = 1; i < cmp->glyph_len; i++)
2143 {
2144 int left, right, btm, top;
2145 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2146 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2147
2148 face = FACE_FROM_ID (it->f, face_id);
2149 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2150 it->multibyte_p);
b4192550
KH
2151 font = face->font;
2152 if (font == NULL)
2153 {
2154 font = FRAME_FONT (it->f);
2155 boff = it->f->output_data.x->baseline_offset;
2156 font_info = NULL;
2157 }
2158 else
2159 {
2160 font_info
2161 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2162 boff = font_info->baseline_offset;
2163 if (font_info->vertical_centering)
2164 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2165 }
2166
1bdeec2e
KH
2167 if (font_info
2168 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2169 {
2170 width = pcm->width;
2171 ascent = pcm->ascent;
2172 descent = pcm->descent;
2173 }
2174 else
2175 {
2176 width = FONT_WIDTH (font);
1bdeec2e
KH
2177 ascent = 1;
2178 descent = 0;
329bed06 2179 }
b4192550
KH
2180
2181 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2182 {
2183 /* Relative composition with or without
2184 alternate chars. */
329bed06
GM
2185 left = (leftmost + rightmost - width) / 2;
2186 btm = - descent + boff;
b4192550
KH
2187 if (font_info && font_info->relative_compose
2188 && (! CHAR_TABLE_P (Vignore_relative_composition)
2189 || NILP (Faref (Vignore_relative_composition,
2190 make_number (ch)))))
2191 {
2192
329bed06 2193 if (- descent >= font_info->relative_compose)
b4192550
KH
2194 /* One extra pixel between two glyphs. */
2195 btm = highest + 1;
329bed06 2196 else if (ascent <= 0)
b4192550 2197 /* One extra pixel between two glyphs. */
329bed06 2198 btm = lowest - 1 - ascent - descent;
b4192550
KH
2199 }
2200 }
2201 else
2202 {
2203 /* A composition rule is specified by an integer
2204 value that encodes global and new reference
2205 points (GREF and NREF). GREF and NREF are
2206 specified by numbers as below:
2207
2208 0---1---2 -- ascent
2209 | |
2210 | |
2211 | |
2212 9--10--11 -- center
2213 | |
2214 ---3---4---5--- baseline
2215 | |
2216 6---7---8 -- descent
2217 */
2218 int rule = COMPOSITION_RULE (cmp, i);
2219 int gref, nref, grefx, grefy, nrefx, nrefy;
2220
2221 COMPOSITION_DECODE_RULE (rule, gref, nref);
2222 grefx = gref % 3, nrefx = nref % 3;
2223 grefy = gref / 3, nrefy = nref / 3;
2224
2225 left = (leftmost
2226 + grefx * (rightmost - leftmost) / 2
329bed06 2227 - nrefx * width / 2);
b4192550
KH
2228 btm = ((grefy == 0 ? highest
2229 : grefy == 1 ? 0
2230 : grefy == 2 ? lowest
2231 : (highest + lowest) / 2)
329bed06
GM
2232 - (nrefy == 0 ? ascent + descent
2233 : nrefy == 1 ? descent - boff
b4192550 2234 : nrefy == 2 ? 0
329bed06 2235 : (ascent + descent) / 2));
b4192550
KH
2236 }
2237
2238 cmp->offsets[i * 2] = left;
329bed06 2239 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2240
2241 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2242 right = left + width;
2243 top = btm + descent + ascent;
b4192550
KH
2244 if (left < leftmost)
2245 leftmost = left;
2246 if (right > rightmost)
2247 rightmost = right;
2248 if (top > highest)
2249 highest = top;
2250 if (btm < lowest)
2251 lowest = btm;
2252 }
2253
2254 /* If there are glyphs whose x-offsets are negative,
2255 shift all glyphs to the right and make all x-offsets
2256 non-negative. */
2257 if (leftmost < 0)
2258 {
2259 for (i = 0; i < cmp->glyph_len; i++)
2260 cmp->offsets[i * 2] -= leftmost;
2261 rightmost -= leftmost;
2262 }
2263
2264 cmp->pixel_width = rightmost;
2265 cmp->ascent = highest;
2266 cmp->descent = - lowest;
2267 if (cmp->ascent < font_ascent)
2268 cmp->ascent = font_ascent;
2269 if (cmp->descent < font_descent)
2270 cmp->descent = font_descent;
2271 }
2272
2273 it->pixel_width = cmp->pixel_width;
2274 it->ascent = it->phys_ascent = cmp->ascent;
2275 it->descent = it->phys_descent = cmp->descent;
2276
2277 if (face->box != FACE_NO_BOX)
2278 {
2279 int thick = face->box_line_width;
ea2ba0d4
KH
2280
2281 if (thick > 0)
2282 {
2283 it->ascent += thick;
2284 it->descent += thick;
2285 }
2286 else
2287 thick = - thick;
b4192550
KH
2288
2289 if (it->start_of_box_run_p)
2290 it->pixel_width += thick;
2291 if (it->end_of_box_run_p)
2292 it->pixel_width += thick;
2293 }
2294
2295 /* If face has an overline, add the height of the overline
2296 (1 pixel) and a 1 pixel margin to the character height. */
2297 if (face->overline_p)
2298 it->ascent += 2;
2299
2300 take_vertical_position_into_account (it);
2301
2302 if (it->glyph_row)
2303 x_append_composite_glyph (it);
2304 }
06a2c219
GM
2305 else if (it->what == IT_IMAGE)
2306 x_produce_image_glyph (it);
2307 else if (it->what == IT_STRETCH)
2308 x_produce_stretch_glyph (it);
2309
3017fdd1
GM
2310 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2311 because this isn't true for images with `:ascent 100'. */
2312 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2313 if (it->area == TEXT_AREA)
2314 it->current_x += it->pixel_width;
66ac4b0e 2315
d365f5bb
GM
2316 it->descent += it->extra_line_spacing;
2317
06a2c219
GM
2318 it->max_ascent = max (it->max_ascent, it->ascent);
2319 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2320 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2321 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2322}
2323
2324
2325/* Estimate the pixel height of the mode or top line on frame F.
2326 FACE_ID specifies what line's height to estimate. */
2327
2328int
2329x_estimate_mode_line_height (f, face_id)
2330 struct frame *f;
2331 enum face_id face_id;
2332{
43281ee3 2333 int height = FONT_HEIGHT (FRAME_FONT (f));
06a2c219
GM
2334
2335 /* This function is called so early when Emacs starts that the face
2336 cache and mode line face are not yet initialized. */
2337 if (FRAME_FACE_CACHE (f))
2338 {
2339 struct face *face = FACE_FROM_ID (f, face_id);
2340 if (face)
43281ee3
GM
2341 {
2342 if (face->font)
2343 height = FONT_HEIGHT (face->font);
ea2ba0d4
KH
2344 if (face->box_line_width > 0)
2345 height += 2 * face->box_line_width;
43281ee3 2346 }
06a2c219
GM
2347 }
2348
2349 return height;
2350}
2351
2352\f
2353/***********************************************************************
2354 Glyph display
2355 ***********************************************************************/
2356
2357/* A sequence of glyphs to be drawn in the same face.
2358
2359 This data structure is not really completely X specific, so it
2360 could possibly, at least partially, be useful for other systems. It
2361 is currently not part of the external redisplay interface because
2362 it's not clear what other systems will need. */
2363
2364struct glyph_string
2365{
2366 /* X-origin of the string. */
2367 int x;
2368
2369 /* Y-origin and y-position of the base line of this string. */
2370 int y, ybase;
2371
2372 /* The width of the string, not including a face extension. */
2373 int width;
2374
2375 /* The width of the string, including a face extension. */
2376 int background_width;
2377
2378 /* The height of this string. This is the height of the line this
2379 string is drawn in, and can be different from the height of the
2380 font the string is drawn in. */
2381 int height;
2382
2383 /* Number of pixels this string overwrites in front of its x-origin.
2384 This number is zero if the string has an lbearing >= 0; it is
2385 -lbearing, if the string has an lbearing < 0. */
2386 int left_overhang;
2387
2388 /* Number of pixels this string overwrites past its right-most
2389 nominal x-position, i.e. x + width. Zero if the string's
2390 rbearing is <= its nominal width, rbearing - width otherwise. */
2391 int right_overhang;
2392
2393 /* The frame on which the glyph string is drawn. */
2394 struct frame *f;
2395
2396 /* The window on which the glyph string is drawn. */
2397 struct window *w;
2398
2399 /* X display and window for convenience. */
2400 Display *display;
2401 Window window;
2402
2403 /* The glyph row for which this string was built. It determines the
2404 y-origin and height of the string. */
2405 struct glyph_row *row;
2406
2407 /* The area within row. */
2408 enum glyph_row_area area;
2409
2410 /* Characters to be drawn, and number of characters. */
2411 XChar2b *char2b;
2412 int nchars;
2413
06a2c219
GM
2414 /* A face-override for drawing cursors, mouse face and similar. */
2415 enum draw_glyphs_face hl;
2416
2417 /* Face in which this string is to be drawn. */
2418 struct face *face;
2419
2420 /* Font in which this string is to be drawn. */
2421 XFontStruct *font;
2422
2423 /* Font info for this string. */
2424 struct font_info *font_info;
2425
b4192550
KH
2426 /* Non-null means this string describes (part of) a composition.
2427 All characters from char2b are drawn composed. */
2428 struct composition *cmp;
06a2c219
GM
2429
2430 /* Index of this glyph string's first character in the glyph
b4192550
KH
2431 definition of CMP. If this is zero, this glyph string describes
2432 the first character of a composition. */
06a2c219
GM
2433 int gidx;
2434
2435 /* 1 means this glyph strings face has to be drawn to the right end
2436 of the window's drawing area. */
2437 unsigned extends_to_end_of_line_p : 1;
2438
2439 /* 1 means the background of this string has been drawn. */
2440 unsigned background_filled_p : 1;
2441
2442 /* 1 means glyph string must be drawn with 16-bit functions. */
2443 unsigned two_byte_p : 1;
2444
2445 /* 1 means that the original font determined for drawing this glyph
2446 string could not be loaded. The member `font' has been set to
2447 the frame's default font in this case. */
2448 unsigned font_not_found_p : 1;
2449
2450 /* 1 means that the face in which this glyph string is drawn has a
2451 stipple pattern. */
2452 unsigned stippled_p : 1;
2453
66ac4b0e
GM
2454 /* 1 means only the foreground of this glyph string must be drawn,
2455 and we should use the physical height of the line this glyph
2456 string appears in as clip rect. */
2457 unsigned for_overlaps_p : 1;
2458
06a2c219
GM
2459 /* The GC to use for drawing this glyph string. */
2460 GC gc;
2461
2462 /* A pointer to the first glyph in the string. This glyph
2463 corresponds to char2b[0]. Needed to draw rectangles if
2464 font_not_found_p is 1. */
2465 struct glyph *first_glyph;
2466
2467 /* Image, if any. */
2468 struct image *img;
2469
2470 struct glyph_string *next, *prev;
2471};
2472
2473
61869b99 2474#if GLYPH_DEBUG
06a2c219
GM
2475
2476static void
2477x_dump_glyph_string (s)
2478 struct glyph_string *s;
2479{
2480 fprintf (stderr, "glyph string\n");
2481 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2482 s->x, s->y, s->width, s->height);
2483 fprintf (stderr, " ybase = %d\n", s->ybase);
2484 fprintf (stderr, " hl = %d\n", s->hl);
2485 fprintf (stderr, " left overhang = %d, right = %d\n",
2486 s->left_overhang, s->right_overhang);
2487 fprintf (stderr, " nchars = %d\n", s->nchars);
2488 fprintf (stderr, " extends to end of line = %d\n",
2489 s->extends_to_end_of_line_p);
2490 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2491 fprintf (stderr, " bg width = %d\n", s->background_width);
2492}
2493
2494#endif /* GLYPH_DEBUG */
2495
2496
2497
2498static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2499 struct glyph_string **,
2500 struct glyph_string *,
2501 struct glyph_string *));
2502static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2503 struct glyph_string **,
2504 struct glyph_string *,
2505 struct glyph_string *));
2506static void x_append_glyph_string P_ ((struct glyph_string **,
2507 struct glyph_string **,
2508 struct glyph_string *));
2509static int x_left_overwritten P_ ((struct glyph_string *));
2510static int x_left_overwriting P_ ((struct glyph_string *));
2511static int x_right_overwritten P_ ((struct glyph_string *));
2512static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2513static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2514 int));
06a2c219
GM
2515static void x_init_glyph_string P_ ((struct glyph_string *,
2516 XChar2b *, struct window *,
2517 struct glyph_row *,
2518 enum glyph_row_area, int,
2519 enum draw_glyphs_face));
2520static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2521 enum glyph_row_area, int, int,
f0a48a01 2522 enum draw_glyphs_face, int));
06a2c219
GM
2523static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2524static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2525static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2526 int));
2527static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2528static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2529static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2530static void x_draw_glyph_string P_ ((struct glyph_string *));
2531static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2532static void x_set_cursor_gc P_ ((struct glyph_string *));
2533static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2534static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2535static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2536 int *, int *));
2537static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2538static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2539 unsigned long *, double, int));
06a2c219 2540static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2541 double, int, unsigned long));
06a2c219
GM
2542static void x_setup_relief_colors P_ ((struct glyph_string *));
2543static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2544static void x_draw_image_relief P_ ((struct glyph_string *));
2545static void x_draw_image_foreground P_ ((struct glyph_string *));
2546static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2547static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2548static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2549 int, int, int));
2550static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2551 int, int, int, int, XRectangle *));
2552static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2553 int, int, int, XRectangle *));
66ac4b0e
GM
2554static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2555 enum glyph_row_area));
209f68d9
GM
2556static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2557 struct glyph_row *,
2558 enum glyph_row_area, int, int));
06a2c219 2559
163dcff3
GM
2560#if GLYPH_DEBUG
2561static void x_check_font P_ ((struct frame *, XFontStruct *));
2562#endif
2563
06a2c219 2564
06a2c219
GM
2565/* Append the list of glyph strings with head H and tail T to the list
2566 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2567
2568static INLINE void
2569x_append_glyph_string_lists (head, tail, h, t)
2570 struct glyph_string **head, **tail;
2571 struct glyph_string *h, *t;
2572{
2573 if (h)
2574 {
2575 if (*head)
2576 (*tail)->next = h;
2577 else
2578 *head = h;
2579 h->prev = *tail;
2580 *tail = t;
2581 }
2582}
2583
2584
2585/* Prepend the list of glyph strings with head H and tail T to the
2586 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2587 result. */
2588
2589static INLINE void
2590x_prepend_glyph_string_lists (head, tail, h, t)
2591 struct glyph_string **head, **tail;
2592 struct glyph_string *h, *t;
2593{
2594 if (h)
2595 {
2596 if (*head)
2597 (*head)->prev = t;
2598 else
2599 *tail = t;
2600 t->next = *head;
2601 *head = h;
2602 }
2603}
2604
2605
2606/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2607 Set *HEAD and *TAIL to the resulting list. */
2608
2609static INLINE void
2610x_append_glyph_string (head, tail, s)
2611 struct glyph_string **head, **tail;
2612 struct glyph_string *s;
2613{
2614 s->next = s->prev = NULL;
2615 x_append_glyph_string_lists (head, tail, s, s);
2616}
2617
2618
2619/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2620 face. */
2621
2622static void
2623x_set_cursor_gc (s)
2624 struct glyph_string *s;
2625{
2626 if (s->font == FRAME_FONT (s->f)
2627 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2628 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2629 && !s->cmp)
06a2c219
GM
2630 s->gc = s->f->output_data.x->cursor_gc;
2631 else
2632 {
2633 /* Cursor on non-default face: must merge. */
2634 XGCValues xgcv;
2635 unsigned long mask;
2636
2637 xgcv.background = s->f->output_data.x->cursor_pixel;
2638 xgcv.foreground = s->face->background;
2639
2640 /* If the glyph would be invisible, try a different foreground. */
2641 if (xgcv.foreground == xgcv.background)
2642 xgcv.foreground = s->face->foreground;
2643 if (xgcv.foreground == xgcv.background)
2644 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2645 if (xgcv.foreground == xgcv.background)
2646 xgcv.foreground = s->face->foreground;
2647
2648 /* Make sure the cursor is distinct from text in this face. */
2649 if (xgcv.background == s->face->background
2650 && xgcv.foreground == s->face->foreground)
2651 {
2652 xgcv.background = s->face->foreground;
2653 xgcv.foreground = s->face->background;
2654 }
2655
2656 IF_DEBUG (x_check_font (s->f, s->font));
2657 xgcv.font = s->font->fid;
2658 xgcv.graphics_exposures = False;
2659 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2660
2661 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2662 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2663 mask, &xgcv);
2664 else
2665 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2666 = XCreateGC (s->display, s->window, mask, &xgcv);
2667
2668 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2669 }
2670}
2671
2672
2673/* Set up S->gc of glyph string S for drawing text in mouse face. */
2674
2675static void
2676x_set_mouse_face_gc (s)
2677 struct glyph_string *s;
2678{
2679 int face_id;
ee569018 2680 struct face *face;
06a2c219 2681
e4ded23c 2682 /* What face has to be used last for the mouse face? */
06a2c219 2683 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2684 face = FACE_FROM_ID (s->f, face_id);
e4ded23c
GM
2685 if (face == NULL)
2686 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2687
033e3e18
GM
2688 if (s->first_glyph->type == CHAR_GLYPH)
2689 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2690 else
2691 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2692 s->face = FACE_FROM_ID (s->f, face_id);
2693 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2694
2695 /* If font in this face is same as S->font, use it. */
2696 if (s->font == s->face->font)
2697 s->gc = s->face->gc;
2698 else
2699 {
2700 /* Otherwise construct scratch_cursor_gc with values from FACE
2701 but font FONT. */
2702 XGCValues xgcv;
2703 unsigned long mask;
2704
2705 xgcv.background = s->face->background;
2706 xgcv.foreground = s->face->foreground;
2707 IF_DEBUG (x_check_font (s->f, s->font));
2708 xgcv.font = s->font->fid;
2709 xgcv.graphics_exposures = False;
2710 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2711
2712 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2713 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2714 mask, &xgcv);
2715 else
2716 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2717 = XCreateGC (s->display, s->window, mask, &xgcv);
2718
2719 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2720 }
2721
2722 xassert (s->gc != 0);
2723}
2724
2725
2726/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2727 Faces to use in the mode line have already been computed when the
2728 matrix was built, so there isn't much to do, here. */
2729
2730static INLINE void
2731x_set_mode_line_face_gc (s)
2732 struct glyph_string *s;
2733{
2734 s->gc = s->face->gc;
06a2c219
GM
2735}
2736
2737
2738/* Set S->gc of glyph string S for drawing that glyph string. Set
2739 S->stippled_p to a non-zero value if the face of S has a stipple
2740 pattern. */
2741
2742static INLINE void
2743x_set_glyph_string_gc (s)
2744 struct glyph_string *s;
2745{
209f68d9
GM
2746 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2747
06a2c219
GM
2748 if (s->hl == DRAW_NORMAL_TEXT)
2749 {
2750 s->gc = s->face->gc;
2751 s->stippled_p = s->face->stipple != 0;
2752 }
2753 else if (s->hl == DRAW_INVERSE_VIDEO)
2754 {
2755 x_set_mode_line_face_gc (s);
2756 s->stippled_p = s->face->stipple != 0;
2757 }
2758 else if (s->hl == DRAW_CURSOR)
2759 {
2760 x_set_cursor_gc (s);
2761 s->stippled_p = 0;
2762 }
2763 else if (s->hl == DRAW_MOUSE_FACE)
2764 {
2765 x_set_mouse_face_gc (s);
2766 s->stippled_p = s->face->stipple != 0;
2767 }
2768 else if (s->hl == DRAW_IMAGE_RAISED
2769 || s->hl == DRAW_IMAGE_SUNKEN)
2770 {
2771 s->gc = s->face->gc;
2772 s->stippled_p = s->face->stipple != 0;
2773 }
2774 else
2775 {
2776 s->gc = s->face->gc;
2777 s->stippled_p = s->face->stipple != 0;
2778 }
2779
2780 /* GC must have been set. */
2781 xassert (s->gc != 0);
2782}
2783
2784
2785/* Return in *R the clipping rectangle for glyph string S. */
2786
2787static void
2788x_get_glyph_string_clip_rect (s, r)
2789 struct glyph_string *s;
2790 XRectangle *r;
2791{
2792 if (s->row->full_width_p)
2793 {
2794 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2795 int canon_x = CANON_X_UNIT (s->f);
2796
2797 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2798 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2799
2800 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2801 {
1da3fd71 2802 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2803 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2804 r->x -= width;
2805 }
2806
b9432a85 2807 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2808
06a2c219
GM
2809 /* Unless displaying a mode or menu bar line, which are always
2810 fully visible, clip to the visible part of the row. */
2811 if (s->w->pseudo_window_p)
2812 r->height = s->row->visible_height;
2813 else
2814 r->height = s->height;
2815 }
2816 else
2817 {
2818 /* This is a text line that may be partially visible. */
2819 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2820 r->width = window_box_width (s->w, s->area);
2821 r->height = s->row->visible_height;
2822 }
2823
66ac4b0e
GM
2824 /* If S draws overlapping rows, it's sufficient to use the top and
2825 bottom of the window for clipping because this glyph string
2826 intentionally draws over other lines. */
2827 if (s->for_overlaps_p)
2828 {
045dee35 2829 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2830 r->height = window_text_bottom_y (s->w) - r->y;
2831 }
98b8a90f
GM
2832 else
2833 {
2834 /* Don't use S->y for clipping because it doesn't take partially
2835 visible lines into account. For example, it can be negative for
2836 partially visible lines at the top of a window. */
2837 if (!s->row->full_width_p
2838 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
2839 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
2840 else
2841 r->y = max (0, s->row->y);
2842
2843 /* If drawing a tool-bar window, draw it over the internal border
2844 at the top of the window. */
2845 if (s->w == XWINDOW (s->f->tool_bar_window))
2846 r->y -= s->f->output_data.x->internal_border_width;
2847 }
2848
66ac4b0e 2849 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2850}
2851
2852
2853/* Set clipping for output of glyph string S. S may be part of a mode
2854 line or menu if we don't have X toolkit support. */
2855
2856static INLINE void
2857x_set_glyph_string_clipping (s)
2858 struct glyph_string *s;
2859{
2860 XRectangle r;
2861 x_get_glyph_string_clip_rect (s, &r);
2862 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2863}
2864
2865
2866/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2867 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2868
2869static INLINE void
2870x_compute_glyph_string_overhangs (s)
2871 struct glyph_string *s;
2872{
b4192550 2873 if (s->cmp == NULL
06a2c219
GM
2874 && s->first_glyph->type == CHAR_GLYPH)
2875 {
2876 XCharStruct cs;
2877 int direction, font_ascent, font_descent;
2878 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2879 &font_ascent, &font_descent, &cs);
2880 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2881 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2882 }
2883}
2884
2885
2886/* Compute overhangs and x-positions for glyph string S and its
2887 predecessors, or successors. X is the starting x-position for S.
2888 BACKWARD_P non-zero means process predecessors. */
2889
2890static void
2891x_compute_overhangs_and_x (s, x, backward_p)
2892 struct glyph_string *s;
2893 int x;
2894 int backward_p;
2895{
2896 if (backward_p)
2897 {
2898 while (s)
2899 {
2900 x_compute_glyph_string_overhangs (s);
2901 x -= s->width;
2902 s->x = x;
2903 s = s->prev;
2904 }
2905 }
2906 else
2907 {
2908 while (s)
2909 {
2910 x_compute_glyph_string_overhangs (s);
2911 s->x = x;
2912 x += s->width;
2913 s = s->next;
2914 }
2915 }
2916}
2917
2918
2919/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2920 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2921 assumed to be zero. */
06a2c219
GM
2922
2923static void
2924x_get_glyph_overhangs (glyph, f, left, right)
2925 struct glyph *glyph;
2926 struct frame *f;
2927 int *left, *right;
2928{
06a2c219
GM
2929 *left = *right = 0;
2930
b4192550 2931 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2932 {
2933 XFontStruct *font;
2934 struct face *face;
2935 struct font_info *font_info;
2936 XChar2b char2b;
ee569018
KH
2937 XCharStruct *pcm;
2938
2939 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2940 font = face->font;
2941 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2942 if (font
2943 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2944 {
06a2c219
GM
2945 if (pcm->rbearing > pcm->width)
2946 *right = pcm->rbearing - pcm->width;
2947 if (pcm->lbearing < 0)
2948 *left = -pcm->lbearing;
2949 }
2950 }
2951}
2952
2953
2954/* Return the index of the first glyph preceding glyph string S that
2955 is overwritten by S because of S's left overhang. Value is -1
2956 if no glyphs are overwritten. */
2957
2958static int
2959x_left_overwritten (s)
2960 struct glyph_string *s;
2961{
2962 int k;
2963
2964 if (s->left_overhang)
2965 {
2966 int x = 0, i;
2967 struct glyph *glyphs = s->row->glyphs[s->area];
2968 int first = s->first_glyph - glyphs;
2969
2970 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2971 x -= glyphs[i].pixel_width;
2972
2973 k = i + 1;
2974 }
2975 else
2976 k = -1;
2977
2978 return k;
2979}
2980
2981
2982/* Return the index of the first glyph preceding glyph string S that
2983 is overwriting S because of its right overhang. Value is -1 if no
2984 glyph in front of S overwrites S. */
2985
2986static int
2987x_left_overwriting (s)
2988 struct glyph_string *s;
2989{
2990 int i, k, x;
2991 struct glyph *glyphs = s->row->glyphs[s->area];
2992 int first = s->first_glyph - glyphs;
2993
2994 k = -1;
2995 x = 0;
2996 for (i = first - 1; i >= 0; --i)
2997 {
2998 int left, right;
2999 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3000 if (x + right > 0)
3001 k = i;
3002 x -= glyphs[i].pixel_width;
3003 }
3004
3005 return k;
3006}
3007
3008
3009/* Return the index of the last glyph following glyph string S that is
3010 not overwritten by S because of S's right overhang. Value is -1 if
3011 no such glyph is found. */
3012
3013static int
3014x_right_overwritten (s)
3015 struct glyph_string *s;
3016{
3017 int k = -1;
3018
3019 if (s->right_overhang)
3020 {
3021 int x = 0, i;
3022 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3023 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3024 int end = s->row->used[s->area];
3025
3026 for (i = first; i < end && s->right_overhang > x; ++i)
3027 x += glyphs[i].pixel_width;
3028
3029 k = i;
3030 }
3031
3032 return k;
3033}
3034
3035
3036/* Return the index of the last glyph following glyph string S that
3037 overwrites S because of its left overhang. Value is negative
3038 if no such glyph is found. */
3039
3040static int
3041x_right_overwriting (s)
3042 struct glyph_string *s;
3043{
3044 int i, k, x;
3045 int end = s->row->used[s->area];
3046 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3047 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3048
3049 k = -1;
3050 x = 0;
3051 for (i = first; i < end; ++i)
3052 {
3053 int left, right;
3054 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3055 if (x - left < 0)
3056 k = i;
3057 x += glyphs[i].pixel_width;
3058 }
3059
3060 return k;
3061}
3062
3063
3064/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3065
3066static INLINE void
3067x_clear_glyph_string_rect (s, x, y, w, h)
3068 struct glyph_string *s;
3069 int x, y, w, h;
3070{
3071 XGCValues xgcv;
3072 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3073 XSetForeground (s->display, s->gc, xgcv.background);
3074 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3075 XSetForeground (s->display, s->gc, xgcv.foreground);
3076}
3077
3078
3079/* Draw the background of glyph_string S. If S->background_filled_p
3080 is non-zero don't draw it. FORCE_P non-zero means draw the
3081 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3082 when a string preceding S draws into the background of S, or S
3083 contains the first component of a composition. */
06a2c219
GM
3084
3085static void
3086x_draw_glyph_string_background (s, force_p)
3087 struct glyph_string *s;
3088 int force_p;
3089{
3090 /* Nothing to do if background has already been drawn or if it
3091 shouldn't be drawn in the first place. */
3092 if (!s->background_filled_p)
3093 {
ea2ba0d4
KH
3094 int box_line_width = max (s->face->box_line_width, 0);
3095
b4192550 3096 if (s->stippled_p)
06a2c219
GM
3097 {
3098 /* Fill background with a stipple pattern. */
3099 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3100 XFillRectangle (s->display, s->window, s->gc, s->x,
ea2ba0d4 3101 s->y + box_line_width,
06a2c219 3102 s->background_width,
ea2ba0d4 3103 s->height - 2 * box_line_width);
06a2c219
GM
3104 XSetFillStyle (s->display, s->gc, FillSolid);
3105 s->background_filled_p = 1;
3106 }
ea2ba0d4 3107 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
06a2c219
GM
3108 || s->font_not_found_p
3109 || s->extends_to_end_of_line_p
06a2c219
GM
3110 || force_p)
3111 {
ea2ba0d4 3112 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
06a2c219 3113 s->background_width,
ea2ba0d4 3114 s->height - 2 * box_line_width);
06a2c219
GM
3115 s->background_filled_p = 1;
3116 }
3117 }
3118}
3119
3120
3121/* Draw the foreground of glyph string S. */
3122
3123static void
3124x_draw_glyph_string_foreground (s)
3125 struct glyph_string *s;
3126{
3127 int i, x;
3128
3129 /* If first glyph of S has a left box line, start drawing the text
3130 of S to the right of that box line. */
3131 if (s->face->box != FACE_NO_BOX
3132 && s->first_glyph->left_box_line_p)
ea2ba0d4 3133 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
3134 else
3135 x = s->x;
3136
b4192550
KH
3137 /* Draw characters of S as rectangles if S's font could not be
3138 loaded. */
3139 if (s->font_not_found_p)
06a2c219 3140 {
b4192550 3141 for (i = 0; i < s->nchars; ++i)
06a2c219 3142 {
b4192550
KH
3143 struct glyph *g = s->first_glyph + i;
3144 XDrawRectangle (s->display, s->window,
3145 s->gc, x, s->y, g->pixel_width - 1,
3146 s->height - 1);
3147 x += g->pixel_width;
06a2c219
GM
3148 }
3149 }
3150 else
3151 {
b4192550
KH
3152 char *char1b = (char *) s->char2b;
3153 int boff = s->font_info->baseline_offset;
06a2c219 3154
b4192550
KH
3155 if (s->font_info->vertical_centering)
3156 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3157
3158 /* If we can use 8-bit functions, condense S->char2b. */
3159 if (!s->two_byte_p)
3160 for (i = 0; i < s->nchars; ++i)
3161 char1b[i] = s->char2b[i].byte2;
3162
3163 /* Draw text with XDrawString if background has already been
3164 filled. Otherwise, use XDrawImageString. (Note that
3165 XDrawImageString is usually faster than XDrawString.) Always
3166 use XDrawImageString when drawing the cursor so that there is
3167 no chance that characters under a box cursor are invisible. */
3168 if (s->for_overlaps_p
3169 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3170 {
3171 /* Draw characters with 16-bit or 8-bit functions. */
3172 if (s->two_byte_p)
3173 XDrawString16 (s->display, s->window, s->gc, x,
3174 s->ybase - boff, s->char2b, s->nchars);
3175 else
3176 XDrawString (s->display, s->window, s->gc, x,
3177 s->ybase - boff, char1b, s->nchars);
3178 }
06a2c219
GM
3179 else
3180 {
b4192550
KH
3181 if (s->two_byte_p)
3182 XDrawImageString16 (s->display, s->window, s->gc, x,
3183 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3184 else
b4192550
KH
3185 XDrawImageString (s->display, s->window, s->gc, x,
3186 s->ybase - boff, char1b, s->nchars);
3187 }
3188 }
3189}
06a2c219 3190
b4192550 3191/* Draw the foreground of composite glyph string S. */
06a2c219 3192
b4192550
KH
3193static void
3194x_draw_composite_glyph_string_foreground (s)
3195 struct glyph_string *s;
3196{
3197 int i, x;
06a2c219 3198
b4192550
KH
3199 /* If first glyph of S has a left box line, start drawing the text
3200 of S to the right of that box line. */
3201 if (s->face->box != FACE_NO_BOX
3202 && s->first_glyph->left_box_line_p)
ea2ba0d4 3203 x = s->x + abs (s->face->box_line_width);
b4192550
KH
3204 else
3205 x = s->x;
06a2c219 3206
b4192550
KH
3207 /* S is a glyph string for a composition. S->gidx is the index of
3208 the first character drawn for glyphs of this composition.
3209 S->gidx == 0 means we are drawing the very first character of
3210 this composition. */
06a2c219 3211
b4192550
KH
3212 /* Draw a rectangle for the composition if the font for the very
3213 first character of the composition could not be loaded. */
3214 if (s->font_not_found_p)
3215 {
3216 if (s->gidx == 0)
3217 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3218 s->width - 1, s->height - 1);
3219 }
3220 else
3221 {
3222 for (i = 0; i < s->nchars; i++, ++s->gidx)
3223 XDrawString16 (s->display, s->window, s->gc,
3224 x + s->cmp->offsets[s->gidx * 2],
3225 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3226 s->char2b + i, 1);
06a2c219
GM
3227 }
3228}
3229
3230
80c32bcc
GM
3231#ifdef USE_X_TOOLKIT
3232
3e71d8f2 3233static struct frame *x_frame_of_widget P_ ((Widget));
651f03b6
GM
3234static Boolean cvt_string_to_pixel P_ ((Display *, XrmValue *, Cardinal *,
3235 XrmValue *, XrmValue *, XtPointer *));
3236static void cvt_pixel_dtor P_ ((XtAppContext, XrmValue *, XtPointer,
3237 XrmValue *, Cardinal *));
80c32bcc 3238
3e71d8f2
GM
3239
3240/* Return the frame on which widget WIDGET is used.. Abort if frame
3241 cannot be determined. */
3242
e851c833 3243static struct frame *
3e71d8f2 3244x_frame_of_widget (widget)
80c32bcc 3245 Widget widget;
80c32bcc 3246{
80c32bcc 3247 struct x_display_info *dpyinfo;
5c187dee 3248 Lisp_Object tail;
3e71d8f2
GM
3249 struct frame *f;
3250
80c32bcc
GM
3251 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3252
3253 /* Find the top-level shell of the widget. Note that this function
3254 can be called when the widget is not yet realized, so XtWindow
3255 (widget) == 0. That's the reason we can't simply use
3256 x_any_window_to_frame. */
3257 while (!XtIsTopLevelShell (widget))
3258 widget = XtParent (widget);
3259
3260 /* Look for a frame with that top-level widget. Allocate the color
3261 on that frame to get the right gamma correction value. */
3262 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3263 if (GC_FRAMEP (XCAR (tail))
3264 && (f = XFRAME (XCAR (tail)),
3265 (f->output_data.nothing != 1
3266 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3267 && f->output_data.x->widget == widget)
3e71d8f2 3268 return f;
80c32bcc
GM
3269
3270 abort ();
3271}
3272
3e71d8f2
GM
3273
3274/* Allocate the color COLOR->pixel on the screen and display of
3275 widget WIDGET in colormap CMAP. If an exact match cannot be
3276 allocated, try the nearest color available. Value is non-zero
3277 if successful. This is called from lwlib. */
3278
3279int
3280x_alloc_nearest_color_for_widget (widget, cmap, color)
3281 Widget widget;
3282 Colormap cmap;
3283 XColor *color;
3284{
3285 struct frame *f = x_frame_of_widget (widget);
3286 return x_alloc_nearest_color (f, cmap, color);
3287}
3288
3289
46d516e5
MB
3290/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3291 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3292 If this produces the same color as PIXEL, try a color where all RGB
3293 values have DELTA added. Return the allocated color in *PIXEL.
3294 DISPLAY is the X display, CMAP is the colormap to operate on.
3295 Value is non-zero if successful. */
3296
3297int
3298x_alloc_lighter_color_for_widget (widget, display, cmap, pixel, factor, delta)
3299 Widget widget;
3300 Display *display;
3301 Colormap cmap;
3302 unsigned long *pixel;
3303 double factor;
3304 int delta;
3305{
3306 struct frame *f = x_frame_of_widget (widget);
3307 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
3308}
3309
3310
651f03b6
GM
3311/* Structure specifying which arguments should be passed by Xt to
3312 cvt_string_to_pixel. We want the widget's screen and colormap. */
3313
3314static XtConvertArgRec cvt_string_to_pixel_args[] =
3315 {
3316 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.screen),
3317 sizeof (Screen *)},
3318 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.colormap),
3319 sizeof (Colormap)}
3320 };
3321
3322
3323/* The address of this variable is returned by
3324 cvt_string_to_pixel. */
3325
3326static Pixel cvt_string_to_pixel_value;
3327
3328
3329/* Convert a color name to a pixel color.
3330
3331 DPY is the display we are working on.
3332
3333 ARGS is an array of *NARGS XrmValue structures holding additional
3334 information about the widget for which the conversion takes place.
3335 The contents of this array are determined by the specification
3336 in cvt_string_to_pixel_args.
3337
3338 FROM is a pointer to an XrmValue which points to the color name to
3339 convert. TO is an XrmValue in which to return the pixel color.
3340
3341 CLOSURE_RET is a pointer to user-data, in which we record if
3342 we allocated the color or not.
3343
3344 Value is True if successful, False otherwise. */
3345
3346static Boolean
3347cvt_string_to_pixel (dpy, args, nargs, from, to, closure_ret)
3348 Display *dpy;
3349 XrmValue *args;
3350 Cardinal *nargs;
3351 XrmValue *from, *to;
3352 XtPointer *closure_ret;
3353{
3354 Screen *screen;
3355 Colormap cmap;
3356 Pixel pixel;
3357 String color_name;
3358 XColor color;
3359
3360 if (*nargs != 2)
3361 {
3362 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3363 "wrongParameters", "cvt_string_to_pixel",
3364 "XtToolkitError",
3365 "Screen and colormap args required", NULL, NULL);
3366 return False;
3367 }
3368
3369 screen = *(Screen **) args[0].addr;
3370 cmap = *(Colormap *) args[1].addr;
3371 color_name = (String) from->addr;
3372
3373 if (strcmp (color_name, XtDefaultBackground) == 0)
3374 {
3375 *closure_ret = (XtPointer) False;
3376 pixel = WhitePixelOfScreen (screen);
3377 }
3378 else if (strcmp (color_name, XtDefaultForeground) == 0)
3379 {
3380 *closure_ret = (XtPointer) False;
3381 pixel = BlackPixelOfScreen (screen);
3382 }
3383 else if (XParseColor (dpy, cmap, color_name, &color)
3384 && x_alloc_nearest_color_1 (dpy, cmap, &color))
3385 {
3386 pixel = color.pixel;
3387 *closure_ret = (XtPointer) True;
3388 }
3389 else
3390 {
3391 String params[1];
3392 Cardinal nparams = 1;
3393
3394 params[0] = color_name;
3395 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3396 "badValue", "cvt_string_to_pixel",
3397 "XtToolkitError", "Invalid color `%s'",
3398 params, &nparams);
3399 return False;
3400 }
3401
3402 if (to->addr != NULL)
3403 {
3404 if (to->size < sizeof (Pixel))
3405 {
3406 to->size = sizeof (Pixel);
3407 return False;
3408 }
3409
3410 *(Pixel *) to->addr = pixel;
3411 }
3412 else
3413 {
3414 cvt_string_to_pixel_value = pixel;
3415 to->addr = (XtPointer) &cvt_string_to_pixel_value;
3416 }
3417
3418 to->size = sizeof (Pixel);
3419 return True;
3420}
3421
3422
3423/* Free a pixel color which was previously allocated via
3424 cvt_string_to_pixel. This is registered as the destructor
3425 for this type of resource via XtSetTypeConverter.
3426
3427 APP is the application context in which we work.
3428
3429 TO is a pointer to an XrmValue holding the color to free.
3430 CLOSURE is the value we stored in CLOSURE_RET for this color
3431 in cvt_string_to_pixel.
3432
3433 ARGS and NARGS are like for cvt_string_to_pixel. */
3434
3435static void
3436cvt_pixel_dtor (app, to, closure, args, nargs)
3437 XtAppContext app;
3438 XrmValuePtr to;
3439 XtPointer closure;
3440 XrmValuePtr args;
3441 Cardinal *nargs;
3442{
3443 if (*nargs != 2)
3444 {
3445 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
3446 "XtToolkitError",
3447 "Screen and colormap arguments required",
3448 NULL, NULL);
3449 }
3450 else if (closure != NULL)
3451 {
3452 /* We did allocate the pixel, so free it. */
3453 Screen *screen = *(Screen **) args[0].addr;
3454 Colormap cmap = *(Colormap *) args[1].addr;
3455 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
97762eb7 3456 (Pixel *) to->addr, 1);
651f03b6
GM
3457 }
3458}
3459
3460
80c32bcc
GM
3461#endif /* USE_X_TOOLKIT */
3462
3463
f04e1297 3464/* Value is an array of XColor structures for the contents of the
651f03b6 3465 color map of display DPY. Set *NCELLS to the size of the array.
f04e1297
GM
3466 Note that this probably shouldn't be called for large color maps,
3467 say a 24-bit TrueColor map. */
3468
3469static const XColor *
651f03b6
GM
3470x_color_cells (dpy, ncells)
3471 Display *dpy;
f04e1297
GM
3472 int *ncells;
3473{
651f03b6 3474 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
f04e1297
GM
3475
3476 if (dpyinfo->color_cells == NULL)
3477 {
651f03b6 3478 Screen *screen = dpyinfo->screen;
f04e1297
GM
3479 int i;
3480
3481 dpyinfo->ncolor_cells
651f03b6 3482 = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
f04e1297
GM
3483 dpyinfo->color_cells
3484 = (XColor *) xmalloc (dpyinfo->ncolor_cells
3485 * sizeof *dpyinfo->color_cells);
3486
3487 for (i = 0; i < dpyinfo->ncolor_cells; ++i)
3488 dpyinfo->color_cells[i].pixel = i;
3489
651f03b6 3490 XQueryColors (dpy, dpyinfo->cmap,
f04e1297
GM
3491 dpyinfo->color_cells, dpyinfo->ncolor_cells);
3492 }
3493
3494 *ncells = dpyinfo->ncolor_cells;
3495 return dpyinfo->color_cells;
3496}
3497
3498
3499/* On frame F, translate pixel colors to RGB values for the NCOLORS
3500 colors in COLORS. Use cached information, if available. */
3501
3502void
3503x_query_colors (f, colors, ncolors)
3504 struct frame *f;
3505 XColor *colors;
3506 int ncolors;
3507{
3508 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3509
3510 if (dpyinfo->color_cells)
3511 {
3512 int i;
3513 for (i = 0; i < ncolors; ++i)
3514 {
3515 unsigned long pixel = colors[i].pixel;
3516 xassert (pixel < dpyinfo->ncolor_cells);
3517 xassert (dpyinfo->color_cells[pixel].pixel == pixel);
3518 colors[i] = dpyinfo->color_cells[pixel];
3519 }
3520 }
3521 else
3522 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
3523}
3524
3525
3526/* On frame F, translate pixel color to RGB values for the color in
3527 COLOR. Use cached information, if available. */
3528
3529void
3530x_query_color (f, color)
3531 struct frame *f;
3532 XColor *color;
3533{
3534 x_query_colors (f, color, 1);
3535}
3536
3537
651f03b6
GM
3538/* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
3539 exact match can't be allocated, try the nearest color available.
3540 Value is non-zero if successful. Set *COLOR to the color
3541 allocated. */
06a2c219 3542
651f03b6
GM
3543static int
3544x_alloc_nearest_color_1 (dpy, cmap, color)
3545 Display *dpy;
06a2c219
GM
3546 Colormap cmap;
3547 XColor *color;
3548{
80c32bcc
GM
3549 int rc;
3550
651f03b6 3551 rc = XAllocColor (dpy, cmap, color);
06a2c219
GM
3552 if (rc == 0)
3553 {
3554 /* If we got to this point, the colormap is full, so we're going
3555 to try to get the next closest color. The algorithm used is
3556 a least-squares matching, which is what X uses for closest
3557 color matching with StaticColor visuals. */
3558 int nearest, i;
3559 unsigned long nearest_delta = ~0;
f04e1297 3560 int ncells;
651f03b6 3561 const XColor *cells = x_color_cells (dpy, &ncells);
06a2c219
GM
3562
3563 for (nearest = i = 0; i < ncells; ++i)
3564 {
3565 long dred = (color->red >> 8) - (cells[i].red >> 8);
3566 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3567 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3568 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3569
3570 if (delta < nearest_delta)
3571 {
3572 nearest = i;
3573 nearest_delta = delta;
3574 }
3575 }
3576
3577 color->red = cells[nearest].red;
3578 color->green = cells[nearest].green;
3579 color->blue = cells[nearest].blue;
651f03b6 3580 rc = XAllocColor (dpy, cmap, color);
06a2c219 3581 }
35efe0a1
GM
3582 else
3583 {
3584 /* If allocation succeeded, and the allocated pixel color is not
3585 equal to a cached pixel color recorded earlier, there was a
3586 change in the colormap, so clear the color cache. */
651f03b6 3587 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
35efe0a1
GM
3588 XColor *cached_color;
3589
3590 if (dpyinfo->color_cells
3591 && (cached_color = &dpyinfo->color_cells[color->pixel],
cae71efe
GM
3592 (cached_color->red != color->red
3593 || cached_color->blue != color->blue
3594 || cached_color->green != color->green)))
35efe0a1
GM
3595 {
3596 xfree (dpyinfo->color_cells);
3597 dpyinfo->color_cells = NULL;
3598 dpyinfo->ncolor_cells = 0;
3599 }
3600 }
06a2c219 3601
d9c545da
GM
3602#ifdef DEBUG_X_COLORS
3603 if (rc)
3604 register_color (color->pixel);
3605#endif /* DEBUG_X_COLORS */
3606
06a2c219
GM
3607 return rc;
3608}
3609
3610
651f03b6
GM
3611/* Allocate the color COLOR->pixel on frame F, colormap CMAP. If an
3612 exact match can't be allocated, try the nearest color available.
3613 Value is non-zero if successful. Set *COLOR to the color
3614 allocated. */
3615
3616int
3617x_alloc_nearest_color (f, cmap, color)
3618 struct frame *f;
3619 Colormap cmap;
3620 XColor *color;
3621{
3622 gamma_correct (f, color);
3623 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
3624}
3625
3626
d9c545da
GM
3627/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3628 It's necessary to do this instead of just using PIXEL directly to
3629 get color reference counts right. */
3630
3631unsigned long
3632x_copy_color (f, pixel)
3633 struct frame *f;
3634 unsigned long pixel;
3635{
3636 XColor color;
3637
3638 color.pixel = pixel;
3639 BLOCK_INPUT;
f04e1297 3640 x_query_color (f, &color);
d9c545da
GM
3641 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3642 UNBLOCK_INPUT;
3643#ifdef DEBUG_X_COLORS
3644 register_color (pixel);
3645#endif
3646 return color.pixel;
3647}
3648
3649
3e71d8f2
GM
3650/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3651 It's necessary to do this instead of just using PIXEL directly to
3652 get color reference counts right. */
3653
3654unsigned long
3655x_copy_dpy_color (dpy, cmap, pixel)
3656 Display *dpy;
3657 Colormap cmap;
3658 unsigned long pixel;
3659{
3660 XColor color;
3661
3662 color.pixel = pixel;
3663 BLOCK_INPUT;
3664 XQueryColor (dpy, cmap, &color);
3665 XAllocColor (dpy, cmap, &color);
3666 UNBLOCK_INPUT;
3667#ifdef DEBUG_X_COLORS
3668 register_color (pixel);
3669#endif
3670 return color.pixel;
3671}
3672
3673
6d8b0acd 3674/* Brightness beyond which a color won't have its highlight brightness
d7361edf 3675 boosted.
6d8b0acd 3676
d7361edf
MB
3677 Nominally, highlight colors for `3d' faces are calculated by
3678 brightening an object's color by a constant scale factor, but this
3679 doesn't yield good results for dark colors, so for colors who's
3680 brightness is less than this value (on a scale of 0-65535) have an
3681 use an additional additive factor.
6d8b0acd
MB
3682
3683 The value here is set so that the default menu-bar/mode-line color
3684 (grey75) will not have its highlights changed at all. */
3685#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
3686
3687
06a2c219
GM
3688/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3689 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3690 If this produces the same color as PIXEL, try a color where all RGB
3691 values have DELTA added. Return the allocated color in *PIXEL.
3692 DISPLAY is the X display, CMAP is the colormap to operate on.
3693 Value is non-zero if successful. */
3694
3695static int
3696x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3697 struct frame *f;
3698 Display *display;
3699 Colormap cmap;
3700 unsigned long *pixel;
68c45bf0 3701 double factor;
06a2c219
GM
3702 int delta;
3703{
3704 XColor color, new;
6d8b0acd 3705 long bright;
06a2c219
GM
3706 int success_p;
3707
3708 /* Get RGB color values. */
3709 color.pixel = *pixel;
f04e1297 3710 x_query_color (f, &color);
06a2c219
GM
3711
3712 /* Change RGB values by specified FACTOR. Avoid overflow! */
3713 xassert (factor >= 0);
3714 new.red = min (0xffff, factor * color.red);
3715 new.green = min (0xffff, factor * color.green);
3716 new.blue = min (0xffff, factor * color.blue);
3717
d7361edf
MB
3718 /* Calculate brightness of COLOR. */
3719 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
6d8b0acd
MB
3720
3721 /* We only boost colors that are darker than
3722 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3723 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3724 /* Make an additive adjustment to NEW, because it's dark enough so
3725 that scaling by FACTOR alone isn't enough. */
3726 {
3727 /* How far below the limit this color is (0 - 1, 1 being darker). */
3728 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3729 /* The additive adjustment. */
d7361edf 3730 int min_delta = delta * dimness * factor / 2;
6d8b0acd
MB
3731
3732 if (factor < 1)
3733 {
6d8b0acd
MB
3734 new.red = max (0, new.red - min_delta);
3735 new.green = max (0, new.green - min_delta);
3736 new.blue = max (0, new.blue - min_delta);
3737 }
3738 else
3739 {
3740 new.red = min (0xffff, min_delta + new.red);
3741 new.green = min (0xffff, min_delta + new.green);
3742 new.blue = min (0xffff, min_delta + new.blue);
3743 }
3744 }
3745
06a2c219 3746 /* Try to allocate the color. */
80c32bcc 3747 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3748 if (success_p)
3749 {
3750 if (new.pixel == *pixel)
3751 {
3752 /* If we end up with the same color as before, try adding
3753 delta to the RGB values. */
0d605c67 3754 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3755
3756 new.red = min (0xffff, delta + color.red);
3757 new.green = min (0xffff, delta + color.green);
3758 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3759 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3760 }
3761 else
3762 success_p = 1;
3763 *pixel = new.pixel;
3764 }
3765
3766 return success_p;
3767}
3768
3769
3770/* Set up the foreground color for drawing relief lines of glyph
3771 string S. RELIEF is a pointer to a struct relief containing the GC
3772 with which lines will be drawn. Use a color that is FACTOR or
3773 DELTA lighter or darker than the relief's background which is found
3774 in S->f->output_data.x->relief_background. If such a color cannot
3775 be allocated, use DEFAULT_PIXEL, instead. */
3776
3777static void
3778x_setup_relief_color (f, relief, factor, delta, default_pixel)
3779 struct frame *f;
3780 struct relief *relief;
68c45bf0 3781 double factor;
06a2c219
GM
3782 int delta;
3783 unsigned long default_pixel;
3784{
3785 XGCValues xgcv;
3786 struct x_output *di = f->output_data.x;
3787 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3788 unsigned long pixel;
3789 unsigned long background = di->relief_background;
43bd1b2b 3790 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3791 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3792 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3793
3794 xgcv.graphics_exposures = False;
3795 xgcv.line_width = 1;
3796
3797 /* Free previously allocated color. The color cell will be reused
3798 when it has been freed as many times as it was allocated, so this
3799 doesn't affect faces using the same colors. */
3800 if (relief->gc
3801 && relief->allocated_p)
3802 {
0d605c67 3803 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3804 relief->allocated_p = 0;
3805 }
3806
3807 /* Allocate new color. */
3808 xgcv.foreground = default_pixel;
3809 pixel = background;
dcd08bfb
GM
3810 if (dpyinfo->n_planes != 1
3811 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3812 {
3813 relief->allocated_p = 1;
3814 xgcv.foreground = relief->pixel = pixel;
3815 }
3816
3817 if (relief->gc == 0)
3818 {
dcd08bfb 3819 xgcv.stipple = dpyinfo->gray;
06a2c219 3820 mask |= GCStipple;
dcd08bfb 3821 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3822 }
3823 else
dcd08bfb 3824 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3825}
3826
3827
3828/* Set up colors for the relief lines around glyph string S. */
3829
3830static void
3831x_setup_relief_colors (s)
3832 struct glyph_string *s;
3833{
3834 struct x_output *di = s->f->output_data.x;
3835 unsigned long color;
3836
3837 if (s->face->use_box_color_for_shadows_p)
3838 color = s->face->box_color;
e2a57b34
MB
3839 else if (s->first_glyph->type == IMAGE_GLYPH
3840 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3841 color = IMAGE_BACKGROUND (s->img, s->f, 0);
06a2c219
GM
3842 else
3843 {
3844 XGCValues xgcv;
3845
3846 /* Get the background color of the face. */
3847 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3848 color = xgcv.background;
3849 }
3850
3851 if (di->white_relief.gc == 0
3852 || color != di->relief_background)
3853 {
3854 di->relief_background = color;
3855 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3856 WHITE_PIX_DEFAULT (s->f));
3857 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3858 BLACK_PIX_DEFAULT (s->f));
3859 }
3860}
3861
3862
3863/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3864 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3865 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3866 relief. LEFT_P non-zero means draw a relief on the left side of
3867 the rectangle. RIGHT_P non-zero means draw a relief on the right
3868 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3869 when drawing. */
3870
3871static void
3872x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3873 raised_p, left_p, right_p, clip_rect)
3874 struct frame *f;
3875 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3876 XRectangle *clip_rect;
3877{
de507556
GM
3878 Display *dpy = FRAME_X_DISPLAY (f);
3879 Window window = FRAME_X_WINDOW (f);
06a2c219
GM
3880 int i;
3881 GC gc;
3882
3883 if (raised_p)
3884 gc = f->output_data.x->white_relief.gc;
3885 else
3886 gc = f->output_data.x->black_relief.gc;
de507556 3887 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3888
3889 /* Top. */
3890 for (i = 0; i < width; ++i)
de507556 3891 XDrawLine (dpy, window, gc,
06a2c219
GM
3892 left_x + i * left_p, top_y + i,
3893 right_x + 1 - i * right_p, top_y + i);
3894
3895 /* Left. */
3896 if (left_p)
3897 for (i = 0; i < width; ++i)
de507556 3898 XDrawLine (dpy, window, gc,
44655e77 3899 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
06a2c219 3900
de507556 3901 XSetClipMask (dpy, gc, None);
06a2c219
GM
3902 if (raised_p)
3903 gc = f->output_data.x->black_relief.gc;
3904 else
3905 gc = f->output_data.x->white_relief.gc;
de507556 3906 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3907
3908 /* Bottom. */
3909 for (i = 0; i < width; ++i)
de507556
GM
3910 XDrawLine (dpy, window, gc,
3911 left_x + i * left_p, bottom_y - i,
327f42ee 3912 right_x + 1 - i * right_p, bottom_y - i);
06a2c219
GM
3913
3914 /* Right. */
3915 if (right_p)
3916 for (i = 0; i < width; ++i)
de507556 3917 XDrawLine (dpy, window, gc,
06a2c219
GM
3918 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3919
de507556 3920 XSetClipMask (dpy, gc, None);
06a2c219
GM
3921}
3922
3923
3924/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3925 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3926 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3927 left side of the rectangle. RIGHT_P non-zero means draw a line
3928 on the right side of the rectangle. CLIP_RECT is the clipping
3929 rectangle to use when drawing. */
3930
3931static void
3932x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3933 left_p, right_p, clip_rect)
3934 struct glyph_string *s;
3935 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3936 XRectangle *clip_rect;
3937{
3938 XGCValues xgcv;
3939
3940 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3941 XSetForeground (s->display, s->gc, s->face->box_color);
3942 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3943
3944 /* Top. */
3945 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3946 left_x, top_y, right_x - left_x + 1, width);
06a2c219
GM
3947
3948 /* Left. */
3949 if (left_p)
3950 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3951 left_x, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3952
3953 /* Bottom. */
3954 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3955 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
06a2c219
GM
3956
3957 /* Right. */
3958 if (right_p)
3959 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3960 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3961
3962 XSetForeground (s->display, s->gc, xgcv.foreground);
3963 XSetClipMask (s->display, s->gc, None);
3964}
3965
3966
3967/* Draw a box around glyph string S. */
3968
3969static void
3970x_draw_glyph_string_box (s)
3971 struct glyph_string *s;
3972{
3973 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3974 int left_p, right_p;
3975 struct glyph *last_glyph;
3976 XRectangle clip_rect;
3977
3978 last_x = window_box_right (s->w, s->area);
3979 if (s->row->full_width_p
3980 && !s->w->pseudo_window_p)
3981 {
3f332ef3 3982 last_x += FRAME_X_RIGHT_FRINGE_WIDTH (s->f);
06a2c219
GM
3983 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3984 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3985 }
3986
3987 /* The glyph that may have a right box line. */
b4192550 3988 last_glyph = (s->cmp || s->img
06a2c219
GM
3989 ? s->first_glyph
3990 : s->first_glyph + s->nchars - 1);
3991
ea2ba0d4 3992 width = abs (s->face->box_line_width);
06a2c219
GM
3993 raised_p = s->face->box == FACE_RAISED_BOX;
3994 left_x = s->x;
57ac7c81
GM
3995 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
3996 ? last_x - 1
3997 : min (last_x, s->x + s->background_width) - 1);
06a2c219
GM
3998 top_y = s->y;
3999 bottom_y = top_y + s->height - 1;
4000
4001 left_p = (s->first_glyph->left_box_line_p
4002 || (s->hl == DRAW_MOUSE_FACE
4003 && (s->prev == NULL
4004 || s->prev->hl != s->hl)));
4005 right_p = (last_glyph->right_box_line_p
4006 || (s->hl == DRAW_MOUSE_FACE
4007 && (s->next == NULL
4008 || s->next->hl != s->hl)));
327f42ee 4009
06a2c219
GM
4010 x_get_glyph_string_clip_rect (s, &clip_rect);
4011
4012 if (s->face->box == FACE_SIMPLE_BOX)
4013 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4014 left_p, right_p, &clip_rect);
4015 else
4016 {
4017 x_setup_relief_colors (s);
4018 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
4019 width, raised_p, left_p, right_p, &clip_rect);
4020 }
4021}
4022
4023
4024/* Draw foreground of image glyph string S. */
4025
4026static void
4027x_draw_image_foreground (s)
4028 struct glyph_string *s;
4029{
4030 int x;
95af8492 4031 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4032
4033 /* If first glyph of S has a left box line, start drawing it to the
4034 right of that line. */
4035 if (s->face->box != FACE_NO_BOX
4036 && s->first_glyph->left_box_line_p)
ea2ba0d4 4037 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4038 else
4039 x = s->x;
4040
4041 /* If there is a margin around the image, adjust x- and y-position
4042 by that margin. */
22d650b8
GM
4043 x += s->img->hmargin;
4044 y += s->img->vmargin;
06a2c219
GM
4045
4046 if (s->img->pixmap)
4047 {
4048 if (s->img->mask)
4049 {
4050 /* We can't set both a clip mask and use XSetClipRectangles
4051 because the latter also sets a clip mask. We also can't
4052 trust on the shape extension to be available
4053 (XShapeCombineRegion). So, compute the rectangle to draw
4054 manually. */
4055 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4056 | GCFunction);
4057 XGCValues xgcv;
4058 XRectangle clip_rect, image_rect, r;
4059
4060 xgcv.clip_mask = s->img->mask;
4061 xgcv.clip_x_origin = x;
4062 xgcv.clip_y_origin = y;
4063 xgcv.function = GXcopy;
4064 XChangeGC (s->display, s->gc, mask, &xgcv);
4065
4066 x_get_glyph_string_clip_rect (s, &clip_rect);
4067 image_rect.x = x;
4068 image_rect.y = y;
4069 image_rect.width = s->img->width;
4070 image_rect.height = s->img->height;
4071 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4072 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4073 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
4074 }
4075 else
4076 {
49ad1d99
GM
4077 XRectangle clip_rect, image_rect, r;
4078
4079 x_get_glyph_string_clip_rect (s, &clip_rect);
4080 image_rect.x = x;
4081 image_rect.y = y;
4082 image_rect.width = s->img->width;
4083 image_rect.height = s->img->height;
4084 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4085 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4086 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
06a2c219
GM
4087
4088 /* When the image has a mask, we can expect that at
4089 least part of a mouse highlight or a block cursor will
4090 be visible. If the image doesn't have a mask, make
4091 a block cursor visible by drawing a rectangle around
4092 the image. I believe it's looking better if we do
4093 nothing here for mouse-face. */
4094 if (s->hl == DRAW_CURSOR)
4095 XDrawRectangle (s->display, s->window, s->gc, x, y,
4096 s->img->width - 1, s->img->height - 1);
4097 }
4098 }
4099 else
4100 /* Draw a rectangle if image could not be loaded. */
4101 XDrawRectangle (s->display, s->window, s->gc, x, y,
4102 s->img->width - 1, s->img->height - 1);
4103}
4104
4105
4106/* Draw a relief around the image glyph string S. */
4107
4108static void
4109x_draw_image_relief (s)
4110 struct glyph_string *s;
4111{
4112 int x0, y0, x1, y1, thick, raised_p;
4113 XRectangle r;
4114 int x;
95af8492 4115 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4116
4117 /* If first glyph of S has a left box line, start drawing it to the
4118 right of that line. */
4119 if (s->face->box != FACE_NO_BOX
4120 && s->first_glyph->left_box_line_p)
ea2ba0d4 4121 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4122 else
4123 x = s->x;
4124
4125 /* If there is a margin around the image, adjust x- and y-position
4126 by that margin. */
22d650b8
GM
4127 x += s->img->hmargin;
4128 y += s->img->vmargin;
06a2c219
GM
4129
4130 if (s->hl == DRAW_IMAGE_SUNKEN
4131 || s->hl == DRAW_IMAGE_RAISED)
4132 {
62854fe2 4133 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
06a2c219
GM
4134 raised_p = s->hl == DRAW_IMAGE_RAISED;
4135 }
4136 else
4137 {
4138 thick = abs (s->img->relief);
4139 raised_p = s->img->relief > 0;
4140 }
4141
4142 x0 = x - thick;
4143 y0 = y - thick;
4144 x1 = x + s->img->width + thick - 1;
4145 y1 = y + s->img->height + thick - 1;
4146
4147 x_setup_relief_colors (s);
4148 x_get_glyph_string_clip_rect (s, &r);
4149 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
4150}
4151
4152
4153/* Draw the foreground of image glyph string S to PIXMAP. */
4154
4155static void
4156x_draw_image_foreground_1 (s, pixmap)
4157 struct glyph_string *s;
4158 Pixmap pixmap;
4159{
4160 int x;
95af8492 4161 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
4162
4163 /* If first glyph of S has a left box line, start drawing it to the
4164 right of that line. */
4165 if (s->face->box != FACE_NO_BOX
4166 && s->first_glyph->left_box_line_p)
ea2ba0d4 4167 x = abs (s->face->box_line_width);
06a2c219
GM
4168 else
4169 x = 0;
4170
4171 /* If there is a margin around the image, adjust x- and y-position
4172 by that margin. */
22d650b8
GM
4173 x += s->img->hmargin;
4174 y += s->img->vmargin;
dc43ef94 4175
06a2c219
GM
4176 if (s->img->pixmap)
4177 {
4178 if (s->img->mask)
4179 {
4180 /* We can't set both a clip mask and use XSetClipRectangles
4181 because the latter also sets a clip mask. We also can't
4182 trust on the shape extension to be available
4183 (XShapeCombineRegion). So, compute the rectangle to draw
4184 manually. */
4185 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4186 | GCFunction);
4187 XGCValues xgcv;
4188
4189 xgcv.clip_mask = s->img->mask;
4190 xgcv.clip_x_origin = x;
4191 xgcv.clip_y_origin = y;
4192 xgcv.function = GXcopy;
4193 XChangeGC (s->display, s->gc, mask, &xgcv);
4194
4195 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4196 0, 0, s->img->width, s->img->height, x, y);
4197 XSetClipMask (s->display, s->gc, None);
4198 }
4199 else
4200 {
4201 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4202 0, 0, s->img->width, s->img->height, x, y);
4203
4204 /* When the image has a mask, we can expect that at
4205 least part of a mouse highlight or a block cursor will
4206 be visible. If the image doesn't have a mask, make
4207 a block cursor visible by drawing a rectangle around
4208 the image. I believe it's looking better if we do
4209 nothing here for mouse-face. */
4210 if (s->hl == DRAW_CURSOR)
4211 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4212 s->img->width - 1, s->img->height - 1);
4213 }
4214 }
4215 else
4216 /* Draw a rectangle if image could not be loaded. */
4217 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4218 s->img->width - 1, s->img->height - 1);
4219}
dc43ef94 4220
990ba854 4221
06a2c219
GM
4222/* Draw part of the background of glyph string S. X, Y, W, and H
4223 give the rectangle to draw. */
a9a5b0a5 4224
06a2c219
GM
4225static void
4226x_draw_glyph_string_bg_rect (s, x, y, w, h)
4227 struct glyph_string *s;
4228 int x, y, w, h;
4229{
4230 if (s->stippled_p)
4231 {
4232 /* Fill background with a stipple pattern. */
4233 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4234 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4235 XSetFillStyle (s->display, s->gc, FillSolid);
4236 }
4237 else
4238 x_clear_glyph_string_rect (s, x, y, w, h);
4239}
07e34cb0 4240
b5210ea7 4241
06a2c219 4242/* Draw image glyph string S.
dc43ef94 4243
06a2c219
GM
4244 s->y
4245 s->x +-------------------------
4246 | s->face->box
4247 |
4248 | +-------------------------
4249 | | s->img->margin
4250 | |
4251 | | +-------------------
4252 | | | the image
dc43ef94 4253
06a2c219 4254 */
dc43ef94 4255
06a2c219
GM
4256static void
4257x_draw_image_glyph_string (s)
4258 struct glyph_string *s;
4259{
4260 int x, y;
ea2ba0d4
KH
4261 int box_line_hwidth = abs (s->face->box_line_width);
4262 int box_line_vwidth = max (s->face->box_line_width, 0);
06a2c219
GM
4263 int height;
4264 Pixmap pixmap = None;
4265
ea2ba0d4 4266 height = s->height - 2 * box_line_vwidth;
06a2c219
GM
4267
4268 /* Fill background with face under the image. Do it only if row is
4269 taller than image or if image has a clip mask to reduce
4270 flickering. */
4271 s->stippled_p = s->face->stipple != 0;
4272 if (height > s->img->height
22d650b8
GM
4273 || s->img->hmargin
4274 || s->img->vmargin
06a2c219
GM
4275 || s->img->mask
4276 || s->img->pixmap == 0
4277 || s->width != s->background_width)
4278 {
ea2ba0d4
KH
4279 if (box_line_hwidth && s->first_glyph->left_box_line_p)
4280 x = s->x + box_line_hwidth;
06a2c219
GM
4281 else
4282 x = s->x;
4283
ea2ba0d4 4284 y = s->y + box_line_vwidth;
06a2c219
GM
4285
4286 if (s->img->mask)
4287 {
f9b5db02
GM
4288 /* Create a pixmap as large as the glyph string. Fill it
4289 with the background color. Copy the image to it, using
4290 its mask. Copy the temporary pixmap to the display. */
06a2c219
GM
4291 Screen *screen = FRAME_X_SCREEN (s->f);
4292 int depth = DefaultDepthOfScreen (screen);
4293
4294 /* Create a pixmap as large as the glyph string. */
4295 pixmap = XCreatePixmap (s->display, s->window,
4296 s->background_width,
4297 s->height, depth);
4298
4299 /* Don't clip in the following because we're working on the
4300 pixmap. */
4301 XSetClipMask (s->display, s->gc, None);
4302
4303 /* Fill the pixmap with the background color/stipple. */
4304 if (s->stippled_p)
4305 {
4306 /* Fill background with a stipple pattern. */
4307 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4308 XFillRectangle (s->display, pixmap, s->gc,
4309 0, 0, s->background_width, s->height);
4310 XSetFillStyle (s->display, s->gc, FillSolid);
4311 }
4312 else
4313 {
4314 XGCValues xgcv;
4315 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4316 &xgcv);
4317 XSetForeground (s->display, s->gc, xgcv.background);
4318 XFillRectangle (s->display, pixmap, s->gc,
4319 0, 0, s->background_width, s->height);
4320 XSetForeground (s->display, s->gc, xgcv.foreground);
4321 }
4322 }
4323 else
06a2c219
GM
4324 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
4325
4326 s->background_filled_p = 1;
4327 }
dc43ef94 4328
06a2c219
GM
4329 /* Draw the foreground. */
4330 if (pixmap != None)
4331 {
4332 x_draw_image_foreground_1 (s, pixmap);
4333 x_set_glyph_string_clipping (s);
4334 XCopyArea (s->display, pixmap, s->window, s->gc,
4335 0, 0, s->background_width, s->height, s->x, s->y);
4336 XFreePixmap (s->display, pixmap);
4337 }
4338 else
4339 x_draw_image_foreground (s);
b5210ea7 4340
06a2c219
GM
4341 /* If we must draw a relief around the image, do it. */
4342 if (s->img->relief
4343 || s->hl == DRAW_IMAGE_RAISED
4344 || s->hl == DRAW_IMAGE_SUNKEN)
4345 x_draw_image_relief (s);
4346}
8c1a6a84 4347
990ba854 4348
06a2c219 4349/* Draw stretch glyph string S. */
dc43ef94 4350
06a2c219
GM
4351static void
4352x_draw_stretch_glyph_string (s)
4353 struct glyph_string *s;
4354{
4355 xassert (s->first_glyph->type == STRETCH_GLYPH);
4356 s->stippled_p = s->face->stipple != 0;
990ba854 4357
06a2c219
GM
4358 if (s->hl == DRAW_CURSOR
4359 && !x_stretch_cursor_p)
4360 {
4361 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4362 as wide as the stretch glyph. */
4363 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4364
06a2c219
GM
4365 /* Draw cursor. */
4366 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4367
06a2c219
GM
4368 /* Clear rest using the GC of the original non-cursor face. */
4369 if (width < s->background_width)
4370 {
06a2c219
GM
4371 int x = s->x + width, y = s->y;
4372 int w = s->background_width - width, h = s->height;
4373 XRectangle r;
b7f83f9e 4374 GC gc;
dc43ef94 4375
b7f83f9e
GM
4376 if (s->row->mouse_face_p
4377 && cursor_in_mouse_face_p (s->w))
4378 {
4379 x_set_mouse_face_gc (s);
4380 gc = s->gc;
4381 }
4382 else
4383 gc = s->face->gc;
4384
06a2c219
GM
4385 x_get_glyph_string_clip_rect (s, &r);
4386 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
b7f83f9e 4387
06a2c219
GM
4388 if (s->face->stipple)
4389 {
4390 /* Fill background with a stipple pattern. */
4391 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4392 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4393 XSetFillStyle (s->display, gc, FillSolid);
4394 }
4395 else
4396 {
4397 XGCValues xgcv;
4398 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4399 XSetForeground (s->display, gc, xgcv.background);
4400 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4401 XSetForeground (s->display, gc, xgcv.foreground);
4402 }
4403 }
4404 }
61e9f9f3 4405 else if (!s->background_filled_p)
06a2c219
GM
4406 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4407 s->height);
4408
4409 s->background_filled_p = 1;
4410}
4411
4412
4413/* Draw glyph string S. */
4414
4415static void
4416x_draw_glyph_string (s)
4417 struct glyph_string *s;
4418{
4458cf11
KH
4419 int relief_drawn_p = 0;
4420
06a2c219
GM
4421 /* If S draws into the background of its successor, draw the
4422 background of the successor first so that S can draw into it.
4423 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4424 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4425 {
4426 xassert (s->next->img == NULL);
4427 x_set_glyph_string_gc (s->next);
4428 x_set_glyph_string_clipping (s->next);
4429 x_draw_glyph_string_background (s->next, 1);
4430 }
97210f4e 4431
06a2c219
GM
4432 /* Set up S->gc, set clipping and draw S. */
4433 x_set_glyph_string_gc (s);
06a2c219 4434
4458cf11
KH
4435 /* Draw relief (if any) in advance for char/composition so that the
4436 glyph string can be drawn over it. */
4437 if (!s->for_overlaps_p
4438 && s->face->box != FACE_NO_BOX
4439 && (s->first_glyph->type == CHAR_GLYPH
4440 || s->first_glyph->type == COMPOSITE_GLYPH))
4441
4442 {
e6269cbb 4443 x_set_glyph_string_clipping (s);
4458cf11
KH
4444 x_draw_glyph_string_background (s, 1);
4445 x_draw_glyph_string_box (s);
e6269cbb 4446 x_set_glyph_string_clipping (s);
4458cf11
KH
4447 relief_drawn_p = 1;
4448 }
e6269cbb
GM
4449 else
4450 x_set_glyph_string_clipping (s);
4458cf11 4451
06a2c219
GM
4452 switch (s->first_glyph->type)
4453 {
4454 case IMAGE_GLYPH:
4455 x_draw_image_glyph_string (s);
4456 break;
4457
4458 case STRETCH_GLYPH:
4459 x_draw_stretch_glyph_string (s);
4460 break;
4461
4462 case CHAR_GLYPH:
66ac4b0e
GM
4463 if (s->for_overlaps_p)
4464 s->background_filled_p = 1;
4465 else
4466 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4467 x_draw_glyph_string_foreground (s);
4468 break;
4469
b4192550
KH
4470 case COMPOSITE_GLYPH:
4471 if (s->for_overlaps_p || s->gidx > 0)
4472 s->background_filled_p = 1;
4473 else
4474 x_draw_glyph_string_background (s, 1);
4475 x_draw_composite_glyph_string_foreground (s);
4476 break;
4477
06a2c219
GM
4478 default:
4479 abort ();
4480 }
4481
66ac4b0e 4482 if (!s->for_overlaps_p)
06a2c219 4483 {
66ac4b0e
GM
4484 /* Draw underline. */
4485 if (s->face->underline_p)
4486 {
e24e84cc
GM
4487 unsigned long tem, h;
4488 int y;
06a2c219 4489
e24e84cc 4490 /* Get the underline thickness. Default is 1 pixel. */
66ac4b0e
GM
4491 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4492 h = 1;
e24e84cc
GM
4493
4494 /* Get the underline position. This is the recommended
4495 vertical offset in pixels from the baseline to the top of
4496 the underline. This is a signed value according to the
4497 specs, and its default is
4498
4499 ROUND ((maximum descent) / 2), with
4500 ROUND(x) = floor (x + 0.5) */
4501
a72d5ce5
GM
4502 if (x_use_underline_position_properties
4503 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
e24e84cc
GM
4504 y = s->ybase + (long) tem;
4505 else if (s->face->font)
4506 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4507 else
a02f1be0 4508 y = s->y + s->height - h;
06a2c219 4509
66ac4b0e 4510 if (s->face->underline_defaulted_p)
e24e84cc
GM
4511 XFillRectangle (s->display, s->window, s->gc,
4512 s->x, y, s->width, h);
66ac4b0e
GM
4513 else
4514 {
4515 XGCValues xgcv;
4516 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4517 XSetForeground (s->display, s->gc, s->face->underline_color);
e24e84cc
GM
4518 XFillRectangle (s->display, s->window, s->gc,
4519 s->x, y, s->width, h);
66ac4b0e
GM
4520 XSetForeground (s->display, s->gc, xgcv.foreground);
4521 }
dc6f92b8 4522 }
07e34cb0 4523
66ac4b0e
GM
4524 /* Draw overline. */
4525 if (s->face->overline_p)
06a2c219 4526 {
66ac4b0e
GM
4527 unsigned long dy = 0, h = 1;
4528
4529 if (s->face->overline_color_defaulted_p)
4530 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4531 s->width, h);
4532 else
4533 {
4534 XGCValues xgcv;
4535 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4536 XSetForeground (s->display, s->gc, s->face->overline_color);
4537 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4538 s->width, h);
4539 XSetForeground (s->display, s->gc, xgcv.foreground);
4540 }
06a2c219 4541 }
06a2c219 4542
66ac4b0e
GM
4543 /* Draw strike-through. */
4544 if (s->face->strike_through_p)
06a2c219 4545 {
66ac4b0e
GM
4546 unsigned long h = 1;
4547 unsigned long dy = (s->height - h) / 2;
4548
4549 if (s->face->strike_through_color_defaulted_p)
4550 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4551 s->width, h);
4552 else
4553 {
4554 XGCValues xgcv;
4555 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4556 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4557 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4558 s->width, h);
4559 XSetForeground (s->display, s->gc, xgcv.foreground);
4560 }
06a2c219 4561 }
06a2c219 4562
4458cf11
KH
4563 /* Draw relief if not yet drawn. */
4564 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
66ac4b0e
GM
4565 x_draw_glyph_string_box (s);
4566 }
06a2c219
GM
4567
4568 /* Reset clipping. */
4569 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4570}
07e34cb0 4571
06a2c219 4572
b4192550
KH
4573static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4574 struct face **, int));
06a2c219 4575
06a2c219 4576
209f68d9
GM
4577/* Fill glyph string S with composition components specified by S->cmp.
4578
b4192550
KH
4579 FACES is an array of faces for all components of this composition.
4580 S->gidx is the index of the first component for S.
4581 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4582 use its physical height for clipping.
06a2c219 4583
b4192550 4584 Value is the index of a component not in S. */
07e34cb0 4585
b4192550
KH
4586static int
4587x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4588 struct glyph_string *s;
b4192550 4589 struct face **faces;
66ac4b0e 4590 int overlaps_p;
07e34cb0 4591{
b4192550 4592 int i;
06a2c219 4593
b4192550 4594 xassert (s);
06a2c219 4595
b4192550 4596 s->for_overlaps_p = overlaps_p;
06a2c219 4597
b4192550
KH
4598 s->face = faces[s->gidx];
4599 s->font = s->face->font;
4600 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4601
b4192550
KH
4602 /* For all glyphs of this composition, starting at the offset
4603 S->gidx, until we reach the end of the definition or encounter a
4604 glyph that requires the different face, add it to S. */
4605 ++s->nchars;
4606 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4607 ++s->nchars;
06a2c219 4608
b4192550
KH
4609 /* All glyph strings for the same composition has the same width,
4610 i.e. the width set for the first component of the composition. */
06a2c219 4611
06a2c219
GM
4612 s->width = s->first_glyph->pixel_width;
4613
4614 /* If the specified font could not be loaded, use the frame's
4615 default font, but record the fact that we couldn't load it in
4616 the glyph string so that we can draw rectangles for the
4617 characters of the glyph string. */
4618 if (s->font == NULL)
4619 {
4620 s->font_not_found_p = 1;
4621 s->font = FRAME_FONT (s->f);
4622 }
4623
4624 /* Adjust base line for subscript/superscript text. */
4625 s->ybase += s->first_glyph->voffset;
4626
4627 xassert (s->face && s->face->gc);
4628
4629 /* This glyph string must always be drawn with 16-bit functions. */
4630 s->two_byte_p = 1;
b4192550
KH
4631
4632 return s->gidx + s->nchars;
06a2c219
GM
4633}
4634
4635
209f68d9
GM
4636/* Fill glyph string S from a sequence of character glyphs.
4637
06a2c219 4638 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4639 first glyph to consider, END is the index of the last + 1.
4640 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4641 use its physical height for clipping.
66ac4b0e
GM
4642
4643 Value is the index of the first glyph not in S. */
06a2c219
GM
4644
4645static int
66ac4b0e 4646x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4647 struct glyph_string *s;
4648 int face_id;
66ac4b0e 4649 int start, end, overlaps_p;
06a2c219
GM
4650{
4651 struct glyph *glyph, *last;
4652 int voffset;
ee569018 4653 int glyph_not_available_p;
06a2c219 4654
06a2c219
GM
4655 xassert (s->f == XFRAME (s->w->frame));
4656 xassert (s->nchars == 0);
4657 xassert (start >= 0 && end > start);
4658
66ac4b0e 4659 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4660 glyph = s->row->glyphs[s->area] + start;
4661 last = s->row->glyphs[s->area] + end;
4662 voffset = glyph->voffset;
4663
ee569018
KH
4664 glyph_not_available_p = glyph->glyph_not_available_p;
4665
06a2c219
GM
4666 while (glyph < last
4667 && glyph->type == CHAR_GLYPH
4668 && glyph->voffset == voffset
ee569018
KH
4669 /* Same face id implies same font, nowadays. */
4670 && glyph->face_id == face_id
4671 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4672 {
ee569018
KH
4673 int two_byte_p;
4674
06a2c219 4675 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4676 s->char2b + s->nchars,
4677 &two_byte_p);
4678 s->two_byte_p = two_byte_p;
06a2c219
GM
4679 ++s->nchars;
4680 xassert (s->nchars <= end - start);
4681 s->width += glyph->pixel_width;
4682 ++glyph;
4683 }
4684
4685 s->font = s->face->font;
4686 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4687
4688 /* If the specified font could not be loaded, use the frame's font,
4689 but record the fact that we couldn't load it in
4690 S->font_not_found_p so that we can draw rectangles for the
4691 characters of the glyph string. */
ee569018 4692 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4693 {
4694 s->font_not_found_p = 1;
4695 s->font = FRAME_FONT (s->f);
4696 }
4697
4698 /* Adjust base line for subscript/superscript text. */
4699 s->ybase += voffset;
66ac4b0e 4700
06a2c219
GM
4701 xassert (s->face && s->face->gc);
4702 return glyph - s->row->glyphs[s->area];
07e34cb0 4703}
dc6f92b8 4704
06a2c219
GM
4705
4706/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4707
dfcf069d 4708static void
06a2c219
GM
4709x_fill_image_glyph_string (s)
4710 struct glyph_string *s;
4711{
4712 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4713 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4714 xassert (s->img);
43d120d8 4715 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4716 s->font = s->face->font;
4717 s->width = s->first_glyph->pixel_width;
4718
4719 /* Adjust base line for subscript/superscript text. */
4720 s->ybase += s->first_glyph->voffset;
4721}
4722
4723
209f68d9 4724/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4725
209f68d9
GM
4726 ROW is the glyph row in which the glyphs are found, AREA is the
4727 area within the row. START is the index of the first glyph to
4728 consider, END is the index of the last + 1.
4729
4730 Value is the index of the first glyph not in S. */
4731
4732static int
4733x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4734 struct glyph_string *s;
209f68d9
GM
4735 struct glyph_row *row;
4736 enum glyph_row_area area;
4737 int start, end;
06a2c219 4738{
209f68d9
GM
4739 struct glyph *glyph, *last;
4740 int voffset, face_id;
4741
06a2c219 4742 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4743
4744 glyph = s->row->glyphs[s->area] + start;
4745 last = s->row->glyphs[s->area] + end;
4746 face_id = glyph->face_id;
4747 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4748 s->font = s->face->font;
209f68d9
GM
4749 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4750 s->width = glyph->pixel_width;
4751 voffset = glyph->voffset;
4752
4753 for (++glyph;
4754 (glyph < last
4755 && glyph->type == STRETCH_GLYPH
4756 && glyph->voffset == voffset
4757 && glyph->face_id == face_id);
4758 ++glyph)
4759 s->width += glyph->pixel_width;
06a2c219
GM
4760
4761 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4762 s->ybase += voffset;
4763
c296fc01
GM
4764 /* The case that face->gc == 0 is handled when drawing the glyph
4765 string by calling PREPARE_FACE_FOR_DISPLAY. */
4766 xassert (s->face);
209f68d9 4767 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4768}
4769
4770
4771/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4772 of XChar2b structures for S; it can't be allocated in
4773 x_init_glyph_string because it must be allocated via `alloca'. W
4774 is the window on which S is drawn. ROW and AREA are the glyph row
4775 and area within the row from which S is constructed. START is the
4776 index of the first glyph structure covered by S. HL is a
4777 face-override for drawing S. */
4778
4779static void
4780x_init_glyph_string (s, char2b, w, row, area, start, hl)
4781 struct glyph_string *s;
4782 XChar2b *char2b;
4783 struct window *w;
4784 struct glyph_row *row;
4785 enum glyph_row_area area;
4786 int start;
4787 enum draw_glyphs_face hl;
4788{
4789 bzero (s, sizeof *s);
4790 s->w = w;
4791 s->f = XFRAME (w->frame);
4792 s->display = FRAME_X_DISPLAY (s->f);
4793 s->window = FRAME_X_WINDOW (s->f);
4794 s->char2b = char2b;
4795 s->hl = hl;
4796 s->row = row;
4797 s->area = area;
4798 s->first_glyph = row->glyphs[area] + start;
4799 s->height = row->height;
4800 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4801
9ea173e8
GM
4802 /* Display the internal border below the tool-bar window. */
4803 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4804 s->y -= s->f->output_data.x->internal_border_width;
4805
4806 s->ybase = s->y + row->ascent;
4807}
4808
4809
4810/* Set background width of glyph string S. START is the index of the
4811 first glyph following S. LAST_X is the right-most x-position + 1
4812 in the drawing area. */
4813
4814static INLINE void
4815x_set_glyph_string_background_width (s, start, last_x)
4816 struct glyph_string *s;
4817 int start;
4818 int last_x;
4819{
4820 /* If the face of this glyph string has to be drawn to the end of
4821 the drawing area, set S->extends_to_end_of_line_p. */
4822 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4823
4824 if (start == s->row->used[s->area]
eb79f5cc 4825 && s->area == TEXT_AREA
7b0870b2
GM
4826 && ((s->hl == DRAW_NORMAL_TEXT
4827 && (s->row->fill_line_p
4828 || s->face->background != default_face->background
4829 || s->face->stipple != default_face->stipple
4830 || s->row->mouse_face_p))
327f42ee
GM
4831 || s->hl == DRAW_MOUSE_FACE
4832 || ((s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN)
4833 && s->row->fill_line_p)))
7b0870b2 4834 s->extends_to_end_of_line_p = 1;
06a2c219
GM
4835
4836 /* If S extends its face to the end of the line, set its
4837 background_width to the distance to the right edge of the drawing
4838 area. */
4839 if (s->extends_to_end_of_line_p)
1da3fd71 4840 s->background_width = last_x - s->x + 1;
06a2c219
GM
4841 else
4842 s->background_width = s->width;
4843}
4844
4845
4846/* Add a glyph string for a stretch glyph to the list of strings
4847 between HEAD and TAIL. START is the index of the stretch glyph in
4848 row area AREA of glyph row ROW. END is the index of the last glyph
4849 in that glyph row area. X is the current output position assigned
4850 to the new glyph string constructed. HL overrides that face of the
4851 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4852 is the right-most x-position of the drawing area. */
4853
8abee2e1
DL
4854/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4855 and below -- keep them on one line. */
4856#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4857 do \
4858 { \
4859 s = (struct glyph_string *) alloca (sizeof *s); \
4860 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4861 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4862 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4863 s->x = (X); \
4864 } \
4865 while (0)
4866
4867
4868/* Add a glyph string for an image glyph to the list of strings
4869 between HEAD and TAIL. START is the index of the image glyph in
4870 row area AREA of glyph row ROW. END is the index of the last glyph
4871 in that glyph row area. X is the current output position assigned
4872 to the new glyph string constructed. HL overrides that face of the
4873 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4874 is the right-most x-position of the drawing area. */
4875
8abee2e1 4876#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4877 do \
4878 { \
4879 s = (struct glyph_string *) alloca (sizeof *s); \
4880 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4881 x_fill_image_glyph_string (s); \
4882 x_append_glyph_string (&HEAD, &TAIL, s); \
4883 ++START; \
4884 s->x = (X); \
4885 } \
4886 while (0)
4887
4888
4889/* Add a glyph string for a sequence of character glyphs to the list
4890 of strings between HEAD and TAIL. START is the index of the first
4891 glyph in row area AREA of glyph row ROW that is part of the new
4892 glyph string. END is the index of the last glyph in that glyph row
4893 area. X is the current output position assigned to the new glyph
4894 string constructed. HL overrides that face of the glyph; e.g. it
4895 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4896 right-most x-position of the drawing area. */
4897
8abee2e1 4898#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4899 do \
4900 { \
3e71d8f2 4901 int c, face_id; \
06a2c219
GM
4902 XChar2b *char2b; \
4903 \
43d120d8 4904 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4905 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4906 \
b4192550
KH
4907 s = (struct glyph_string *) alloca (sizeof *s); \
4908 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4909 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4910 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4911 s->x = (X); \
4912 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4913 OVERLAPS_P); \
06a2c219
GM
4914 } \
4915 while (0)
4916
4917
b4192550
KH
4918/* Add a glyph string for a composite sequence to the list of strings
4919 between HEAD and TAIL. START is the index of the first glyph in
4920 row area AREA of glyph row ROW that is part of the new glyph
4921 string. END is the index of the last glyph in that glyph row area.
4922 X is the current output position assigned to the new glyph string
4923 constructed. HL overrides that face of the glyph; e.g. it is
4924 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4925 x-position of the drawing area. */
4926
6c27ec25 4927#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4928 do { \
43d120d8
KH
4929 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4930 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4931 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4932 struct composition *cmp = composition_table[cmp_id]; \
4933 int glyph_len = cmp->glyph_len; \
4934 XChar2b *char2b; \
4935 struct face **faces; \
4936 struct glyph_string *first_s = NULL; \
4937 int n; \
4938 \
ee569018 4939 base_face = base_face->ascii_face; \
b4192550
KH
4940 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4941 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4942 /* At first, fill in `char2b' and `faces'. */ \
4943 for (n = 0; n < glyph_len; n++) \
4944 { \
43d120d8 4945 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4946 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4947 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4948 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4949 this_face_id, char2b + n, 1); \
b4192550
KH
4950 } \
4951 \
4952 /* Make glyph_strings for each glyph sequence that is drawable by \
4953 the same face, and append them to HEAD/TAIL. */ \
4954 for (n = 0; n < cmp->glyph_len;) \
4955 { \
4956 s = (struct glyph_string *) alloca (sizeof *s); \
4957 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4958 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4959 s->cmp = cmp; \
4960 s->gidx = n; \
b4192550
KH
4961 s->x = (X); \
4962 \
4963 if (n == 0) \
4964 first_s = s; \
4965 \
4966 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4967 } \
4968 \
4969 ++START; \
4970 s = first_s; \
4971 } while (0)
4972
4973
06a2c219
GM
4974/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4975 of AREA of glyph row ROW on window W between indices START and END.
4976 HL overrides the face for drawing glyph strings, e.g. it is
4977 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4978 x-positions of the drawing area.
4979
4980 This is an ugly monster macro construct because we must use alloca
4981 to allocate glyph strings (because x_draw_glyphs can be called
4982 asynchronously). */
4983
8abee2e1 4984#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4985 do \
4986 { \
4987 HEAD = TAIL = NULL; \
4988 while (START < END) \
4989 { \
4990 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4991 switch (first_glyph->type) \
4992 { \
4993 case CHAR_GLYPH: \
4994 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
4995 TAIL, HL, X, LAST_X, \
4996 OVERLAPS_P); \
06a2c219
GM
4997 break; \
4998 \
b4192550
KH
4999 case COMPOSITE_GLYPH: \
5000 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
5001 HEAD, TAIL, HL, X, LAST_X,\
5002 OVERLAPS_P); \
5003 break; \
5004 \
06a2c219
GM
5005 case STRETCH_GLYPH: \
5006 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
5007 HEAD, TAIL, HL, X, LAST_X); \
5008 break; \
5009 \
5010 case IMAGE_GLYPH: \
5011 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
5012 TAIL, HL, X, LAST_X); \
5013 break; \
5014 \
5015 default: \
5016 abort (); \
5017 } \
5018 \
5019 x_set_glyph_string_background_width (s, START, LAST_X); \
5020 (X) += s->width; \
5021 } \
5022 } \
5023 while (0)
5024
5025
5026/* Draw glyphs between START and END in AREA of ROW on window W,
5027 starting at x-position X. X is relative to AREA in W. HL is a
5028 face-override with the following meaning:
5029
5030 DRAW_NORMAL_TEXT draw normally
5031 DRAW_CURSOR draw in cursor face
5032 DRAW_MOUSE_FACE draw in mouse face.
5033 DRAW_INVERSE_VIDEO draw in mode line face
5034 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
5035 DRAW_IMAGE_RAISED draw an image with a raised relief around it
5036
66ac4b0e
GM
5037 If OVERLAPS_P is non-zero, draw only the foreground of characters
5038 and clip to the physical height of ROW.
5039
06a2c219
GM
5040 Value is the x-position reached, relative to AREA of W. */
5041
5042static int
f0a48a01 5043x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
06a2c219
GM
5044 struct window *w;
5045 int x;
5046 struct glyph_row *row;
5047 enum glyph_row_area area;
5048 int start, end;
5049 enum draw_glyphs_face hl;
66ac4b0e 5050 int overlaps_p;
dc6f92b8 5051{
06a2c219
GM
5052 struct glyph_string *head, *tail;
5053 struct glyph_string *s;
5054 int last_x, area_width;
5055 int x_reached;
5056 int i, j;
5057
5058 /* Let's rather be paranoid than getting a SEGV. */
06a2c219 5059 end = min (end, row->used[area]);
a8710abf
GM
5060 start = max (0, start);
5061 start = min (end, start);
06a2c219
GM
5062
5063 /* Translate X to frame coordinates. Set last_x to the right
5064 end of the drawing area. */
5065 if (row->full_width_p)
5066 {
5067 /* X is relative to the left edge of W, without scroll bars
3f332ef3 5068 or fringes. */
06a2c219 5069 struct frame *f = XFRAME (w->frame);
06a2c219 5070 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 5071
06a2c219
GM
5072 x += window_left_x;
5073 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
5074 last_x = window_left_x + area_width;
5075
5076 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5077 {
110859fc 5078 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
5079 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
5080 last_x += width;
5081 else
5082 x -= width;
5083 }
dc6f92b8 5084
b9432a85 5085 x += FRAME_INTERNAL_BORDER_WIDTH (f);
98fedd97 5086 last_x += FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
5087 }
5088 else
dc6f92b8 5089 {
06a2c219
GM
5090 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
5091 area_width = window_box_width (w, area);
5092 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
5093 }
5094
06a2c219
GM
5095 /* Build a doubly-linked list of glyph_string structures between
5096 head and tail from what we have to draw. Note that the macro
5097 BUILD_GLYPH_STRINGS will modify its start parameter. That's
5098 the reason we use a separate variable `i'. */
5099 i = start;
66ac4b0e
GM
5100 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
5101 overlaps_p);
06a2c219
GM
5102 if (tail)
5103 x_reached = tail->x + tail->background_width;
5104 else
5105 x_reached = x;
90e65f07 5106
06a2c219
GM
5107 /* If there are any glyphs with lbearing < 0 or rbearing > width in
5108 the row, redraw some glyphs in front or following the glyph
5109 strings built above. */
a8710abf 5110 if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
5111 {
5112 int dummy_x = 0;
5113 struct glyph_string *h, *t;
5114
5115 /* Compute overhangs for all glyph strings. */
5116 for (s = head; s; s = s->next)
5117 x_compute_glyph_string_overhangs (s);
5118
5119 /* Prepend glyph strings for glyphs in front of the first glyph
5120 string that are overwritten because of the first glyph
5121 string's left overhang. The background of all strings
5122 prepended must be drawn because the first glyph string
5123 draws over it. */
5124 i = x_left_overwritten (head);
5125 if (i >= 0)
5126 {
5127 j = i;
5128 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
5129 DRAW_NORMAL_TEXT, dummy_x, last_x,
5130 overlaps_p);
06a2c219 5131 start = i;
06a2c219
GM
5132 x_compute_overhangs_and_x (t, head->x, 1);
5133 x_prepend_glyph_string_lists (&head, &tail, h, t);
5134 }
58769bee 5135
06a2c219
GM
5136 /* Prepend glyph strings for glyphs in front of the first glyph
5137 string that overwrite that glyph string because of their
5138 right overhang. For these strings, only the foreground must
5139 be drawn, because it draws over the glyph string at `head'.
5140 The background must not be drawn because this would overwrite
5141 right overhangs of preceding glyphs for which no glyph
5142 strings exist. */
5143 i = x_left_overwriting (head);
5144 if (i >= 0)
5145 {
5146 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
5147 DRAW_NORMAL_TEXT, dummy_x, last_x,
5148 overlaps_p);
06a2c219
GM
5149 for (s = h; s; s = s->next)
5150 s->background_filled_p = 1;
06a2c219
GM
5151 x_compute_overhangs_and_x (t, head->x, 1);
5152 x_prepend_glyph_string_lists (&head, &tail, h, t);
5153 }
dbcb258a 5154
06a2c219
GM
5155 /* Append glyphs strings for glyphs following the last glyph
5156 string tail that are overwritten by tail. The background of
5157 these strings has to be drawn because tail's foreground draws
5158 over it. */
5159 i = x_right_overwritten (tail);
5160 if (i >= 0)
5161 {
5162 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5163 DRAW_NORMAL_TEXT, x, last_x,
5164 overlaps_p);
06a2c219
GM
5165 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5166 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219 5167 }
dc6f92b8 5168
06a2c219
GM
5169 /* Append glyph strings for glyphs following the last glyph
5170 string tail that overwrite tail. The foreground of such
5171 glyphs has to be drawn because it writes into the background
5172 of tail. The background must not be drawn because it could
5173 paint over the foreground of following glyphs. */
5174 i = x_right_overwriting (tail);
5175 if (i >= 0)
5176 {
5177 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5178 DRAW_NORMAL_TEXT, x, last_x,
5179 overlaps_p);
06a2c219
GM
5180 for (s = h; s; s = s->next)
5181 s->background_filled_p = 1;
5182 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5183 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219
GM
5184 }
5185 }
58769bee 5186
06a2c219
GM
5187 /* Draw all strings. */
5188 for (s = head; s; s = s->next)
5189 x_draw_glyph_string (s);
dc6f92b8 5190
bb313871
GM
5191 if (area == TEXT_AREA
5192 && !row->full_width_p
5193 /* When drawing overlapping rows, only the glyph strings'
5194 foreground is drawn, which doesn't erase a cursor
5195 completely. */
5196 && !overlaps_p)
f0a48a01
GM
5197 {
5198 int x0 = head ? head->x : x;
5199 int x1 = tail ? tail->x + tail->background_width : x;
5200
5201 x0 = FRAME_TO_WINDOW_PIXEL_X (w, x0);
5202 x1 = FRAME_TO_WINDOW_PIXEL_X (w, x1);
5203
bb313871 5204 if (XFASTINT (w->left_margin_width) != 0)
f0a48a01
GM
5205 {
5206 int left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
5207 x0 -= left_area_width;
5208 x1 -= left_area_width;
5209 }
5210
60626bab
GM
5211 notice_overwritten_cursor (w, area, x0, x1,
5212 row->y, MATRIX_ROW_BOTTOM_Y (row));
f0a48a01
GM
5213 }
5214
06a2c219
GM
5215 /* Value is the x-position up to which drawn, relative to AREA of W.
5216 This doesn't include parts drawn because of overhangs. */
5217 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
5218 if (!row->full_width_p)
5219 {
f0a48a01 5220 if (area > LEFT_MARGIN_AREA && XFASTINT (w->left_margin_width) != 0)
06a2c219
GM
5221 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
5222 if (area > TEXT_AREA)
5223 x_reached -= window_box_width (w, TEXT_AREA);
5224 }
a8710abf 5225
06a2c219
GM
5226 return x_reached;
5227}
dc6f92b8 5228
dc6f92b8 5229
66ac4b0e
GM
5230/* Fix the display of area AREA of overlapping row ROW in window W. */
5231
5232static void
5233x_fix_overlapping_area (w, row, area)
5234 struct window *w;
5235 struct glyph_row *row;
5236 enum glyph_row_area area;
5237{
5238 int i, x;
5239
5240 BLOCK_INPUT;
5241
5242 if (area == LEFT_MARGIN_AREA)
5243 x = 0;
5244 else if (area == TEXT_AREA)
5245 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5246 else
5247 x = (window_box_width (w, LEFT_MARGIN_AREA)
5248 + window_box_width (w, TEXT_AREA));
5249
5250 for (i = 0; i < row->used[area];)
5251 {
5252 if (row->glyphs[area][i].overlaps_vertically_p)
5253 {
5254 int start = i, start_x = x;
5255
5256 do
5257 {
5258 x += row->glyphs[area][i].pixel_width;
5259 ++i;
5260 }
5261 while (i < row->used[area]
5262 && row->glyphs[area][i].overlaps_vertically_p);
5263
5264 x_draw_glyphs (w, start_x, row, area, start, i,
f0a48a01 5265 DRAW_NORMAL_TEXT, 1);
66ac4b0e
GM
5266 }
5267 else
5268 {
5269 x += row->glyphs[area][i].pixel_width;
5270 ++i;
5271 }
5272 }
5273
5274 UNBLOCK_INPUT;
5275}
5276
5277
06a2c219
GM
5278/* Output LEN glyphs starting at START at the nominal cursor position.
5279 Advance the nominal cursor over the text. The global variable
5280 updated_window contains the window being updated, updated_row is
5281 the glyph row being updated, and updated_area is the area of that
5282 row being updated. */
dc6f92b8 5283
06a2c219
GM
5284static void
5285x_write_glyphs (start, len)
5286 struct glyph *start;
5287 int len;
5288{
f0a48a01 5289 int x, hpos;
d9cdbb3d 5290
06a2c219 5291 xassert (updated_window && updated_row);
dc6f92b8 5292 BLOCK_INPUT;
06a2c219
GM
5293
5294 /* Write glyphs. */
dc6f92b8 5295
06a2c219
GM
5296 hpos = start - updated_row->glyphs[updated_area];
5297 x = x_draw_glyphs (updated_window, output_cursor.x,
5298 updated_row, updated_area,
5299 hpos, hpos + len,
f0a48a01 5300 DRAW_NORMAL_TEXT, 0);
dc6f92b8
JB
5301
5302 UNBLOCK_INPUT;
06a2c219
GM
5303
5304 /* Advance the output cursor. */
5305 output_cursor.hpos += len;
5306 output_cursor.x = x;
dc6f92b8
JB
5307}
5308
0cdd0c9f 5309
06a2c219 5310/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 5311
06a2c219
GM
5312static void
5313x_insert_glyphs (start, len)
5314 struct glyph *start;
5315 register int len;
5316{
5317 struct frame *f;
5318 struct window *w;
5319 int line_height, shift_by_width, shifted_region_width;
5320 struct glyph_row *row;
5321 struct glyph *glyph;
2beb36f9 5322 int frame_x, frame_y, hpos;
58769bee 5323
06a2c219 5324 xassert (updated_window && updated_row);
0cdd0c9f 5325 BLOCK_INPUT;
06a2c219
GM
5326 w = updated_window;
5327 f = XFRAME (WINDOW_FRAME (w));
5328
5329 /* Get the height of the line we are in. */
5330 row = updated_row;
5331 line_height = row->height;
5332
5333 /* Get the width of the glyphs to insert. */
5334 shift_by_width = 0;
5335 for (glyph = start; glyph < start + len; ++glyph)
5336 shift_by_width += glyph->pixel_width;
5337
5338 /* Get the width of the region to shift right. */
5339 shifted_region_width = (window_box_width (w, updated_area)
5340 - output_cursor.x
5341 - shift_by_width);
5342
5343 /* Shift right. */
bf0ab8a2 5344 frame_x = window_box_left (w, updated_area) + output_cursor.x;
06a2c219
GM
5345 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
5346 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5347 f->output_data.x->normal_gc,
5348 frame_x, frame_y,
5349 shifted_region_width, line_height,
5350 frame_x + shift_by_width, frame_y);
5351
5352 /* Write the glyphs. */
5353 hpos = start - row->glyphs[updated_area];
5354 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
f0a48a01 5355 DRAW_NORMAL_TEXT, 0);
06a2c219
GM
5356
5357 /* Advance the output cursor. */
5358 output_cursor.hpos += len;
5359 output_cursor.x += shift_by_width;
0cdd0c9f
RS
5360 UNBLOCK_INPUT;
5361}
0cdd0c9f 5362
0cdd0c9f 5363
06a2c219
GM
5364/* Delete N glyphs at the nominal cursor position. Not implemented
5365 for X frames. */
c83febd7
RS
5366
5367static void
06a2c219
GM
5368x_delete_glyphs (n)
5369 register int n;
c83febd7 5370{
06a2c219 5371 abort ();
c83febd7
RS
5372}
5373
0cdd0c9f 5374
c5e6e06b
GM
5375/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
5376 If they are <= 0, this is probably an error. */
5377
5378void
5379x_clear_area (dpy, window, x, y, width, height, exposures)
5380 Display *dpy;
5381 Window window;
5382 int x, y;
5383 int width, height;
5384 int exposures;
5385{
5386 xassert (width > 0 && height > 0);
5387 XClearArea (dpy, window, x, y, width, height, exposures);
5388}
5389
5390
06a2c219
GM
5391/* Erase the current text line from the nominal cursor position
5392 (inclusive) to pixel column TO_X (exclusive). The idea is that
5393 everything from TO_X onward is already erased.
5394
5395 TO_X is a pixel position relative to updated_area of
5396 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 5397
06a2c219
GM
5398static void
5399x_clear_end_of_line (to_x)
5400 int to_x;
5401{
5402 struct frame *f;
5403 struct window *w = updated_window;
5404 int max_x, min_y, max_y;
5405 int from_x, from_y, to_y;
5406
5407 xassert (updated_window && updated_row);
5408 f = XFRAME (w->frame);
5409
5410 if (updated_row->full_width_p)
5411 {
5412 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
5413 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5414 && !w->pseudo_window_p)
5415 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 5416 }
06a2c219
GM
5417 else
5418 max_x = window_box_width (w, updated_area);
5419 max_y = window_text_bottom_y (w);
dc6f92b8 5420
06a2c219
GM
5421 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5422 of window. For TO_X > 0, truncate to end of drawing area. */
5423 if (to_x == 0)
5424 return;
5425 else if (to_x < 0)
5426 to_x = max_x;
5427 else
5428 to_x = min (to_x, max_x);
dbc4e1c1 5429
06a2c219
GM
5430 to_y = min (max_y, output_cursor.y + updated_row->height);
5431
5432 /* Notice if the cursor will be cleared by this operation. */
5433 if (!updated_row->full_width_p)
60626bab
GM
5434 notice_overwritten_cursor (w, updated_area,
5435 output_cursor.x, -1,
5436 updated_row->y,
5437 MATRIX_ROW_BOTTOM_Y (updated_row));
dbc4e1c1 5438
06a2c219
GM
5439 from_x = output_cursor.x;
5440
5441 /* Translate to frame coordinates. */
5442 if (updated_row->full_width_p)
5443 {
5444 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5445 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5446 }
0cdd0c9f
RS
5447 else
5448 {
06a2c219
GM
5449 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5450 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5451 }
5452
045dee35 5453 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5454 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5455 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5456
5457 /* Prevent inadvertently clearing to end of the X window. */
5458 if (to_x > from_x && to_y > from_y)
5459 {
5460 BLOCK_INPUT;
c5e6e06b
GM
5461 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5462 from_x, from_y, to_x - from_x, to_y - from_y,
5463 False);
06a2c219 5464 UNBLOCK_INPUT;
0cdd0c9f 5465 }
0cdd0c9f 5466}
dbc4e1c1 5467
0cdd0c9f 5468
06a2c219 5469/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5470 frame. Otherwise clear the selected frame. */
06a2c219
GM
5471
5472static void
5473x_clear_frame ()
0cdd0c9f 5474{
06a2c219 5475 struct frame *f;
0cdd0c9f 5476
06a2c219
GM
5477 if (updating_frame)
5478 f = updating_frame;
0cdd0c9f 5479 else
b86bd3dd 5480 f = SELECTED_FRAME ();
58769bee 5481
06a2c219
GM
5482 /* Clearing the frame will erase any cursor, so mark them all as no
5483 longer visible. */
5484 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5485 output_cursor.hpos = output_cursor.vpos = 0;
5486 output_cursor.x = -1;
5487
5488 /* We don't set the output cursor here because there will always
5489 follow an explicit cursor_to. */
5490 BLOCK_INPUT;
5491 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5492
5493 /* We have to clear the scroll bars, too. If we have changed
5494 colors or something like that, then they should be notified. */
5495 x_scroll_bar_clear (f);
0cdd0c9f 5496
06a2c219
GM
5497 XFlush (FRAME_X_DISPLAY (f));
5498 UNBLOCK_INPUT;
dc6f92b8 5499}
06a2c219
GM
5500
5501
dc6f92b8 5502\f
dbc4e1c1
JB
5503/* Invert the middle quarter of the frame for .15 sec. */
5504
06a2c219
GM
5505/* We use the select system call to do the waiting, so we have to make
5506 sure it's available. If it isn't, we just won't do visual bells. */
5507
dbc4e1c1
JB
5508#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5509
06a2c219
GM
5510
5511/* Subtract the `struct timeval' values X and Y, storing the result in
5512 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5513
5514static int
5515timeval_subtract (result, x, y)
5516 struct timeval *result, x, y;
5517{
06a2c219
GM
5518 /* Perform the carry for the later subtraction by updating y. This
5519 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5520 if (x.tv_usec < y.tv_usec)
5521 {
5522 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5523 y.tv_usec -= 1000000 * nsec;
5524 y.tv_sec += nsec;
5525 }
06a2c219 5526
dbc4e1c1
JB
5527 if (x.tv_usec - y.tv_usec > 1000000)
5528 {
5529 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5530 y.tv_usec += 1000000 * nsec;
5531 y.tv_sec -= nsec;
5532 }
5533
06a2c219
GM
5534 /* Compute the time remaining to wait. tv_usec is certainly
5535 positive. */
dbc4e1c1
JB
5536 result->tv_sec = x.tv_sec - y.tv_sec;
5537 result->tv_usec = x.tv_usec - y.tv_usec;
5538
06a2c219
GM
5539 /* Return indication of whether the result should be considered
5540 negative. */
dbc4e1c1
JB
5541 return x.tv_sec < y.tv_sec;
5542}
dc6f92b8 5543
dfcf069d 5544void
f676886a
JB
5545XTflash (f)
5546 struct frame *f;
dc6f92b8 5547{
dbc4e1c1 5548 BLOCK_INPUT;
dc6f92b8 5549
dbc4e1c1
JB
5550 {
5551 GC gc;
dc6f92b8 5552
06a2c219
GM
5553 /* Create a GC that will use the GXxor function to flip foreground
5554 pixels into background pixels. */
dbc4e1c1
JB
5555 {
5556 XGCValues values;
dc6f92b8 5557
dbc4e1c1 5558 values.function = GXxor;
7556890b
RS
5559 values.foreground = (f->output_data.x->foreground_pixel
5560 ^ f->output_data.x->background_pixel);
58769bee 5561
334208b7 5562 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5563 GCFunction | GCForeground, &values);
5564 }
dc6f92b8 5565
dbc4e1c1 5566 {
e84e14c3
RS
5567 /* Get the height not including a menu bar widget. */
5568 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5569 /* Height of each line to flash. */
5570 int flash_height = FRAME_LINE_HEIGHT (f);
5571 /* These will be the left and right margins of the rectangles. */
5572 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5573 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5574
5575 int width;
5576
5577 /* Don't flash the area between a scroll bar and the frame
5578 edge it is next to. */
5579 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5580 {
5581 case vertical_scroll_bar_left:
5582 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5583 break;
5584
5585 case vertical_scroll_bar_right:
5586 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5587 break;
06a2c219
GM
5588
5589 default:
5590 break;
e84e14c3
RS
5591 }
5592
5593 width = flash_right - flash_left;
5594
5595 /* If window is tall, flash top and bottom line. */
5596 if (height > 3 * FRAME_LINE_HEIGHT (f))
5597 {
5598 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5599 flash_left,
5600 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5601 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5602 width, flash_height);
5603 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5604 flash_left,
5605 (height - flash_height
5606 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5607 width, flash_height);
5608 }
5609 else
5610 /* If it is short, flash it all. */
5611 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5612 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5613 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5614
06a2c219 5615 x_flush (f);
dc6f92b8 5616
dbc4e1c1 5617 {
06a2c219 5618 struct timeval wakeup;
dc6f92b8 5619
66c30ea1 5620 EMACS_GET_TIME (wakeup);
dc6f92b8 5621
dbc4e1c1
JB
5622 /* Compute time to wait until, propagating carry from usecs. */
5623 wakeup.tv_usec += 150000;
5624 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5625 wakeup.tv_usec %= 1000000;
5626
101922c3
GM
5627 /* Keep waiting until past the time wakeup or any input gets
5628 available. */
5629 while (! detect_input_pending ())
dbc4e1c1 5630 {
101922c3 5631 struct timeval current;
dbc4e1c1
JB
5632 struct timeval timeout;
5633
101922c3 5634 EMACS_GET_TIME (current);
dbc4e1c1 5635
101922c3
GM
5636 /* Break if result would be negative. */
5637 if (timeval_subtract (&current, wakeup, current))
dbc4e1c1
JB
5638 break;
5639
101922c3
GM
5640 /* How long `select' should wait. */
5641 timeout.tv_sec = 0;
5642 timeout.tv_usec = 10000;
5643
dbc4e1c1 5644 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5645 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5646 }
5647 }
58769bee 5648
e84e14c3
RS
5649 /* If window is tall, flash top and bottom line. */
5650 if (height > 3 * FRAME_LINE_HEIGHT (f))
5651 {
5652 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5653 flash_left,
5654 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5655 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5656 width, flash_height);
5657 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5658 flash_left,
5659 (height - flash_height
5660 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5661 width, flash_height);
5662 }
5663 else
5664 /* If it is short, flash it all. */
5665 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5666 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5667 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5668
334208b7 5669 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5670 x_flush (f);
dc6f92b8 5671 }
dbc4e1c1
JB
5672 }
5673
5674 UNBLOCK_INPUT;
dc6f92b8
JB
5675}
5676
06a2c219 5677#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5678
5679
dc6f92b8
JB
5680/* Make audible bell. */
5681
dfcf069d 5682void
dc6f92b8
JB
5683XTring_bell ()
5684{
b86bd3dd
GM
5685 struct frame *f = SELECTED_FRAME ();
5686
5687 if (FRAME_X_DISPLAY (f))
5688 {
dbc4e1c1 5689#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5690 if (visible_bell)
5691 XTflash (f);
5692 else
dbc4e1c1 5693#endif
b86bd3dd
GM
5694 {
5695 BLOCK_INPUT;
5696 XBell (FRAME_X_DISPLAY (f), 0);
5697 XFlush (FRAME_X_DISPLAY (f));
5698 UNBLOCK_INPUT;
5699 }
dc6f92b8
JB
5700 }
5701}
06a2c219 5702
dc6f92b8 5703\f
06a2c219
GM
5704/* Specify how many text lines, from the top of the window,
5705 should be affected by insert-lines and delete-lines operations.
5706 This, and those operations, are used only within an update
5707 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5708
dfcf069d 5709static void
06a2c219
GM
5710XTset_terminal_window (n)
5711 register int n;
dc6f92b8 5712{
06a2c219 5713 /* This function intentionally left blank. */
dc6f92b8
JB
5714}
5715
06a2c219
GM
5716
5717\f
5718/***********************************************************************
5719 Line Dance
5720 ***********************************************************************/
5721
5722/* Perform an insert-lines or delete-lines operation, inserting N
5723 lines or deleting -N lines at vertical position VPOS. */
5724
dfcf069d 5725static void
06a2c219
GM
5726x_ins_del_lines (vpos, n)
5727 int vpos, n;
dc6f92b8
JB
5728{
5729 abort ();
5730}
06a2c219
GM
5731
5732
5733/* Scroll part of the display as described by RUN. */
dc6f92b8 5734
dfcf069d 5735static void
06a2c219
GM
5736x_scroll_run (w, run)
5737 struct window *w;
5738 struct run *run;
dc6f92b8 5739{
06a2c219
GM
5740 struct frame *f = XFRAME (w->frame);
5741 int x, y, width, height, from_y, to_y, bottom_y;
5742
5743 /* Get frame-relative bounding box of the text display area of W,
3f332ef3
KS
5744 without mode lines. Include in this box the left and right
5745 fringe of W. */
06a2c219 5746 window_box (w, -1, &x, &y, &width, &height);
3f332ef3
KS
5747 width += FRAME_X_FRINGE_WIDTH (f);
5748 x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
06a2c219
GM
5749
5750 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5751 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5752 bottom_y = y + height;
dc6f92b8 5753
06a2c219
GM
5754 if (to_y < from_y)
5755 {
5756 /* Scrolling up. Make sure we don't copy part of the mode
5757 line at the bottom. */
5758 if (from_y + run->height > bottom_y)
5759 height = bottom_y - from_y;
5760 else
5761 height = run->height;
5762 }
dc6f92b8 5763 else
06a2c219
GM
5764 {
5765 /* Scolling down. Make sure we don't copy over the mode line.
5766 at the bottom. */
5767 if (to_y + run->height > bottom_y)
5768 height = bottom_y - to_y;
5769 else
5770 height = run->height;
5771 }
7a13e894 5772
06a2c219
GM
5773 BLOCK_INPUT;
5774
5775 /* Cursor off. Will be switched on again in x_update_window_end. */
5776 updated_window = w;
5777 x_clear_cursor (w);
5778
5779 XCopyArea (FRAME_X_DISPLAY (f),
5780 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5781 f->output_data.x->normal_gc,
5782 x, from_y,
5783 width, height,
5784 x, to_y);
5785
5786 UNBLOCK_INPUT;
5787}
dc6f92b8 5788
dc6f92b8 5789
06a2c219
GM
5790\f
5791/***********************************************************************
5792 Exposure Events
5793 ***********************************************************************/
5794
5795/* Redisplay an exposed area of frame F. X and Y are the upper-left
5796 corner of the exposed rectangle. W and H are width and height of
5797 the exposed area. All are pixel values. W or H zero means redraw
5798 the entire frame. */
dc6f92b8 5799
06a2c219
GM
5800static void
5801expose_frame (f, x, y, w, h)
5802 struct frame *f;
5803 int x, y, w, h;
dc6f92b8 5804{
06a2c219 5805 XRectangle r;
82f053ab 5806 int mouse_face_overwritten_p = 0;
dc6f92b8 5807
06a2c219 5808 TRACE ((stderr, "expose_frame "));
dc6f92b8 5809
06a2c219
GM
5810 /* No need to redraw if frame will be redrawn soon. */
5811 if (FRAME_GARBAGED_P (f))
dc6f92b8 5812 {
06a2c219
GM
5813 TRACE ((stderr, " garbaged\n"));
5814 return;
5815 }
5816
5817 /* If basic faces haven't been realized yet, there is no point in
5818 trying to redraw anything. This can happen when we get an expose
5819 event while Emacs is starting, e.g. by moving another window. */
5820 if (FRAME_FACE_CACHE (f) == NULL
5821 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5822 {
5823 TRACE ((stderr, " no faces\n"));
5824 return;
58769bee 5825 }
06a2c219
GM
5826
5827 if (w == 0 || h == 0)
58769bee 5828 {
06a2c219
GM
5829 r.x = r.y = 0;
5830 r.width = CANON_X_UNIT (f) * f->width;
5831 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5832 }
5833 else
5834 {
06a2c219
GM
5835 r.x = x;
5836 r.y = y;
5837 r.width = w;
5838 r.height = h;
5839 }
5840
5841 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
82f053ab 5842 mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
06a2c219 5843
9ea173e8 5844 if (WINDOWP (f->tool_bar_window))
82f053ab
GM
5845 mouse_face_overwritten_p
5846 |= expose_window (XWINDOW (f->tool_bar_window), &r);
06a2c219
GM
5847
5848#ifndef USE_X_TOOLKIT
5849 if (WINDOWP (f->menu_bar_window))
82f053ab
GM
5850 mouse_face_overwritten_p
5851 |= expose_window (XWINDOW (f->menu_bar_window), &r);
06a2c219 5852#endif /* not USE_X_TOOLKIT */
82f053ab
GM
5853
5854 /* Some window managers support a focus-follows-mouse style with
5855 delayed raising of frames. Imagine a partially obscured frame,
5856 and moving the mouse into partially obscured mouse-face on that
5857 frame. The visible part of the mouse-face will be highlighted,
5858 then the WM raises the obscured frame. With at least one WM, KDE
5859 2.1, Emacs is not getting any event for the raising of the frame
5860 (even tried with SubstructureRedirectMask), only Expose events.
5861 These expose events will draw text normally, i.e. not
5862 highlighted. Which means we must redo the highlight here.
5863 Subsume it under ``we love X''. --gerd 2001-08-15 */
5864 if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
5865 {
5866 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5867 if (f == dpyinfo->mouse_face_mouse_frame)
5868 {
5869 int x = dpyinfo->mouse_face_mouse_x;
5870 int y = dpyinfo->mouse_face_mouse_y;
5871 clear_mouse_face (dpyinfo);
5872 note_mouse_highlight (f, x, y);
5873 }
5874 }
dc6f92b8
JB
5875}
5876
06a2c219
GM
5877
5878/* Redraw (parts) of all windows in the window tree rooted at W that
82f053ab
GM
5879 intersect R. R contains frame pixel coordinates. Value is
5880 non-zero if the exposure overwrites mouse-face. */
06a2c219 5881
82f053ab 5882static int
06a2c219
GM
5883expose_window_tree (w, r)
5884 struct window *w;
5885 XRectangle *r;
dc6f92b8 5886{
82f053ab
GM
5887 struct frame *f = XFRAME (w->frame);
5888 int mouse_face_overwritten_p = 0;
5889
5890 while (w && !FRAME_GARBAGED_P (f))
06a2c219
GM
5891 {
5892 if (!NILP (w->hchild))
82f053ab
GM
5893 mouse_face_overwritten_p
5894 |= expose_window_tree (XWINDOW (w->hchild), r);
06a2c219 5895 else if (!NILP (w->vchild))
82f053ab
GM
5896 mouse_face_overwritten_p
5897 |= expose_window_tree (XWINDOW (w->vchild), r);
5898 else
5899 mouse_face_overwritten_p |= expose_window (w, r);
5900
a02f1be0 5901 w = NILP (w->next) ? NULL : XWINDOW (w->next);
06a2c219 5902 }
82f053ab
GM
5903
5904 return mouse_face_overwritten_p;
06a2c219 5905}
58769bee 5906
dc6f92b8 5907
06a2c219
GM
5908/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5909 which intersects rectangle R. R is in window-relative coordinates. */
5910
5911static void
5912expose_area (w, row, r, area)
5913 struct window *w;
5914 struct glyph_row *row;
5915 XRectangle *r;
5916 enum glyph_row_area area;
5917{
06a2c219
GM
5918 struct glyph *first = row->glyphs[area];
5919 struct glyph *end = row->glyphs[area] + row->used[area];
5920 struct glyph *last;
4bc6dcc7 5921 int first_x, start_x, x;
06a2c219 5922
6fb13182
GM
5923 if (area == TEXT_AREA && row->fill_line_p)
5924 /* If row extends face to end of line write the whole line. */
153f5ed7 5925 x_draw_glyphs (w, 0, row, area, 0, row->used[area],
f0a48a01 5926 DRAW_NORMAL_TEXT, 0);
6fb13182
GM
5927 else
5928 {
4bc6dcc7
GM
5929 /* Set START_X to the window-relative start position for drawing glyphs of
5930 AREA. The first glyph of the text area can be partially visible.
5931 The first glyphs of other areas cannot. */
5932 if (area == LEFT_MARGIN_AREA)
5933 start_x = 0;
5934 else if (area == TEXT_AREA)
5935 start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5936 else
5937 start_x = (window_box_width (w, LEFT_MARGIN_AREA)
5938 + window_box_width (w, TEXT_AREA));
5939 x = start_x;
5940
6fb13182
GM
5941 /* Find the first glyph that must be redrawn. */
5942 while (first < end
5943 && x + first->pixel_width < r->x)
5944 {
5945 x += first->pixel_width;
5946 ++first;
5947 }
5948
5949 /* Find the last one. */
5950 last = first;
5951 first_x = x;
5952 while (last < end
5953 && x < r->x + r->width)
5954 {
5955 x += last->pixel_width;
5956 ++last;
5957 }
5958
5959 /* Repaint. */
5960 if (last > first)
4bc6dcc7 5961 x_draw_glyphs (w, first_x - start_x, row, area,
6fb13182
GM
5962 first - row->glyphs[area],
5963 last - row->glyphs[area],
f0a48a01 5964 DRAW_NORMAL_TEXT, 0);
6fb13182 5965 }
06a2c219
GM
5966}
5967
58769bee 5968
06a2c219 5969/* Redraw the parts of the glyph row ROW on window W intersecting
82f053ab
GM
5970 rectangle R. R is in window-relative coordinates. Value is
5971 non-zero if mouse-face was overwritten. */
dc6f92b8 5972
82f053ab 5973static int
06a2c219
GM
5974expose_line (w, row, r)
5975 struct window *w;
5976 struct glyph_row *row;
5977 XRectangle *r;
5978{
5979 xassert (row->enabled_p);
5980
5981 if (row->mode_line_p || w->pseudo_window_p)
5982 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
f0a48a01 5983 DRAW_NORMAL_TEXT, 0);
06a2c219
GM
5984 else
5985 {
5986 if (row->used[LEFT_MARGIN_AREA])
5987 expose_area (w, row, r, LEFT_MARGIN_AREA);
5988 if (row->used[TEXT_AREA])
5989 expose_area (w, row, r, TEXT_AREA);
5990 if (row->used[RIGHT_MARGIN_AREA])
5991 expose_area (w, row, r, RIGHT_MARGIN_AREA);
3f332ef3 5992 x_draw_row_fringe_bitmaps (w, row);
06a2c219 5993 }
82f053ab
GM
5994
5995 return row->mouse_face_p;
06a2c219 5996}
dc6f92b8 5997
58769bee 5998
06a2c219
GM
5999/* Return non-zero if W's cursor intersects rectangle R. */
6000
6001static int
6002x_phys_cursor_in_rect_p (w, r)
6003 struct window *w;
6004 XRectangle *r;
6005{
6006 XRectangle cr, result;
6007 struct glyph *cursor_glyph;
6008
6009 cursor_glyph = get_phys_cursor_glyph (w);
6010 if (cursor_glyph)
6011 {
6012 cr.x = w->phys_cursor.x;
6013 cr.y = w->phys_cursor.y;
6014 cr.width = cursor_glyph->pixel_width;
6015 cr.height = w->phys_cursor_height;
6016 return x_intersect_rectangles (&cr, r, &result);
6017 }
6018 else
6019 return 0;
dc6f92b8 6020}
dc6f92b8 6021
06a2c219 6022
a02f1be0
GM
6023/* Redraw the part of window W intersection rectangle FR. Pixel
6024 coordinates in FR are frame-relative. Call this function with
82f053ab
GM
6025 input blocked. Value is non-zero if the exposure overwrites
6026 mouse-face. */
dc6f92b8 6027
a39202f6 6028static int
a02f1be0 6029expose_window (w, fr)
06a2c219 6030 struct window *w;
a02f1be0 6031 XRectangle *fr;
dc6f92b8 6032{
a02f1be0 6033 struct frame *f = XFRAME (w->frame);
a02f1be0 6034 XRectangle wr, r;
82f053ab 6035 int mouse_face_overwritten_p = 0;
dc6f92b8 6036
80c32bcc
GM
6037 /* If window is not yet fully initialized, do nothing. This can
6038 happen when toolkit scroll bars are used and a window is split.
6039 Reconfiguring the scroll bar will generate an expose for a newly
6040 created window. */
a39202f6 6041 if (w->current_matrix == NULL)
82f053ab 6042 return 0;
a39202f6
GM
6043
6044 /* When we're currently updating the window, display and current
6045 matrix usually don't agree. Arrange for a thorough display
6046 later. */
6047 if (w == updated_window)
6048 {
6049 SET_FRAME_GARBAGED (f);
6050 return 0;
6051 }
80c32bcc 6052
a39202f6 6053 /* Frame-relative pixel rectangle of W. */
a02f1be0
GM
6054 wr.x = XFASTINT (w->left) * CANON_X_UNIT (f);
6055 wr.y = XFASTINT (w->top) * CANON_Y_UNIT (f);
6056 wr.width = XFASTINT (w->width) * CANON_X_UNIT (f);
6057 wr.height = XFASTINT (w->height) * CANON_Y_UNIT (f);
6058
a39202f6
GM
6059 if (x_intersect_rectangles (fr, &wr, &r))
6060 {
6061 int yb = window_text_bottom_y (w);
6062 struct glyph_row *row;
6063 int cursor_cleared_p;
a02f1be0 6064
a39202f6
GM
6065 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
6066 r.x, r.y, r.width, r.height));
dc6f92b8 6067
a39202f6
GM
6068 /* Convert to window coordinates. */
6069 r.x = FRAME_TO_WINDOW_PIXEL_X (w, r.x);
6070 r.y = FRAME_TO_WINDOW_PIXEL_Y (w, r.y);
dc6f92b8 6071
a39202f6
GM
6072 /* Turn off the cursor. */
6073 if (!w->pseudo_window_p
6074 && x_phys_cursor_in_rect_p (w, &r))
6075 {
6076 x_clear_cursor (w);
6077 cursor_cleared_p = 1;
6078 }
6079 else
6080 cursor_cleared_p = 0;
06a2c219 6081
a39202f6
GM
6082 /* Find the first row intersecting the rectangle R. */
6083 for (row = w->current_matrix->rows;
6084 row->enabled_p;
6085 ++row)
6086 {
6087 int y0 = row->y;
6088 int y1 = MATRIX_ROW_BOTTOM_Y (row);
6089
6090 if ((y0 >= r.y && y0 < r.y + r.height)
6091 || (y1 > r.y && y1 < r.y + r.height)
6092 || (r.y >= y0 && r.y < y1)
6093 || (r.y + r.height > y0 && r.y + r.height < y1))
82f053ab
GM
6094 {
6095 if (expose_line (w, row, &r))
6096 mouse_face_overwritten_p = 1;
6097 }
6098
a39202f6
GM
6099 if (y1 >= yb)
6100 break;
6101 }
dc6f92b8 6102
a39202f6
GM
6103 /* Display the mode line if there is one. */
6104 if (WINDOW_WANTS_MODELINE_P (w)
6105 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
6106 row->enabled_p)
6107 && row->y < r.y + r.height)
82f053ab
GM
6108 {
6109 if (expose_line (w, row, &r))
6110 mouse_face_overwritten_p = 1;
6111 }
a39202f6
GM
6112
6113 if (!w->pseudo_window_p)
6114 {
6115 /* Draw border between windows. */
6116 x_draw_vertical_border (w);
06a2c219 6117
a39202f6
GM
6118 /* Turn the cursor on again. */
6119 if (cursor_cleared_p)
6120 x_update_window_cursor (w, 1);
6121 }
06a2c219 6122 }
82f053ab
GM
6123
6124 return mouse_face_overwritten_p;
06a2c219 6125}
dc6f92b8 6126
dc6f92b8 6127
06a2c219
GM
6128/* Determine the intersection of two rectangles R1 and R2. Return
6129 the intersection in *RESULT. Value is non-zero if RESULT is not
6130 empty. */
6131
6132static int
6133x_intersect_rectangles (r1, r2, result)
6134 XRectangle *r1, *r2, *result;
6135{
6136 XRectangle *left, *right;
6137 XRectangle *upper, *lower;
6138 int intersection_p = 0;
6139
6140 /* Rearrange so that R1 is the left-most rectangle. */
6141 if (r1->x < r2->x)
6142 left = r1, right = r2;
6143 else
6144 left = r2, right = r1;
6145
6146 /* X0 of the intersection is right.x0, if this is inside R1,
6147 otherwise there is no intersection. */
6148 if (right->x <= left->x + left->width)
6149 {
6150 result->x = right->x;
6151
6152 /* The right end of the intersection is the minimum of the
6153 the right ends of left and right. */
6154 result->width = (min (left->x + left->width, right->x + right->width)
6155 - result->x);
6156
6157 /* Same game for Y. */
6158 if (r1->y < r2->y)
6159 upper = r1, lower = r2;
6160 else
6161 upper = r2, lower = r1;
6162
6163 /* The upper end of the intersection is lower.y0, if this is inside
6164 of upper. Otherwise, there is no intersection. */
6165 if (lower->y <= upper->y + upper->height)
dc43ef94 6166 {
06a2c219
GM
6167 result->y = lower->y;
6168
6169 /* The lower end of the intersection is the minimum of the lower
6170 ends of upper and lower. */
6171 result->height = (min (lower->y + lower->height,
6172 upper->y + upper->height)
6173 - result->y);
6174 intersection_p = 1;
dc43ef94 6175 }
dc6f92b8
JB
6176 }
6177
06a2c219 6178 return intersection_p;
dc6f92b8 6179}
06a2c219
GM
6180
6181
6182
6183
dc6f92b8 6184\f
dc6f92b8 6185static void
334208b7
RS
6186frame_highlight (f)
6187 struct frame *f;
dc6f92b8 6188{
b3e1e05c
JB
6189 /* We used to only do this if Vx_no_window_manager was non-nil, but
6190 the ICCCM (section 4.1.6) says that the window's border pixmap
6191 and border pixel are window attributes which are "private to the
6192 client", so we can always change it to whatever we want. */
6193 BLOCK_INPUT;
334208b7 6194 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6195 f->output_data.x->border_pixel);
b3e1e05c 6196 UNBLOCK_INPUT;
5d46f928 6197 x_update_cursor (f, 1);
dc6f92b8
JB
6198}
6199
6200static void
334208b7
RS
6201frame_unhighlight (f)
6202 struct frame *f;
dc6f92b8 6203{
b3e1e05c
JB
6204 /* We used to only do this if Vx_no_window_manager was non-nil, but
6205 the ICCCM (section 4.1.6) says that the window's border pixmap
6206 and border pixel are window attributes which are "private to the
6207 client", so we can always change it to whatever we want. */
6208 BLOCK_INPUT;
334208b7 6209 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6210 f->output_data.x->border_tile);
b3e1e05c 6211 UNBLOCK_INPUT;
5d46f928 6212 x_update_cursor (f, 1);
dc6f92b8 6213}
dc6f92b8 6214
f676886a
JB
6215/* The focus has changed. Update the frames as necessary to reflect
6216 the new situation. Note that we can't change the selected frame
c5acd733 6217 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 6218 Each event gets marked with the frame in which it occurred, so the
c5acd733 6219 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 6220
6d4238f3 6221static void
0f941935
KH
6222x_new_focus_frame (dpyinfo, frame)
6223 struct x_display_info *dpyinfo;
f676886a 6224 struct frame *frame;
dc6f92b8 6225{
0f941935 6226 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 6227
0f941935 6228 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 6229 {
58769bee 6230 /* Set this before calling other routines, so that they see
f676886a 6231 the correct value of x_focus_frame. */
0f941935 6232 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
6233
6234 if (old_focus && old_focus->auto_lower)
f676886a 6235 x_lower_frame (old_focus);
dc6f92b8
JB
6236
6237#if 0
f676886a 6238 selected_frame = frame;
e0c1aef2
KH
6239 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6240 selected_frame);
f676886a
JB
6241 Fselect_window (selected_frame->selected_window);
6242 choose_minibuf_frame ();
c118dd06 6243#endif /* ! 0 */
dc6f92b8 6244
0f941935
KH
6245 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6246 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
6247 else
6248 pending_autoraise_frame = 0;
6d4238f3 6249 }
dc6f92b8 6250
0f941935 6251 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
6252}
6253
37c2c98b
RS
6254/* Handle an event saying the mouse has moved out of an Emacs frame. */
6255
6256void
0f941935
KH
6257x_mouse_leave (dpyinfo)
6258 struct x_display_info *dpyinfo;
37c2c98b 6259{
0f941935 6260 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 6261}
6d4238f3 6262
f451eb13
JB
6263/* The focus has changed, or we have redirected a frame's focus to
6264 another frame (this happens when a frame uses a surrogate
06a2c219 6265 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
6266
6267 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 6268 frame is being highlighted or un-highlighted; we only use it to find
0f941935 6269 the appropriate X display info. */
06a2c219 6270
6d4238f3 6271static void
0f941935
KH
6272XTframe_rehighlight (frame)
6273 struct frame *frame;
6d4238f3 6274{
0f941935
KH
6275 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6276}
6d4238f3 6277
0f941935
KH
6278static void
6279x_frame_rehighlight (dpyinfo)
6280 struct x_display_info *dpyinfo;
6281{
6282 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6283
6284 if (dpyinfo->x_focus_frame)
6d4238f3 6285 {
0f941935
KH
6286 dpyinfo->x_highlight_frame
6287 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6288 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6289 : dpyinfo->x_focus_frame);
6290 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 6291 {
0f941935
KH
6292 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6293 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 6294 }
dc6f92b8 6295 }
6d4238f3 6296 else
0f941935 6297 dpyinfo->x_highlight_frame = 0;
dc6f92b8 6298
0f941935 6299 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
6300 {
6301 if (old_highlight)
f676886a 6302 frame_unhighlight (old_highlight);
0f941935
KH
6303 if (dpyinfo->x_highlight_frame)
6304 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 6305 }
dc6f92b8 6306}
06a2c219
GM
6307
6308
dc6f92b8 6309\f
06a2c219 6310/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 6311
28430d3c
JB
6312/* Initialize mode_switch_bit and modifier_meaning. */
6313static void
334208b7
RS
6314x_find_modifier_meanings (dpyinfo)
6315 struct x_display_info *dpyinfo;
28430d3c 6316{
f689eb05 6317 int min_code, max_code;
28430d3c
JB
6318 KeySym *syms;
6319 int syms_per_code;
6320 XModifierKeymap *mods;
6321
334208b7
RS
6322 dpyinfo->meta_mod_mask = 0;
6323 dpyinfo->shift_lock_mask = 0;
6324 dpyinfo->alt_mod_mask = 0;
6325 dpyinfo->super_mod_mask = 0;
6326 dpyinfo->hyper_mod_mask = 0;
58769bee 6327
9658a521 6328#ifdef HAVE_X11R4
334208b7 6329 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 6330#else
4a60f8c5
RS
6331 min_code = dpyinfo->display->min_keycode;
6332 max_code = dpyinfo->display->max_keycode;
9658a521
JB
6333#endif
6334
334208b7 6335 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
6336 min_code, max_code - min_code + 1,
6337 &syms_per_code);
334208b7 6338 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 6339
58769bee 6340 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 6341 Alt keysyms are on. */
28430d3c 6342 {
06a2c219 6343 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
6344
6345 for (row = 3; row < 8; row++)
6346 for (col = 0; col < mods->max_keypermod; col++)
6347 {
0299d313
RS
6348 KeyCode code
6349 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 6350
af92970c
KH
6351 /* Zeroes are used for filler. Skip them. */
6352 if (code == 0)
6353 continue;
6354
28430d3c
JB
6355 /* Are any of this keycode's keysyms a meta key? */
6356 {
6357 int code_col;
6358
6359 for (code_col = 0; code_col < syms_per_code; code_col++)
6360 {
f689eb05 6361 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 6362
f689eb05 6363 switch (sym)
28430d3c 6364 {
f689eb05
JB
6365 case XK_Meta_L:
6366 case XK_Meta_R:
334208b7 6367 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 6368 break;
f689eb05
JB
6369
6370 case XK_Alt_L:
6371 case XK_Alt_R:
334208b7 6372 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
6373 break;
6374
6375 case XK_Hyper_L:
6376 case XK_Hyper_R:
334208b7 6377 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
6378 break;
6379
6380 case XK_Super_L:
6381 case XK_Super_R:
334208b7 6382 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 6383 break;
11edeb03
JB
6384
6385 case XK_Shift_Lock:
6386 /* Ignore this if it's not on the lock modifier. */
6387 if ((1 << row) == LockMask)
334208b7 6388 dpyinfo->shift_lock_mask = LockMask;
11edeb03 6389 break;
28430d3c
JB
6390 }
6391 }
6392 }
6393 }
6394 }
6395
f689eb05 6396 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 6397 if (! dpyinfo->meta_mod_mask)
a3c44b14 6398 {
334208b7
RS
6399 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6400 dpyinfo->alt_mod_mask = 0;
a3c44b14 6401 }
f689eb05 6402
148c4b70
RS
6403 /* If some keys are both alt and meta,
6404 make them just meta, not alt. */
334208b7 6405 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 6406 {
334208b7 6407 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 6408 }
58769bee 6409
28430d3c 6410 XFree ((char *) syms);
f689eb05 6411 XFreeModifiermap (mods);
28430d3c
JB
6412}
6413
dfeccd2d
JB
6414/* Convert between the modifier bits X uses and the modifier bits
6415 Emacs uses. */
06a2c219 6416
7c5283e4 6417static unsigned int
334208b7
RS
6418x_x_to_emacs_modifiers (dpyinfo, state)
6419 struct x_display_info *dpyinfo;
dc6f92b8
JB
6420 unsigned int state;
6421{
334208b7
RS
6422 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
6423 | ((state & ControlMask) ? ctrl_modifier : 0)
6424 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
6425 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
6426 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
6427 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
6428}
6429
dfeccd2d 6430static unsigned int
334208b7
RS
6431x_emacs_to_x_modifiers (dpyinfo, state)
6432 struct x_display_info *dpyinfo;
dfeccd2d
JB
6433 unsigned int state;
6434{
334208b7
RS
6435 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
6436 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6437 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6438 | ((state & shift_modifier) ? ShiftMask : 0)
6439 | ((state & ctrl_modifier) ? ControlMask : 0)
6440 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6441}
d047c4eb
KH
6442
6443/* Convert a keysym to its name. */
6444
6445char *
6446x_get_keysym_name (keysym)
6447 KeySym keysym;
6448{
6449 char *value;
6450
6451 BLOCK_INPUT;
6452 value = XKeysymToString (keysym);
6453 UNBLOCK_INPUT;
6454
6455 return value;
6456}
06a2c219
GM
6457
6458
e4571a43
JB
6459\f
6460/* Mouse clicks and mouse movement. Rah. */
e4571a43 6461
06a2c219
GM
6462/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6463 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6464 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6465 not force the value into range. */
69388238 6466
c8dba240 6467void
69388238 6468pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6469 FRAME_PTR f;
69388238 6470 register int pix_x, pix_y;
e4571a43
JB
6471 register int *x, *y;
6472 XRectangle *bounds;
69388238 6473 int noclip;
e4571a43 6474{
06a2c219 6475 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6476 even for negative values. */
6477 if (pix_x < 0)
7556890b 6478 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6479 if (pix_y < 0)
7556890b 6480 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6481
e4571a43
JB
6482 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6483 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6484
6485 if (bounds)
6486 {
7556890b
RS
6487 bounds->width = FONT_WIDTH (f->output_data.x->font);
6488 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6489 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6490 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6491 }
6492
69388238
RS
6493 if (!noclip)
6494 {
6495 if (pix_x < 0)
6496 pix_x = 0;
3cbd2e0b
RS
6497 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6498 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6499
6500 if (pix_y < 0)
6501 pix_y = 0;
6502 else if (pix_y > f->height)
6503 pix_y = f->height;
6504 }
e4571a43
JB
6505
6506 *x = pix_x;
6507 *y = pix_y;
6508}
6509
06a2c219
GM
6510
6511/* Given HPOS/VPOS in the current matrix of W, return corresponding
6512 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6513 can't tell the positions because W's display is not up to date,
6514 return 0. */
6515
6516int
6517glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6518 struct window *w;
6519 int hpos, vpos;
6520 int *frame_x, *frame_y;
2b5c9e71 6521{
06a2c219
GM
6522 int success_p;
6523
6524 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6525 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6526
6527 if (display_completed)
6528 {
6529 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6530 struct glyph *glyph = row->glyphs[TEXT_AREA];
6531 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6532
6533 *frame_y = row->y;
6534 *frame_x = row->x;
6535 while (glyph < end)
6536 {
6537 *frame_x += glyph->pixel_width;
6538 ++glyph;
6539 }
6540
6541 success_p = 1;
6542 }
6543 else
6544 {
6545 *frame_y = *frame_x = 0;
6546 success_p = 0;
6547 }
6548
6549 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6550 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6551 return success_p;
2b5c9e71
RS
6552}
6553
06a2c219 6554
dc6f92b8
JB
6555/* Prepare a mouse-event in *RESULT for placement in the input queue.
6556
6557 If the event is a button press, then note that we have grabbed
f451eb13 6558 the mouse. */
dc6f92b8
JB
6559
6560static Lisp_Object
f451eb13 6561construct_mouse_click (result, event, f)
dc6f92b8
JB
6562 struct input_event *result;
6563 XButtonEvent *event;
f676886a 6564 struct frame *f;
dc6f92b8 6565{
f451eb13 6566 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6567 otherwise. */
f451eb13 6568 result->kind = mouse_click;
69388238 6569 result->code = event->button - Button1;
1113d9db 6570 result->timestamp = event->time;
334208b7
RS
6571 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6572 event->state)
f689eb05 6573 | (event->type == ButtonRelease
58769bee 6574 ? up_modifier
f689eb05 6575 : down_modifier));
dc6f92b8 6576
06a2c219
GM
6577 XSETINT (result->x, event->x);
6578 XSETINT (result->y, event->y);
6579 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6580 result->arg = Qnil;
06a2c219 6581 return Qnil;
dc6f92b8 6582}
b849c413 6583
69388238 6584\f
90e65f07
JB
6585/* Function to report a mouse movement to the mainstream Emacs code.
6586 The input handler calls this.
6587
6588 We have received a mouse movement event, which is given in *event.
6589 If the mouse is over a different glyph than it was last time, tell
6590 the mainstream emacs code by setting mouse_moved. If not, ask for
6591 another motion event, so we can check again the next time it moves. */
b8009dd1 6592
06a2c219
GM
6593static XMotionEvent last_mouse_motion_event;
6594static Lisp_Object last_mouse_motion_frame;
6595
90e65f07 6596static void
12ba150f 6597note_mouse_movement (frame, event)
f676886a 6598 FRAME_PTR frame;
90e65f07 6599 XMotionEvent *event;
90e65f07 6600{
e5d77022 6601 last_mouse_movement_time = event->time;
06a2c219
GM
6602 last_mouse_motion_event = *event;
6603 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6604
27f338af
RS
6605 if (event->window != FRAME_X_WINDOW (frame))
6606 {
39d8bb4d 6607 frame->mouse_moved = 1;
27f338af 6608 last_mouse_scroll_bar = Qnil;
27f338af 6609 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6610 }
6611
90e65f07 6612 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6613 else if (event->x < last_mouse_glyph.x
6614 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6615 || event->y < last_mouse_glyph.y
6616 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6617 {
39d8bb4d 6618 frame->mouse_moved = 1;
ab648270 6619 last_mouse_scroll_bar = Qnil;
b8009dd1 6620 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6621 }
6622}
6623
bf1c0ba1 6624/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6625
06a2c219
GM
6626 int disable_mouse_highlight;
6627
6628
6629\f
6630/************************************************************************
6631 Mouse Face
6632 ************************************************************************/
6633
6634/* Find the glyph under window-relative coordinates X/Y in window W.
6635 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6636 strings. Return in *HPOS and *VPOS the row and column number of
6637 the glyph found. Return in *AREA the glyph area containing X.
6638 Value is a pointer to the glyph found or null if X/Y is not on
6639 text, or we can't tell because W's current matrix is not up to
6640 date. */
6641
6642static struct glyph *
f9db2310 6643x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
06a2c219
GM
6644 struct window *w;
6645 int x, y;
6646 int *hpos, *vpos, *area;
f9db2310 6647 int buffer_only_p;
06a2c219
GM
6648{
6649 struct glyph *glyph, *end;
3e71d8f2 6650 struct glyph_row *row = NULL;
06a2c219
GM
6651 int x0, i, left_area_width;
6652
6653 /* Find row containing Y. Give up if some row is not enabled. */
6654 for (i = 0; i < w->current_matrix->nrows; ++i)
6655 {
6656 row = MATRIX_ROW (w->current_matrix, i);
6657 if (!row->enabled_p)
6658 return NULL;
6659 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6660 break;
6661 }
6662
6663 *vpos = i;
6664 *hpos = 0;
6665
6666 /* Give up if Y is not in the window. */
6667 if (i == w->current_matrix->nrows)
6668 return NULL;
6669
6670 /* Get the glyph area containing X. */
6671 if (w->pseudo_window_p)
6672 {
6673 *area = TEXT_AREA;
6674 x0 = 0;
6675 }
6676 else
6677 {
6678 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6679 if (x < left_area_width)
6680 {
6681 *area = LEFT_MARGIN_AREA;
6682 x0 = 0;
6683 }
6684 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6685 {
6686 *area = TEXT_AREA;
6687 x0 = row->x + left_area_width;
6688 }
6689 else
6690 {
6691 *area = RIGHT_MARGIN_AREA;
6692 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6693 }
6694 }
6695
6696 /* Find glyph containing X. */
6697 glyph = row->glyphs[*area];
6698 end = glyph + row->used[*area];
6699 while (glyph < end)
6700 {
6701 if (x < x0 + glyph->pixel_width)
6702 {
6703 if (w->pseudo_window_p)
6704 break;
f9db2310 6705 else if (!buffer_only_p || BUFFERP (glyph->object))
06a2c219
GM
6706 break;
6707 }
6708
6709 x0 += glyph->pixel_width;
6710 ++glyph;
6711 }
6712
6713 if (glyph == end)
6714 return NULL;
6715
6716 *hpos = glyph - row->glyphs[*area];
6717 return glyph;
6718}
6719
6720
6721/* Convert frame-relative x/y to coordinates relative to window W.
6722 Takes pseudo-windows into account. */
6723
6724static void
6725frame_to_window_pixel_xy (w, x, y)
6726 struct window *w;
6727 int *x, *y;
6728{
6729 if (w->pseudo_window_p)
6730 {
6731 /* A pseudo-window is always full-width, and starts at the
6732 left edge of the frame, plus a frame border. */
6733 struct frame *f = XFRAME (w->frame);
6734 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6735 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6736 }
6737 else
6738 {
6739 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6740 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6741 }
6742}
6743
6744
e371a781 6745/* Take proper action when mouse has moved to the mode or header line of
06a2c219
GM
6746 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6747 mode line. X is relative to the start of the text display area of
3f332ef3 6748 W, so the width of fringes and scroll bars must be subtracted
06a2c219
GM
6749 to get a position relative to the start of the mode line. */
6750
6751static void
6752note_mode_line_highlight (w, x, mode_line_p)
6753 struct window *w;
6754 int x, mode_line_p;
6755{
6756 struct frame *f = XFRAME (w->frame);
6757 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6758 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6759 struct glyph_row *row;
6760
6761 if (mode_line_p)
6762 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6763 else
045dee35 6764 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
e371a781 6765
06a2c219
GM
6766 if (row->enabled_p)
6767 {
6768 struct glyph *glyph, *end;
6769 Lisp_Object help, map;
6770 int x0;
6771
6772 /* Find the glyph under X. */
6773 glyph = row->glyphs[TEXT_AREA];
6774 end = glyph + row->used[TEXT_AREA];
6775 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
3f332ef3 6776 + FRAME_X_LEFT_FRINGE_WIDTH (f));
e371a781 6777
06a2c219
GM
6778 while (glyph < end
6779 && x >= x0 + glyph->pixel_width)
6780 {
6781 x0 += glyph->pixel_width;
6782 ++glyph;
6783 }
6784
6785 if (glyph < end
6786 && STRINGP (glyph->object)
6787 && XSTRING (glyph->object)->intervals
6788 && glyph->charpos >= 0
6789 && glyph->charpos < XSTRING (glyph->object)->size)
6790 {
6791 /* If we're on a string with `help-echo' text property,
6792 arrange for the help to be displayed. This is done by
6793 setting the global variable help_echo to the help string. */
6794 help = Fget_text_property (make_number (glyph->charpos),
6795 Qhelp_echo, glyph->object);
b7e80413 6796 if (!NILP (help))
be010514
GM
6797 {
6798 help_echo = help;
7cea38bc 6799 XSETWINDOW (help_echo_window, w);
be010514
GM
6800 help_echo_object = glyph->object;
6801 help_echo_pos = glyph->charpos;
6802 }
06a2c219
GM
6803
6804 /* Change the mouse pointer according to what is under X/Y. */
6805 map = Fget_text_property (make_number (glyph->charpos),
6806 Qlocal_map, glyph->object);
02067692 6807 if (KEYMAPP (map))
06a2c219 6808 cursor = f->output_data.x->nontext_cursor;
be010514
GM
6809 else
6810 {
6811 map = Fget_text_property (make_number (glyph->charpos),
6812 Qkeymap, glyph->object);
02067692 6813 if (KEYMAPP (map))
be010514
GM
6814 cursor = f->output_data.x->nontext_cursor;
6815 }
06a2c219
GM
6816 }
6817 }
6818
6819 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6820}
6821
6822
6823/* Take proper action when the mouse has moved to position X, Y on
6824 frame F as regards highlighting characters that have mouse-face
6825 properties. Also de-highlighting chars where the mouse was before.
27f338af 6826 X and Y can be negative or out of range. */
b8009dd1
RS
6827
6828static void
6829note_mouse_highlight (f, x, y)
06a2c219 6830 struct frame *f;
c32cdd9a 6831 int x, y;
b8009dd1 6832{
06a2c219
GM
6833 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6834 int portion;
b8009dd1
RS
6835 Lisp_Object window;
6836 struct window *w;
0d487c52
GM
6837 Cursor cursor = None;
6838 struct buffer *b;
b8009dd1 6839
06a2c219
GM
6840 /* When a menu is active, don't highlight because this looks odd. */
6841#ifdef USE_X_TOOLKIT
6842 if (popup_activated ())
6843 return;
6844#endif
6845
04fff9c0
GM
6846 if (disable_mouse_highlight
6847 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6848 return;
6849
06a2c219
GM
6850 dpyinfo->mouse_face_mouse_x = x;
6851 dpyinfo->mouse_face_mouse_y = y;
6852 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6853
06a2c219 6854 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6855 return;
6856
514e4681
RS
6857 if (gc_in_progress)
6858 {
06a2c219 6859 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6860 return;
6861 }
6862
b8009dd1 6863 /* Which window is that in? */
06a2c219 6864 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6865
6866 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6867 if (! EQ (window, dpyinfo->mouse_face_window))
6868 clear_mouse_face (dpyinfo);
6869
6870 /* Not on a window -> return. */
6871 if (!WINDOWP (window))
6872 return;
6873
6874 /* Convert to window-relative pixel coordinates. */
6875 w = XWINDOW (window);
6876 frame_to_window_pixel_xy (w, &x, &y);
6877
9ea173e8 6878 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6879 buffer. */
9ea173e8 6880 if (EQ (window, f->tool_bar_window))
06a2c219 6881 {
9ea173e8 6882 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6883 return;
6884 }
6885
0d487c52 6886 /* Mouse is on the mode or header line? */
06a2c219
GM
6887 if (portion == 1 || portion == 3)
6888 {
06a2c219
GM
6889 note_mode_line_highlight (w, x, portion == 1);
6890 return;
6891 }
0d487c52
GM
6892
6893 if (portion == 2)
6894 cursor = f->output_data.x->horizontal_drag_cursor;
06a2c219 6895 else
0d487c52 6896 cursor = f->output_data.x->text_cursor;
b8009dd1 6897
0cdd0c9f
RS
6898 /* Are we in a window whose display is up to date?
6899 And verify the buffer's text has not changed. */
0d487c52 6900 b = XBUFFER (w->buffer);
06a2c219
GM
6901 if (/* Within text portion of the window. */
6902 portion == 0
0cdd0c9f 6903 && EQ (w->window_end_valid, w->buffer)
0d487c52
GM
6904 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
6905 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
b8009dd1 6906 {
06a2c219
GM
6907 int hpos, vpos, pos, i, area;
6908 struct glyph *glyph;
f9db2310 6909 Lisp_Object object;
0d487c52
GM
6910 Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
6911 Lisp_Object *overlay_vec = NULL;
6912 int len, noverlays;
6913 struct buffer *obuf;
6914 int obegv, ozv, same_region;
b8009dd1 6915
06a2c219 6916 /* Find the glyph under X/Y. */
f9db2310 6917 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
06a2c219
GM
6918
6919 /* Clear mouse face if X/Y not over text. */
6920 if (glyph == NULL
6921 || area != TEXT_AREA
6922 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6923 {
fa262c07
GM
6924 if (clear_mouse_face (dpyinfo))
6925 cursor = None;
6926 goto set_cursor;
06a2c219
GM
6927 }
6928
6929 pos = glyph->charpos;
f9db2310
GM
6930 object = glyph->object;
6931 if (!STRINGP (object) && !BUFFERP (object))
fa262c07 6932 goto set_cursor;
06a2c219 6933
0d487c52
GM
6934 /* If we get an out-of-range value, return now; avoid an error. */
6935 if (BUFFERP (object) && pos > BUF_Z (b))
fa262c07 6936 goto set_cursor;
06a2c219 6937
0d487c52
GM
6938 /* Make the window's buffer temporarily current for
6939 overlays_at and compute_char_face. */
6940 obuf = current_buffer;
6941 current_buffer = b;
6942 obegv = BEGV;
6943 ozv = ZV;
6944 BEGV = BEG;
6945 ZV = Z;
06a2c219 6946
0d487c52
GM
6947 /* Is this char mouse-active or does it have help-echo? */
6948 position = make_number (pos);
f9db2310 6949
0d487c52
GM
6950 if (BUFFERP (object))
6951 {
6952 /* Put all the overlays we want in a vector in overlay_vec.
6953 Store the length in len. If there are more than 10, make
6954 enough space for all, and try again. */
6955 len = 10;
6956 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6957 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
6958 if (noverlays > len)
6959 {
6960 len = noverlays;
6961 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6962 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
6963 }
f8349001 6964
0d487c52
GM
6965 /* Sort overlays into increasing priority order. */
6966 noverlays = sort_overlays (overlay_vec, noverlays, w);
6967 }
6968 else
6969 noverlays = 0;
6970
6971 same_region = (EQ (window, dpyinfo->mouse_face_window)
6972 && vpos >= dpyinfo->mouse_face_beg_row
6973 && vpos <= dpyinfo->mouse_face_end_row
6974 && (vpos > dpyinfo->mouse_face_beg_row
6975 || hpos >= dpyinfo->mouse_face_beg_col)
6976 && (vpos < dpyinfo->mouse_face_end_row
6977 || hpos < dpyinfo->mouse_face_end_col
6978 || dpyinfo->mouse_face_past_end));
6979
6980 if (same_region)
6981 cursor = None;
6982
6983 /* Check mouse-face highlighting. */
6984 if (! same_region
6985 /* If there exists an overlay with mouse-face overlapping
6986 the one we are currently highlighting, we have to
6987 check if we enter the overlapping overlay, and then
6988 highlight only that. */
6989 || (OVERLAYP (dpyinfo->mouse_face_overlay)
6990 && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
6991 {
0d487c52
GM
6992 /* Find the highest priority overlay that has a mouse-face
6993 property. */
6994 overlay = Qnil;
6995 for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
6996 {
6997 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6998 if (!NILP (mouse_face))
6999 overlay = overlay_vec[i];
7000 }
8bd189fb
GM
7001
7002 /* If we're actually highlighting the same overlay as
7003 before, there's no need to do that again. */
7004 if (!NILP (overlay)
7005 && EQ (overlay, dpyinfo->mouse_face_overlay))
7006 goto check_help_echo;
f9db2310 7007
8bd189fb
GM
7008 dpyinfo->mouse_face_overlay = overlay;
7009
7010 /* Clear the display of the old active region, if any. */
7011 if (clear_mouse_face (dpyinfo))
7012 cursor = None;
7013
0d487c52
GM
7014 /* If no overlay applies, get a text property. */
7015 if (NILP (overlay))
7016 mouse_face = Fget_text_property (position, Qmouse_face, object);
06a2c219 7017
0d487c52
GM
7018 /* Handle the overlay case. */
7019 if (!NILP (overlay))
7020 {
7021 /* Find the range of text around this char that
7022 should be active. */
7023 Lisp_Object before, after;
7024 int ignore;
7025
7026 before = Foverlay_start (overlay);
7027 after = Foverlay_end (overlay);
7028 /* Record this as the current active region. */
7029 fast_find_position (w, XFASTINT (before),
7030 &dpyinfo->mouse_face_beg_col,
7031 &dpyinfo->mouse_face_beg_row,
7032 &dpyinfo->mouse_face_beg_x,
7e376260
GM
7033 &dpyinfo->mouse_face_beg_y, Qnil);
7034
0d487c52
GM
7035 dpyinfo->mouse_face_past_end
7036 = !fast_find_position (w, XFASTINT (after),
7037 &dpyinfo->mouse_face_end_col,
7038 &dpyinfo->mouse_face_end_row,
7039 &dpyinfo->mouse_face_end_x,
7e376260 7040 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7041 dpyinfo->mouse_face_window = window;
7042 dpyinfo->mouse_face_face_id
7043 = face_at_buffer_position (w, pos, 0, 0,
7044 &ignore, pos + 1, 1);
7045
7046 /* Display it as active. */
7047 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7048 cursor = None;
0d487c52
GM
7049 }
7050 /* Handle the text property case. */
7051 else if (!NILP (mouse_face) && BUFFERP (object))
7052 {
7053 /* Find the range of text around this char that
7054 should be active. */
7055 Lisp_Object before, after, beginning, end;
7056 int ignore;
7057
7058 beginning = Fmarker_position (w->start);
7059 end = make_number (BUF_Z (XBUFFER (object))
7060 - XFASTINT (w->window_end_pos));
7061 before
7062 = Fprevious_single_property_change (make_number (pos + 1),
7063 Qmouse_face,
7064 object, beginning);
7065 after
7066 = Fnext_single_property_change (position, Qmouse_face,
7067 object, end);
7068
7069 /* Record this as the current active region. */
7070 fast_find_position (w, XFASTINT (before),
7071 &dpyinfo->mouse_face_beg_col,
7072 &dpyinfo->mouse_face_beg_row,
7073 &dpyinfo->mouse_face_beg_x,
7e376260 7074 &dpyinfo->mouse_face_beg_y, Qnil);
0d487c52
GM
7075 dpyinfo->mouse_face_past_end
7076 = !fast_find_position (w, XFASTINT (after),
7077 &dpyinfo->mouse_face_end_col,
7078 &dpyinfo->mouse_face_end_row,
7079 &dpyinfo->mouse_face_end_x,
7e376260 7080 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7081 dpyinfo->mouse_face_window = window;
7082
7083 if (BUFFERP (object))
06a2c219
GM
7084 dpyinfo->mouse_face_face_id
7085 = face_at_buffer_position (w, pos, 0, 0,
7086 &ignore, pos + 1, 1);
7087
0d487c52
GM
7088 /* Display it as active. */
7089 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7090 cursor = None;
0d487c52
GM
7091 }
7092 else if (!NILP (mouse_face) && STRINGP (object))
7093 {
7094 Lisp_Object b, e;
7095 int ignore;
f9db2310 7096
0d487c52
GM
7097 b = Fprevious_single_property_change (make_number (pos + 1),
7098 Qmouse_face,
7099 object, Qnil);
7100 e = Fnext_single_property_change (position, Qmouse_face,
7101 object, Qnil);
7102 if (NILP (b))
7103 b = make_number (0);
7104 if (NILP (e))
7105 e = make_number (XSTRING (object)->size - 1);
7106 fast_find_string_pos (w, XINT (b), object,
06a2c219
GM
7107 &dpyinfo->mouse_face_beg_col,
7108 &dpyinfo->mouse_face_beg_row,
7109 &dpyinfo->mouse_face_beg_x,
0d487c52
GM
7110 &dpyinfo->mouse_face_beg_y, 0);
7111 fast_find_string_pos (w, XINT (e), object,
7112 &dpyinfo->mouse_face_end_col,
7113 &dpyinfo->mouse_face_end_row,
7114 &dpyinfo->mouse_face_end_x,
7115 &dpyinfo->mouse_face_end_y, 1);
7116 dpyinfo->mouse_face_past_end = 0;
7117 dpyinfo->mouse_face_window = window;
7118 dpyinfo->mouse_face_face_id
7119 = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
7120 glyph->face_id, 1);
7121 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7122 cursor = None;
0d487c52 7123 }
7e376260
GM
7124 else if (STRINGP (object) && NILP (mouse_face))
7125 {
7126 /* A string which doesn't have mouse-face, but
7127 the text ``under'' it might have. */
7128 struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
7129 int start = MATRIX_ROW_START_CHARPOS (r);
7130
7131 pos = string_buffer_position (w, object, start);
7132 if (pos > 0)
7133 mouse_face = get_char_property_and_overlay (make_number (pos),
7134 Qmouse_face,
7135 w->buffer,
7136 &overlay);
7137 if (!NILP (mouse_face) && !NILP (overlay))
7138 {
7139 Lisp_Object before = Foverlay_start (overlay);
7140 Lisp_Object after = Foverlay_end (overlay);
91c153e2 7141 int ignore;
7e376260
GM
7142
7143 /* Note that we might not be able to find position
7144 BEFORE in the glyph matrix if the overlay is
7145 entirely covered by a `display' property. In
7146 this case, we overshoot. So let's stop in
7147 the glyph matrix before glyphs for OBJECT. */
7148 fast_find_position (w, XFASTINT (before),
7149 &dpyinfo->mouse_face_beg_col,
7150 &dpyinfo->mouse_face_beg_row,
7151 &dpyinfo->mouse_face_beg_x,
7152 &dpyinfo->mouse_face_beg_y,
7153 object);
7154
7155 dpyinfo->mouse_face_past_end
7156 = !fast_find_position (w, XFASTINT (after),
7157 &dpyinfo->mouse_face_end_col,
7158 &dpyinfo->mouse_face_end_row,
7159 &dpyinfo->mouse_face_end_x,
7160 &dpyinfo->mouse_face_end_y,
7161 Qnil);
7162 dpyinfo->mouse_face_window = window;
7163 dpyinfo->mouse_face_face_id
7164 = face_at_buffer_position (w, pos, 0, 0,
7165 &ignore, pos + 1, 1);
7166
7167 /* Display it as active. */
7168 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
7169 cursor = None;
7170 }
7171 }
0d487c52 7172 }
06a2c219 7173
8bd189fb
GM
7174 check_help_echo:
7175
0d487c52
GM
7176 /* Look for a `help-echo' property. */
7177 {
7178 Lisp_Object help, overlay;
06a2c219 7179
0d487c52
GM
7180 /* Check overlays first. */
7181 help = overlay = Qnil;
7182 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
7183 {
7184 overlay = overlay_vec[i];
7185 help = Foverlay_get (overlay, Qhelp_echo);
7186 }
be010514 7187
0d487c52
GM
7188 if (!NILP (help))
7189 {
7190 help_echo = help;
7191 help_echo_window = window;
7192 help_echo_object = overlay;
7193 help_echo_pos = pos;
7194 }
7195 else
7196 {
7197 Lisp_Object object = glyph->object;
7198 int charpos = glyph->charpos;
7177d86b 7199
0d487c52
GM
7200 /* Try text properties. */
7201 if (STRINGP (object)
7202 && charpos >= 0
7203 && charpos < XSTRING (object)->size)
7204 {
7205 help = Fget_text_property (make_number (charpos),
7206 Qhelp_echo, object);
7207 if (NILP (help))
7208 {
7209 /* If the string itself doesn't specify a help-echo,
7210 see if the buffer text ``under'' it does. */
7211 struct glyph_row *r
7212 = MATRIX_ROW (w->current_matrix, vpos);
7213 int start = MATRIX_ROW_START_CHARPOS (r);
7214 int pos = string_buffer_position (w, object, start);
7215 if (pos > 0)
7216 {
7e376260 7217 help = Fget_char_property (make_number (pos),
0d487c52
GM
7218 Qhelp_echo, w->buffer);
7219 if (!NILP (help))
7220 {
7221 charpos = pos;
7222 object = w->buffer;
7223 }
7224 }
7225 }
7226 }
7227 else if (BUFFERP (object)
7228 && charpos >= BEGV
7229 && charpos < ZV)
7230 help = Fget_text_property (make_number (charpos), Qhelp_echo,
7231 object);
06a2c219 7232
0d487c52
GM
7233 if (!NILP (help))
7234 {
7235 help_echo = help;
7236 help_echo_window = window;
7237 help_echo_object = object;
7238 help_echo_pos = charpos;
7239 }
7240 }
06a2c219 7241 }
0d487c52
GM
7242
7243 BEGV = obegv;
7244 ZV = ozv;
7245 current_buffer = obuf;
06a2c219 7246 }
0d487c52 7247
fa262c07
GM
7248 set_cursor:
7249
0d487c52
GM
7250 if (cursor != None)
7251 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
06a2c219
GM
7252}
7253
7254static void
7255redo_mouse_highlight ()
7256{
7257 if (!NILP (last_mouse_motion_frame)
7258 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
7259 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
7260 last_mouse_motion_event.x,
7261 last_mouse_motion_event.y);
7262}
7263
7264
7265\f
7266/***********************************************************************
9ea173e8 7267 Tool-bars
06a2c219
GM
7268 ***********************************************************************/
7269
9ea173e8
GM
7270static int x_tool_bar_item P_ ((struct frame *, int, int,
7271 struct glyph **, int *, int *, int *));
06a2c219 7272
9ea173e8 7273/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
7274 or -1. */
7275
9ea173e8 7276static int last_tool_bar_item;
06a2c219
GM
7277
7278
9ea173e8
GM
7279/* Get information about the tool-bar item at position X/Y on frame F.
7280 Return in *GLYPH a pointer to the glyph of the tool-bar item in
7281 the current matrix of the tool-bar window of F, or NULL if not
7282 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
8daf1204 7283 item in F->tool_bar_items. Value is
06a2c219 7284
9ea173e8 7285 -1 if X/Y is not on a tool-bar item
06a2c219
GM
7286 0 if X/Y is on the same item that was highlighted before.
7287 1 otherwise. */
7288
7289static int
9ea173e8 7290x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
7291 struct frame *f;
7292 int x, y;
7293 struct glyph **glyph;
7294 int *hpos, *vpos, *prop_idx;
7295{
7296 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7297 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7298 int area;
7299
7300 /* Find the glyph under X/Y. */
f9db2310 7301 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
06a2c219
GM
7302 if (*glyph == NULL)
7303 return -1;
7304
9ea173e8 7305 /* Get the start of this tool-bar item's properties in
8daf1204 7306 f->tool_bar_items. */
9ea173e8 7307 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
7308 return -1;
7309
7310 /* Is mouse on the highlighted item? */
9ea173e8 7311 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
7312 && *vpos >= dpyinfo->mouse_face_beg_row
7313 && *vpos <= dpyinfo->mouse_face_end_row
7314 && (*vpos > dpyinfo->mouse_face_beg_row
7315 || *hpos >= dpyinfo->mouse_face_beg_col)
7316 && (*vpos < dpyinfo->mouse_face_end_row
7317 || *hpos < dpyinfo->mouse_face_end_col
7318 || dpyinfo->mouse_face_past_end))
7319 return 0;
7320
7321 return 1;
7322}
7323
7324
9ea173e8 7325/* Handle mouse button event on the tool-bar of frame F, at
6c4a22e6 7326 frame-relative coordinates X/Y. EVENT_TYPE is either ButtonPress
06a2c219
GM
7327 or ButtonRelase. */
7328
7329static void
9ea173e8 7330x_handle_tool_bar_click (f, button_event)
06a2c219
GM
7331 struct frame *f;
7332 XButtonEvent *button_event;
7333{
7334 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7335 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7336 int hpos, vpos, prop_idx;
7337 struct glyph *glyph;
7338 Lisp_Object enabled_p;
7339 int x = button_event->x;
7340 int y = button_event->y;
7341
9ea173e8 7342 /* If not on the highlighted tool-bar item, return. */
06a2c219 7343 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 7344 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
7345 return;
7346
7347 /* If item is disabled, do nothing. */
8daf1204 7348 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7349 if (NILP (enabled_p))
7350 return;
7351
7352 if (button_event->type == ButtonPress)
7353 {
7354 /* Show item in pressed state. */
7355 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
7356 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 7357 last_tool_bar_item = prop_idx;
06a2c219
GM
7358 }
7359 else
7360 {
7361 Lisp_Object key, frame;
7362 struct input_event event;
7363
7364 /* Show item in released state. */
7365 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
7366 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
7367
8daf1204 7368 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
06a2c219
GM
7369
7370 XSETFRAME (frame, f);
9ea173e8 7371 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7372 event.frame_or_window = frame;
7373 event.arg = frame;
06a2c219
GM
7374 kbd_buffer_store_event (&event);
7375
9ea173e8 7376 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7377 event.frame_or_window = frame;
7378 event.arg = key;
06a2c219
GM
7379 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7380 button_event->state);
7381 kbd_buffer_store_event (&event);
9ea173e8 7382 last_tool_bar_item = -1;
06a2c219
GM
7383 }
7384}
7385
7386
9ea173e8
GM
7387/* Possibly highlight a tool-bar item on frame F when mouse moves to
7388 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
7389 note_mouse_highlight. */
7390
7391static void
9ea173e8 7392note_tool_bar_highlight (f, x, y)
06a2c219
GM
7393 struct frame *f;
7394 int x, y;
7395{
9ea173e8 7396 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
7397 struct window *w = XWINDOW (window);
7398 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7399 int hpos, vpos;
7400 struct glyph *glyph;
7401 struct glyph_row *row;
5c187dee 7402 int i;
06a2c219
GM
7403 Lisp_Object enabled_p;
7404 int prop_idx;
140330de 7405 enum draw_glyphs_face draw;
5c187dee 7406 int mouse_down_p, rc;
06a2c219
GM
7407
7408 /* Function note_mouse_highlight is called with negative x(y
7409 values when mouse moves outside of the frame. */
7410 if (x <= 0 || y <= 0)
7411 {
7412 clear_mouse_face (dpyinfo);
7413 return;
7414 }
7415
9ea173e8 7416 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
7417 if (rc < 0)
7418 {
9ea173e8 7419 /* Not on tool-bar item. */
06a2c219
GM
7420 clear_mouse_face (dpyinfo);
7421 return;
7422 }
7423 else if (rc == 0)
06a2c219 7424 goto set_help_echo;
b8009dd1 7425
06a2c219
GM
7426 clear_mouse_face (dpyinfo);
7427
9ea173e8 7428 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
7429 mouse_down_p = (dpyinfo->grabbed
7430 && f == last_mouse_frame
7431 && FRAME_LIVE_P (f));
7432 if (mouse_down_p
9ea173e8 7433 && last_tool_bar_item != prop_idx)
06a2c219
GM
7434 return;
7435
7436 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7437 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7438
9ea173e8 7439 /* If tool-bar item is not enabled, don't highlight it. */
8daf1204 7440 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7441 if (!NILP (enabled_p))
7442 {
7443 /* Compute the x-position of the glyph. In front and past the
7444 image is a space. We include this is the highlighted area. */
7445 row = MATRIX_ROW (w->current_matrix, vpos);
7446 for (i = x = 0; i < hpos; ++i)
7447 x += row->glyphs[TEXT_AREA][i].pixel_width;
7448
7449 /* Record this as the current active region. */
7450 dpyinfo->mouse_face_beg_col = hpos;
7451 dpyinfo->mouse_face_beg_row = vpos;
7452 dpyinfo->mouse_face_beg_x = x;
7453 dpyinfo->mouse_face_beg_y = row->y;
7454 dpyinfo->mouse_face_past_end = 0;
7455
7456 dpyinfo->mouse_face_end_col = hpos + 1;
7457 dpyinfo->mouse_face_end_row = vpos;
7458 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7459 dpyinfo->mouse_face_end_y = row->y;
7460 dpyinfo->mouse_face_window = window;
9ea173e8 7461 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
7462
7463 /* Display it as active. */
7464 show_mouse_face (dpyinfo, draw);
7465 dpyinfo->mouse_face_image_state = draw;
b8009dd1 7466 }
06a2c219
GM
7467
7468 set_help_echo:
7469
9ea173e8 7470 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 7471 XTread_socket does the rest. */
7cea38bc 7472 help_echo_object = help_echo_window = Qnil;
be010514 7473 help_echo_pos = -1;
8daf1204 7474 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
b7e80413 7475 if (NILP (help_echo))
8daf1204 7476 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
b8009dd1 7477}
4d73d038 7478
06a2c219
GM
7479
7480\f
9f8531e5
GM
7481/* Find the glyph matrix position of buffer position CHARPOS in window
7482 *W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7483 current glyphs must be up to date. If CHARPOS is above window
7484 start return (0, 0, 0, 0). If CHARPOS is after end of W, return end
7485 of last line in W. In the row containing CHARPOS, stop before glyphs
7e376260 7486 having STOP as object. */
b8009dd1 7487
9f8531e5
GM
7488#if 0 /* This is a version of fast_find_position that's more correct
7489 in the presence of hscrolling, for example. I didn't install
7490 it right away because the problem fixed is minor, it failed
7491 in 20.x as well, and I think it's too risky to install
7492 so near the release of 21.1. 2001-09-25 gerd. */
7493
7494static int
7495fast_find_position (w, charpos, hpos, vpos, x, y, stop)
7496 struct window *w;
7497 int charpos;
7498 int *hpos, *vpos, *x, *y;
7499 Lisp_Object stop;
7500{
7501 struct glyph_row *row, *first;
7502 struct glyph *glyph, *end;
7503 int i, past_end = 0;
7504
7505 first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
62e33982 7506 row = row_containing_pos (w, charpos, first, NULL, 0);
9f8531e5
GM
7507 if (row == NULL)
7508 {
7509 if (charpos < MATRIX_ROW_START_CHARPOS (first))
7510 {
7511 *x = *y = *hpos = *vpos = 0;
7512 return 0;
7513 }
7514 else
7515 {
7516 row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
7517 past_end = 1;
7518 }
7519 }
7520
7521 *x = row->x;
7522 *y = row->y;
7523 *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7524
7525 glyph = row->glyphs[TEXT_AREA];
7526 end = glyph + row->used[TEXT_AREA];
7527
7528 /* Skip over glyphs not having an object at the start of the row.
7529 These are special glyphs like truncation marks on terminal
7530 frames. */
7531 if (row->displays_text_p)
7532 while (glyph < end
7533 && INTEGERP (glyph->object)
7534 && !EQ (stop, glyph->object)
7535 && glyph->charpos < 0)
7536 {
7537 *x += glyph->pixel_width;
7538 ++glyph;
7539 }
7540
7541 while (glyph < end
7542 && !INTEGERP (glyph->object)
7543 && !EQ (stop, glyph->object)
7544 && (!BUFFERP (glyph->object)
7545 || glyph->charpos < charpos))
7546 {
7547 *x += glyph->pixel_width;
7548 ++glyph;
7549 }
7550
7551 *hpos = glyph - row->glyphs[TEXT_AREA];
7552 return past_end;
7553}
7554
7555#else /* not 0 */
7556
b8009dd1 7557static int
7e376260 7558fast_find_position (w, pos, hpos, vpos, x, y, stop)
06a2c219 7559 struct window *w;
b8009dd1 7560 int pos;
06a2c219 7561 int *hpos, *vpos, *x, *y;
7e376260 7562 Lisp_Object stop;
b8009dd1 7563{
b8009dd1 7564 int i;
bf1c0ba1 7565 int lastcol;
06a2c219
GM
7566 int maybe_next_line_p = 0;
7567 int line_start_position;
7568 int yb = window_text_bottom_y (w);
03d1a189
GM
7569 struct glyph_row *row, *best_row;
7570 int row_vpos, best_row_vpos;
06a2c219
GM
7571 int current_x;
7572
03d1a189
GM
7573 row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7574 row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7575
06a2c219 7576 while (row->y < yb)
b8009dd1 7577 {
06a2c219
GM
7578 if (row->used[TEXT_AREA])
7579 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7580 else
7581 line_start_position = 0;
7582
7583 if (line_start_position > pos)
b8009dd1 7584 break;
77b68646
RS
7585 /* If the position sought is the end of the buffer,
7586 don't include the blank lines at the bottom of the window. */
06a2c219
GM
7587 else if (line_start_position == pos
7588 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 7589 {
06a2c219 7590 maybe_next_line_p = 1;
77b68646
RS
7591 break;
7592 }
06a2c219
GM
7593 else if (line_start_position > 0)
7594 {
7595 best_row = row;
7596 best_row_vpos = row_vpos;
7597 }
4b0bb6f3
GM
7598
7599 if (row->y + row->height >= yb)
7600 break;
06a2c219
GM
7601
7602 ++row;
7603 ++row_vpos;
b8009dd1 7604 }
06a2c219
GM
7605
7606 /* Find the right column within BEST_ROW. */
7607 lastcol = 0;
7608 current_x = best_row->x;
7609 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 7610 {
06a2c219 7611 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7e376260 7612 int charpos = glyph->charpos;
06a2c219 7613
7e376260 7614 if (BUFFERP (glyph->object))
bf1c0ba1 7615 {
7e376260
GM
7616 if (charpos == pos)
7617 {
7618 *hpos = i;
7619 *vpos = best_row_vpos;
7620 *x = current_x;
7621 *y = best_row->y;
7622 return 1;
7623 }
7624 else if (charpos > pos)
7625 break;
bf1c0ba1 7626 }
7e376260 7627 else if (EQ (glyph->object, stop))
4d73d038 7628 break;
06a2c219 7629
7e376260
GM
7630 if (charpos > 0)
7631 lastcol = i;
06a2c219 7632 current_x += glyph->pixel_width;
bf1c0ba1 7633 }
b8009dd1 7634
77b68646
RS
7635 /* If we're looking for the end of the buffer,
7636 and we didn't find it in the line we scanned,
7637 use the start of the following line. */
06a2c219 7638 if (maybe_next_line_p)
77b68646 7639 {
06a2c219
GM
7640 ++best_row;
7641 ++best_row_vpos;
7642 lastcol = 0;
7643 current_x = best_row->x;
77b68646
RS
7644 }
7645
06a2c219
GM
7646 *vpos = best_row_vpos;
7647 *hpos = lastcol + 1;
7648 *x = current_x;
7649 *y = best_row->y;
b8009dd1
RS
7650 return 0;
7651}
7652
9f8531e5
GM
7653#endif /* not 0 */
7654
06a2c219 7655
f9db2310
GM
7656/* Find the position of the the glyph for position POS in OBJECT in
7657 window W's current matrix, and return in *X/*Y the pixel
7658 coordinates, and return in *HPOS/*VPOS the column/row of the glyph.
7659
7660 RIGHT_P non-zero means return the position of the right edge of the
7661 glyph, RIGHT_P zero means return the left edge position.
7662
7663 If no glyph for POS exists in the matrix, return the position of
7664 the glyph with the next smaller position that is in the matrix, if
7665 RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS
7666 exists in the matrix, return the position of the glyph with the
7667 next larger position in OBJECT.
7668
7669 Value is non-zero if a glyph was found. */
7670
7671static int
7672fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
7673 struct window *w;
7674 int pos;
7675 Lisp_Object object;
7676 int *hpos, *vpos, *x, *y;
7677 int right_p;
7678{
7679 int yb = window_text_bottom_y (w);
7680 struct glyph_row *r;
7681 struct glyph *best_glyph = NULL;
7682 struct glyph_row *best_row = NULL;
7683 int best_x = 0;
7684
7685 for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7686 r->enabled_p && r->y < yb;
7687 ++r)
7688 {
7689 struct glyph *g = r->glyphs[TEXT_AREA];
7690 struct glyph *e = g + r->used[TEXT_AREA];
7691 int gx;
7692
7693 for (gx = r->x; g < e; gx += g->pixel_width, ++g)
7694 if (EQ (g->object, object))
7695 {
7696 if (g->charpos == pos)
7697 {
7698 best_glyph = g;
7699 best_x = gx;
7700 best_row = r;
7701 goto found;
7702 }
7703 else if (best_glyph == NULL
7704 || ((abs (g->charpos - pos)
7705 < abs (best_glyph->charpos - pos))
7706 && (right_p
7707 ? g->charpos < pos
7708 : g->charpos > pos)))
7709 {
7710 best_glyph = g;
7711 best_x = gx;
7712 best_row = r;
7713 }
7714 }
7715 }
7716
7717 found:
7718
7719 if (best_glyph)
7720 {
7721 *x = best_x;
7722 *hpos = best_glyph - best_row->glyphs[TEXT_AREA];
7723
7724 if (right_p)
7725 {
7726 *x += best_glyph->pixel_width;
7727 ++*hpos;
7728 }
7729
7730 *y = best_row->y;
7731 *vpos = best_row - w->current_matrix->rows;
7732 }
7733
7734 return best_glyph != NULL;
7735}
7736
7737
b8009dd1
RS
7738/* Display the active region described by mouse_face_*
7739 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7740
7741static void
06a2c219 7742show_mouse_face (dpyinfo, draw)
7a13e894 7743 struct x_display_info *dpyinfo;
06a2c219 7744 enum draw_glyphs_face draw;
b8009dd1 7745{
7a13e894 7746 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7747 struct frame *f = XFRAME (WINDOW_FRAME (w));
06a2c219 7748
b2bbd509
GM
7749 if (/* If window is in the process of being destroyed, don't bother
7750 to do anything. */
7751 w->current_matrix != NULL
7752 /* Recognize when we are called to operate on rows that don't exist
7753 anymore. This can happen when a window is split. */
7754 && dpyinfo->mouse_face_end_row < w->current_matrix->nrows)
06a2c219 7755 {
b2bbd509
GM
7756 int phys_cursor_on_p = w->phys_cursor_on_p;
7757 struct glyph_row *row, *first, *last;
06a2c219 7758
b2bbd509
GM
7759 first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row);
7760 last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row);
7761
7762 for (row = first; row <= last && row->enabled_p; ++row)
06a2c219 7763 {
b2bbd509 7764 int start_hpos, end_hpos, start_x;
06a2c219 7765
b2bbd509
GM
7766 /* For all but the first row, the highlight starts at column 0. */
7767 if (row == first)
7768 {
7769 start_hpos = dpyinfo->mouse_face_beg_col;
7770 start_x = dpyinfo->mouse_face_beg_x;
7771 }
7772 else
7773 {
7774 start_hpos = 0;
7775 start_x = 0;
7776 }
06a2c219 7777
b2bbd509
GM
7778 if (row == last)
7779 end_hpos = dpyinfo->mouse_face_end_col;
7780 else
7781 end_hpos = row->used[TEXT_AREA];
b8009dd1 7782
b2bbd509
GM
7783 if (end_hpos > start_hpos)
7784 {
7785 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7786 start_hpos, end_hpos, draw, 0);
b8009dd1 7787
60626bab
GM
7788 row->mouse_face_p
7789 = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED;
b2bbd509
GM
7790 }
7791 }
2729a2b5 7792
b2bbd509
GM
7793 /* When we've written over the cursor, arrange for it to
7794 be displayed again. */
7795 if (phys_cursor_on_p && !w->phys_cursor_on_p)
7796 x_display_cursor (w, 1,
7797 w->phys_cursor.hpos, w->phys_cursor.vpos,
7798 w->phys_cursor.x, w->phys_cursor.y);
7799 }
fb3b7de5 7800
06a2c219
GM
7801 /* Change the mouse cursor. */
7802 if (draw == DRAW_NORMAL_TEXT)
7803 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7804 f->output_data.x->text_cursor);
7805 else if (draw == DRAW_MOUSE_FACE)
334208b7 7806 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7807 f->output_data.x->cross_cursor);
27ead1d5 7808 else
334208b7 7809 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7810 f->output_data.x->nontext_cursor);
b8009dd1
RS
7811}
7812
7813/* Clear out the mouse-highlighted active region.
fa262c07
GM
7814 Redraw it un-highlighted first. Value is non-zero if mouse
7815 face was actually drawn unhighlighted. */
b8009dd1 7816
fa262c07 7817static int
7a13e894
RS
7818clear_mouse_face (dpyinfo)
7819 struct x_display_info *dpyinfo;
b8009dd1 7820{
fa262c07 7821 int cleared = 0;
06a2c219 7822
fa262c07
GM
7823 if (!NILP (dpyinfo->mouse_face_window))
7824 {
7825 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
7826 cleared = 1;
7827 }
b8009dd1 7828
7a13e894
RS
7829 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7830 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7831 dpyinfo->mouse_face_window = Qnil;
1b85dc1c 7832 dpyinfo->mouse_face_overlay = Qnil;
fa262c07 7833 return cleared;
b8009dd1 7834}
e687d06e 7835
71b8321e
GM
7836
7837/* Clear any mouse-face on window W. This function is part of the
7838 redisplay interface, and is called from try_window_id and similar
7839 functions to ensure the mouse-highlight is off. */
7840
7841static void
7842x_clear_mouse_face (w)
7843 struct window *w;
7844{
7845 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7846 Lisp_Object window;
7847
2e636f9d 7848 BLOCK_INPUT;
71b8321e
GM
7849 XSETWINDOW (window, w);
7850 if (EQ (window, dpyinfo->mouse_face_window))
7851 clear_mouse_face (dpyinfo);
2e636f9d 7852 UNBLOCK_INPUT;
71b8321e
GM
7853}
7854
7855
e687d06e
RS
7856/* Just discard the mouse face information for frame F, if any.
7857 This is used when the size of F is changed. */
7858
dfcf069d 7859void
e687d06e
RS
7860cancel_mouse_face (f)
7861 FRAME_PTR f;
7862{
7863 Lisp_Object window;
7864 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7865
7866 window = dpyinfo->mouse_face_window;
7867 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7868 {
7869 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7870 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7871 dpyinfo->mouse_face_window = Qnil;
7872 }
7873}
b52b65bd 7874
b8009dd1 7875\f
b52b65bd
GM
7876static int glyph_rect P_ ((struct frame *f, int, int, XRectangle *));
7877
7878
7879/* Try to determine frame pixel position and size of the glyph under
7880 frame pixel coordinates X/Y on frame F . Return the position and
7881 size in *RECT. Value is non-zero if we could compute these
7882 values. */
7883
7884static int
7885glyph_rect (f, x, y, rect)
7886 struct frame *f;
7887 int x, y;
7888 XRectangle *rect;
7889{
7890 Lisp_Object window;
7891 int part, found = 0;
7892
7893 window = window_from_coordinates (f, x, y, &part, 0);
7894 if (!NILP (window))
7895 {
7896 struct window *w = XWINDOW (window);
7897 struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7898 struct glyph_row *end = r + w->current_matrix->nrows - 1;
b52b65bd
GM
7899
7900 frame_to_window_pixel_xy (w, &x, &y);
7901
7902 for (; !found && r < end && r->enabled_p; ++r)
7903 if (r->y >= y)
7904 {
7905 struct glyph *g = r->glyphs[TEXT_AREA];
7906 struct glyph *end = g + r->used[TEXT_AREA];
7907 int gx;
7908
7909 for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
7910 if (gx >= x)
7911 {
7912 rect->width = g->pixel_width;
7913 rect->height = r->height;
7914 rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
7915 rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
7916 found = 1;
7917 }
7918 }
7919 }
7920
7921 return found;
7922}
7923
12ba150f 7924
90e65f07 7925/* Return the current position of the mouse.
b52b65bd 7926 *FP should be a frame which indicates which display to ask about.
90e65f07 7927
b52b65bd
GM
7928 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
7929 and *PART to the frame, window, and scroll bar part that the mouse
7930 is over. Set *X and *Y to the portion and whole of the mouse's
ab648270 7931 position on the scroll bar.
12ba150f 7932
b52b65bd
GM
7933 If the mouse movement started elsewhere, set *FP to the frame the
7934 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
12ba150f
JB
7935 the mouse is over.
7936
b52b65bd 7937 Set *TIME to the server time-stamp for the time at which the mouse
12ba150f
JB
7938 was at this position.
7939
a135645a
RS
7940 Don't store anything if we don't have a valid set of values to report.
7941
90e65f07 7942 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7943 movement. */
90e65f07
JB
7944
7945static void
1cf412ec 7946XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7947 FRAME_PTR *fp;
1cf412ec 7948 int insist;
12ba150f 7949 Lisp_Object *bar_window;
ab648270 7950 enum scroll_bar_part *part;
90e65f07 7951 Lisp_Object *x, *y;
e5d77022 7952 unsigned long *time;
90e65f07 7953{
a135645a
RS
7954 FRAME_PTR f1;
7955
90e65f07
JB
7956 BLOCK_INPUT;
7957
8bcee03e 7958 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7959 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7960 else
7961 {
12ba150f
JB
7962 Window root;
7963 int root_x, root_y;
90e65f07 7964
12ba150f
JB
7965 Window dummy_window;
7966 int dummy;
7967
39d8bb4d
KH
7968 Lisp_Object frame, tail;
7969
7970 /* Clear the mouse-moved flag for every frame on this display. */
7971 FOR_EACH_FRAME (tail, frame)
7972 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7973 XFRAME (frame)->mouse_moved = 0;
7974
ab648270 7975 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7976
7977 /* Figure out which root window we're on. */
334208b7
RS
7978 XQueryPointer (FRAME_X_DISPLAY (*fp),
7979 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7980
7981 /* The root window which contains the pointer. */
7982 &root,
7983
7984 /* Trash which we can't trust if the pointer is on
7985 a different screen. */
7986 &dummy_window,
7987
7988 /* The position on that root window. */
58769bee 7989 &root_x, &root_y,
12ba150f
JB
7990
7991 /* More trash we can't trust. */
7992 &dummy, &dummy,
7993
7994 /* Modifier keys and pointer buttons, about which
7995 we don't care. */
7996 (unsigned int *) &dummy);
7997
7998 /* Now we have a position on the root; find the innermost window
7999 containing the pointer. */
8000 {
8001 Window win, child;
8002 int win_x, win_y;
06a2c219 8003 int parent_x = 0, parent_y = 0;
e99db5a1 8004 int count;
12ba150f
JB
8005
8006 win = root;
69388238 8007
2d7fc7e8
RS
8008 /* XTranslateCoordinates can get errors if the window
8009 structure is changing at the same time this function
8010 is running. So at least we must not crash from them. */
8011
e99db5a1 8012 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 8013
334208b7 8014 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 8015 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 8016 {
69388238
RS
8017 /* If mouse was grabbed on a frame, give coords for that frame
8018 even if the mouse is now outside it. */
334208b7 8019 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 8020
12ba150f 8021 /* From-window, to-window. */
69388238 8022 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
8023
8024 /* From-position, to-position. */
8025 root_x, root_y, &win_x, &win_y,
8026
8027 /* Child of win. */
8028 &child);
69388238
RS
8029 f1 = last_mouse_frame;
8030 }
8031 else
8032 {
8033 while (1)
8034 {
334208b7 8035 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 8036
69388238
RS
8037 /* From-window, to-window. */
8038 root, win,
12ba150f 8039
69388238
RS
8040 /* From-position, to-position. */
8041 root_x, root_y, &win_x, &win_y,
8042
8043 /* Child of win. */
8044 &child);
8045
9af3143a 8046 if (child == None || child == win)
69388238
RS
8047 break;
8048
8049 win = child;
8050 parent_x = win_x;
8051 parent_y = win_y;
8052 }
12ba150f 8053
69388238
RS
8054 /* Now we know that:
8055 win is the innermost window containing the pointer
8056 (XTC says it has no child containing the pointer),
8057 win_x and win_y are the pointer's position in it
8058 (XTC did this the last time through), and
8059 parent_x and parent_y are the pointer's position in win's parent.
8060 (They are what win_x and win_y were when win was child.
8061 If win is the root window, it has no parent, and
8062 parent_{x,y} are invalid, but that's okay, because we'll
8063 never use them in that case.) */
8064
8065 /* Is win one of our frames? */
19126e11 8066 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
aad0f6ab
GM
8067
8068#ifdef USE_X_TOOLKIT
8069 /* If we end up with the menu bar window, say it's not
8070 on the frame. */
8071 if (f1 != NULL
8072 && f1->output_data.x->menubar_widget
8073 && win == XtWindow (f1->output_data.x->menubar_widget))
8074 f1 = NULL;
8075#endif /* USE_X_TOOLKIT */
69388238 8076 }
58769bee 8077
2d7fc7e8
RS
8078 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
8079 f1 = 0;
8080
e99db5a1 8081 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 8082
ab648270 8083 /* If not, is it one of our scroll bars? */
a135645a 8084 if (! f1)
12ba150f 8085 {
ab648270 8086 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
8087
8088 if (bar)
8089 {
a135645a 8090 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
8091 win_x = parent_x;
8092 win_y = parent_y;
8093 }
8094 }
90e65f07 8095
8bcee03e 8096 if (f1 == 0 && insist > 0)
b86bd3dd 8097 f1 = SELECTED_FRAME ();
1cf412ec 8098
a135645a 8099 if (f1)
12ba150f 8100 {
06a2c219
GM
8101 /* Ok, we found a frame. Store all the values.
8102 last_mouse_glyph is a rectangle used to reduce the
8103 generation of mouse events. To not miss any motion
8104 events, we must divide the frame into rectangles of the
8105 size of the smallest character that could be displayed
8106 on it, i.e. into the same rectangles that matrices on
8107 the frame are divided into. */
8108
b52b65bd
GM
8109 int width, height, gx, gy;
8110 XRectangle rect;
8111
8112 if (glyph_rect (f1, win_x, win_y, &rect))
8113 last_mouse_glyph = rect;
8114 else
8115 {
8116 width = FRAME_SMALLEST_CHAR_WIDTH (f1);
8117 height = FRAME_SMALLEST_FONT_HEIGHT (f1);
8118 gx = win_x;
8119 gy = win_y;
06a2c219 8120
b52b65bd
GM
8121 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
8122 round down even for negative values. */
8123 if (gx < 0)
8124 gx -= width - 1;
4f00e84d 8125 if (gy < 0)
b52b65bd
GM
8126 gy -= height - 1;
8127 gx = (gx + width - 1) / width * width;
8128 gy = (gy + height - 1) / height * height;
8129
8130 last_mouse_glyph.width = width;
8131 last_mouse_glyph.height = height;
8132 last_mouse_glyph.x = gx;
8133 last_mouse_glyph.y = gy;
8134 }
12ba150f
JB
8135
8136 *bar_window = Qnil;
8137 *part = 0;
334208b7 8138 *fp = f1;
e0c1aef2
KH
8139 XSETINT (*x, win_x);
8140 XSETINT (*y, win_y);
12ba150f
JB
8141 *time = last_mouse_movement_time;
8142 }
8143 }
8144 }
90e65f07
JB
8145
8146 UNBLOCK_INPUT;
8147}
f451eb13 8148
06a2c219 8149
06a2c219 8150#ifdef USE_X_TOOLKIT
bffcfca9
GM
8151
8152/* Atimer callback function for TIMER. Called every 0.1s to process
8153 Xt timeouts, if needed. We must avoid calling XtAppPending as
8154 much as possible because that function does an implicit XFlush
8155 that slows us down. */
8156
8157static void
8158x_process_timeouts (timer)
8159 struct atimer *timer;
8160{
8161 if (toolkit_scroll_bar_interaction || popup_activated_flag)
8162 {
8163 BLOCK_INPUT;
8164 while (XtAppPending (Xt_app_con) & XtIMTimer)
8165 XtAppProcessEvent (Xt_app_con, XtIMTimer);
8166 UNBLOCK_INPUT;
8167 }
06a2c219
GM
8168}
8169
bffcfca9 8170#endif /* USE_X_TOOLKIT */
06a2c219
GM
8171
8172\f
8173/* Scroll bar support. */
8174
8175/* Given an X window ID, find the struct scroll_bar which manages it.
8176 This can be called in GC, so we have to make sure to strip off mark
8177 bits. */
bffcfca9 8178
06a2c219
GM
8179static struct scroll_bar *
8180x_window_to_scroll_bar (window_id)
8181 Window window_id;
8182{
8183 Lisp_Object tail;
8184
8185 for (tail = Vframe_list;
8186 XGCTYPE (tail) == Lisp_Cons;
8e713be6 8187 tail = XCDR (tail))
06a2c219
GM
8188 {
8189 Lisp_Object frame, bar, condemned;
8190
8e713be6 8191 frame = XCAR (tail);
06a2c219
GM
8192 /* All elements of Vframe_list should be frames. */
8193 if (! GC_FRAMEP (frame))
8194 abort ();
8195
8196 /* Scan this frame's scroll bar list for a scroll bar with the
8197 right window ID. */
8198 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
8199 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
8200 /* This trick allows us to search both the ordinary and
8201 condemned scroll bar lists with one loop. */
8202 ! GC_NILP (bar) || (bar = condemned,
8203 condemned = Qnil,
8204 ! GC_NILP (bar));
8205 bar = XSCROLL_BAR (bar)->next)
8206 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
8207 return XSCROLL_BAR (bar);
8208 }
8209
8210 return 0;
8211}
8212
8213
01f67d2c 8214#if defined USE_LUCID
c95fc5f1
GM
8215
8216/* Return the Lucid menu bar WINDOW is part of. Return null
8217 if WINDOW is not part of a menu bar. */
8218
8219static Widget
8220x_window_to_menu_bar (window)
8221 Window window;
8222{
8223 Lisp_Object tail;
8224
8225 for (tail = Vframe_list;
8226 XGCTYPE (tail) == Lisp_Cons;
8227 tail = XCDR (tail))
8228 {
8229 Lisp_Object frame = XCAR (tail);
8230 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
8231
8232 if (menu_bar && xlwmenu_window_p (menu_bar, window))
8233 return menu_bar;
8234 }
8235
8236 return NULL;
8237}
8238
01f67d2c 8239#endif /* USE_LUCID */
c95fc5f1 8240
06a2c219
GM
8241\f
8242/************************************************************************
8243 Toolkit scroll bars
8244 ************************************************************************/
8245
eccc05db 8246#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8247
8248static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
8249static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
8250static void x_create_toolkit_scroll_bar P_ ((struct frame *,
8251 struct scroll_bar *));
8252static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
8253 int, int, int));
8254
8255
8256/* Id of action hook installed for scroll bars. */
8257
8258static XtActionHookId action_hook_id;
8259
8260/* Lisp window being scrolled. Set when starting to interact with
8261 a toolkit scroll bar, reset to nil when ending the interaction. */
8262
8263static Lisp_Object window_being_scrolled;
8264
8265/* Last scroll bar part sent in xm_scroll_callback. */
8266
8267static int last_scroll_bar_part;
8268
ec18280f
SM
8269/* Whether this is an Xaw with arrow-scrollbars. This should imply
8270 that movements of 1/20 of the screen size are mapped to up/down. */
8271
8272static Boolean xaw3d_arrow_scroll;
8273
8274/* Whether the drag scrolling maintains the mouse at the top of the
8275 thumb. If not, resizing the thumb needs to be done more carefully
8276 to avoid jerkyness. */
8277
8278static Boolean xaw3d_pick_top;
8279
06a2c219
GM
8280
8281/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 8282 bars are used.. The hook is responsible for detecting when
06a2c219
GM
8283 the user ends an interaction with the scroll bar, and generates
8284 a `end-scroll' scroll_bar_click' event if so. */
8285
8286static void
8287xt_action_hook (widget, client_data, action_name, event, params,
8288 num_params)
8289 Widget widget;
8290 XtPointer client_data;
8291 String action_name;
8292 XEvent *event;
8293 String *params;
8294 Cardinal *num_params;
8295{
8296 int scroll_bar_p;
8297 char *end_action;
8298
8299#ifdef USE_MOTIF
8300 scroll_bar_p = XmIsScrollBar (widget);
8301 end_action = "Release";
ec18280f 8302#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8303 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
8304 end_action = "EndScroll";
ec18280f 8305#endif /* USE_MOTIF */
06a2c219 8306
06a2c219
GM
8307 if (scroll_bar_p
8308 && strcmp (action_name, end_action) == 0
8309 && WINDOWP (window_being_scrolled))
8310 {
8311 struct window *w;
8312
8313 x_send_scroll_bar_event (window_being_scrolled,
8314 scroll_bar_end_scroll, 0, 0);
8315 w = XWINDOW (window_being_scrolled);
8316 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
8317 window_being_scrolled = Qnil;
8318 last_scroll_bar_part = -1;
bffcfca9
GM
8319
8320 /* Xt timeouts no longer needed. */
8321 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
8322 }
8323}
8324
07b3d16e
GM
8325/* A vector of windows used for communication between
8326 x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
8327
8328static struct window **scroll_bar_windows;
8329static int scroll_bar_windows_size;
8330
06a2c219
GM
8331
8332/* Send a client message with message type Xatom_Scrollbar for a
8333 scroll action to the frame of WINDOW. PART is a value identifying
8334 the part of the scroll bar that was clicked on. PORTION is the
8335 amount to scroll of a whole of WHOLE. */
8336
8337static void
8338x_send_scroll_bar_event (window, part, portion, whole)
8339 Lisp_Object window;
8340 int part, portion, whole;
8341{
8342 XEvent event;
8343 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
07b3d16e
GM
8344 struct window *w = XWINDOW (window);
8345 struct frame *f = XFRAME (w->frame);
8346 int i;
06a2c219 8347
07b3d16e
GM
8348 BLOCK_INPUT;
8349
06a2c219
GM
8350 /* Construct a ClientMessage event to send to the frame. */
8351 ev->type = ClientMessage;
8352 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
8353 ev->display = FRAME_X_DISPLAY (f);
8354 ev->window = FRAME_X_WINDOW (f);
8355 ev->format = 32;
07b3d16e
GM
8356
8357 /* We can only transfer 32 bits in the XClientMessageEvent, which is
8358 not enough to store a pointer or Lisp_Object on a 64 bit system.
8359 So, store the window in scroll_bar_windows and pass the index
8360 into that array in the event. */
8361 for (i = 0; i < scroll_bar_windows_size; ++i)
8362 if (scroll_bar_windows[i] == NULL)
8363 break;
8364
8365 if (i == scroll_bar_windows_size)
8366 {
8367 int new_size = max (10, 2 * scroll_bar_windows_size);
8368 size_t nbytes = new_size * sizeof *scroll_bar_windows;
8369 size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows;
8370
8371 scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
8372 nbytes);
8373 bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
8374 scroll_bar_windows_size = new_size;
8375 }
8376
8377 scroll_bar_windows[i] = w;
8378 ev->data.l[0] = (long) i;
06a2c219
GM
8379 ev->data.l[1] = (long) part;
8380 ev->data.l[2] = (long) 0;
8381 ev->data.l[3] = (long) portion;
8382 ev->data.l[4] = (long) whole;
8383
bffcfca9
GM
8384 /* Make Xt timeouts work while the scroll bar is active. */
8385 toolkit_scroll_bar_interaction = 1;
8386
06a2c219
GM
8387 /* Setting the event mask to zero means that the message will
8388 be sent to the client that created the window, and if that
8389 window no longer exists, no event will be sent. */
06a2c219
GM
8390 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
8391 UNBLOCK_INPUT;
8392}
8393
8394
8395/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
8396 in *IEVENT. */
8397
8398static void
8399x_scroll_bar_to_input_event (event, ievent)
8400 XEvent *event;
8401 struct input_event *ievent;
8402{
8403 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
8404 Lisp_Object window;
8405 struct frame *f;
07b3d16e
GM
8406 struct window *w;
8407
8408 w = scroll_bar_windows[ev->data.l[0]];
8409 scroll_bar_windows[ev->data.l[0]] = NULL;
52e386c2 8410
07b3d16e
GM
8411 XSETWINDOW (window, w);
8412 f = XFRAME (w->frame);
06a2c219
GM
8413
8414 ievent->kind = scroll_bar_click;
8415 ievent->frame_or_window = window;
0f8aabe9 8416 ievent->arg = Qnil;
06a2c219
GM
8417 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
8418 ievent->part = ev->data.l[1];
8419 ievent->code = ev->data.l[2];
8420 ievent->x = make_number ((int) ev->data.l[3]);
8421 ievent->y = make_number ((int) ev->data.l[4]);
8422 ievent->modifiers = 0;
8423}
8424
8425
8426#ifdef USE_MOTIF
8427
8428/* Minimum and maximum values used for Motif scroll bars. */
8429
8430#define XM_SB_MIN 1
8431#define XM_SB_MAX 10000000
8432#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
8433
8434
8435/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
8436 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
8437 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
8438
8439static void
8440xm_scroll_callback (widget, client_data, call_data)
8441 Widget widget;
8442 XtPointer client_data, call_data;
8443{
8444 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8445 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
06a2c219
GM
8446 int part = -1, whole = 0, portion = 0;
8447
8448 switch (cs->reason)
8449 {
8450 case XmCR_DECREMENT:
8451 bar->dragging = Qnil;
8452 part = scroll_bar_up_arrow;
8453 break;
8454
8455 case XmCR_INCREMENT:
8456 bar->dragging = Qnil;
8457 part = scroll_bar_down_arrow;
8458 break;
8459
8460 case XmCR_PAGE_DECREMENT:
8461 bar->dragging = Qnil;
8462 part = scroll_bar_above_handle;
8463 break;
8464
8465 case XmCR_PAGE_INCREMENT:
8466 bar->dragging = Qnil;
8467 part = scroll_bar_below_handle;
8468 break;
8469
8470 case XmCR_TO_TOP:
8471 bar->dragging = Qnil;
8472 part = scroll_bar_to_top;
8473 break;
8474
8475 case XmCR_TO_BOTTOM:
8476 bar->dragging = Qnil;
8477 part = scroll_bar_to_bottom;
8478 break;
8479
8480 case XmCR_DRAG:
8481 {
8482 int slider_size;
8483 int dragging_down_p = (INTEGERP (bar->dragging)
8484 && XINT (bar->dragging) <= cs->value);
8485
8486 /* Get the slider size. */
8487 BLOCK_INPUT;
8488 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
8489 UNBLOCK_INPUT;
8490
8491 /* At the max position of the scroll bar, do a line-wise
23442ae4
GM
8492 movement. Without doing anything, we would be called with
8493 the same cs->value again and again. If we want to make
8494 sure that we can reach the end of the buffer, we have to do
8495 something.
06a2c219
GM
8496
8497 Implementation note: setting bar->dragging always to
8498 cs->value gives a smoother movement at the max position.
8499 Setting it to nil when doing line-wise movement gives
8500 a better slider behavior. */
8501
8502 if (cs->value + slider_size == XM_SB_MAX
8503 || (dragging_down_p
8504 && last_scroll_bar_part == scroll_bar_down_arrow))
8505 {
8506 part = scroll_bar_down_arrow;
8507 bar->dragging = Qnil;
8508 }
8509 else
8510 {
8511 whole = XM_SB_RANGE;
8512 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
8513 part = scroll_bar_handle;
8514 bar->dragging = make_number (cs->value);
8515 }
8516 }
8517 break;
8518
8519 case XmCR_VALUE_CHANGED:
8520 break;
8521 };
8522
8523 if (part >= 0)
8524 {
8525 window_being_scrolled = bar->window;
8526 last_scroll_bar_part = part;
8527 x_send_scroll_bar_event (bar->window, part, portion, whole);
8528 }
8529}
8530
8531
ec18280f 8532#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
8533
8534
ec18280f 8535/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
8536 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
8537 scroll bar struct. CALL_DATA is a pointer to a float saying where
8538 the thumb is. */
8539
8540static void
ec18280f 8541xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
8542 Widget widget;
8543 XtPointer client_data, call_data;
8544{
8545 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8546 float top = *(float *) call_data;
8547 float shown;
ec18280f
SM
8548 int whole, portion, height;
8549 int part;
06a2c219
GM
8550
8551 /* Get the size of the thumb, a value between 0 and 1. */
8552 BLOCK_INPUT;
ec18280f 8553 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
8554 UNBLOCK_INPUT;
8555
8556 whole = 10000000;
8557 portion = shown < 1 ? top * whole : 0;
06a2c219 8558
ec18280f
SM
8559 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
8560 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
8561 the bottom, so we force the scrolling whenever we see that we're
8562 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
8563 we try to ensure that we always stay two pixels away from the
8564 bottom). */
06a2c219
GM
8565 part = scroll_bar_down_arrow;
8566 else
8567 part = scroll_bar_handle;
8568
8569 window_being_scrolled = bar->window;
8570 bar->dragging = make_number (portion);
8571 last_scroll_bar_part = part;
8572 x_send_scroll_bar_event (bar->window, part, portion, whole);
8573}
8574
8575
ec18280f
SM
8576/* Xaw scroll bar callback. Invoked for incremental scrolling.,
8577 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
8578 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
8579 the scroll bar. CALL_DATA is an integer specifying the action that
8580 has taken place. It's magnitude is in the range 0..height of the
8581 scroll bar. Negative values mean scroll towards buffer start.
8582 Values < height of scroll bar mean line-wise movement. */
8583
8584static void
ec18280f 8585xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
8586 Widget widget;
8587 XtPointer client_data, call_data;
8588{
8589 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8590 int position = (int) call_data;
8591 Dimension height;
8592 int part;
8593
8594 /* Get the height of the scroll bar. */
8595 BLOCK_INPUT;
8596 XtVaGetValues (widget, XtNheight, &height, NULL);
8597 UNBLOCK_INPUT;
8598
ec18280f
SM
8599 if (abs (position) >= height)
8600 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
8601
8602 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
8603 it maps line-movement to call_data = max(5, height/20). */
8604 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
8605 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 8606 else
ec18280f 8607 part = scroll_bar_move_ratio;
06a2c219
GM
8608
8609 window_being_scrolled = bar->window;
8610 bar->dragging = Qnil;
8611 last_scroll_bar_part = part;
ec18280f 8612 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
8613}
8614
8615
8616#endif /* not USE_MOTIF */
8617
8618
8619/* Create the widget for scroll bar BAR on frame F. Record the widget
8620 and X window of the scroll bar in BAR. */
8621
8622static void
8623x_create_toolkit_scroll_bar (f, bar)
8624 struct frame *f;
8625 struct scroll_bar *bar;
8626{
8627 Window xwindow;
8628 Widget widget;
8629 Arg av[20];
8630 int ac = 0;
8631 char *scroll_bar_name = "verticalScrollBar";
8632 unsigned long pixel;
8633
8634 BLOCK_INPUT;
8635
8636#ifdef USE_MOTIF
06a2c219
GM
8637 /* Set resources. Create the widget. */
8638 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8639 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
8640 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
8641 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
8642 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
8643 XtSetArg (av[ac], XmNincrement, 1); ++ac;
8644 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
8645
8646 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8647 if (pixel != -1)
8648 {
8649 XtSetArg (av[ac], XmNforeground, pixel);
8650 ++ac;
8651 }
8652
8653 pixel = f->output_data.x->scroll_bar_background_pixel;
8654 if (pixel != -1)
8655 {
8656 XtSetArg (av[ac], XmNbackground, pixel);
8657 ++ac;
8658 }
8659
8660 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
8661 scroll_bar_name, av, ac);
8662
8663 /* Add one callback for everything that can happen. */
8664 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
8665 (XtPointer) bar);
8666 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
8667 (XtPointer) bar);
8668 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
8669 (XtPointer) bar);
8670 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
8671 (XtPointer) bar);
8672 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
8673 (XtPointer) bar);
8674 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
8675 (XtPointer) bar);
8676 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
8677 (XtPointer) bar);
8678
8679 /* Realize the widget. Only after that is the X window created. */
8680 XtRealizeWidget (widget);
8681
8682 /* Set the cursor to an arrow. I didn't find a resource to do that.
8683 And I'm wondering why it hasn't an arrow cursor by default. */
8684 XDefineCursor (XtDisplay (widget), XtWindow (widget),
8685 f->output_data.x->nontext_cursor);
8686
ec18280f 8687#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8688
8689 /* Set resources. Create the widget. The background of the
8690 Xaw3d scroll bar widget is a little bit light for my taste.
8691 We don't alter it here to let users change it according
8692 to their taste with `emacs*verticalScrollBar.background: xxx'. */
8693 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8694 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
8695 /* For smoother scrolling with Xaw3d -sm */
8696 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
06a2c219
GM
8697
8698 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8699 if (pixel != -1)
8700 {
8701 XtSetArg (av[ac], XtNforeground, pixel);
8702 ++ac;
8703 }
8704
8705 pixel = f->output_data.x->scroll_bar_background_pixel;
8706 if (pixel != -1)
8707 {
8708 XtSetArg (av[ac], XtNbackground, pixel);
8709 ++ac;
8710 }
7c1bef7a
MB
8711
8712 /* Top/bottom shadow colors. */
8713
8714 /* Allocate them, if necessary. */
8715 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
8716 {
8717 pixel = f->output_data.x->scroll_bar_background_pixel;
8718 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8719 &pixel, 1.2, 0x8000))
8720 pixel = -1;
8721 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
8722 }
8723 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8724 {
8725 pixel = f->output_data.x->scroll_bar_background_pixel;
8726 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8727 &pixel, 0.6, 0x4000))
8728 pixel = -1;
8729 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
8730 }
8731
8732 /* Tell the toolkit about them. */
8733 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
8734 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8735 /* We tried to allocate a color for the top/bottom shadow, and
8736 failed, so tell Xaw3d to use dithering instead. */
8737 {
8738 XtSetArg (av[ac], XtNbeNiceToColormap, True);
8739 ++ac;
8740 }
8741 else
8742 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
8743 be more consistent with other emacs 3d colors, and since Xaw3d is
8744 not good at dealing with allocation failure. */
8745 {
8746 /* This tells Xaw3d to use real colors instead of dithering for
8747 the shadows. */
8748 XtSetArg (av[ac], XtNbeNiceToColormap, False);
8749 ++ac;
8750
8751 /* Specify the colors. */
8752 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
8753 if (pixel != -1)
8754 {
8755 XtSetArg (av[ac], "topShadowPixel", pixel);
8756 ++ac;
8757 }
8758 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
8759 if (pixel != -1)
8760 {
8761 XtSetArg (av[ac], "bottomShadowPixel", pixel);
8762 ++ac;
8763 }
8764 }
8765
06a2c219
GM
8766 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
8767 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
8768
8769 {
8770 char *initial = "";
8771 char *val = initial;
8772 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
8773 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
8774 if (val == initial)
8775 { /* ARROW_SCROLL */
8776 xaw3d_arrow_scroll = True;
8777 /* Isn't that just a personal preference ? -sm */
8778 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
8779 }
8780 }
06a2c219
GM
8781
8782 /* Define callbacks. */
ec18280f
SM
8783 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
8784 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
8785 (XtPointer) bar);
8786
8787 /* Realize the widget. Only after that is the X window created. */
8788 XtRealizeWidget (widget);
8789
ec18280f 8790#endif /* !USE_MOTIF */
06a2c219
GM
8791
8792 /* Install an action hook that let's us detect when the user
8793 finishes interacting with a scroll bar. */
8794 if (action_hook_id == 0)
8795 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
8796
8797 /* Remember X window and widget in the scroll bar vector. */
8798 SET_SCROLL_BAR_X_WIDGET (bar, widget);
8799 xwindow = XtWindow (widget);
8800 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
8801
8802 UNBLOCK_INPUT;
8803}
8804
8805
8806/* Set the thumb size and position of scroll bar BAR. We are currently
8807 displaying PORTION out of a whole WHOLE, and our position POSITION. */
8808
8809static void
8810x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
8811 struct scroll_bar *bar;
8812 int portion, position, whole;
f451eb13 8813{
e83dc917
GM
8814 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8815 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
06a2c219 8816 float top, shown;
f451eb13 8817
06a2c219
GM
8818 if (whole == 0)
8819 top = 0, shown = 1;
8820 else
f451eb13 8821 {
06a2c219
GM
8822 top = (float) position / whole;
8823 shown = (float) portion / whole;
8824 }
f451eb13 8825
06a2c219 8826 BLOCK_INPUT;
f451eb13 8827
06a2c219
GM
8828#ifdef USE_MOTIF
8829 {
8830 int size, value;
06a2c219 8831
ec18280f 8832 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
8833 is the scroll bar's maximum and MIN is the scroll bar's minimum
8834 value. */
8835 size = shown * XM_SB_RANGE;
8836 size = min (size, XM_SB_RANGE);
8837 size = max (size, 1);
8838
8839 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
8840 value = top * XM_SB_RANGE;
8841 value = min (value, XM_SB_MAX - size);
8842 value = max (value, XM_SB_MIN);
8843
06a2c219
GM
8844 if (NILP (bar->dragging))
8845 XmScrollBarSetValues (widget, value, size, 0, 0, False);
8846 else if (last_scroll_bar_part == scroll_bar_down_arrow)
8847 /* This has the negative side effect that the slider value is
ec18280f 8848 not what it would be if we scrolled here using line-wise or
06a2c219
GM
8849 page-wise movement. */
8850 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
8851 else
8852 {
8853 /* If currently dragging, only update the slider size.
8854 This reduces flicker effects. */
8855 int old_value, old_size, increment, page_increment;
8856
8857 XmScrollBarGetValues (widget, &old_value, &old_size,
8858 &increment, &page_increment);
8859 XmScrollBarSetValues (widget, old_value,
8860 min (size, XM_SB_RANGE - old_value),
8861 0, 0, False);
8862 }
06a2c219 8863 }
ec18280f 8864#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 8865 {
ec18280f
SM
8866 float old_top, old_shown;
8867 Dimension height;
8868 XtVaGetValues (widget,
8869 XtNtopOfThumb, &old_top,
8870 XtNshown, &old_shown,
8871 XtNheight, &height,
8872 NULL);
8873
8874 /* Massage the top+shown values. */
8875 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8876 top = max (0, min (1, top));
8877 else
8878 top = old_top;
8879 /* Keep two pixels available for moving the thumb down. */
8880 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8881
8882 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8883 check that your system's configuration file contains a define
8884 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8885 if (top != old_top || shown != old_shown)
eb393530 8886 {
ec18280f 8887 if (NILP (bar->dragging))
eb393530 8888 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8889 else
8890 {
ec18280f
SM
8891#ifdef HAVE_XAW3D
8892 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8893 int scroll_mode = 0;
ec18280f
SM
8894
8895 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8896 if (xaw3d_arrow_scroll)
8897 {
8898 /* Xaw3d stupidly ignores resize requests while dragging
8899 so we have to make it believe it's not in dragging mode. */
8900 scroll_mode = sb->scrollbar.scroll_mode;
8901 if (scroll_mode == 2)
8902 sb->scrollbar.scroll_mode = 0;
8903 }
8904#endif
8905 /* Try to make the scrolling a tad smoother. */
8906 if (!xaw3d_pick_top)
8907 shown = min (shown, old_shown);
8908
8909 XawScrollbarSetThumb (widget, top, shown);
8910
8911#ifdef HAVE_XAW3D
8912 if (xaw3d_arrow_scroll && scroll_mode == 2)
8913 sb->scrollbar.scroll_mode = scroll_mode;
8914#endif
06a2c219 8915 }
06a2c219
GM
8916 }
8917 }
ec18280f 8918#endif /* !USE_MOTIF */
06a2c219
GM
8919
8920 UNBLOCK_INPUT;
f451eb13
JB
8921}
8922
06a2c219
GM
8923#endif /* USE_TOOLKIT_SCROLL_BARS */
8924
8925
8926\f
8927/************************************************************************
8928 Scroll bars, general
8929 ************************************************************************/
8930
8931/* Create a scroll bar and return the scroll bar vector for it. W is
8932 the Emacs window on which to create the scroll bar. TOP, LEFT,
8933 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8934 scroll bar. */
8935
ab648270 8936static struct scroll_bar *
06a2c219
GM
8937x_scroll_bar_create (w, top, left, width, height)
8938 struct window *w;
f451eb13
JB
8939 int top, left, width, height;
8940{
06a2c219 8941 struct frame *f = XFRAME (w->frame);
334208b7
RS
8942 struct scroll_bar *bar
8943 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8944
8945 BLOCK_INPUT;
8946
eccc05db 8947#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8948 x_create_toolkit_scroll_bar (f, bar);
8949#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8950 {
8951 XSetWindowAttributes a;
8952 unsigned long mask;
5c187dee 8953 Window window;
06a2c219
GM
8954
8955 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8956 if (a.background_pixel == -1)
8957 a.background_pixel = f->output_data.x->background_pixel;
8958
12ba150f 8959 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 8960 | ButtonMotionMask | PointerMotionHintMask
12ba150f 8961 | ExposureMask);
7a13e894 8962 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 8963
dbc4e1c1 8964 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8965
06a2c219
GM
8966 /* Clear the area of W that will serve as a scroll bar. This is
8967 for the case that a window has been split horizontally. In
8968 this case, no clear_frame is generated to reduce flickering. */
7b49b9d2
GM
8969 if (width > 0 && height > 0)
8970 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8971 left, top, width,
8972 window_box_height (w), False);
06a2c219
GM
8973
8974 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8975 /* Position and size of scroll bar. */
8976 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8977 top,
8978 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8979 height,
8980 /* Border width, depth, class, and visual. */
8981 0,
8982 CopyFromParent,
8983 CopyFromParent,
8984 CopyFromParent,
8985 /* Attributes. */
8986 mask, &a);
8987 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 8988 }
06a2c219 8989#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8990
06a2c219 8991 XSETWINDOW (bar->window, w);
e0c1aef2
KH
8992 XSETINT (bar->top, top);
8993 XSETINT (bar->left, left);
8994 XSETINT (bar->width, width);
8995 XSETINT (bar->height, height);
8996 XSETINT (bar->start, 0);
8997 XSETINT (bar->end, 0);
12ba150f 8998 bar->dragging = Qnil;
f451eb13
JB
8999
9000 /* Add bar to its frame's list of scroll bars. */
334208b7 9001 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 9002 bar->prev = Qnil;
334208b7 9003 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 9004 if (!NILP (bar->next))
e0c1aef2 9005 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 9006
06a2c219 9007 /* Map the window/widget. */
eccc05db 9008#ifdef USE_TOOLKIT_SCROLL_BARS
f964b4d7
GM
9009 {
9010 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
9011 XtConfigureWidget (scroll_bar,
9012 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9013 top,
9014 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
9015 max (height, 1), 0);
9016 XtMapWidget (scroll_bar);
9017 }
06a2c219 9018#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 9019 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 9020#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9021
9022 UNBLOCK_INPUT;
12ba150f 9023 return bar;
f451eb13
JB
9024}
9025
06a2c219 9026
12ba150f 9027/* Draw BAR's handle in the proper position.
06a2c219 9028
12ba150f
JB
9029 If the handle is already drawn from START to END, don't bother
9030 redrawing it, unless REBUILD is non-zero; in that case, always
9031 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 9032 events.)
12ba150f
JB
9033
9034 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
9035 fit inside its rectangle, but if the user is dragging the scroll
9036 bar handle, we want to let them drag it down all the way, so that
9037 the bar's top is as far down as it goes; otherwise, there's no way
9038 to move to the very end of the buffer. */
9039
5c187dee
GM
9040#ifndef USE_TOOLKIT_SCROLL_BARS
9041
f451eb13 9042static void
ab648270
JB
9043x_scroll_bar_set_handle (bar, start, end, rebuild)
9044 struct scroll_bar *bar;
f451eb13 9045 int start, end;
12ba150f 9046 int rebuild;
f451eb13 9047{
12ba150f 9048 int dragging = ! NILP (bar->dragging);
ab648270 9049 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9050 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9051 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
9052
9053 /* If the display is already accurate, do nothing. */
9054 if (! rebuild
9055 && start == XINT (bar->start)
9056 && end == XINT (bar->end))
9057 return;
9058
f451eb13
JB
9059 BLOCK_INPUT;
9060
9061 {
d9cdbb3d
RS
9062 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
9063 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
9064 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
9065
9066 /* Make sure the values are reasonable, and try to preserve
9067 the distance between start and end. */
12ba150f
JB
9068 {
9069 int length = end - start;
9070
9071 if (start < 0)
9072 start = 0;
9073 else if (start > top_range)
9074 start = top_range;
9075 end = start + length;
9076
9077 if (end < start)
9078 end = start;
9079 else if (end > top_range && ! dragging)
9080 end = top_range;
9081 }
f451eb13 9082
ab648270 9083 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
9084 XSETINT (bar->start, start);
9085 XSETINT (bar->end, end);
f451eb13 9086
12ba150f
JB
9087 /* Clip the end position, just for display. */
9088 if (end > top_range)
9089 end = top_range;
f451eb13 9090
ab648270 9091 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
9092 below top positions, to make sure the handle is always at least
9093 that many pixels tall. */
ab648270 9094 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 9095
12ba150f
JB
9096 /* Draw the empty space above the handle. Note that we can't clear
9097 zero-height areas; that means "clear to end of window." */
9098 if (0 < start)
c5e6e06b
GM
9099 x_clear_area (FRAME_X_DISPLAY (f), w,
9100 /* x, y, width, height, and exposures. */
9101 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9102 VERTICAL_SCROLL_BAR_TOP_BORDER,
9103 inside_width, start,
9104 False);
f451eb13 9105
06a2c219
GM
9106 /* Change to proper foreground color if one is specified. */
9107 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9108 XSetForeground (FRAME_X_DISPLAY (f), gc,
9109 f->output_data.x->scroll_bar_foreground_pixel);
9110
12ba150f 9111 /* Draw the handle itself. */
334208b7 9112 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
12ba150f 9113 /* x, y, width, height */
ab648270
JB
9114 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9115 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 9116 inside_width, end - start);
f451eb13 9117
06a2c219
GM
9118 /* Restore the foreground color of the GC if we changed it above. */
9119 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9120 XSetForeground (FRAME_X_DISPLAY (f), gc,
9121 f->output_data.x->foreground_pixel);
f451eb13 9122
12ba150f
JB
9123 /* Draw the empty space below the handle. Note that we can't
9124 clear zero-height areas; that means "clear to end of window." */
9125 if (end < inside_height)
c5e6e06b
GM
9126 x_clear_area (FRAME_X_DISPLAY (f), w,
9127 /* x, y, width, height, and exposures. */
9128 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9129 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
9130 inside_width, inside_height - end,
9131 False);
f451eb13 9132
f451eb13
JB
9133 }
9134
f451eb13
JB
9135 UNBLOCK_INPUT;
9136}
9137
5c187dee 9138#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 9139
06a2c219
GM
9140/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
9141 nil. */
58769bee 9142
12ba150f 9143static void
ab648270
JB
9144x_scroll_bar_remove (bar)
9145 struct scroll_bar *bar;
12ba150f 9146{
e83dc917 9147 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
9148 BLOCK_INPUT;
9149
eccc05db 9150#ifdef USE_TOOLKIT_SCROLL_BARS
e83dc917
GM
9151 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
9152#else
9153 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
9154#endif
06a2c219 9155
ab648270
JB
9156 /* Disassociate this scroll bar from its window. */
9157 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
9158
9159 UNBLOCK_INPUT;
9160}
9161
06a2c219 9162
12ba150f
JB
9163/* Set the handle of the vertical scroll bar for WINDOW to indicate
9164 that we are displaying PORTION characters out of a total of WHOLE
ab648270 9165 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 9166 create one. */
06a2c219 9167
12ba150f 9168static void
06a2c219
GM
9169XTset_vertical_scroll_bar (w, portion, whole, position)
9170 struct window *w;
f451eb13
JB
9171 int portion, whole, position;
9172{
06a2c219 9173 struct frame *f = XFRAME (w->frame);
ab648270 9174 struct scroll_bar *bar;
3c6ede7b 9175 int top, height, left, sb_left, width, sb_width;
06a2c219 9176 int window_x, window_y, window_width, window_height;
06a2c219 9177
3c6ede7b 9178 /* Get window dimensions. */
06a2c219 9179 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
9180 top = window_y;
9181 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9182 height = window_height;
06a2c219 9183
3c6ede7b 9184 /* Compute the left edge of the scroll bar area. */
06a2c219 9185 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
9186 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
9187 else
9188 left = XFASTINT (w->left);
9189 left *= CANON_X_UNIT (f);
9190 left += FRAME_INTERNAL_BORDER_WIDTH (f);
9191
9192 /* Compute the width of the scroll bar which might be less than
9193 the width of the area reserved for the scroll bar. */
9194 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
9195 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 9196 else
3c6ede7b 9197 sb_width = width;
12ba150f 9198
3c6ede7b
GM
9199 /* Compute the left edge of the scroll bar. */
9200#ifdef USE_TOOLKIT_SCROLL_BARS
9201 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9202 sb_left = left + width - sb_width - (width - sb_width) / 2;
9203 else
9204 sb_left = left + (width - sb_width) / 2;
9205#else
9206 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9207 sb_left = left + width - sb_width;
9208 else
9209 sb_left = left;
9210#endif
9211
ab648270 9212 /* Does the scroll bar exist yet? */
06a2c219 9213 if (NILP (w->vertical_scroll_bar))
3c6ede7b 9214 {
7b49b9d2 9215 if (width > 0 && height > 0)
b547b6e8
GM
9216 {
9217 BLOCK_INPUT;
9218 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9219 left, top, width, height, False);
9220 UNBLOCK_INPUT;
9221 }
9222
3c6ede7b
GM
9223 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
9224 }
f451eb13 9225 else
12ba150f
JB
9226 {
9227 /* It may just need to be moved and resized. */
06a2c219
GM
9228 unsigned int mask = 0;
9229
9230 bar = XSCROLL_BAR (w->vertical_scroll_bar);
9231
9232 BLOCK_INPUT;
9233
3c6ede7b 9234 if (sb_left != XINT (bar->left))
06a2c219 9235 mask |= CWX;
3c6ede7b 9236 if (top != XINT (bar->top))
06a2c219 9237 mask |= CWY;
3c6ede7b 9238 if (sb_width != XINT (bar->width))
06a2c219 9239 mask |= CWWidth;
3c6ede7b 9240 if (height != XINT (bar->height))
06a2c219
GM
9241 mask |= CWHeight;
9242
9243#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
9244
9245 /* Since toolkit scroll bars are smaller than the space reserved
9246 for them on the frame, we have to clear "under" them. */
7b49b9d2 9247 if (width > 0 && height > 0)
f964b4d7
GM
9248 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9249 left, top, width, height, False);
06a2c219
GM
9250
9251 /* Move/size the scroll bar widget. */
9252 if (mask)
e83dc917 9253 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
3c6ede7b
GM
9254 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9255 top,
9256 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
f964b4d7 9257 max (height, 1), 0);
06a2c219
GM
9258
9259#else /* not USE_TOOLKIT_SCROLL_BARS */
9260
357e7376
GM
9261 /* Clear areas not covered by the scroll bar because of
9262 VERTICAL_SCROLL_BAR_WIDTH_TRIM. */
e1f6572f
RS
9263 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
9264 {
c5e6e06b
GM
9265 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9266 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9267 height, False);
9268 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9269 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9270 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9271 height, False);
e1f6572f 9272 }
357e7376
GM
9273
9274 /* Clear areas not covered by the scroll bar because it's not as
9275 wide as the area reserved for it . This makes sure a
9276 previous mode line display is cleared after C-x 2 C-x 1, for
9277 example. */
9278 {
9279 int area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9280 int rest = area_width - sb_width;
38d2af0c
GM
9281 if (rest > 0 && height > 0)
9282 {
9283 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
9284 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9285 left + area_width - rest, top,
9286 rest, height, False);
9287 else
9288 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9289 left, top, rest, height, False);
9290 }
357e7376 9291 }
06a2c219
GM
9292
9293 /* Move/size the scroll bar window. */
9294 if (mask)
9295 {
9296 XWindowChanges wc;
9297
3c6ede7b
GM
9298 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
9299 wc.y = top;
9300 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
9301 wc.height = height;
06a2c219
GM
9302 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
9303 mask, &wc);
9304 }
9305
9306#endif /* not USE_TOOLKIT_SCROLL_BARS */
9307
9308 /* Remember new settings. */
3c6ede7b
GM
9309 XSETINT (bar->left, sb_left);
9310 XSETINT (bar->top, top);
9311 XSETINT (bar->width, sb_width);
9312 XSETINT (bar->height, height);
06a2c219
GM
9313
9314 UNBLOCK_INPUT;
12ba150f 9315 }
f451eb13 9316
eccc05db 9317#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
9318 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
9319#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 9320 /* Set the scroll bar's current state, unless we're currently being
f451eb13 9321 dragged. */
12ba150f 9322 if (NILP (bar->dragging))
f451eb13 9323 {
92857db0 9324 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 9325
12ba150f 9326 if (whole == 0)
ab648270 9327 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
9328 else
9329 {
43f868f5
JB
9330 int start = ((double) position * top_range) / whole;
9331 int end = ((double) (position + portion) * top_range) / whole;
ab648270 9332 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 9333 }
f451eb13 9334 }
06a2c219 9335#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9336
06a2c219 9337 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
9338}
9339
12ba150f 9340
f451eb13 9341/* The following three hooks are used when we're doing a thorough
ab648270 9342 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 9343 are going to be deleted, because keeping track of when windows go
12ba150f
JB
9344 away is a real pain - "Can you say set-window-configuration, boys
9345 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 9346 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 9347 from the fiery pit when we actually redisplay its window. */
f451eb13 9348
ab648270
JB
9349/* Arrange for all scroll bars on FRAME to be removed at the next call
9350 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
9351 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
9352
58769bee 9353static void
ab648270 9354XTcondemn_scroll_bars (frame)
f451eb13
JB
9355 FRAME_PTR frame;
9356{
f9e24cb9
RS
9357 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
9358 while (! NILP (FRAME_SCROLL_BARS (frame)))
9359 {
9360 Lisp_Object bar;
9361 bar = FRAME_SCROLL_BARS (frame);
9362 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
9363 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
9364 XSCROLL_BAR (bar)->prev = Qnil;
9365 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
9366 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
9367 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
9368 }
f451eb13
JB
9369}
9370
fa2dfc30 9371
06a2c219 9372/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 9373 Note that WINDOW isn't necessarily condemned at all. */
fa2dfc30 9374
f451eb13 9375static void
ab648270 9376XTredeem_scroll_bar (window)
12ba150f 9377 struct window *window;
f451eb13 9378{
ab648270 9379 struct scroll_bar *bar;
fa2dfc30 9380 struct frame *f;
12ba150f 9381
ab648270
JB
9382 /* We can't redeem this window's scroll bar if it doesn't have one. */
9383 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
9384 abort ();
9385
ab648270 9386 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
9387
9388 /* Unlink it from the condemned list. */
fa2dfc30
GM
9389 f = XFRAME (WINDOW_FRAME (window));
9390 if (NILP (bar->prev))
9391 {
9392 /* If the prev pointer is nil, it must be the first in one of
9393 the lists. */
9394 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
9395 /* It's not condemned. Everything's fine. */
9396 return;
9397 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
9398 window->vertical_scroll_bar))
9399 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
9400 else
9401 /* If its prev pointer is nil, it must be at the front of
9402 one or the other! */
9403 abort ();
9404 }
9405 else
9406 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f 9407
fa2dfc30
GM
9408 if (! NILP (bar->next))
9409 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 9410
fa2dfc30
GM
9411 bar->next = FRAME_SCROLL_BARS (f);
9412 bar->prev = Qnil;
9413 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
9414 if (! NILP (bar->next))
9415 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13
JB
9416}
9417
ab648270
JB
9418/* Remove all scroll bars on FRAME that haven't been saved since the
9419 last call to `*condemn_scroll_bars_hook'. */
06a2c219 9420
f451eb13 9421static void
ab648270 9422XTjudge_scroll_bars (f)
12ba150f 9423 FRAME_PTR f;
f451eb13 9424{
12ba150f 9425 Lisp_Object bar, next;
f451eb13 9426
ab648270 9427 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
9428
9429 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
9430 more events on the hapless scroll bars. */
9431 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
9432
9433 for (; ! NILP (bar); bar = next)
f451eb13 9434 {
ab648270 9435 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 9436
ab648270 9437 x_scroll_bar_remove (b);
12ba150f
JB
9438
9439 next = b->next;
9440 b->next = b->prev = Qnil;
f451eb13 9441 }
12ba150f 9442
ab648270 9443 /* Now there should be no references to the condemned scroll bars,
12ba150f 9444 and they should get garbage-collected. */
f451eb13
JB
9445}
9446
9447
06a2c219
GM
9448/* Handle an Expose or GraphicsExpose event on a scroll bar. This
9449 is a no-op when using toolkit scroll bars.
ab648270
JB
9450
9451 This may be called from a signal handler, so we have to ignore GC
9452 mark bits. */
06a2c219 9453
f451eb13 9454static void
ab648270
JB
9455x_scroll_bar_expose (bar, event)
9456 struct scroll_bar *bar;
f451eb13
JB
9457 XEvent *event;
9458{
06a2c219
GM
9459#ifndef USE_TOOLKIT_SCROLL_BARS
9460
ab648270 9461 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9462 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9463 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 9464 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 9465
f451eb13
JB
9466 BLOCK_INPUT;
9467
ab648270 9468 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 9469
06a2c219 9470 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 9471 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
9472
9473 /* x, y, width, height */
d9cdbb3d 9474 0, 0,
3cbd2e0b 9475 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
9476 XINT (bar->height) - 1);
9477
f451eb13 9478 UNBLOCK_INPUT;
06a2c219
GM
9479
9480#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9481}
9482
ab648270
JB
9483/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
9484 is set to something other than no_event, it is enqueued.
9485
9486 This may be called from a signal handler, so we have to ignore GC
9487 mark bits. */
06a2c219 9488
5c187dee
GM
9489#ifndef USE_TOOLKIT_SCROLL_BARS
9490
f451eb13 9491static void
ab648270
JB
9492x_scroll_bar_handle_click (bar, event, emacs_event)
9493 struct scroll_bar *bar;
f451eb13
JB
9494 XEvent *event;
9495 struct input_event *emacs_event;
9496{
0299d313 9497 if (! GC_WINDOWP (bar->window))
12ba150f
JB
9498 abort ();
9499
ab648270 9500 emacs_event->kind = scroll_bar_click;
69388238 9501 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
9502 emacs_event->modifiers
9503 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
9504 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
9505 event->xbutton.state)
9506 | (event->type == ButtonRelease
9507 ? up_modifier
9508 : down_modifier));
12ba150f 9509 emacs_event->frame_or_window = bar->window;
0f8aabe9 9510 emacs_event->arg = Qnil;
f451eb13 9511 emacs_event->timestamp = event->xbutton.time;
12ba150f 9512 {
06a2c219 9513#if 0
d9cdbb3d 9514 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 9515 int internal_height
d9cdbb3d 9516 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9517#endif
0299d313 9518 int top_range
d9cdbb3d 9519 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 9520 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
9521
9522 if (y < 0) y = 0;
9523 if (y > top_range) y = top_range;
9524
9525 if (y < XINT (bar->start))
ab648270
JB
9526 emacs_event->part = scroll_bar_above_handle;
9527 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9528 emacs_event->part = scroll_bar_handle;
12ba150f 9529 else
ab648270 9530 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
9531
9532 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
9533 they want to drag it. Lisp code needs to be able to decide
9534 whether or not we're dragging. */
929787e1 9535#if 0
12ba150f
JB
9536 /* If the user has just clicked on the handle, record where they're
9537 holding it. */
9538 if (event->type == ButtonPress
ab648270 9539 && emacs_event->part == scroll_bar_handle)
e0c1aef2 9540 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 9541#endif
12ba150f
JB
9542
9543 /* If the user has released the handle, set it to its final position. */
9544 if (event->type == ButtonRelease
9545 && ! NILP (bar->dragging))
9546 {
9547 int new_start = y - XINT (bar->dragging);
9548 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 9549
ab648270 9550 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
9551 bar->dragging = Qnil;
9552 }
f451eb13 9553
5116f055
JB
9554 /* Same deal here as the other #if 0. */
9555#if 0
58769bee 9556 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 9557 the handle. */
ab648270 9558 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
9559 emacs_event->x = bar->start;
9560 else
e0c1aef2 9561 XSETINT (emacs_event->x, y);
5116f055 9562#else
e0c1aef2 9563 XSETINT (emacs_event->x, y);
5116f055 9564#endif
f451eb13 9565
e0c1aef2 9566 XSETINT (emacs_event->y, top_range);
12ba150f
JB
9567 }
9568}
f451eb13 9569
ab648270
JB
9570/* Handle some mouse motion while someone is dragging the scroll bar.
9571
9572 This may be called from a signal handler, so we have to ignore GC
9573 mark bits. */
06a2c219 9574
f451eb13 9575static void
ab648270
JB
9576x_scroll_bar_note_movement (bar, event)
9577 struct scroll_bar *bar;
f451eb13
JB
9578 XEvent *event;
9579{
39d8bb4d
KH
9580 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
9581
f451eb13
JB
9582 last_mouse_movement_time = event->xmotion.time;
9583
39d8bb4d 9584 f->mouse_moved = 1;
e0c1aef2 9585 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
9586
9587 /* If we're dragging the bar, display it. */
ab648270 9588 if (! GC_NILP (bar->dragging))
f451eb13
JB
9589 {
9590 /* Where should the handle be now? */
12ba150f 9591 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 9592
12ba150f 9593 if (new_start != XINT (bar->start))
f451eb13 9594 {
12ba150f 9595 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 9596
ab648270 9597 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
9598 }
9599 }
f451eb13
JB
9600}
9601
5c187dee
GM
9602#endif /* !USE_TOOLKIT_SCROLL_BARS */
9603
12ba150f 9604/* Return information to the user about the current position of the mouse
ab648270 9605 on the scroll bar. */
06a2c219 9606
12ba150f 9607static void
334208b7
RS
9608x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
9609 FRAME_PTR *fp;
12ba150f 9610 Lisp_Object *bar_window;
ab648270 9611 enum scroll_bar_part *part;
12ba150f
JB
9612 Lisp_Object *x, *y;
9613 unsigned long *time;
9614{
ab648270 9615 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
9616 Window w = SCROLL_BAR_X_WINDOW (bar);
9617 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 9618 int win_x, win_y;
559cb2fb
JB
9619 Window dummy_window;
9620 int dummy_coord;
9621 unsigned int dummy_mask;
12ba150f 9622
cf7cb199
JB
9623 BLOCK_INPUT;
9624
ab648270 9625 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 9626 report that. */
334208b7 9627 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 9628
559cb2fb
JB
9629 /* Root, child, root x and root y. */
9630 &dummy_window, &dummy_window,
9631 &dummy_coord, &dummy_coord,
12ba150f 9632
559cb2fb
JB
9633 /* Position relative to scroll bar. */
9634 &win_x, &win_y,
12ba150f 9635
559cb2fb
JB
9636 /* Mouse buttons and modifier keys. */
9637 &dummy_mask))
7a13e894 9638 ;
559cb2fb
JB
9639 else
9640 {
06a2c219 9641#if 0
559cb2fb 9642 int inside_height
d9cdbb3d 9643 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9644#endif
559cb2fb 9645 int top_range
d9cdbb3d 9646 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
9647
9648 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
9649
9650 if (! NILP (bar->dragging))
9651 win_y -= XINT (bar->dragging);
9652
9653 if (win_y < 0)
9654 win_y = 0;
9655 if (win_y > top_range)
9656 win_y = top_range;
9657
334208b7 9658 *fp = f;
7a13e894 9659 *bar_window = bar->window;
559cb2fb
JB
9660
9661 if (! NILP (bar->dragging))
9662 *part = scroll_bar_handle;
9663 else if (win_y < XINT (bar->start))
9664 *part = scroll_bar_above_handle;
9665 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9666 *part = scroll_bar_handle;
9667 else
9668 *part = scroll_bar_below_handle;
12ba150f 9669
e0c1aef2
KH
9670 XSETINT (*x, win_y);
9671 XSETINT (*y, top_range);
12ba150f 9672
39d8bb4d 9673 f->mouse_moved = 0;
559cb2fb
JB
9674 last_mouse_scroll_bar = Qnil;
9675 }
12ba150f 9676
559cb2fb 9677 *time = last_mouse_movement_time;
cf7cb199 9678
cf7cb199 9679 UNBLOCK_INPUT;
12ba150f
JB
9680}
9681
f451eb13 9682
dbc4e1c1 9683/* The screen has been cleared so we may have changed foreground or
ab648270
JB
9684 background colors, and the scroll bars may need to be redrawn.
9685 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
9686 redraw them. */
9687
dfcf069d 9688void
ab648270 9689x_scroll_bar_clear (f)
dbc4e1c1
JB
9690 FRAME_PTR f;
9691{
06a2c219 9692#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
9693 Lisp_Object bar;
9694
b80c363e
RS
9695 /* We can have scroll bars even if this is 0,
9696 if we just turned off scroll bar mode.
9697 But in that case we should not clear them. */
9698 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
9699 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
9700 bar = XSCROLL_BAR (bar)->next)
c5e6e06b
GM
9701 XClearArea (FRAME_X_DISPLAY (f),
9702 SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
b80c363e 9703 0, 0, 0, 0, True);
06a2c219 9704#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
9705}
9706
06a2c219 9707/* This processes Expose events from the menu-bar specific X event
19126e11 9708 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 9709 when handling menu-bar or pop-up items. */
3afe33e7 9710
06a2c219 9711int
3afe33e7
RS
9712process_expose_from_menu (event)
9713 XEvent event;
9714{
9715 FRAME_PTR f;
19126e11 9716 struct x_display_info *dpyinfo;
06a2c219 9717 int frame_exposed_p = 0;
3afe33e7 9718
f94397b5
KH
9719 BLOCK_INPUT;
9720
19126e11
KH
9721 dpyinfo = x_display_info_for_display (event.xexpose.display);
9722 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
9723 if (f)
9724 {
9725 if (f->async_visible == 0)
9726 {
9727 f->async_visible = 1;
9728 f->async_iconified = 0;
06c488fd 9729 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
9730 SET_FRAME_GARBAGED (f);
9731 }
9732 else
9733 {
06a2c219
GM
9734 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
9735 event.xexpose.x, event.xexpose.y,
9736 event.xexpose.width, event.xexpose.height);
9737 frame_exposed_p = 1;
3afe33e7
RS
9738 }
9739 }
9740 else
9741 {
9742 struct scroll_bar *bar
9743 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9744
3afe33e7
RS
9745 if (bar)
9746 x_scroll_bar_expose (bar, &event);
9747 }
f94397b5
KH
9748
9749 UNBLOCK_INPUT;
06a2c219 9750 return frame_exposed_p;
3afe33e7 9751}
09756a85
RS
9752\f
9753/* Define a queue to save up SelectionRequest events for later handling. */
9754
9755struct selection_event_queue
9756 {
9757 XEvent event;
9758 struct selection_event_queue *next;
9759 };
9760
9761static struct selection_event_queue *queue;
9762
9763/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 9764
09756a85
RS
9765static int x_queue_selection_requests;
9766
9767/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 9768
09756a85 9769static void
334208b7
RS
9770x_queue_event (f, event)
9771 FRAME_PTR f;
09756a85
RS
9772 XEvent *event;
9773{
9774 struct selection_event_queue *queue_tmp
06a2c219 9775 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 9776
58769bee 9777 if (queue_tmp != NULL)
09756a85
RS
9778 {
9779 queue_tmp->event = *event;
9780 queue_tmp->next = queue;
9781 queue = queue_tmp;
9782 }
9783}
9784
9785/* Take all the queued events and put them back
9786 so that they get processed afresh. */
9787
9788static void
db3906fd
RS
9789x_unqueue_events (display)
9790 Display *display;
09756a85 9791{
58769bee 9792 while (queue != NULL)
09756a85
RS
9793 {
9794 struct selection_event_queue *queue_tmp = queue;
db3906fd 9795 XPutBackEvent (display, &queue_tmp->event);
09756a85 9796 queue = queue_tmp->next;
06a2c219 9797 xfree ((char *)queue_tmp);
09756a85
RS
9798 }
9799}
9800
9801/* Start queuing SelectionRequest events. */
9802
9803void
db3906fd
RS
9804x_start_queuing_selection_requests (display)
9805 Display *display;
09756a85
RS
9806{
9807 x_queue_selection_requests++;
9808}
9809
9810/* Stop queuing SelectionRequest events. */
9811
9812void
db3906fd
RS
9813x_stop_queuing_selection_requests (display)
9814 Display *display;
09756a85
RS
9815{
9816 x_queue_selection_requests--;
db3906fd 9817 x_unqueue_events (display);
09756a85 9818}
f451eb13
JB
9819\f
9820/* The main X event-reading loop - XTread_socket. */
dc6f92b8 9821
06a2c219 9822/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
9823 but we have to put it out here, since static variables within functions
9824 sometimes don't work. */
06a2c219 9825
dc6f92b8
JB
9826static Time enter_timestamp;
9827
11edeb03 9828/* This holds the state XLookupString needs to implement dead keys
58769bee 9829 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
9830 says that a portable program can't use this, but Stephen Gildea assures
9831 me that letting the compiler initialize it to zeros will work okay.
9832
9833 This must be defined outside of XTread_socket, for the same reasons
f7d40b3b 9834 given for enter_timestamp, above. */
06a2c219 9835
11edeb03
JB
9836static XComposeStatus compose_status;
9837
10e6549c
RS
9838/* Record the last 100 characters stored
9839 to help debug the loss-of-chars-during-GC problem. */
06a2c219 9840
2224b905
RS
9841static int temp_index;
9842static short temp_buffer[100];
10e6549c 9843
7a13e894
RS
9844/* Set this to nonzero to fake an "X I/O error"
9845 on a particular display. */
06a2c219 9846
7a13e894
RS
9847struct x_display_info *XTread_socket_fake_io_error;
9848
2224b905
RS
9849/* When we find no input here, we occasionally do a no-op command
9850 to verify that the X server is still running and we can still talk with it.
9851 We try all the open displays, one by one.
9852 This variable is used for cycling thru the displays. */
06a2c219 9853
2224b905
RS
9854static struct x_display_info *next_noop_dpyinfo;
9855
06a2c219
GM
9856#define SET_SAVED_MENU_EVENT(size) \
9857 do \
9858 { \
9859 if (f->output_data.x->saved_menu_event == 0) \
9860 f->output_data.x->saved_menu_event \
9861 = (XEvent *) xmalloc (sizeof (XEvent)); \
9862 bcopy (&event, f->output_data.x->saved_menu_event, size); \
9863 if (numchars >= 1) \
9864 { \
9865 bufp->kind = menu_bar_activate_event; \
9866 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 9867 bufp->arg = Qnil; \
06a2c219
GM
9868 bufp++; \
9869 count++; \
9870 numchars--; \
9871 } \
9872 } \
9873 while (0)
9874
8805890a 9875#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 9876#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 9877
dc6f92b8
JB
9878/* Read events coming from the X server.
9879 This routine is called by the SIGIO handler.
9880 We return as soon as there are no more events to be read.
9881
9882 Events representing keys are stored in buffer BUFP,
9883 which can hold up to NUMCHARS characters.
9884 We return the number of characters stored into the buffer,
9885 thus pretending to be `read'.
9886
dc6f92b8
JB
9887 EXPECTED is nonzero if the caller knows input is available. */
9888
7c5283e4 9889int
f66868ba 9890XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 9891 register int sd;
8805890a
KH
9892 /* register */ struct input_event *bufp;
9893 /* register */ int numchars;
dc6f92b8
JB
9894 int expected;
9895{
9896 int count = 0;
9897 int nbytes = 0;
dc6f92b8 9898 XEvent event;
f676886a 9899 struct frame *f;
66f55a9d 9900 int event_found = 0;
334208b7 9901 struct x_display_info *dpyinfo;
379b5ac0 9902 struct coding_system coding;
dc6f92b8 9903
9ac0d9e0 9904 if (interrupt_input_blocked)
dc6f92b8 9905 {
9ac0d9e0 9906 interrupt_input_pending = 1;
dc6f92b8
JB
9907 return -1;
9908 }
9909
9ac0d9e0 9910 interrupt_input_pending = 0;
dc6f92b8 9911 BLOCK_INPUT;
c0a04927
RS
9912
9913 /* So people can tell when we have read the available input. */
9914 input_signal_count++;
9915
dc6f92b8 9916 if (numchars <= 0)
06a2c219 9917 abort (); /* Don't think this happens. */
dc6f92b8 9918
bde5503b
GM
9919 ++handling_signal;
9920
379b5ac0
KH
9921 /* The input should be decoded if it is from XIM. Currently the
9922 locale of XIM is the same as that of the system. So, we can use
9923 Vlocale_coding_system which is initialized properly at Emacs
9924 startup time. */
9925 setup_coding_system (Vlocale_coding_system, &coding);
9926 coding.src_multibyte = 0;
9927 coding.dst_multibyte = 1;
9928 /* The input is converted to events, thus we can't handle
9929 composition. Anyway, there's no XIM that gives us composition
9930 information. */
9931 coding.composing = COMPOSITION_DISABLED;
9932
7a13e894
RS
9933 /* Find the display we are supposed to read input for.
9934 It's the one communicating on descriptor SD. */
9935 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9936 {
9937#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9938#ifdef FIOSNBIO
7a13e894
RS
9939 /* If available, Xlib uses FIOSNBIO to make the socket
9940 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9941 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9942 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9943 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9944#endif /* ! defined (FIOSNBIO) */
7a13e894 9945#endif
dc6f92b8 9946
7a13e894
RS
9947#if 0 /* This code can't be made to work, with multiple displays,
9948 and appears not to be used on any system any more.
9949 Also keyboard.c doesn't turn O_NDELAY on and off
9950 for X connections. */
dc6f92b8
JB
9951#ifndef SIGIO
9952#ifndef HAVE_SELECT
7a13e894
RS
9953 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9954 {
9955 extern int read_alarm_should_throw;
9956 read_alarm_should_throw = 1;
9957 XPeekEvent (dpyinfo->display, &event);
9958 read_alarm_should_throw = 0;
9959 }
c118dd06
JB
9960#endif /* HAVE_SELECT */
9961#endif /* SIGIO */
7a13e894 9962#endif
dc6f92b8 9963
7a13e894
RS
9964 /* For debugging, this gives a way to fake an I/O error. */
9965 if (dpyinfo == XTread_socket_fake_io_error)
9966 {
9967 XTread_socket_fake_io_error = 0;
9968 x_io_error_quitter (dpyinfo->display);
9969 }
dc6f92b8 9970
06a2c219 9971 while (XPending (dpyinfo->display))
dc6f92b8 9972 {
7a13e894 9973 XNextEvent (dpyinfo->display, &event);
06a2c219 9974
531483fb 9975#ifdef HAVE_X_I18N
d1bc4182 9976 {
f2be1146
GM
9977 /* Filter events for the current X input method.
9978 XFilterEvent returns non-zero if the input method has
9979 consumed the event. We pass the frame's X window to
9980 XFilterEvent because that's the one for which the IC
9981 was created. */
f5d11644
GM
9982 struct frame *f1 = x_any_window_to_frame (dpyinfo,
9983 event.xclient.window);
9984 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
9985 break;
9986 }
0cd6403b 9987#endif
7a13e894
RS
9988 event_found = 1;
9989
9990 switch (event.type)
9991 {
9992 case ClientMessage:
c047688c 9993 {
7a13e894
RS
9994 if (event.xclient.message_type
9995 == dpyinfo->Xatom_wm_protocols
9996 && event.xclient.format == 32)
c047688c 9997 {
7a13e894
RS
9998 if (event.xclient.data.l[0]
9999 == dpyinfo->Xatom_wm_take_focus)
c047688c 10000 {
8c1a6a84
RS
10001 /* Use x_any_window_to_frame because this
10002 could be the shell widget window
10003 if the frame has no title bar. */
10004 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
10005#ifdef HAVE_X_I18N
10006 /* Not quite sure this is needed -pd */
8c1a6a84 10007 if (f && FRAME_XIC (f))
6c183ba5
RS
10008 XSetICFocus (FRAME_XIC (f));
10009#endif
f1da8f06
GM
10010#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
10011 instructs the WM to set the input focus automatically for
10012 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
10013 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
10014 it has set the focus. So, XSetInputFocus below is not
10015 needed.
10016
10017 The call to XSetInputFocus below has also caused trouble. In
10018 cases where the XSetInputFocus done by the WM and the one
10019 below are temporally close (on a fast machine), the call
10020 below can generate additional FocusIn events which confuse
10021 Emacs. */
10022
bf7253f4
RS
10023 /* Since we set WM_TAKE_FOCUS, we must call
10024 XSetInputFocus explicitly. But not if f is null,
10025 since that might be an event for a deleted frame. */
7a13e894 10026 if (f)
bf7253f4
RS
10027 {
10028 Display *d = event.xclient.display;
10029 /* Catch and ignore errors, in case window has been
10030 iconified by a window manager such as GWM. */
10031 int count = x_catch_errors (d);
10032 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
10033 /* The ICCCM says this is
10034 the only valid choice. */
10035 RevertToParent,
bf7253f4
RS
10036 event.xclient.data.l[1]);
10037 /* This is needed to detect the error
10038 if there is an error. */
10039 XSync (d, False);
10040 x_uncatch_errors (d, count);
10041 }
7a13e894 10042 /* Not certain about handling scroll bars here */
f1da8f06 10043#endif /* 0 */
c047688c 10044 }
7a13e894
RS
10045 else if (event.xclient.data.l[0]
10046 == dpyinfo->Xatom_wm_save_yourself)
10047 {
10048 /* Save state modify the WM_COMMAND property to
06a2c219 10049 something which can reinstate us. This notifies
7a13e894
RS
10050 the session manager, who's looking for such a
10051 PropertyNotify. Can restart processing when
06a2c219 10052 a keyboard or mouse event arrives. */
7a13e894
RS
10053 if (numchars > 0)
10054 {
19126e11
KH
10055 f = x_top_window_to_frame (dpyinfo,
10056 event.xclient.window);
7a13e894
RS
10057
10058 /* This is just so we only give real data once
10059 for a single Emacs process. */
b86bd3dd 10060 if (f == SELECTED_FRAME ())
7a13e894
RS
10061 XSetCommand (FRAME_X_DISPLAY (f),
10062 event.xclient.window,
10063 initial_argv, initial_argc);
f000f5c5 10064 else if (f)
7a13e894
RS
10065 XSetCommand (FRAME_X_DISPLAY (f),
10066 event.xclient.window,
10067 0, 0);
10068 }
10069 }
10070 else if (event.xclient.data.l[0]
10071 == dpyinfo->Xatom_wm_delete_window)
1fb20991 10072 {
19126e11
KH
10073 struct frame *f
10074 = x_any_window_to_frame (dpyinfo,
10075 event.xclient.window);
1fb20991 10076
7a13e894
RS
10077 if (f)
10078 {
10079 if (numchars == 0)
10080 abort ();
1fb20991 10081
7a13e894
RS
10082 bufp->kind = delete_window_event;
10083 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10084 bufp->arg = Qnil;
7a13e894
RS
10085 bufp++;
10086
10087 count += 1;
10088 numchars -= 1;
10089 }
1fb20991 10090 }
c047688c 10091 }
7a13e894
RS
10092 else if (event.xclient.message_type
10093 == dpyinfo->Xatom_wm_configure_denied)
10094 {
10095 }
10096 else if (event.xclient.message_type
10097 == dpyinfo->Xatom_wm_window_moved)
10098 {
10099 int new_x, new_y;
19126e11
KH
10100 struct frame *f
10101 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 10102
7a13e894
RS
10103 new_x = event.xclient.data.s[0];
10104 new_y = event.xclient.data.s[1];
1fb20991 10105
7a13e894
RS
10106 if (f)
10107 {
7556890b
RS
10108 f->output_data.x->left_pos = new_x;
10109 f->output_data.x->top_pos = new_y;
7a13e894 10110 }
1fb20991 10111 }
0fdff6bb 10112#ifdef HACK_EDITRES
7a13e894
RS
10113 else if (event.xclient.message_type
10114 == dpyinfo->Xatom_editres)
10115 {
19126e11
KH
10116 struct frame *f
10117 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 10118 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 10119 &event, NULL);
7a13e894 10120 }
0fdff6bb 10121#endif /* HACK_EDITRES */
06a2c219
GM
10122 else if ((event.xclient.message_type
10123 == dpyinfo->Xatom_DONE)
10124 || (event.xclient.message_type
10125 == dpyinfo->Xatom_PAGE))
10126 {
10127 /* Ghostview job completed. Kill it. We could
10128 reply with "Next" if we received "Page", but we
10129 currently never do because we are interested in
10130 images, only, which should have 1 page. */
06a2c219
GM
10131 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
10132 struct frame *f
10133 = x_window_to_frame (dpyinfo, event.xclient.window);
10134 x_kill_gs_process (pixmap, f);
10135 expose_frame (f, 0, 0, 0, 0);
10136 }
10137#ifdef USE_TOOLKIT_SCROLL_BARS
10138 /* Scroll bar callbacks send a ClientMessage from which
10139 we construct an input_event. */
10140 else if (event.xclient.message_type
10141 == dpyinfo->Xatom_Scrollbar)
10142 {
10143 x_scroll_bar_to_input_event (&event, bufp);
10144 ++bufp, ++count, --numchars;
10145 goto out;
10146 }
10147#endif /* USE_TOOLKIT_SCROLL_BARS */
10148 else
10149 goto OTHER;
7a13e894
RS
10150 }
10151 break;
dc6f92b8 10152
7a13e894 10153 case SelectionNotify:
3afe33e7 10154#ifdef USE_X_TOOLKIT
19126e11 10155 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 10156 goto OTHER;
3afe33e7 10157#endif /* not USE_X_TOOLKIT */
dfcf069d 10158 x_handle_selection_notify (&event.xselection);
7a13e894 10159 break;
d56a553a 10160
06a2c219 10161 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 10162#ifdef USE_X_TOOLKIT
19126e11 10163 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 10164 goto OTHER;
3afe33e7 10165#endif /* USE_X_TOOLKIT */
7a13e894
RS
10166 {
10167 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 10168
7a13e894
RS
10169 if (numchars == 0)
10170 abort ();
d56a553a 10171
7a13e894
RS
10172 bufp->kind = selection_clear_event;
10173 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10174 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10175 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10176 bufp->frame_or_window = Qnil;
0f8aabe9 10177 bufp->arg = Qnil;
7a13e894 10178 bufp++;
d56a553a 10179
7a13e894
RS
10180 count += 1;
10181 numchars -= 1;
10182 }
10183 break;
dc6f92b8 10184
06a2c219 10185 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 10186#ifdef USE_X_TOOLKIT
19126e11 10187 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 10188 goto OTHER;
3afe33e7 10189#endif /* USE_X_TOOLKIT */
7a13e894 10190 if (x_queue_selection_requests)
19126e11 10191 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
10192 &event);
10193 else
10194 {
1d2b2268
GM
10195 XSelectionRequestEvent *eventp
10196 = (XSelectionRequestEvent *) &event;
dc6f92b8 10197
7a13e894
RS
10198 if (numchars == 0)
10199 abort ();
10200
10201 bufp->kind = selection_request_event;
10202 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10203 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
10204 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10205 SELECTION_EVENT_TARGET (bufp) = eventp->target;
10206 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
10207 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10208 bufp->frame_or_window = Qnil;
0f8aabe9 10209 bufp->arg = Qnil;
7a13e894
RS
10210 bufp++;
10211
10212 count += 1;
10213 numchars -= 1;
10214 }
10215 break;
10216
10217 case PropertyNotify:
1d2b2268
GM
10218#if 0 /* This is plain wrong. In the case that we are waiting for a
10219 PropertyNotify used as an ACK in incremental selection
10220 transfer, the property will be on the receiver's window. */
10221#if defined USE_X_TOOLKIT
19126e11 10222 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 10223 goto OTHER;
1d2b2268
GM
10224#endif
10225#endif
dfcf069d 10226 x_handle_property_notify (&event.xproperty);
1d2b2268 10227 goto OTHER;
dc6f92b8 10228
7a13e894 10229 case ReparentNotify:
19126e11 10230 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
10231 if (f)
10232 {
10233 int x, y;
7556890b 10234 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 10235 x_real_positions (f, &x, &y);
7556890b
RS
10236 f->output_data.x->left_pos = x;
10237 f->output_data.x->top_pos = y;
7a13e894
RS
10238 }
10239 break;
3bd330d4 10240
7a13e894 10241 case Expose:
19126e11 10242 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 10243 if (f)
dc6f92b8 10244 {
7a13e894
RS
10245 if (f->async_visible == 0)
10246 {
10247 f->async_visible = 1;
10248 f->async_iconified = 0;
06c488fd 10249 f->output_data.x->has_been_visible = 1;
7a13e894
RS
10250 SET_FRAME_GARBAGED (f);
10251 }
10252 else
06a2c219
GM
10253 expose_frame (x_window_to_frame (dpyinfo,
10254 event.xexpose.window),
10255 event.xexpose.x, event.xexpose.y,
10256 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
10257 }
10258 else
7a13e894 10259 {
12949a7f
EZ
10260#ifndef USE_TOOLKIT_SCROLL_BARS
10261 struct scroll_bar *bar;
10262#endif
01f67d2c 10263#if defined USE_LUCID
c95fc5f1
GM
10264 /* Submenus of the Lucid menu bar aren't widgets
10265 themselves, so there's no way to dispatch events
10266 to them. Recognize this case separately. */
10267 {
10268 Widget widget
10269 = x_window_to_menu_bar (event.xexpose.window);
10270 if (widget)
10271 xlwmenu_redisplay (widget);
10272 }
01f67d2c
PJ
10273#endif /* USE_LUCID */
10274
06a2c219
GM
10275#ifdef USE_TOOLKIT_SCROLL_BARS
10276 /* Dispatch event to the widget. */
10277 goto OTHER;
10278#else /* not USE_TOOLKIT_SCROLL_BARS */
12949a7f 10279 bar = x_window_to_scroll_bar (event.xexpose.window);
58769bee 10280
7a13e894
RS
10281 if (bar)
10282 x_scroll_bar_expose (bar, &event);
3afe33e7 10283#ifdef USE_X_TOOLKIT
7a13e894
RS
10284 else
10285 goto OTHER;
3afe33e7 10286#endif /* USE_X_TOOLKIT */
06a2c219 10287#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10288 }
10289 break;
dc6f92b8 10290
7a13e894 10291 case GraphicsExpose: /* This occurs when an XCopyArea's
d624284c
PJ
10292 source area was obscured or not
10293 available. */
19126e11 10294 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
10295 if (f)
10296 {
06a2c219
GM
10297 expose_frame (f,
10298 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
10299 event.xgraphicsexpose.width,
10300 event.xgraphicsexpose.height);
7a13e894 10301 }
3afe33e7 10302#ifdef USE_X_TOOLKIT
7a13e894
RS
10303 else
10304 goto OTHER;
3afe33e7 10305#endif /* USE_X_TOOLKIT */
7a13e894 10306 break;
dc6f92b8 10307
7a13e894 10308 case NoExpose: /* This occurs when an XCopyArea's
06a2c219 10309 source area was completely
d624284c 10310 available. */
7a13e894 10311 break;
dc6f92b8 10312
7a13e894 10313 case UnmapNotify:
06a2c219
GM
10314 /* Redo the mouse-highlight after the tooltip has gone. */
10315 if (event.xmap.window == tip_window)
10316 {
10317 tip_window = 0;
10318 redo_mouse_highlight ();
10319 }
10320
91ea2a7a 10321 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894 10322 if (f) /* F may no longer exist if
d624284c 10323 the frame was deleted. */
7a13e894
RS
10324 {
10325 /* While a frame is unmapped, display generation is
10326 disabled; you don't want to spend time updating a
10327 display that won't ever be seen. */
10328 f->async_visible = 0;
10329 /* We can't distinguish, from the event, whether the window
10330 has become iconified or invisible. So assume, if it
10331 was previously visible, than now it is iconified.
1aa6072f
RS
10332 But x_make_frame_invisible clears both
10333 the visible flag and the iconified flag;
10334 and that way, we know the window is not iconified now. */
7a13e894 10335 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
10336 {
10337 f->async_iconified = 1;
bddd097c 10338
1aa6072f
RS
10339 bufp->kind = iconify_event;
10340 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10341 bufp->arg = Qnil;
1aa6072f
RS
10342 bufp++;
10343 count++;
10344 numchars--;
10345 }
7a13e894 10346 }
7a13e894 10347 goto OTHER;
dc6f92b8 10348
7a13e894 10349 case MapNotify:
06a2c219
GM
10350 if (event.xmap.window == tip_window)
10351 /* The tooltip has been drawn already. Avoid
10352 the SET_FRAME_GARBAGED below. */
10353 goto OTHER;
10354
10355 /* We use x_top_window_to_frame because map events can
10356 come for sub-windows and they don't mean that the
10357 frame is visible. */
19126e11 10358 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
10359 if (f)
10360 {
10361 f->async_visible = 1;
10362 f->async_iconified = 0;
06c488fd 10363 f->output_data.x->has_been_visible = 1;
dc6f92b8 10364
7a13e894
RS
10365 /* wait_reading_process_input will notice this and update
10366 the frame's display structures. */
10367 SET_FRAME_GARBAGED (f);
bddd097c 10368
d806e720
RS
10369 if (f->iconified)
10370 {
10371 bufp->kind = deiconify_event;
10372 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10373 bufp->arg = Qnil;
d806e720
RS
10374 bufp++;
10375 count++;
10376 numchars--;
10377 }
e73ec6fa 10378 else if (! NILP (Vframe_list)
8e713be6 10379 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
10380 /* Force a redisplay sooner or later
10381 to update the frame titles
10382 in case this is the second frame. */
10383 record_asynch_buffer_change ();
7a13e894 10384 }
7a13e894 10385 goto OTHER;
dc6f92b8 10386
7a13e894 10387 case KeyPress:
19126e11 10388 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 10389
eccc05db 10390#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
10391 if (f == 0)
10392 {
2564ea1b
GM
10393 /* Scroll bars consume key events, but we want
10394 the keys to go to the scroll bar's frame. */
06a2c219
GM
10395 Widget widget = XtWindowToWidget (dpyinfo->display,
10396 event.xkey.window);
10397 if (widget && XmIsScrollBar (widget))
10398 {
10399 widget = XtParent (widget);
10400 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
10401 }
10402 }
eccc05db 10403#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
06a2c219 10404
7a13e894
RS
10405 if (f != 0)
10406 {
10407 KeySym keysym, orig_keysym;
379b5ac0
KH
10408 /* al%imercury@uunet.uu.net says that making this 81
10409 instead of 80 fixed a bug whereby meta chars made
10410 his Emacs hang.
10411
10412 It seems that some version of XmbLookupString has
10413 a bug of not returning XBufferOverflow in
10414 status_return even if the input is too long to
10415 fit in 81 bytes. So, we must prepare sufficient
10416 bytes for copy_buffer. 513 bytes (256 chars for
6c4a22e6 10417 two-byte character set) seems to be a fairly good
379b5ac0
KH
10418 approximation. -- 2000.8.10 handa@etl.go.jp */
10419 unsigned char copy_buffer[513];
10420 unsigned char *copy_bufptr = copy_buffer;
10421 int copy_bufsiz = sizeof (copy_buffer);
7a13e894 10422 int modifiers;
64bb1782 10423
7a13e894
RS
10424 event.xkey.state
10425 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
10426 extra_keyboard_modifiers);
10427 modifiers = event.xkey.state;
3a2712f9 10428
7a13e894 10429 /* This will have to go some day... */
752a043f 10430
7a13e894
RS
10431 /* make_lispy_event turns chars into control chars.
10432 Don't do it here because XLookupString is too eager. */
10433 event.xkey.state &= ~ControlMask;
5d46f928
RS
10434 event.xkey.state &= ~(dpyinfo->meta_mod_mask
10435 | dpyinfo->super_mod_mask
10436 | dpyinfo->hyper_mod_mask
10437 | dpyinfo->alt_mod_mask);
10438
1cf4a0d1
RS
10439 /* In case Meta is ComposeCharacter,
10440 clear its status. According to Markus Ehrnsperger
10441 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
10442 this enables ComposeCharacter to work whether or
10443 not it is combined with Meta. */
10444 if (modifiers & dpyinfo->meta_mod_mask)
10445 bzero (&compose_status, sizeof (compose_status));
10446
6c183ba5
RS
10447#ifdef HAVE_X_I18N
10448 if (FRAME_XIC (f))
10449 {
f5d11644
GM
10450 Status status_return;
10451
6c183ba5 10452 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
10453 &event.xkey, copy_bufptr,
10454 copy_bufsiz, &keysym,
6c183ba5 10455 &status_return);
f5d11644
GM
10456 if (status_return == XBufferOverflow)
10457 {
10458 copy_bufsiz = nbytes + 1;
10459 copy_bufptr = (char *) alloca (copy_bufsiz);
10460 nbytes = XmbLookupString (FRAME_XIC (f),
10461 &event.xkey, copy_bufptr,
10462 copy_bufsiz, &keysym,
10463 &status_return);
10464 }
10465
1decb680
PE
10466 if (status_return == XLookupNone)
10467 break;
10468 else if (status_return == XLookupChars)
fdd9d55e
GM
10469 {
10470 keysym = NoSymbol;
10471 modifiers = 0;
10472 }
1decb680
PE
10473 else if (status_return != XLookupKeySym
10474 && status_return != XLookupBoth)
10475 abort ();
6c183ba5
RS
10476 }
10477 else
379b5ac0
KH
10478 nbytes = XLookupString (&event.xkey, copy_bufptr,
10479 copy_bufsiz, &keysym,
10480 &compose_status);
6c183ba5 10481#else
379b5ac0
KH
10482 nbytes = XLookupString (&event.xkey, copy_bufptr,
10483 copy_bufsiz, &keysym,
10484 &compose_status);
6c183ba5 10485#endif
dc6f92b8 10486
7a13e894 10487 orig_keysym = keysym;
55123275 10488
7a13e894
RS
10489 if (numchars > 1)
10490 {
10491 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
10492 || keysym == XK_Delete
1097aea0 10493#ifdef XK_ISO_Left_Tab
441affdb 10494 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 10495#endif
852bff8f 10496 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
10497 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
10498 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 10499#ifdef HPUX
7a13e894
RS
10500 /* This recognizes the "extended function keys".
10501 It seems there's no cleaner way.
10502 Test IsModifierKey to avoid handling mode_switch
10503 incorrectly. */
10504 || ((unsigned) (keysym) >= XK_Select
10505 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
10506#endif
10507#ifdef XK_dead_circumflex
7a13e894 10508 || orig_keysym == XK_dead_circumflex
69388238
RS
10509#endif
10510#ifdef XK_dead_grave
7a13e894 10511 || orig_keysym == XK_dead_grave
69388238
RS
10512#endif
10513#ifdef XK_dead_tilde
7a13e894 10514 || orig_keysym == XK_dead_tilde
69388238
RS
10515#endif
10516#ifdef XK_dead_diaeresis
7a13e894 10517 || orig_keysym == XK_dead_diaeresis
69388238
RS
10518#endif
10519#ifdef XK_dead_macron
7a13e894 10520 || orig_keysym == XK_dead_macron
69388238
RS
10521#endif
10522#ifdef XK_dead_degree
7a13e894 10523 || orig_keysym == XK_dead_degree
69388238
RS
10524#endif
10525#ifdef XK_dead_acute
7a13e894 10526 || orig_keysym == XK_dead_acute
69388238
RS
10527#endif
10528#ifdef XK_dead_cedilla
7a13e894 10529 || orig_keysym == XK_dead_cedilla
69388238
RS
10530#endif
10531#ifdef XK_dead_breve
7a13e894 10532 || orig_keysym == XK_dead_breve
69388238
RS
10533#endif
10534#ifdef XK_dead_ogonek
7a13e894 10535 || orig_keysym == XK_dead_ogonek
69388238
RS
10536#endif
10537#ifdef XK_dead_caron
7a13e894 10538 || orig_keysym == XK_dead_caron
69388238
RS
10539#endif
10540#ifdef XK_dead_doubleacute
7a13e894 10541 || orig_keysym == XK_dead_doubleacute
69388238
RS
10542#endif
10543#ifdef XK_dead_abovedot
7a13e894 10544 || orig_keysym == XK_dead_abovedot
c34790e0 10545#endif
7a13e894
RS
10546 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
10547 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
10548 /* Any "vendor-specific" key is ok. */
f0e299de
GM
10549 || (orig_keysym & (1 << 28))
10550 || (keysym != NoSymbol && nbytes == 0))
7a13e894 10551 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
10552#ifndef HAVE_X11R5
10553#ifdef XK_Mode_switch
7a13e894 10554 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
10555#endif
10556#ifdef XK_Num_Lock
7a13e894 10557 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
10558#endif
10559#endif /* not HAVE_X11R5 */
7a13e894 10560 ))
dc6f92b8 10561 {
10e6549c
RS
10562 if (temp_index == sizeof temp_buffer / sizeof (short))
10563 temp_index = 0;
7a13e894
RS
10564 temp_buffer[temp_index++] = keysym;
10565 bufp->kind = non_ascii_keystroke;
10566 bufp->code = keysym;
e0c1aef2 10567 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10568 bufp->arg = Qnil;
334208b7
RS
10569 bufp->modifiers
10570 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10571 modifiers);
1113d9db 10572 bufp->timestamp = event.xkey.time;
dc6f92b8 10573 bufp++;
7a13e894
RS
10574 count++;
10575 numchars--;
dc6f92b8 10576 }
7a13e894
RS
10577 else if (numchars > nbytes)
10578 {
10579 register int i;
379b5ac0 10580 register int c;
379b5ac0 10581 int nchars, len;
7a13e894
RS
10582
10583 for (i = 0; i < nbytes; i++)
10584 {
379b5ac0
KH
10585 if (temp_index == (sizeof temp_buffer
10586 / sizeof (short)))
7a13e894 10587 temp_index = 0;
379b5ac0
KH
10588 temp_buffer[temp_index++] = copy_bufptr[i];
10589 }
10590
10591 if (/* If the event is not from XIM, */
10592 event.xkey.keycode != 0
10593 /* or the current locale doesn't request
10594 decoding of the intup data, ... */
10595 || coding.type == coding_type_raw_text
10596 || coding.type == coding_type_no_conversion)
10597 {
10598 /* ... we can use the input data as is. */
10599 nchars = nbytes;
10600 }
10601 else
10602 {
10603 /* We have to decode the input data. */
10604 int require;
10605 unsigned char *p;
10606
10607 require = decoding_buffer_size (&coding, nbytes);
10608 p = (unsigned char *) alloca (require);
10609 coding.mode |= CODING_MODE_LAST_BLOCK;
10610 decode_coding (&coding, copy_bufptr, p,
10611 nbytes, require);
10612 nbytes = coding.produced;
10613 nchars = coding.produced_char;
10614 copy_bufptr = p;
10615 }
10616
10617 /* Convert the input data to a sequence of
10618 character events. */
10619 for (i = 0; i < nbytes; i += len)
10620 {
fee2aedc
GM
10621 if (nchars == nbytes)
10622 c = copy_bufptr[i], len = 1;
10623 else
10624 c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
10625 nbytes - i, len);
10626
379b5ac0
KH
10627 bufp->kind = (SINGLE_BYTE_CHAR_P (c)
10628 ? ascii_keystroke
10629 : multibyte_char_keystroke);
10630 bufp->code = c;
7a13e894 10631 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10632 bufp->arg = Qnil;
7a13e894
RS
10633 bufp->modifiers
10634 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10635 modifiers);
10636 bufp->timestamp = event.xkey.time;
10637 bufp++;
10638 }
10639
379b5ac0
KH
10640 count += nchars;
10641 numchars -= nchars;
1decb680
PE
10642
10643 if (keysym == NoSymbol)
10644 break;
7a13e894
RS
10645 }
10646 else
10647 abort ();
dc6f92b8 10648 }
10e6549c
RS
10649 else
10650 abort ();
dc6f92b8 10651 }
59ddecde
GM
10652#ifdef HAVE_X_I18N
10653 /* Don't dispatch this event since XtDispatchEvent calls
10654 XFilterEvent, and two calls in a row may freeze the
10655 client. */
10656 break;
10657#else
717ca130 10658 goto OTHER;
59ddecde 10659#endif
f451eb13 10660
f5d11644 10661 case KeyRelease:
59ddecde
GM
10662#ifdef HAVE_X_I18N
10663 /* Don't dispatch this event since XtDispatchEvent calls
10664 XFilterEvent, and two calls in a row may freeze the
10665 client. */
10666 break;
10667#else
f5d11644 10668 goto OTHER;
59ddecde 10669#endif
f5d11644 10670
7a13e894 10671 /* Here's a possible interpretation of the whole
06a2c219
GM
10672 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
10673 you get a FocusIn event, you have to get a FocusOut
10674 event before you relinquish the focus. If you
10675 haven't received a FocusIn event, then a mere
10676 LeaveNotify is enough to free you. */
f451eb13 10677
7a13e894 10678 case EnterNotify:
06a2c219 10679 {
06a2c219
GM
10680 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
10681
2c850e26 10682#if 0
582c60f8 10683 if (event.xcrossing.focus)
06a2c219
GM
10684 {
10685 /* Avoid nasty pop/raise loops. */
10686 if (f && (!(f->auto_raise)
10687 || !(f->auto_lower)
10688 || (event.xcrossing.time - enter_timestamp) > 500))
10689 {
10690 x_new_focus_frame (dpyinfo, f);
10691 enter_timestamp = event.xcrossing.time;
10692 }
10693 }
10694 else if (f == dpyinfo->x_focus_frame)
10695 x_new_focus_frame (dpyinfo, 0);
2c850e26
RS
10696#endif
10697
06a2c219
GM
10698 /* EnterNotify counts as mouse movement,
10699 so update things that depend on mouse position. */
2533c408 10700 if (f && !f->output_data.x->hourglass_p)
06a2c219
GM
10701 note_mouse_movement (f, &event.xmotion);
10702 goto OTHER;
10703 }
dc6f92b8 10704
7a13e894 10705 case FocusIn:
19126e11 10706 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10707 if (event.xfocus.detail != NotifyPointer)
0f941935 10708 dpyinfo->x_focus_event_frame = f;
7a13e894 10709 if (f)
eb72635f
GM
10710 {
10711 x_new_focus_frame (dpyinfo, f);
10712
10713 /* Don't stop displaying the initial startup message
10714 for a switch-frame event we don't need. */
10715 if (GC_NILP (Vterminal_frame)
10716 && GC_CONSP (Vframe_list)
10717 && !GC_NILP (XCDR (Vframe_list)))
10718 {
10719 bufp->kind = FOCUS_IN_EVENT;
10720 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10721 bufp->arg = Qnil;
eb72635f
GM
10722 ++bufp, ++count, --numchars;
10723 }
10724 }
f9e24cb9 10725
6c183ba5
RS
10726#ifdef HAVE_X_I18N
10727 if (f && FRAME_XIC (f))
10728 XSetICFocus (FRAME_XIC (f));
10729#endif
10730
7a13e894 10731 goto OTHER;
10c5e63d 10732
7a13e894 10733 case LeaveNotify:
19126e11 10734 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 10735 if (f)
10c5e63d 10736 {
7a13e894 10737 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
10738 {
10739 /* If we move outside the frame, then we're
10740 certainly no longer on any text in the frame. */
10741 clear_mouse_face (dpyinfo);
10742 dpyinfo->mouse_face_mouse_frame = 0;
10743 }
10744
10745 /* Generate a nil HELP_EVENT to cancel a help-echo.
10746 Do it only if there's something to cancel.
10747 Otherwise, the startup message is cleared when
10748 the mouse leaves the frame. */
10749 if (any_help_event_p)
10750 {
be010514
GM
10751 Lisp_Object frame;
10752 int n;
10753
06a2c219 10754 XSETFRAME (frame, f);
82c5d67a 10755 help_echo = Qnil;
5ab2570d
GM
10756 n = gen_help_event (bufp, numchars,
10757 Qnil, frame, Qnil, Qnil, 0);
be010514 10758 bufp += n, count += n, numchars -= n;
06a2c219 10759 }
7a13e894 10760
2c850e26 10761#if 0
582c60f8 10762 if (event.xcrossing.focus)
0f941935 10763 x_mouse_leave (dpyinfo);
10c5e63d 10764 else
7a13e894 10765 {
0f941935
KH
10766 if (f == dpyinfo->x_focus_event_frame)
10767 dpyinfo->x_focus_event_frame = 0;
140d6643 10768 if (f == dpyinfo->x_focus_frame)
0f941935 10769 x_new_focus_frame (dpyinfo, 0);
7a13e894 10770 }
2c850e26 10771#endif
10c5e63d 10772 }
7a13e894 10773 goto OTHER;
dc6f92b8 10774
7a13e894 10775 case FocusOut:
19126e11 10776 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10777 if (event.xfocus.detail != NotifyPointer
0f941935
KH
10778 && f == dpyinfo->x_focus_event_frame)
10779 dpyinfo->x_focus_event_frame = 0;
10780 if (f && f == dpyinfo->x_focus_frame)
10781 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 10782
6c183ba5
RS
10783#ifdef HAVE_X_I18N
10784 if (f && FRAME_XIC (f))
10785 XUnsetICFocus (FRAME_XIC (f));
10786#endif
10787
7a13e894 10788 goto OTHER;
dc6f92b8 10789
7a13e894 10790 case MotionNotify:
dc6f92b8 10791 {
06a2c219 10792 previous_help_echo = help_echo;
7cea38bc 10793 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 10794 help_echo_pos = -1;
06a2c219 10795
7a13e894
RS
10796 if (dpyinfo->grabbed && last_mouse_frame
10797 && FRAME_LIVE_P (last_mouse_frame))
10798 f = last_mouse_frame;
10799 else
19126e11 10800 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 10801
7a13e894
RS
10802 if (f)
10803 note_mouse_movement (f, &event.xmotion);
10804 else
10805 {
e88b3c50 10806#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10807 struct scroll_bar *bar
10808 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 10809
7a13e894
RS
10810 if (bar)
10811 x_scroll_bar_note_movement (bar, &event);
e88b3c50 10812#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 10813
06a2c219
GM
10814 /* If we move outside the frame, then we're
10815 certainly no longer on any text in the frame. */
7a13e894
RS
10816 clear_mouse_face (dpyinfo);
10817 }
06a2c219
GM
10818
10819 /* If the contents of the global variable help_echo
10820 has changed, generate a HELP_EVENT. */
b7e80413
SM
10821 if (!NILP (help_echo)
10822 || !NILP (previous_help_echo))
06a2c219
GM
10823 {
10824 Lisp_Object frame;
be010514 10825 int n;
06a2c219
GM
10826
10827 if (f)
10828 XSETFRAME (frame, f);
10829 else
10830 frame = Qnil;
10831
10832 any_help_event_p = 1;
5ab2570d 10833 n = gen_help_event (bufp, numchars, help_echo, frame,
7cea38bc
GM
10834 help_echo_window, help_echo_object,
10835 help_echo_pos);
be010514 10836 bufp += n, count += n, numchars -= n;
06a2c219
GM
10837 }
10838
10839 goto OTHER;
dc6f92b8 10840 }
dc6f92b8 10841
7a13e894 10842 case ConfigureNotify:
9829ddba
RS
10843 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
10844 if (f)
af395ec1 10845 {
5c187dee 10846#ifndef USE_X_TOOLKIT
bf1b7b30
KH
10847 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
10848 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 10849
2d7fc7e8
RS
10850 /* In the toolkit version, change_frame_size
10851 is called by the code that handles resizing
10852 of the EmacsFrame widget. */
7a13e894 10853
7a13e894
RS
10854 /* Even if the number of character rows and columns has
10855 not changed, the font size may have changed, so we need
10856 to check the pixel dimensions as well. */
10857 if (columns != f->width
10858 || rows != f->height
7556890b
RS
10859 || event.xconfigure.width != f->output_data.x->pixel_width
10860 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 10861 {
7d1e984f 10862 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 10863 SET_FRAME_GARBAGED (f);
e687d06e 10864 cancel_mouse_face (f);
7a13e894 10865 }
2d7fc7e8 10866#endif
af395ec1 10867
7556890b
RS
10868 f->output_data.x->pixel_width = event.xconfigure.width;
10869 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
10870
10871 /* What we have now is the position of Emacs's own window.
10872 Convert that to the position of the window manager window. */
dcb07ae9
RS
10873 x_real_positions (f, &f->output_data.x->left_pos,
10874 &f->output_data.x->top_pos);
10875
f5d11644
GM
10876#ifdef HAVE_X_I18N
10877 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
10878 xic_set_statusarea (f);
10879#endif
10880
dcb07ae9
RS
10881 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
10882 {
10883 /* Since the WM decorations come below top_pos now,
10884 we must put them below top_pos in the future. */
10885 f->output_data.x->win_gravity = NorthWestGravity;
10886 x_wm_set_size_hint (f, (long) 0, 0);
10887 }
8f08dc93
KH
10888#ifdef USE_MOTIF
10889 /* Some window managers pass (0,0) as the location of
10890 the window, and the Motif event handler stores it
10891 in the emacs widget, which messes up Motif menus. */
10892 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
10893 {
10894 event.xconfigure.x = f->output_data.x->widget->core.x;
10895 event.xconfigure.y = f->output_data.x->widget->core.y;
10896 }
06a2c219 10897#endif /* USE_MOTIF */
7a13e894 10898 }
2d7fc7e8 10899 goto OTHER;
dc6f92b8 10900
7a13e894
RS
10901 case ButtonPress:
10902 case ButtonRelease:
10903 {
10904 /* If we decide we want to generate an event to be seen
10905 by the rest of Emacs, we put it here. */
10906 struct input_event emacs_event;
9ea173e8 10907 int tool_bar_p = 0;
06a2c219 10908
7a13e894 10909 emacs_event.kind = no_event;
7a13e894 10910 bzero (&compose_status, sizeof (compose_status));
9b07615b 10911
06a2c219
GM
10912 if (dpyinfo->grabbed
10913 && last_mouse_frame
9f67f20b
RS
10914 && FRAME_LIVE_P (last_mouse_frame))
10915 f = last_mouse_frame;
10916 else
2224b905 10917 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 10918
06a2c219
GM
10919 if (f)
10920 {
9ea173e8
GM
10921 /* Is this in the tool-bar? */
10922 if (WINDOWP (f->tool_bar_window)
10923 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
10924 {
10925 Lisp_Object window;
10926 int p, x, y;
10927
10928 x = event.xbutton.x;
10929 y = event.xbutton.y;
10930
10931 /* Set x and y. */
10932 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 10933 if (EQ (window, f->tool_bar_window))
06a2c219 10934 {
9ea173e8
GM
10935 x_handle_tool_bar_click (f, &event.xbutton);
10936 tool_bar_p = 1;
06a2c219
GM
10937 }
10938 }
10939
9ea173e8 10940 if (!tool_bar_p)
06a2c219
GM
10941 if (!dpyinfo->x_focus_frame
10942 || f == dpyinfo->x_focus_frame)
10943 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
10944 }
10945 else
10946 {
06a2c219 10947#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10948 struct scroll_bar *bar
10949 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 10950
7a13e894
RS
10951 if (bar)
10952 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 10953#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10954 }
10955
10956 if (event.type == ButtonPress)
10957 {
10958 dpyinfo->grabbed |= (1 << event.xbutton.button);
10959 last_mouse_frame = f;
edad46f6
KH
10960 /* Ignore any mouse motion that happened
10961 before this event; any subsequent mouse-movement
10962 Emacs events should reflect only motion after
10963 the ButtonPress. */
a00e91cd
KH
10964 if (f != 0)
10965 f->mouse_moved = 0;
06a2c219 10966
9ea173e8
GM
10967 if (!tool_bar_p)
10968 last_tool_bar_item = -1;
7a13e894 10969 }
3afe33e7
RS
10970 else
10971 {
7a13e894 10972 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10973 }
23faf38f 10974
7a13e894
RS
10975 if (numchars >= 1 && emacs_event.kind != no_event)
10976 {
10977 bcopy (&emacs_event, bufp, sizeof (struct input_event));
10978 bufp++;
10979 count++;
10980 numchars--;
10981 }
3afe33e7
RS
10982
10983#ifdef USE_X_TOOLKIT
2224b905
RS
10984 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
10985 /* For a down-event in the menu bar,
10986 don't pass it to Xt right now.
10987 Instead, save it away
10988 and we will pass it to Xt from kbd_buffer_get_event.
10989 That way, we can run some Lisp code first. */
91375f8f
RS
10990 if (f && event.type == ButtonPress
10991 /* Verify the event is really within the menu bar
10992 and not just sent to it due to grabbing. */
10993 && event.xbutton.x >= 0
10994 && event.xbutton.x < f->output_data.x->pixel_width
10995 && event.xbutton.y >= 0
10996 && event.xbutton.y < f->output_data.x->menubar_height
10997 && event.xbutton.same_screen)
2224b905 10998 {
8805890a 10999 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
11000 XSETFRAME (last_mouse_press_frame, f);
11001 }
11002 else if (event.type == ButtonPress)
11003 {
11004 last_mouse_press_frame = Qnil;
30e671c3 11005 goto OTHER;
ce89ef46 11006 }
06a2c219 11007
2237cac9
RS
11008#ifdef USE_MOTIF /* This should do not harm for Lucid,
11009 but I am trying to be cautious. */
ce89ef46
RS
11010 else if (event.type == ButtonRelease)
11011 {
2237cac9 11012 if (!NILP (last_mouse_press_frame))
f10ded1c 11013 {
2237cac9
RS
11014 f = XFRAME (last_mouse_press_frame);
11015 if (f->output_data.x)
06a2c219 11016 SET_SAVED_BUTTON_EVENT;
f10ded1c 11017 }
06a2c219 11018 else
30e671c3 11019 goto OTHER;
2224b905 11020 }
2237cac9 11021#endif /* USE_MOTIF */
2224b905
RS
11022 else
11023 goto OTHER;
3afe33e7 11024#endif /* USE_X_TOOLKIT */
7a13e894
RS
11025 }
11026 break;
dc6f92b8 11027
7a13e894 11028 case CirculateNotify:
06a2c219
GM
11029 goto OTHER;
11030
7a13e894 11031 case CirculateRequest:
06a2c219
GM
11032 goto OTHER;
11033
11034 case VisibilityNotify:
11035 goto OTHER;
dc6f92b8 11036
7a13e894
RS
11037 case MappingNotify:
11038 /* Someone has changed the keyboard mapping - update the
11039 local cache. */
11040 switch (event.xmapping.request)
11041 {
11042 case MappingModifier:
11043 x_find_modifier_meanings (dpyinfo);
11044 /* This is meant to fall through. */
11045 case MappingKeyboard:
11046 XRefreshKeyboardMapping (&event.xmapping);
11047 }
7a13e894 11048 goto OTHER;
dc6f92b8 11049
7a13e894 11050 default:
7a13e894 11051 OTHER:
717ca130 11052#ifdef USE_X_TOOLKIT
7a13e894
RS
11053 BLOCK_INPUT;
11054 XtDispatchEvent (&event);
11055 UNBLOCK_INPUT;
3afe33e7 11056#endif /* USE_X_TOOLKIT */
7a13e894
RS
11057 break;
11058 }
dc6f92b8
JB
11059 }
11060 }
11061
06a2c219
GM
11062 out:;
11063
9a5196d0
RS
11064 /* On some systems, an X bug causes Emacs to get no more events
11065 when the window is destroyed. Detect that. (1994.) */
58769bee 11066 if (! event_found)
ef2a22d0 11067 {
ef2a22d0
RS
11068 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
11069 One XNOOP in 100 loops will make Emacs terminate.
11070 B. Bretthauer, 1994 */
11071 x_noop_count++;
58769bee 11072 if (x_noop_count >= 100)
ef2a22d0
RS
11073 {
11074 x_noop_count=0;
2224b905
RS
11075
11076 if (next_noop_dpyinfo == 0)
11077 next_noop_dpyinfo = x_display_list;
11078
11079 XNoOp (next_noop_dpyinfo->display);
11080
11081 /* Each time we get here, cycle through the displays now open. */
11082 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
11083 }
11084 }
502add23 11085
06a2c219 11086 /* If the focus was just given to an auto-raising frame,
0134a210 11087 raise it now. */
7a13e894 11088 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
11089 if (pending_autoraise_frame)
11090 {
11091 x_raise_frame (pending_autoraise_frame);
11092 pending_autoraise_frame = 0;
11093 }
0134a210 11094
dc6f92b8 11095 UNBLOCK_INPUT;
bde5503b 11096 --handling_signal;
dc6f92b8
JB
11097 return count;
11098}
06a2c219
GM
11099
11100
11101
dc6f92b8 11102\f
06a2c219
GM
11103/***********************************************************************
11104 Text Cursor
11105 ***********************************************************************/
11106
60626bab
GM
11107/* Notice when the text cursor of window W has been completely
11108 overwritten by a drawing operation that outputs glyphs in AREA
11109 starting at X0 and ending at X1 in the line starting at Y0 and
11110 ending at Y1. X coordinates are area-relative. X1 < 0 means all
11111 the rest of the line after X0 has been written. Y coordinates
11112 are window-relative. */
06a2c219
GM
11113
11114static void
60626bab 11115notice_overwritten_cursor (w, area, x0, x1, y0, y1)
06a2c219 11116 struct window *w;
60626bab
GM
11117 enum glyph_row_area area;
11118 int x0, y0, x1, y1;
06a2c219 11119{
60626bab 11120 if (area == TEXT_AREA
f0a48a01 11121 && w->phys_cursor_on_p
60626bab
GM
11122 && y0 <= w->phys_cursor.y
11123 && y1 >= w->phys_cursor.y + w->phys_cursor_height
11124 && x0 <= w->phys_cursor.x
11125 && (x1 < 0 || x1 > w->phys_cursor.x))
f0a48a01 11126 w->phys_cursor_on_p = 0;
06a2c219 11127}
f451eb13
JB
11128
11129
06a2c219
GM
11130/* Set clipping for output in glyph row ROW. W is the window in which
11131 we operate. GC is the graphics context to set clipping in.
11132 WHOLE_LINE_P non-zero means include the areas used for truncation
11133 mark display and alike in the clipping rectangle.
11134
11135 ROW may be a text row or, e.g., a mode line. Text rows must be
11136 clipped to the interior of the window dedicated to text display,
11137 mode lines must be clipped to the whole window. */
dc6f92b8
JB
11138
11139static void
06a2c219
GM
11140x_clip_to_row (w, row, gc, whole_line_p)
11141 struct window *w;
11142 struct glyph_row *row;
11143 GC gc;
11144 int whole_line_p;
dc6f92b8 11145{
06a2c219
GM
11146 struct frame *f = XFRAME (WINDOW_FRAME (w));
11147 XRectangle clip_rect;
11148 int window_x, window_y, window_width, window_height;
dc6f92b8 11149
06a2c219 11150 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 11151
06a2c219
GM
11152 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
11153 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
11154 clip_rect.y = max (clip_rect.y, window_y);
11155 clip_rect.width = window_width;
11156 clip_rect.height = row->visible_height;
5c1aae96 11157
06a2c219
GM
11158 /* If clipping to the whole line, including trunc marks, extend
11159 the rectangle to the left and increase its width. */
11160 if (whole_line_p)
11161 {
3f332ef3
KS
11162 clip_rect.x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
11163 clip_rect.width += FRAME_X_FRINGE_WIDTH (f);
06a2c219 11164 }
5c1aae96 11165
06a2c219 11166 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
11167}
11168
06a2c219
GM
11169
11170/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
11171
11172static void
06a2c219
GM
11173x_draw_hollow_cursor (w, row)
11174 struct window *w;
11175 struct glyph_row *row;
dc6f92b8 11176{
06a2c219
GM
11177 struct frame *f = XFRAME (WINDOW_FRAME (w));
11178 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11179 Display *dpy = FRAME_X_DISPLAY (f);
11180 int x, y, wd, h;
11181 XGCValues xgcv;
11182 struct glyph *cursor_glyph;
11183 GC gc;
11184
11185 /* Compute frame-relative coordinates from window-relative
11186 coordinates. */
11187 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11188 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
11189 + row->ascent - w->phys_cursor_ascent);
11190 h = row->height - 1;
11191
11192 /* Get the glyph the cursor is on. If we can't tell because
11193 the current matrix is invalid or such, give up. */
11194 cursor_glyph = get_phys_cursor_glyph (w);
11195 if (cursor_glyph == NULL)
dc6f92b8
JB
11196 return;
11197
06a2c219
GM
11198 /* Compute the width of the rectangle to draw. If on a stretch
11199 glyph, and `x-stretch-block-cursor' is nil, don't draw a
11200 rectangle as wide as the glyph, but use a canonical character
11201 width instead. */
11202 wd = cursor_glyph->pixel_width - 1;
11203 if (cursor_glyph->type == STRETCH_GLYPH
11204 && !x_stretch_cursor_p)
11205 wd = min (CANON_X_UNIT (f), wd);
11206
11207 /* The foreground of cursor_gc is typically the same as the normal
11208 background color, which can cause the cursor box to be invisible. */
11209 xgcv.foreground = f->output_data.x->cursor_pixel;
11210 if (dpyinfo->scratch_cursor_gc)
11211 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
11212 else
11213 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
11214 GCForeground, &xgcv);
11215 gc = dpyinfo->scratch_cursor_gc;
11216
11217 /* Set clipping, draw the rectangle, and reset clipping again. */
11218 x_clip_to_row (w, row, gc, 0);
11219 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
11220 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
11221}
11222
06a2c219
GM
11223
11224/* Draw a bar cursor on window W in glyph row ROW.
11225
11226 Implementation note: One would like to draw a bar cursor with an
11227 angle equal to the one given by the font property XA_ITALIC_ANGLE.
11228 Unfortunately, I didn't find a font yet that has this property set.
11229 --gerd. */
dc6f92b8
JB
11230
11231static void
f02d8aa0 11232x_draw_bar_cursor (w, row, width)
06a2c219
GM
11233 struct window *w;
11234 struct glyph_row *row;
f02d8aa0 11235 int width;
dc6f92b8 11236{
92f424df
GM
11237 struct frame *f = XFRAME (w->frame);
11238 struct glyph *cursor_glyph;
06a2c219 11239
92f424df
GM
11240 /* If cursor is out of bounds, don't draw garbage. This can happen
11241 in mini-buffer windows when switching between echo area glyphs
11242 and mini-buffer. */
11243 cursor_glyph = get_phys_cursor_glyph (w);
11244 if (cursor_glyph == NULL)
11245 return;
06a2c219 11246
92f424df
GM
11247 /* If on an image, draw like a normal cursor. That's usually better
11248 visible than drawing a bar, esp. if the image is large so that
11249 the bar might not be in the window. */
11250 if (cursor_glyph->type == IMAGE_GLYPH)
11251 {
11252 struct glyph_row *row;
11253 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
11254 x_draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
11255 }
11256 else
11257 {
34e5d0af
GM
11258 Display *dpy = FRAME_X_DISPLAY (f);
11259 Window window = FRAME_X_WINDOW (f);
11260 GC gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
11261 unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures;
11262 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
11263 XGCValues xgcv;
11264
11265 /* If the glyph's background equals the color we normally draw
11266 the bar cursor in, the bar cursor in its normal color is
11267 invisible. Use the glyph's foreground color instead in this
11268 case, on the assumption that the glyph's colors are chosen so
11269 that the glyph is legible. */
11270 if (face->background == f->output_data.x->cursor_pixel)
11271 xgcv.background = xgcv.foreground = face->foreground;
11272 else
11273 xgcv.background = xgcv.foreground = f->output_data.x->cursor_pixel;
06a2c219 11274 xgcv.graphics_exposures = 0;
92f424df 11275
06a2c219
GM
11276 if (gc)
11277 XChangeGC (dpy, gc, mask, &xgcv);
11278 else
11279 {
11280 gc = XCreateGC (dpy, window, mask, &xgcv);
11281 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
11282 }
92f424df 11283
f02d8aa0
GM
11284 if (width < 0)
11285 width = f->output_data.x->cursor_width;
34e5d0af 11286 width = min (cursor_glyph->pixel_width, width);
92f424df 11287
06a2c219
GM
11288 x_clip_to_row (w, row, gc, 0);
11289 XFillRectangle (dpy, window, gc,
34e5d0af 11290 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
06a2c219 11291 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
34e5d0af 11292 width, row->height);
06a2c219
GM
11293 XSetClipMask (dpy, gc, None);
11294 }
dc6f92b8
JB
11295}
11296
06a2c219
GM
11297
11298/* Clear the cursor of window W to background color, and mark the
11299 cursor as not shown. This is used when the text where the cursor
11300 is is about to be rewritten. */
11301
dc6f92b8 11302static void
06a2c219
GM
11303x_clear_cursor (w)
11304 struct window *w;
dc6f92b8 11305{
06a2c219
GM
11306 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
11307 x_update_window_cursor (w, 0);
11308}
90e65f07 11309
dbc4e1c1 11310
06a2c219
GM
11311/* Draw the cursor glyph of window W in glyph row ROW. See the
11312 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 11313
06a2c219
GM
11314static void
11315x_draw_phys_cursor_glyph (w, row, hl)
11316 struct window *w;
11317 struct glyph_row *row;
11318 enum draw_glyphs_face hl;
11319{
11320 /* If cursor hpos is out of bounds, don't draw garbage. This can
11321 happen in mini-buffer windows when switching between echo area
11322 glyphs and mini-buffer. */
11323 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e 11324 {
f0a48a01
GM
11325 int on_p = w->phys_cursor_on_p;
11326
66ac4b0e
GM
11327 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
11328 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
f0a48a01
GM
11329 hl, 0);
11330 w->phys_cursor_on_p = on_p;
66ac4b0e
GM
11331
11332 /* When we erase the cursor, and ROW is overlapped by other
11333 rows, make sure that these overlapping parts of other rows
11334 are redrawn. */
11335 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
11336 {
11337 if (row > w->current_matrix->rows
11338 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
11339 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
11340
11341 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
11342 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
11343 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
11344 }
11345 }
06a2c219 11346}
dbc4e1c1 11347
eea6af04 11348
06a2c219 11349/* Erase the image of a cursor of window W from the screen. */
eea6af04 11350
06a2c219
GM
11351static void
11352x_erase_phys_cursor (w)
11353 struct window *w;
11354{
11355 struct frame *f = XFRAME (w->frame);
11356 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11357 int hpos = w->phys_cursor.hpos;
11358 int vpos = w->phys_cursor.vpos;
11359 int mouse_face_here_p = 0;
11360 struct glyph_matrix *active_glyphs = w->current_matrix;
11361 struct glyph_row *cursor_row;
11362 struct glyph *cursor_glyph;
11363 enum draw_glyphs_face hl;
11364
11365 /* No cursor displayed or row invalidated => nothing to do on the
11366 screen. */
11367 if (w->phys_cursor_type == NO_CURSOR)
11368 goto mark_cursor_off;
11369
11370 /* VPOS >= active_glyphs->nrows means that window has been resized.
11371 Don't bother to erase the cursor. */
11372 if (vpos >= active_glyphs->nrows)
11373 goto mark_cursor_off;
11374
11375 /* If row containing cursor is marked invalid, there is nothing we
11376 can do. */
11377 cursor_row = MATRIX_ROW (active_glyphs, vpos);
11378 if (!cursor_row->enabled_p)
11379 goto mark_cursor_off;
11380
11381 /* This can happen when the new row is shorter than the old one.
11382 In this case, either x_draw_glyphs or clear_end_of_line
11383 should have cleared the cursor. Note that we wouldn't be
11384 able to erase the cursor in this case because we don't have a
11385 cursor glyph at hand. */
11386 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
11387 goto mark_cursor_off;
11388
11389 /* If the cursor is in the mouse face area, redisplay that when
11390 we clear the cursor. */
8801a864
KR
11391 if (! NILP (dpyinfo->mouse_face_window)
11392 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
11393 && (vpos > dpyinfo->mouse_face_beg_row
11394 || (vpos == dpyinfo->mouse_face_beg_row
11395 && hpos >= dpyinfo->mouse_face_beg_col))
11396 && (vpos < dpyinfo->mouse_face_end_row
11397 || (vpos == dpyinfo->mouse_face_end_row
11398 && hpos < dpyinfo->mouse_face_end_col))
11399 /* Don't redraw the cursor's spot in mouse face if it is at the
11400 end of a line (on a newline). The cursor appears there, but
11401 mouse highlighting does not. */
11402 && cursor_row->used[TEXT_AREA] > hpos)
11403 mouse_face_here_p = 1;
11404
11405 /* Maybe clear the display under the cursor. */
11406 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
11407 {
11408 int x;
045dee35 11409 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 11410
06a2c219
GM
11411 cursor_glyph = get_phys_cursor_glyph (w);
11412 if (cursor_glyph == NULL)
11413 goto mark_cursor_off;
dbc4e1c1 11414
e0300d33 11415 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
06a2c219 11416
c5e6e06b
GM
11417 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11418 x,
11419 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
11420 cursor_row->y)),
11421 cursor_glyph->pixel_width,
11422 cursor_row->visible_height,
11423 False);
dbc4e1c1 11424 }
06a2c219
GM
11425
11426 /* Erase the cursor by redrawing the character underneath it. */
11427 if (mouse_face_here_p)
11428 hl = DRAW_MOUSE_FACE;
06a2c219
GM
11429 else
11430 hl = DRAW_NORMAL_TEXT;
11431 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 11432
06a2c219
GM
11433 mark_cursor_off:
11434 w->phys_cursor_on_p = 0;
11435 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
11436}
11437
11438
b7f83f9e
GM
11439/* Non-zero if physical cursor of window W is within mouse face. */
11440
11441static int
11442cursor_in_mouse_face_p (w)
11443 struct window *w;
11444{
11445 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
11446 int in_mouse_face = 0;
11447
11448 if (WINDOWP (dpyinfo->mouse_face_window)
11449 && XWINDOW (dpyinfo->mouse_face_window) == w)
11450 {
11451 int hpos = w->phys_cursor.hpos;
11452 int vpos = w->phys_cursor.vpos;
11453
11454 if (vpos >= dpyinfo->mouse_face_beg_row
11455 && vpos <= dpyinfo->mouse_face_end_row
11456 && (vpos > dpyinfo->mouse_face_beg_row
11457 || hpos >= dpyinfo->mouse_face_beg_col)
11458 && (vpos < dpyinfo->mouse_face_end_row
11459 || hpos < dpyinfo->mouse_face_end_col
11460 || dpyinfo->mouse_face_past_end))
11461 in_mouse_face = 1;
11462 }
11463
11464 return in_mouse_face;
11465}
11466
11467
06a2c219
GM
11468/* Display or clear cursor of window W. If ON is zero, clear the
11469 cursor. If it is non-zero, display the cursor. If ON is nonzero,
11470 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 11471
06a2c219
GM
11472void
11473x_display_and_set_cursor (w, on, hpos, vpos, x, y)
11474 struct window *w;
11475 int on, hpos, vpos, x, y;
dbc4e1c1 11476{
06a2c219
GM
11477 struct frame *f = XFRAME (w->frame);
11478 int new_cursor_type;
f02d8aa0 11479 int new_cursor_width;
06a2c219
GM
11480 struct glyph_matrix *current_glyphs;
11481 struct glyph_row *glyph_row;
11482 struct glyph *glyph;
34368a22 11483 int cursor_non_selected;
dbc4e1c1 11484
49d838ea 11485 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
11486 windows and frames; in the latter case, the frame or window may
11487 be in the midst of changing its size, and x and y may be off the
11488 window. */
11489 if (! FRAME_VISIBLE_P (f)
11490 || FRAME_GARBAGED_P (f)
11491 || vpos >= w->current_matrix->nrows
11492 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
11493 return;
11494
11495 /* If cursor is off and we want it off, return quickly. */
06a2c219 11496 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
11497 return;
11498
06a2c219
GM
11499 current_glyphs = w->current_matrix;
11500 glyph_row = MATRIX_ROW (current_glyphs, vpos);
11501 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
11502
11503 /* If cursor row is not enabled, we don't really know where to
11504 display the cursor. */
11505 if (!glyph_row->enabled_p)
11506 {
11507 w->phys_cursor_on_p = 0;
11508 return;
11509 }
11510
11511 xassert (interrupt_input_blocked);
11512
11513 /* Set new_cursor_type to the cursor we want to be displayed. In a
11514 mini-buffer window, we want the cursor only to appear if we are
11515 reading input from this window. For the selected window, we want
11516 the cursor type given by the frame parameter. If explicitly
11517 marked off, draw no cursor. In all other cases, we want a hollow
11518 box cursor. */
34368a22
RS
11519 cursor_non_selected
11520 = !NILP (Fbuffer_local_value (Qcursor_in_non_selected_windows,
11521 w->buffer));
f02d8aa0 11522 new_cursor_width = -1;
9b4a7047
GM
11523 if (cursor_in_echo_area
11524 && FRAME_HAS_MINIBUF_P (f)
11525 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 11526 {
9b4a7047
GM
11527 if (w == XWINDOW (echo_area_window))
11528 new_cursor_type = FRAME_DESIRED_CURSOR (f);
34368a22 11529 else if (cursor_non_selected)
06a2c219 11530 new_cursor_type = HOLLOW_BOX_CURSOR;
9a7bdceb
GM
11531 else
11532 new_cursor_type = NO_CURSOR;
06a2c219 11533 }
06a2c219 11534 else
9b4a7047 11535 {
7a58ab59
GM
11536 if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
11537 || w != XWINDOW (f->selected_window))
9b4a7047 11538 {
2c850e26 11539 if ((MINI_WINDOW_P (w) && minibuf_level == 0)
34368a22 11540 || !cursor_non_selected
5cefa566 11541 || NILP (XBUFFER (w->buffer)->cursor_type))
9b4a7047
GM
11542 new_cursor_type = NO_CURSOR;
11543 else
11544 new_cursor_type = HOLLOW_BOX_CURSOR;
11545 }
11546 else if (w->cursor_off_p)
11547 new_cursor_type = NO_CURSOR;
11548 else
f02d8aa0
GM
11549 {
11550 struct buffer *b = XBUFFER (w->buffer);
11551
11552 if (EQ (b->cursor_type, Qt))
11553 new_cursor_type = FRAME_DESIRED_CURSOR (f);
11554 else
11555 new_cursor_type = x_specified_cursor_type (b->cursor_type,
11556 &new_cursor_width);
11557 }
9b4a7047 11558 }
06a2c219
GM
11559
11560 /* If cursor is currently being shown and we don't want it to be or
11561 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 11562 erase it. */
06a2c219 11563 if (w->phys_cursor_on_p
dc6f92b8 11564 && (!on
06a2c219
GM
11565 || w->phys_cursor.x != x
11566 || w->phys_cursor.y != y
11567 || new_cursor_type != w->phys_cursor_type))
11568 x_erase_phys_cursor (w);
11569
11570 /* If the cursor is now invisible and we want it to be visible,
11571 display it. */
11572 if (on && !w->phys_cursor_on_p)
11573 {
11574 w->phys_cursor_ascent = glyph_row->ascent;
11575 w->phys_cursor_height = glyph_row->height;
11576
11577 /* Set phys_cursor_.* before x_draw_.* is called because some
11578 of them may need the information. */
11579 w->phys_cursor.x = x;
11580 w->phys_cursor.y = glyph_row->y;
11581 w->phys_cursor.hpos = hpos;
11582 w->phys_cursor.vpos = vpos;
11583 w->phys_cursor_type = new_cursor_type;
11584 w->phys_cursor_on_p = 1;
11585
11586 switch (new_cursor_type)
dc6f92b8 11587 {
06a2c219
GM
11588 case HOLLOW_BOX_CURSOR:
11589 x_draw_hollow_cursor (w, glyph_row);
11590 break;
11591
11592 case FILLED_BOX_CURSOR:
11593 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
11594 break;
11595
11596 case BAR_CURSOR:
f02d8aa0 11597 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
11598 break;
11599
11600 case NO_CURSOR:
11601 break;
dc6f92b8 11602
06a2c219
GM
11603 default:
11604 abort ();
11605 }
59ddecde
GM
11606
11607#ifdef HAVE_X_I18N
11608 if (w == XWINDOW (f->selected_window))
11609 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
11610 xic_set_preeditarea (w, x, y);
11611#endif
dc6f92b8
JB
11612 }
11613
06a2c219 11614#ifndef XFlush
f676886a 11615 if (updating_frame != f)
334208b7 11616 XFlush (FRAME_X_DISPLAY (f));
06a2c219 11617#endif
dc6f92b8
JB
11618}
11619
06a2c219
GM
11620
11621/* Display the cursor on window W, or clear it. X and Y are window
11622 relative pixel coordinates. HPOS and VPOS are glyph matrix
11623 positions. If W is not the selected window, display a hollow
11624 cursor. ON non-zero means display the cursor at X, Y which
11625 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 11626
dfcf069d 11627void
06a2c219
GM
11628x_display_cursor (w, on, hpos, vpos, x, y)
11629 struct window *w;
11630 int on, hpos, vpos, x, y;
dc6f92b8 11631{
f94397b5 11632 BLOCK_INPUT;
06a2c219 11633 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
11634 UNBLOCK_INPUT;
11635}
11636
06a2c219
GM
11637
11638/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
11639 Don't change the cursor's position. */
11640
dfcf069d 11641void
06a2c219 11642x_update_cursor (f, on_p)
5d46f928 11643 struct frame *f;
5d46f928 11644{
06a2c219
GM
11645 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
11646}
11647
11648
11649/* Call x_update_window_cursor with parameter ON_P on all leaf windows
11650 in the window tree rooted at W. */
11651
11652static void
11653x_update_cursor_in_window_tree (w, on_p)
11654 struct window *w;
11655 int on_p;
11656{
11657 while (w)
11658 {
11659 if (!NILP (w->hchild))
11660 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
11661 else if (!NILP (w->vchild))
11662 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
11663 else
11664 x_update_window_cursor (w, on_p);
11665
11666 w = NILP (w->next) ? 0 : XWINDOW (w->next);
11667 }
11668}
5d46f928 11669
f94397b5 11670
06a2c219
GM
11671/* Switch the display of W's cursor on or off, according to the value
11672 of ON. */
11673
11674static void
11675x_update_window_cursor (w, on)
11676 struct window *w;
11677 int on;
11678{
16b5d424
GM
11679 /* Don't update cursor in windows whose frame is in the process
11680 of being deleted. */
11681 if (w->current_matrix)
11682 {
11683 BLOCK_INPUT;
11684 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
11685 w->phys_cursor.x, w->phys_cursor.y);
11686 UNBLOCK_INPUT;
11687 }
dc6f92b8 11688}
06a2c219
GM
11689
11690
11691
dc6f92b8
JB
11692\f
11693/* Icons. */
11694
dbc4e1c1 11695/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
11696
11697int
990ba854 11698x_bitmap_icon (f, file)
f676886a 11699 struct frame *f;
990ba854 11700 Lisp_Object file;
dc6f92b8 11701{
06a2c219 11702 int bitmap_id;
dc6f92b8 11703
c118dd06 11704 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11705 return 1;
11706
990ba854 11707 /* Free up our existing icon bitmap if any. */
7556890b
RS
11708 if (f->output_data.x->icon_bitmap > 0)
11709 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11710 f->output_data.x->icon_bitmap = 0;
990ba854
RS
11711
11712 if (STRINGP (file))
7f2ae036
RS
11713 bitmap_id = x_create_bitmap_from_file (f, file);
11714 else
11715 {
990ba854 11716 /* Create the GNU bitmap if necessary. */
5bf01b68 11717 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
11718 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
11719 = x_create_bitmap_from_data (f, gnu_bits,
11720 gnu_width, gnu_height);
990ba854
RS
11721
11722 /* The first time we create the GNU bitmap,
06a2c219 11723 this increments the ref-count one extra time.
990ba854
RS
11724 As a result, the GNU bitmap is never freed.
11725 That way, we don't have to worry about allocating it again. */
334208b7 11726 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 11727
334208b7 11728 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
11729 }
11730
11731 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 11732 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
11733
11734 return 0;
11735}
11736
11737
1be2d067
KH
11738/* Make the x-window of frame F use a rectangle with text.
11739 Use ICON_NAME as the text. */
dc6f92b8
JB
11740
11741int
f676886a
JB
11742x_text_icon (f, icon_name)
11743 struct frame *f;
dc6f92b8
JB
11744 char *icon_name;
11745{
c118dd06 11746 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11747 return 1;
11748
1be2d067
KH
11749#ifdef HAVE_X11R4
11750 {
11751 XTextProperty text;
11752 text.value = (unsigned char *) icon_name;
11753 text.encoding = XA_STRING;
11754 text.format = 8;
11755 text.nitems = strlen (icon_name);
11756#ifdef USE_X_TOOLKIT
7556890b 11757 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
11758 &text);
11759#else /* not USE_X_TOOLKIT */
11760 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
11761#endif /* not USE_X_TOOLKIT */
11762 }
11763#else /* not HAVE_X11R4 */
11764 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
11765#endif /* not HAVE_X11R4 */
58769bee 11766
7556890b
RS
11767 if (f->output_data.x->icon_bitmap > 0)
11768 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11769 f->output_data.x->icon_bitmap = 0;
b1c884c3 11770 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
11771
11772 return 0;
11773}
11774\f
e99db5a1
RS
11775#define X_ERROR_MESSAGE_SIZE 200
11776
11777/* If non-nil, this should be a string.
11778 It means catch X errors and store the error message in this string. */
11779
11780static Lisp_Object x_error_message_string;
11781
11782/* An X error handler which stores the error message in
11783 x_error_message_string. This is called from x_error_handler if
11784 x_catch_errors is in effect. */
11785
06a2c219 11786static void
e99db5a1
RS
11787x_error_catcher (display, error)
11788 Display *display;
11789 XErrorEvent *error;
11790{
11791 XGetErrorText (display, error->error_code,
11792 XSTRING (x_error_message_string)->data,
11793 X_ERROR_MESSAGE_SIZE);
11794}
11795
11796/* Begin trapping X errors for display DPY. Actually we trap X errors
11797 for all displays, but DPY should be the display you are actually
11798 operating on.
11799
11800 After calling this function, X protocol errors no longer cause
11801 Emacs to exit; instead, they are recorded in the string
11802 stored in x_error_message_string.
11803
11804 Calling x_check_errors signals an Emacs error if an X error has
11805 occurred since the last call to x_catch_errors or x_check_errors.
11806
11807 Calling x_uncatch_errors resumes the normal error handling. */
11808
11809void x_check_errors ();
11810static Lisp_Object x_catch_errors_unwind ();
11811
11812int
11813x_catch_errors (dpy)
11814 Display *dpy;
11815{
11816 int count = specpdl_ptr - specpdl;
11817
11818 /* Make sure any errors from previous requests have been dealt with. */
11819 XSync (dpy, False);
11820
11821 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
11822
11823 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
11824 XSTRING (x_error_message_string)->data[0] = 0;
11825
11826 return count;
11827}
11828
11829/* Unbind the binding that we made to check for X errors. */
11830
11831static Lisp_Object
11832x_catch_errors_unwind (old_val)
11833 Lisp_Object old_val;
11834{
11835 x_error_message_string = old_val;
11836 return Qnil;
11837}
11838
11839/* If any X protocol errors have arrived since the last call to
11840 x_catch_errors or x_check_errors, signal an Emacs error using
11841 sprintf (a buffer, FORMAT, the x error message text) as the text. */
11842
11843void
11844x_check_errors (dpy, format)
11845 Display *dpy;
11846 char *format;
11847{
11848 /* Make sure to catch any errors incurred so far. */
11849 XSync (dpy, False);
11850
11851 if (XSTRING (x_error_message_string)->data[0])
11852 error (format, XSTRING (x_error_message_string)->data);
11853}
11854
9829ddba
RS
11855/* Nonzero if we had any X protocol errors
11856 since we did x_catch_errors on DPY. */
e99db5a1
RS
11857
11858int
11859x_had_errors_p (dpy)
11860 Display *dpy;
11861{
11862 /* Make sure to catch any errors incurred so far. */
11863 XSync (dpy, False);
11864
11865 return XSTRING (x_error_message_string)->data[0] != 0;
11866}
11867
9829ddba
RS
11868/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
11869
06a2c219 11870void
9829ddba
RS
11871x_clear_errors (dpy)
11872 Display *dpy;
11873{
11874 XSTRING (x_error_message_string)->data[0] = 0;
11875}
11876
e99db5a1
RS
11877/* Stop catching X protocol errors and let them make Emacs die.
11878 DPY should be the display that was passed to x_catch_errors.
11879 COUNT should be the value that was returned by
11880 the corresponding call to x_catch_errors. */
11881
11882void
11883x_uncatch_errors (dpy, count)
11884 Display *dpy;
11885 int count;
11886{
11887 unbind_to (count, Qnil);
11888}
11889
11890#if 0
11891static unsigned int x_wire_count;
11892x_trace_wire ()
11893{
11894 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
11895}
11896#endif /* ! 0 */
11897
11898\f
11899/* Handle SIGPIPE, which can happen when the connection to a server
11900 simply goes away. SIGPIPE is handled by x_connection_signal.
11901 Don't need to do anything, because the write which caused the
11902 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 11903 which will do the appropriate cleanup for us. */
e99db5a1
RS
11904
11905static SIGTYPE
11906x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 11907 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
11908{
11909#ifdef USG
11910 /* USG systems forget handlers when they are used;
11911 must reestablish each time */
11912 signal (signalnum, x_connection_signal);
11913#endif /* USG */
11914}
0da1ab50 11915
e99db5a1 11916\f
0da1ab50
GM
11917/************************************************************************
11918 Handling X errors
11919 ************************************************************************/
4746118a 11920
f0e299de
GM
11921/* Error message passed to x_connection_closed. */
11922
11923static char *error_msg;
11924
a7248e4f 11925/* Function installed as fatal_error_signal_hook in
f0e299de
GM
11926 x_connection_closed. Print the X error message, and exit normally,
11927 instead of dumping core when XtCloseDisplay fails. */
11928
11929static void
11930x_fatal_error_signal ()
11931{
11932 fprintf (stderr, "%s\n", error_msg);
11933 exit (70);
11934}
11935
0da1ab50
GM
11936/* Handle the loss of connection to display DPY. ERROR_MESSAGE is
11937 the text of an error message that lead to the connection loss. */
16bd92ea 11938
4746118a 11939static SIGTYPE
5978125e
GM
11940x_connection_closed (dpy, error_message)
11941 Display *dpy;
7a13e894 11942 char *error_message;
4746118a 11943{
5978125e 11944 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
7a13e894 11945 Lisp_Object frame, tail;
0da1ab50 11946 int count;
0da1ab50 11947
f0e299de
GM
11948 error_msg = (char *) alloca (strlen (error_message) + 1);
11949 strcpy (error_msg, error_message);
1a532e54
GM
11950 handling_signal = 0;
11951
0da1ab50
GM
11952 /* Prevent being called recursively because of an error condition
11953 below. Otherwise, we might end up with printing ``can't find per
11954 display information'' in the recursive call instead of printing
11955 the original message here. */
11956 count = x_catch_errors (dpy);
11957
8a4f36cc
GM
11958 /* We have to close the display to inform Xt that it doesn't
11959 exist anymore. If we don't, Xt will continue to wait for
11960 events from the display. As a consequence, a sequence of
11961
11962 M-x make-frame-on-display RET :1 RET
11963 ...kill the new frame, so that we get an IO error...
11964 M-x make-frame-on-display RET :1 RET
11965
11966 will indefinitely wait in Xt for events for display `:1', opened
11967 in the first class to make-frame-on-display.
6186a4a0 11968
8a4f36cc
GM
11969 Closing the display is reported to lead to a bus error on
11970 OpenWindows in certain situations. I suspect that is a bug
11971 in OpenWindows. I don't know how to cicumvent it here. */
11972
f613a4c8 11973#ifdef USE_X_TOOLKIT
ae24cb3b
GM
11974 /* If DPYINFO is null, this means we didn't open the display
11975 in the first place, so don't try to close it. */
11976 if (dpyinfo)
f0e299de
GM
11977 {
11978 extern void (*fatal_error_signal_hook) P_ ((void));
11979 fatal_error_signal_hook = x_fatal_error_signal;
11980 XtCloseDisplay (dpy);
11981 fatal_error_signal_hook = NULL;
11982 }
f613a4c8 11983#endif
adabc3a9 11984
8a4f36cc 11985 /* Indicate that this display is dead. */
9e80b57d
KR
11986 if (dpyinfo)
11987 dpyinfo->display = 0;
6186a4a0 11988
06a2c219 11989 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
11990 that are on the dead display. */
11991 FOR_EACH_FRAME (tail, frame)
11992 {
11993 Lisp_Object minibuf_frame;
11994 minibuf_frame
11995 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
11996 if (FRAME_X_P (XFRAME (frame))
11997 && FRAME_X_P (XFRAME (minibuf_frame))
11998 && ! EQ (frame, minibuf_frame)
11999 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
12000 Fdelete_frame (frame, Qt);
12001 }
12002
12003 /* Now delete all remaining frames on the dead display.
06a2c219 12004 We are now sure none of these is used as the mini-buffer
7a13e894
RS
12005 for another frame that we need to delete. */
12006 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
12007 if (FRAME_X_P (XFRAME (frame))
12008 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
12009 {
12010 /* Set this to t so that Fdelete_frame won't get confused
12011 trying to find a replacement. */
12012 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
12013 Fdelete_frame (frame, Qt);
12014 }
7a13e894 12015
482a1bd2
KH
12016 if (dpyinfo)
12017 x_delete_display (dpyinfo);
7a13e894 12018
0da1ab50
GM
12019 x_uncatch_errors (dpy, count);
12020
7a13e894
RS
12021 if (x_display_list == 0)
12022 {
f0e299de 12023 fprintf (stderr, "%s\n", error_msg);
7a13e894
RS
12024 shut_down_emacs (0, 0, Qnil);
12025 exit (70);
12026 }
12ba150f 12027
7a13e894
RS
12028 /* Ordinary stack unwind doesn't deal with these. */
12029#ifdef SIGIO
12030 sigunblock (sigmask (SIGIO));
12031#endif
12032 sigunblock (sigmask (SIGALRM));
12033 TOTALLY_UNBLOCK_INPUT;
12034
aa4d9a9e 12035 clear_waiting_for_input ();
f0e299de 12036 error ("%s", error_msg);
4746118a
JB
12037}
12038
0da1ab50 12039
7a13e894
RS
12040/* This is the usual handler for X protocol errors.
12041 It kills all frames on the display that we got the error for.
12042 If that was the only one, it prints an error message and kills Emacs. */
12043
06a2c219 12044static void
c118dd06
JB
12045x_error_quitter (display, error)
12046 Display *display;
12047 XErrorEvent *error;
12048{
7a13e894 12049 char buf[256], buf1[356];
dc6f92b8 12050
58769bee 12051 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 12052 original error handler. */
dc6f92b8 12053
c118dd06 12054 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 12055 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 12056 buf, error->request_code);
7a13e894 12057 x_connection_closed (display, buf1);
dc6f92b8
JB
12058}
12059
0da1ab50 12060
e99db5a1
RS
12061/* This is the first-level handler for X protocol errors.
12062 It calls x_error_quitter or x_error_catcher. */
7a13e894 12063
8922af5f 12064static int
e99db5a1 12065x_error_handler (display, error)
8922af5f 12066 Display *display;
e99db5a1 12067 XErrorEvent *error;
8922af5f 12068{
e99db5a1
RS
12069 if (! NILP (x_error_message_string))
12070 x_error_catcher (display, error);
12071 else
12072 x_error_quitter (display, error);
06a2c219 12073 return 0;
f9e24cb9 12074}
c118dd06 12075
e99db5a1
RS
12076/* This is the handler for X IO errors, always.
12077 It kills all frames on the display that we lost touch with.
12078 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 12079
c118dd06 12080static int
e99db5a1 12081x_io_error_quitter (display)
c118dd06 12082 Display *display;
c118dd06 12083{
e99db5a1 12084 char buf[256];
dc6f92b8 12085
e99db5a1
RS
12086 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
12087 x_connection_closed (display, buf);
06a2c219 12088 return 0;
dc6f92b8 12089}
dc6f92b8 12090\f
f451eb13
JB
12091/* Changing the font of the frame. */
12092
76bcdf39
RS
12093/* Give frame F the font named FONTNAME as its default font, and
12094 return the full name of that font. FONTNAME may be a wildcard
12095 pattern; in that case, we choose some font that fits the pattern.
12096 The return value shows which font we chose. */
12097
b5cf7a0e 12098Lisp_Object
f676886a
JB
12099x_new_font (f, fontname)
12100 struct frame *f;
dc6f92b8
JB
12101 register char *fontname;
12102{
dc43ef94 12103 struct font_info *fontp
ee569018 12104 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 12105
dc43ef94
KH
12106 if (!fontp)
12107 return Qnil;
2224a5fc 12108
dc43ef94 12109 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 12110 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94 12111 f->output_data.x->fontset = -1;
976b73d7
KS
12112
12113 x_compute_fringe_widths (f, 1);
12114
b2cad826
KH
12115 /* Compute the scroll bar width in character columns. */
12116 if (f->scroll_bar_pixel_width > 0)
12117 {
7556890b 12118 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
12119 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
12120 }
12121 else
4e61bddf
RS
12122 {
12123 int wid = FONT_WIDTH (f->output_data.x->font);
12124 f->scroll_bar_cols = (14 + wid - 1) / wid;
12125 }
b2cad826 12126
f676886a 12127 /* Now make the frame display the given font. */
c118dd06 12128 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 12129 {
7556890b
RS
12130 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
12131 f->output_data.x->font->fid);
12132 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
12133 f->output_data.x->font->fid);
12134 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
12135 f->output_data.x->font->fid);
f676886a 12136
a27f9f86 12137 frame_update_line_height (f);
3497f73e
GM
12138
12139 /* Don't change the size of a tip frame; there's no point in
12140 doing it because it's done in Fx_show_tip, and it leads to
12141 problems because the tip frame has no widget. */
12142 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
12143 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 12144 }
a27f9f86
RS
12145 else
12146 /* If we are setting a new frame's font for the first time,
12147 there are no faces yet, so this font's height is the line height. */
7556890b 12148 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 12149
dc43ef94
KH
12150 return build_string (fontp->full_name);
12151}
12152
12153/* Give frame F the fontset named FONTSETNAME as its default font, and
12154 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
12155 pattern; in that case, we choose some fontset that fits the pattern.
12156 The return value shows which fontset we chose. */
b5cf7a0e 12157
dc43ef94
KH
12158Lisp_Object
12159x_new_fontset (f, fontsetname)
12160 struct frame *f;
12161 char *fontsetname;
12162{
ee569018 12163 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 12164 Lisp_Object result;
b5cf7a0e 12165
dc43ef94
KH
12166 if (fontset < 0)
12167 return Qnil;
b5cf7a0e 12168
2da424f1
KH
12169 if (f->output_data.x->fontset == fontset)
12170 /* This fontset is already set in frame F. There's nothing more
12171 to do. */
ee569018 12172 return fontset_name (fontset);
dc43ef94 12173
ee569018 12174 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
12175
12176 if (!STRINGP (result))
12177 /* Can't load ASCII font. */
12178 return Qnil;
12179
12180 /* Since x_new_font doesn't update any fontset information, do it now. */
12181 f->output_data.x->fontset = fontset;
dc43ef94 12182
f5d11644
GM
12183#ifdef HAVE_X_I18N
12184 if (FRAME_XIC (f)
12185 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 12186 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
12187#endif
12188
dc43ef94 12189 return build_string (fontsetname);
dc6f92b8 12190}
f5d11644 12191
976b73d7
KS
12192/* Compute actual fringe widths */
12193
12194void
12195x_compute_fringe_widths (f, redraw)
12196 struct frame *f;
12197 int redraw;
12198{
12199 int o_left = f->output_data.x->left_fringe_width;
12200 int o_right = f->output_data.x->right_fringe_width;
12201 int o_cols = f->output_data.x->fringe_cols;
12202
12203 Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist);
12204 Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist);
12205 int left_fringe_width, right_fringe_width;
12206
12207 if (!NILP (left_fringe))
12208 left_fringe = Fcdr (left_fringe);
12209 if (!NILP (right_fringe))
12210 right_fringe = Fcdr (right_fringe);
12211
12212 left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 :
12213 XINT (left_fringe));
12214 right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 :
12215 XINT (right_fringe));
12216
12217 if (left_fringe_width || right_fringe_width)
12218 {
12219 int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width;
12220 int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width;
12221 int conf_wid = left_wid + right_wid;
12222 int font_wid = FONT_WIDTH (f->output_data.x->font);
12223 int cols = (left_wid + right_wid + font_wid-1) / font_wid;
12224 int real_wid = cols * font_wid;
12225 if (left_wid && right_wid)
12226 {
12227 if (left_fringe_width < 0)
12228 {
12229 /* Left fringe width is fixed, adjust right fringe if necessary */
12230 f->output_data.x->left_fringe_width = left_wid;
12231 f->output_data.x->right_fringe_width = real_wid - left_wid;
12232 }
12233 else if (right_fringe_width < 0)
12234 {
12235 /* Right fringe width is fixed, adjust left fringe if necessary */
12236 f->output_data.x->left_fringe_width = real_wid - right_wid;
12237 f->output_data.x->right_fringe_width = right_wid;
12238 }
12239 else
12240 {
12241 /* Adjust both fringes with an equal amount.
12242 Note that we are doing integer arithmetic here, so don't
12243 lose a pixel if the total width is an odd number. */
12244 int fill = real_wid - conf_wid;
12245 f->output_data.x->left_fringe_width = left_wid + fill/2;
12246 f->output_data.x->right_fringe_width = right_wid + fill - fill/2;
12247 }
12248 }
12249 else if (left_fringe_width)
12250 {
12251 f->output_data.x->left_fringe_width = real_wid;
12252 f->output_data.x->right_fringe_width = 0;
12253 }
12254 else
12255 {
12256 f->output_data.x->left_fringe_width = 0;
12257 f->output_data.x->right_fringe_width = real_wid;
12258 }
12259 f->output_data.x->fringe_cols = cols;
12260 f->output_data.x->fringes_extra = real_wid;
12261 }
12262 else
12263 {
12264 f->output_data.x->left_fringe_width = 0;
12265 f->output_data.x->right_fringe_width = 0;
12266 f->output_data.x->fringe_cols = 0;
12267 f->output_data.x->fringes_extra = 0;
12268 }
12269
12270 if (redraw && FRAME_VISIBLE_P (f))
12271 if (o_left != f->output_data.x->left_fringe_width ||
12272 o_right != f->output_data.x->right_fringe_width ||
12273 o_cols != f->output_data.x->fringe_cols)
12274 redraw_frame (f);
12275}
f5d11644
GM
12276\f
12277/***********************************************************************
12278 X Input Methods
12279 ***********************************************************************/
12280
12281#ifdef HAVE_X_I18N
12282
12283#ifdef HAVE_X11R6
12284
12285/* XIM destroy callback function, which is called whenever the
12286 connection to input method XIM dies. CLIENT_DATA contains a
12287 pointer to the x_display_info structure corresponding to XIM. */
12288
12289static void
12290xim_destroy_callback (xim, client_data, call_data)
12291 XIM xim;
12292 XPointer client_data;
12293 XPointer call_data;
12294{
12295 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
12296 Lisp_Object frame, tail;
12297
12298 BLOCK_INPUT;
12299
12300 /* No need to call XDestroyIC.. */
12301 FOR_EACH_FRAME (tail, frame)
12302 {
12303 struct frame *f = XFRAME (frame);
12304 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
12305 {
12306 FRAME_XIC (f) = NULL;
12307 if (FRAME_XIC_FONTSET (f))
12308 {
12309 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
12310 FRAME_XIC_FONTSET (f) = NULL;
12311 }
12312 }
12313 }
12314
12315 /* No need to call XCloseIM. */
12316 dpyinfo->xim = NULL;
12317 XFree (dpyinfo->xim_styles);
12318 UNBLOCK_INPUT;
12319}
12320
12321#endif /* HAVE_X11R6 */
12322
12323/* Open the connection to the XIM server on display DPYINFO.
12324 RESOURCE_NAME is the resource name Emacs uses. */
12325
12326static void
12327xim_open_dpy (dpyinfo, resource_name)
12328 struct x_display_info *dpyinfo;
12329 char *resource_name;
12330{
287f7dd6 12331#ifdef USE_XIM
f5d11644
GM
12332 XIM xim;
12333
12334 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
12335 dpyinfo->xim = xim;
12336
12337 if (xim)
12338 {
f5d11644
GM
12339#ifdef HAVE_X11R6
12340 XIMCallback destroy;
12341#endif
12342
12343 /* Get supported styles and XIM values. */
12344 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
12345
12346#ifdef HAVE_X11R6
12347 destroy.callback = xim_destroy_callback;
12348 destroy.client_data = (XPointer)dpyinfo;
cea2ad76 12349 /* This isn't prototyped in OSF 5.0. */
f5d11644
GM
12350 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
12351#endif
12352 }
287f7dd6
GM
12353
12354#else /* not USE_XIM */
12355 dpyinfo->xim = NULL;
12356#endif /* not USE_XIM */
f5d11644
GM
12357}
12358
12359
b9de836c 12360#ifdef HAVE_X11R6_XIM
f5d11644
GM
12361
12362struct xim_inst_t
12363{
12364 struct x_display_info *dpyinfo;
12365 char *resource_name;
12366};
12367
12368/* XIM instantiate callback function, which is called whenever an XIM
12369 server is available. DISPLAY is teh display of the XIM.
12370 CLIENT_DATA contains a pointer to an xim_inst_t structure created
12371 when the callback was registered. */
12372
12373static void
12374xim_instantiate_callback (display, client_data, call_data)
12375 Display *display;
12376 XPointer client_data;
12377 XPointer call_data;
12378{
12379 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
12380 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
12381
12382 /* We don't support multiple XIM connections. */
12383 if (dpyinfo->xim)
12384 return;
12385
12386 xim_open_dpy (dpyinfo, xim_inst->resource_name);
12387
12388 /* Create XIC for the existing frames on the same display, as long
12389 as they have no XIC. */
12390 if (dpyinfo->xim && dpyinfo->reference_count > 0)
12391 {
12392 Lisp_Object tail, frame;
12393
12394 BLOCK_INPUT;
12395 FOR_EACH_FRAME (tail, frame)
12396 {
12397 struct frame *f = XFRAME (frame);
12398
12399 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
12400 if (FRAME_XIC (f) == NULL)
12401 {
12402 create_frame_xic (f);
12403 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
12404 xic_set_statusarea (f);
12405 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
12406 {
12407 struct window *w = XWINDOW (f->selected_window);
12408 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
12409 }
12410 }
12411 }
12412
12413 UNBLOCK_INPUT;
12414 }
12415}
12416
b9de836c 12417#endif /* HAVE_X11R6_XIM */
f5d11644
GM
12418
12419
12420/* Open a connection to the XIM server on display DPYINFO.
12421 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
12422 connection only at the first time. On X11R6, open the connection
12423 in the XIM instantiate callback function. */
12424
12425static void
12426xim_initialize (dpyinfo, resource_name)
12427 struct x_display_info *dpyinfo;
12428 char *resource_name;
12429{
287f7dd6 12430#ifdef USE_XIM
b9de836c 12431#ifdef HAVE_X11R6_XIM
f5d11644
GM
12432 struct xim_inst_t *xim_inst;
12433 int len;
12434
12435 dpyinfo->xim = NULL;
12436 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
12437 xim_inst->dpyinfo = dpyinfo;
12438 len = strlen (resource_name);
12439 xim_inst->resource_name = (char *) xmalloc (len + 1);
12440 bcopy (resource_name, xim_inst->resource_name, len + 1);
12441 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12442 resource_name, EMACS_CLASS,
12443 xim_instantiate_callback,
2ebb2f8b
DL
12444 /* Fixme: This is XPointer in
12445 XFree86 but (XPointer *) on
12446 Tru64, at least. */
12447 (XPointer) xim_inst);
b9de836c 12448#else /* not HAVE_X11R6_XIM */
f5d11644
GM
12449 dpyinfo->xim = NULL;
12450 xim_open_dpy (dpyinfo, resource_name);
b9de836c 12451#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
12452
12453#else /* not USE_XIM */
12454 dpyinfo->xim = NULL;
12455#endif /* not USE_XIM */
f5d11644
GM
12456}
12457
12458
12459/* Close the connection to the XIM server on display DPYINFO. */
12460
12461static void
12462xim_close_dpy (dpyinfo)
12463 struct x_display_info *dpyinfo;
12464{
287f7dd6 12465#ifdef USE_XIM
b9de836c 12466#ifdef HAVE_X11R6_XIM
8a4f36cc
GM
12467 if (dpyinfo->display)
12468 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12469 NULL, EMACS_CLASS,
12470 xim_instantiate_callback, NULL);
b9de836c 12471#endif /* not HAVE_X11R6_XIM */
8a4f36cc
GM
12472 if (dpyinfo->display)
12473 XCloseIM (dpyinfo->xim);
f5d11644
GM
12474 dpyinfo->xim = NULL;
12475 XFree (dpyinfo->xim_styles);
287f7dd6 12476#endif /* USE_XIM */
f5d11644
GM
12477}
12478
b9de836c 12479#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
12480
12481
dc6f92b8 12482\f
2e365682
RS
12483/* Calculate the absolute position in frame F
12484 from its current recorded position values and gravity. */
12485
dfcf069d 12486void
43bca5d5 12487x_calc_absolute_position (f)
f676886a 12488 struct frame *f;
dc6f92b8 12489{
06a2c219 12490 Window child;
6dba1858 12491 int win_x = 0, win_y = 0;
7556890b 12492 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
12493 int this_window;
12494
9829ddba
RS
12495 /* We have nothing to do if the current position
12496 is already for the top-left corner. */
12497 if (! ((flags & XNegative) || (flags & YNegative)))
12498 return;
12499
c81412a0 12500#ifdef USE_X_TOOLKIT
7556890b 12501 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
12502#else
12503 this_window = FRAME_X_WINDOW (f);
12504#endif
6dba1858
RS
12505
12506 /* Find the position of the outside upper-left corner of
9829ddba
RS
12507 the inner window, with respect to the outer window.
12508 But do this only if we will need the results. */
7556890b 12509 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 12510 {
9829ddba
RS
12511 int count;
12512
6dba1858 12513 BLOCK_INPUT;
9829ddba
RS
12514 count = x_catch_errors (FRAME_X_DISPLAY (f));
12515 while (1)
12516 {
12517 x_clear_errors (FRAME_X_DISPLAY (f));
12518 XTranslateCoordinates (FRAME_X_DISPLAY (f),
12519
12520 /* From-window, to-window. */
12521 this_window,
12522 f->output_data.x->parent_desc,
12523
12524 /* From-position, to-position. */
12525 0, 0, &win_x, &win_y,
12526
12527 /* Child of win. */
12528 &child);
12529 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12530 {
12531 Window newroot, newparent = 0xdeadbeef;
12532 Window *newchildren;
2ebb2f8b 12533 unsigned int nchildren;
9829ddba
RS
12534
12535 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
12536 &newparent, &newchildren, &nchildren))
12537 break;
58769bee 12538
7c3c78a3 12539 XFree ((char *) newchildren);
6dba1858 12540
9829ddba
RS
12541 f->output_data.x->parent_desc = newparent;
12542 }
12543 else
12544 break;
12545 }
6dba1858 12546
9829ddba 12547 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
12548 UNBLOCK_INPUT;
12549 }
12550
12551 /* Treat negative positions as relative to the leftmost bottommost
12552 position that fits on the screen. */
20f55f9a 12553 if (flags & XNegative)
7556890b 12554 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
12555 - 2 * f->output_data.x->border_width - win_x
12556 - PIXEL_WIDTH (f)
12557 + f->output_data.x->left_pos);
dc6f92b8 12558
7708ced0
GM
12559 {
12560 int height = PIXEL_HEIGHT (f);
06a2c219 12561
7708ced0
GM
12562#if defined USE_X_TOOLKIT && defined USE_MOTIF
12563 /* Something is fishy here. When using Motif, starting Emacs with
12564 `-g -0-0', the frame appears too low by a few pixels.
12565
12566 This seems to be so because initially, while Emacs is starting,
12567 the column widget's height and the frame's pixel height are
12568 different. The column widget's height is the right one. In
12569 later invocations, when Emacs is up, the frame's pixel height
12570 is right, though.
12571
12572 It's not obvious where the initial small difference comes from.
12573 2000-12-01, gerd. */
12574
12575 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
06a2c219 12576#endif
2e365682 12577
7708ced0
GM
12578 if (flags & YNegative)
12579 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
12580 - 2 * f->output_data.x->border_width
12581 - win_y
12582 - height
12583 + f->output_data.x->top_pos);
12584 }
12585
3a35ab44
RS
12586 /* The left_pos and top_pos
12587 are now relative to the top and left screen edges,
12588 so the flags should correspond. */
7556890b 12589 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
12590}
12591
3a35ab44
RS
12592/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
12593 to really change the position, and 0 when calling from
12594 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
12595 position values). It is -1 when calling from x_set_frame_parameters,
12596 which means, do adjust for borders but don't change the gravity. */
3a35ab44 12597
dfcf069d 12598void
dc05a16b 12599x_set_offset (f, xoff, yoff, change_gravity)
f676886a 12600 struct frame *f;
dc6f92b8 12601 register int xoff, yoff;
dc05a16b 12602 int change_gravity;
dc6f92b8 12603{
4a4cbdd5
KH
12604 int modified_top, modified_left;
12605
aa3ff7c9 12606 if (change_gravity > 0)
3a35ab44 12607 {
7556890b
RS
12608 f->output_data.x->top_pos = yoff;
12609 f->output_data.x->left_pos = xoff;
12610 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 12611 if (xoff < 0)
7556890b 12612 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 12613 if (yoff < 0)
7556890b
RS
12614 f->output_data.x->size_hint_flags |= YNegative;
12615 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 12616 }
43bca5d5 12617 x_calc_absolute_position (f);
dc6f92b8
JB
12618
12619 BLOCK_INPUT;
c32cdd9a 12620 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 12621
7556890b
RS
12622 modified_left = f->output_data.x->left_pos;
12623 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
12624#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
12625 this seems to be unnecessary and incorrect. rms, 4/17/97. */
12626 /* It is a mystery why we need to add the border_width here
12627 when the frame is already visible, but experiment says we do. */
aa3ff7c9 12628 if (change_gravity != 0)
4a4cbdd5 12629 {
7556890b
RS
12630 modified_left += f->output_data.x->border_width;
12631 modified_top += f->output_data.x->border_width;
4a4cbdd5 12632 }
e73ec6fa 12633#endif
4a4cbdd5 12634
3afe33e7 12635#ifdef USE_X_TOOLKIT
7556890b 12636 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 12637 modified_left, modified_top);
3afe33e7 12638#else /* not USE_X_TOOLKIT */
334208b7 12639 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 12640 modified_left, modified_top);
3afe33e7 12641#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12642 UNBLOCK_INPUT;
12643}
12644
dc6f92b8 12645
499b1844
GM
12646/* Change the size of frame F's X window to COLS/ROWS in the case F
12647 doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
12648 top-left-corner window gravity for this size change and subsequent
12649 size changes. Otherwise we leave the window gravity unchanged. */
12650
12651static void
12652x_set_window_size_1 (f, change_gravity, cols, rows)
f676886a 12653 struct frame *f;
bc20ebbf 12654 int change_gravity;
b1c884c3 12655 int cols, rows;
dc6f92b8
JB
12656{
12657 int pixelwidth, pixelheight;
80fd1fe2 12658
b1c884c3 12659 check_frame_size (f, &rows, &cols);
7556890b 12660 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
12661 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
12662 ? 0
12663 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 12664 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 12665 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
976b73d7
KS
12666
12667 x_compute_fringe_widths (f, 0);
12668
f451eb13
JB
12669 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
12670 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 12671
7556890b 12672 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 12673 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 12674
334208b7
RS
12675 XSync (FRAME_X_DISPLAY (f), False);
12676 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12677 pixelwidth, pixelheight);
b1c884c3
JB
12678
12679 /* Now, strictly speaking, we can't be sure that this is accurate,
12680 but the window manager will get around to dealing with the size
12681 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
12682 ConfigureNotify event gets here.
12683
12684 We could just not bother storing any of this information here,
12685 and let the ConfigureNotify event set everything up, but that
fddd5ceb 12686 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 12687 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
12688 point in the future when the ConfigureNotify event arrives.
12689
12690 We pass 1 for DELAY since we can't run Lisp code inside of
12691 a BLOCK_INPUT. */
7d1e984f 12692 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
12693 PIXEL_WIDTH (f) = pixelwidth;
12694 PIXEL_HEIGHT (f) = pixelheight;
12695
aee9a898
RS
12696 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
12697 receive in the ConfigureNotify event; if we get what we asked
12698 for, then the event won't cause the screen to become garbaged, so
12699 we have to make sure to do it here. */
12700 SET_FRAME_GARBAGED (f);
12701
12702 XFlush (FRAME_X_DISPLAY (f));
499b1844
GM
12703}
12704
12705
12706/* Call this to change the size of frame F's x-window.
12707 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
12708 for this size change and subsequent size changes.
12709 Otherwise we leave the window gravity unchanged. */
aee9a898 12710
499b1844
GM
12711void
12712x_set_window_size (f, change_gravity, cols, rows)
12713 struct frame *f;
12714 int change_gravity;
12715 int cols, rows;
12716{
12717 BLOCK_INPUT;
12718
12719#ifdef USE_X_TOOLKIT
12720
f1f4d345 12721 if (f->output_data.x->widget != NULL)
499b1844
GM
12722 {
12723 /* The x and y position of the widget is clobbered by the
12724 call to XtSetValues within EmacsFrameSetCharSize.
12725 This is a real kludge, but I don't understand Xt so I can't
12726 figure out a correct fix. Can anyone else tell me? -- rms. */
12727 int xpos = f->output_data.x->widget->core.x;
12728 int ypos = f->output_data.x->widget->core.y;
12729 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
12730 f->output_data.x->widget->core.x = xpos;
12731 f->output_data.x->widget->core.y = ypos;
12732 }
12733 else
12734 x_set_window_size_1 (f, change_gravity, cols, rows);
12735
12736#else /* not USE_X_TOOLKIT */
12737
12738 x_set_window_size_1 (f, change_gravity, cols, rows);
12739
aee9a898
RS
12740#endif /* not USE_X_TOOLKIT */
12741
4d73d038 12742 /* If cursor was outside the new size, mark it as off. */
06a2c219 12743 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 12744
aee9a898
RS
12745 /* Clear out any recollection of where the mouse highlighting was,
12746 since it might be in a place that's outside the new frame size.
12747 Actually checking whether it is outside is a pain in the neck,
12748 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 12749 cancel_mouse_face (f);
dbc4e1c1 12750
dc6f92b8
JB
12751 UNBLOCK_INPUT;
12752}
dc6f92b8 12753\f
d047c4eb 12754/* Mouse warping. */
dc6f92b8 12755
9b378208 12756void
f676886a
JB
12757x_set_mouse_position (f, x, y)
12758 struct frame *f;
dc6f92b8
JB
12759 int x, y;
12760{
12761 int pix_x, pix_y;
12762
7556890b
RS
12763 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
12764 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
12765
12766 if (pix_x < 0) pix_x = 0;
12767 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
12768
12769 if (pix_y < 0) pix_y = 0;
12770 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
12771
12772 BLOCK_INPUT;
dc6f92b8 12773
334208b7
RS
12774 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12775 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
12776 UNBLOCK_INPUT;
12777}
12778
9b378208
RS
12779/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
12780
12781void
12782x_set_mouse_pixel_position (f, pix_x, pix_y)
12783 struct frame *f;
12784 int pix_x, pix_y;
12785{
12786 BLOCK_INPUT;
12787
334208b7
RS
12788 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12789 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
12790 UNBLOCK_INPUT;
12791}
d047c4eb
KH
12792\f
12793/* focus shifting, raising and lowering. */
9b378208 12794
dfcf069d 12795void
f676886a
JB
12796x_focus_on_frame (f)
12797 struct frame *f;
dc6f92b8 12798{
1fb20991 12799#if 0 /* This proves to be unpleasant. */
f676886a 12800 x_raise_frame (f);
1fb20991 12801#endif
6d4238f3
JB
12802#if 0
12803 /* I don't think that the ICCCM allows programs to do things like this
12804 without the interaction of the window manager. Whatever you end up
f676886a 12805 doing with this code, do it to x_unfocus_frame too. */
334208b7 12806 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 12807 RevertToPointerRoot, CurrentTime);
c118dd06 12808#endif /* ! 0 */
dc6f92b8
JB
12809}
12810
dfcf069d 12811void
f676886a
JB
12812x_unfocus_frame (f)
12813 struct frame *f;
dc6f92b8 12814{
6d4238f3 12815#if 0
f676886a 12816 /* Look at the remarks in x_focus_on_frame. */
0f941935 12817 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 12818 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 12819 RevertToPointerRoot, CurrentTime);
c118dd06 12820#endif /* ! 0 */
dc6f92b8
JB
12821}
12822
f676886a 12823/* Raise frame F. */
dc6f92b8 12824
dfcf069d 12825void
f676886a
JB
12826x_raise_frame (f)
12827 struct frame *f;
dc6f92b8 12828{
3a88c238 12829 if (f->async_visible)
dc6f92b8
JB
12830 {
12831 BLOCK_INPUT;
3afe33e7 12832#ifdef USE_X_TOOLKIT
7556890b 12833 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12834#else /* not USE_X_TOOLKIT */
334208b7 12835 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12836#endif /* not USE_X_TOOLKIT */
334208b7 12837 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12838 UNBLOCK_INPUT;
12839 }
12840}
12841
f676886a 12842/* Lower frame F. */
dc6f92b8 12843
dfcf069d 12844void
f676886a
JB
12845x_lower_frame (f)
12846 struct frame *f;
dc6f92b8 12847{
3a88c238 12848 if (f->async_visible)
dc6f92b8
JB
12849 {
12850 BLOCK_INPUT;
3afe33e7 12851#ifdef USE_X_TOOLKIT
7556890b 12852 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12853#else /* not USE_X_TOOLKIT */
334208b7 12854 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12855#endif /* not USE_X_TOOLKIT */
334208b7 12856 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12857 UNBLOCK_INPUT;
12858 }
12859}
12860
dbc4e1c1 12861static void
6b0442dc 12862XTframe_raise_lower (f, raise_flag)
dbc4e1c1 12863 FRAME_PTR f;
6b0442dc 12864 int raise_flag;
dbc4e1c1 12865{
6b0442dc 12866 if (raise_flag)
dbc4e1c1
JB
12867 x_raise_frame (f);
12868 else
12869 x_lower_frame (f);
12870}
d047c4eb
KH
12871\f
12872/* Change of visibility. */
dc6f92b8 12873
9382638d
KH
12874/* This tries to wait until the frame is really visible.
12875 However, if the window manager asks the user where to position
12876 the frame, this will return before the user finishes doing that.
12877 The frame will not actually be visible at that time,
12878 but it will become visible later when the window manager
12879 finishes with it. */
12880
dfcf069d 12881void
f676886a
JB
12882x_make_frame_visible (f)
12883 struct frame *f;
dc6f92b8 12884{
990ba854 12885 Lisp_Object type;
1aa6072f 12886 int original_top, original_left;
31be9251
GM
12887 int retry_count = 2;
12888
12889 retry:
dc6f92b8 12890
dc6f92b8 12891 BLOCK_INPUT;
dc6f92b8 12892
990ba854
RS
12893 type = x_icon_type (f);
12894 if (!NILP (type))
12895 x_bitmap_icon (f, type);
bdcd49ba 12896
f676886a 12897 if (! FRAME_VISIBLE_P (f))
90e65f07 12898 {
1aa6072f
RS
12899 /* We test FRAME_GARBAGED_P here to make sure we don't
12900 call x_set_offset a second time
12901 if we get to x_make_frame_visible a second time
12902 before the window gets really visible. */
12903 if (! FRAME_ICONIFIED_P (f)
12904 && ! f->output_data.x->asked_for_visible)
12905 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
12906
12907 f->output_data.x->asked_for_visible = 1;
12908
90e65f07 12909 if (! EQ (Vx_no_window_manager, Qt))
f676886a 12910 x_wm_set_window_state (f, NormalState);
3afe33e7 12911#ifdef USE_X_TOOLKIT
d7a38a2e 12912 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 12913 XtMapWidget (f->output_data.x->widget);
3afe33e7 12914#else /* not USE_X_TOOLKIT */
7f9c7f94 12915 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12916#endif /* not USE_X_TOOLKIT */
0134a210
RS
12917#if 0 /* This seems to bring back scroll bars in the wrong places
12918 if the window configuration has changed. They seem
12919 to come back ok without this. */
ab648270 12920 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 12921 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 12922#endif
90e65f07 12923 }
dc6f92b8 12924
334208b7 12925 XFlush (FRAME_X_DISPLAY (f));
90e65f07 12926
0dacf791
RS
12927 /* Synchronize to ensure Emacs knows the frame is visible
12928 before we do anything else. We do this loop with input not blocked
12929 so that incoming events are handled. */
12930 {
12931 Lisp_Object frame;
12ce2351 12932 int count;
28c01ffe
RS
12933 /* This must be before UNBLOCK_INPUT
12934 since events that arrive in response to the actions above
12935 will set it when they are handled. */
12936 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
12937
12938 original_left = f->output_data.x->left_pos;
12939 original_top = f->output_data.x->top_pos;
c0a04927
RS
12940
12941 /* This must come after we set COUNT. */
12942 UNBLOCK_INPUT;
12943
2745e6c4 12944 /* We unblock here so that arriving X events are processed. */
1aa6072f 12945
dcb07ae9
RS
12946 /* Now move the window back to where it was "supposed to be".
12947 But don't do it if the gravity is negative.
12948 When the gravity is negative, this uses a position
28c01ffe
RS
12949 that is 3 pixels too low. Perhaps that's really the border width.
12950
12951 Don't do this if the window has never been visible before,
12952 because the window manager may choose the position
12953 and we don't want to override it. */
1aa6072f 12954
4d3f5d9a 12955 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 12956 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 12957 && previously_visible)
1aa6072f 12958 {
2745e6c4
RS
12959 Drawable rootw;
12960 int x, y;
12961 unsigned int width, height, border, depth;
06a2c219 12962
1aa6072f 12963 BLOCK_INPUT;
9829ddba 12964
06a2c219
GM
12965 /* On some window managers (such as FVWM) moving an existing
12966 window, even to the same place, causes the window manager
12967 to introduce an offset. This can cause the window to move
12968 to an unexpected location. Check the geometry (a little
12969 slow here) and then verify that the window is in the right
12970 place. If the window is not in the right place, move it
12971 there, and take the potential window manager hit. */
2745e6c4
RS
12972 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12973 &rootw, &x, &y, &width, &height, &border, &depth);
12974
12975 if (original_left != x || original_top != y)
12976 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12977 original_left, original_top);
12978
1aa6072f
RS
12979 UNBLOCK_INPUT;
12980 }
9829ddba 12981
e0c1aef2 12982 XSETFRAME (frame, f);
c0a04927 12983
12ce2351
GM
12984 /* Wait until the frame is visible. Process X events until a
12985 MapNotify event has been seen, or until we think we won't get a
12986 MapNotify at all.. */
12987 for (count = input_signal_count + 10;
12988 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 12989 {
12ce2351 12990 /* Force processing of queued events. */
334208b7 12991 x_sync (f);
12ce2351
GM
12992
12993 /* Machines that do polling rather than SIGIO have been
12994 observed to go into a busy-wait here. So we'll fake an
12995 alarm signal to let the handler know that there's something
12996 to be read. We used to raise a real alarm, but it seems
12997 that the handler isn't always enabled here. This is
12998 probably a bug. */
8b2f8d4e 12999 if (input_polling_used ())
3b2fa4e6 13000 {
12ce2351
GM
13001 /* It could be confusing if a real alarm arrives while
13002 processing the fake one. Turn it off and let the
13003 handler reset it. */
3e71d8f2 13004 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
13005 int old_poll_suppress_count = poll_suppress_count;
13006 poll_suppress_count = 1;
13007 poll_for_input_1 ();
13008 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 13009 }
12ce2351
GM
13010
13011 /* See if a MapNotify event has been processed. */
13012 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 13013 }
31be9251
GM
13014
13015 /* 2000-09-28: In
13016
13017 (let ((f (selected-frame)))
13018 (iconify-frame f)
13019 (raise-frame f))
13020
13021 the frame is not raised with various window managers on
13022 FreeBSD, Linux and Solaris. It turns out that, for some
13023 unknown reason, the call to XtMapWidget is completely ignored.
13024 Mapping the widget a second time works. */
13025
13026 if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
13027 goto retry;
0dacf791 13028 }
dc6f92b8
JB
13029}
13030
06a2c219 13031/* Change from mapped state to withdrawn state. */
dc6f92b8 13032
d047c4eb
KH
13033/* Make the frame visible (mapped and not iconified). */
13034
dfcf069d 13035void
f676886a
JB
13036x_make_frame_invisible (f)
13037 struct frame *f;
dc6f92b8 13038{
546e6d5b
RS
13039 Window window;
13040
13041#ifdef USE_X_TOOLKIT
13042 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 13043 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
13044#else /* not USE_X_TOOLKIT */
13045 window = FRAME_X_WINDOW (f);
13046#endif /* not USE_X_TOOLKIT */
dc6f92b8 13047
9319ae23 13048 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
13049 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
13050 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 13051
5627c40e 13052#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 13053 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 13054 return;
5627c40e 13055#endif
dc6f92b8
JB
13056
13057 BLOCK_INPUT;
c118dd06 13058
af31d76f
RS
13059 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
13060 that the current position of the window is user-specified, rather than
13061 program-specified, so that when the window is mapped again, it will be
13062 placed at the same location, without forcing the user to position it
13063 by hand again (they have already done that once for this window.) */
c32cdd9a 13064 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 13065
c118dd06
JB
13066#ifdef HAVE_X11R4
13067
334208b7
RS
13068 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
13069 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
13070 {
13071 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13072 error ("Can't notify window manager of window withdrawal");
c118dd06 13073 }
c118dd06 13074#else /* ! defined (HAVE_X11R4) */
16bd92ea 13075
c118dd06 13076 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
13077 if (! EQ (Vx_no_window_manager, Qt))
13078 {
16bd92ea 13079 XEvent unmap;
dc6f92b8 13080
16bd92ea 13081 unmap.xunmap.type = UnmapNotify;
546e6d5b 13082 unmap.xunmap.window = window;
334208b7 13083 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 13084 unmap.xunmap.from_configure = False;
334208b7
RS
13085 if (! XSendEvent (FRAME_X_DISPLAY (f),
13086 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 13087 False,
06a2c219 13088 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
13089 &unmap))
13090 {
13091 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13092 error ("Can't notify window manager of withdrawal");
16bd92ea 13093 }
dc6f92b8
JB
13094 }
13095
16bd92ea 13096 /* Unmap the window ourselves. Cheeky! */
334208b7 13097 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 13098#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 13099
5627c40e
RS
13100 /* We can't distinguish this from iconification
13101 just by the event that we get from the server.
13102 So we can't win using the usual strategy of letting
13103 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
13104 and synchronize with the server to make sure we agree. */
13105 f->visible = 0;
13106 FRAME_ICONIFIED_P (f) = 0;
13107 f->async_visible = 0;
13108 f->async_iconified = 0;
13109
334208b7 13110 x_sync (f);
5627c40e 13111
dc6f92b8
JB
13112 UNBLOCK_INPUT;
13113}
13114
06a2c219 13115/* Change window state from mapped to iconified. */
dc6f92b8 13116
dfcf069d 13117void
f676886a
JB
13118x_iconify_frame (f)
13119 struct frame *f;
dc6f92b8 13120{
3afe33e7 13121 int result;
990ba854 13122 Lisp_Object type;
dc6f92b8 13123
9319ae23 13124 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
13125 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
13126 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 13127
3a88c238 13128 if (f->async_iconified)
dc6f92b8
JB
13129 return;
13130
3afe33e7 13131 BLOCK_INPUT;
546e6d5b 13132
9af3143a
RS
13133 FRAME_SAMPLE_VISIBILITY (f);
13134
990ba854
RS
13135 type = x_icon_type (f);
13136 if (!NILP (type))
13137 x_bitmap_icon (f, type);
bdcd49ba
RS
13138
13139#ifdef USE_X_TOOLKIT
13140
546e6d5b
RS
13141 if (! FRAME_VISIBLE_P (f))
13142 {
13143 if (! EQ (Vx_no_window_manager, Qt))
13144 x_wm_set_window_state (f, IconicState);
13145 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 13146 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
13147 /* The server won't give us any event to indicate
13148 that an invisible frame was changed to an icon,
13149 so we have to record it here. */
13150 f->iconified = 1;
1e6bc770 13151 f->visible = 1;
9cf30a30 13152 f->async_iconified = 1;
1e6bc770 13153 f->async_visible = 0;
546e6d5b
RS
13154 UNBLOCK_INPUT;
13155 return;
13156 }
13157
334208b7 13158 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 13159 XtWindow (f->output_data.x->widget),
334208b7 13160 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
13161 UNBLOCK_INPUT;
13162
13163 if (!result)
546e6d5b 13164 error ("Can't notify window manager of iconification");
3afe33e7
RS
13165
13166 f->async_iconified = 1;
1e6bc770
RS
13167 f->async_visible = 0;
13168
8c002a25
KH
13169
13170 BLOCK_INPUT;
334208b7 13171 XFlush (FRAME_X_DISPLAY (f));
8c002a25 13172 UNBLOCK_INPUT;
3afe33e7
RS
13173#else /* not USE_X_TOOLKIT */
13174
fd13dbb2
RS
13175 /* Make sure the X server knows where the window should be positioned,
13176 in case the user deiconifies with the window manager. */
13177 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 13178 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 13179
16bd92ea
JB
13180 /* Since we don't know which revision of X we're running, we'll use both
13181 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
13182
13183 /* X11R4: send a ClientMessage to the window manager using the
13184 WM_CHANGE_STATE type. */
13185 {
13186 XEvent message;
58769bee 13187
c118dd06 13188 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 13189 message.xclient.type = ClientMessage;
334208b7 13190 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
13191 message.xclient.format = 32;
13192 message.xclient.data.l[0] = IconicState;
13193
334208b7
RS
13194 if (! XSendEvent (FRAME_X_DISPLAY (f),
13195 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
13196 False,
13197 SubstructureRedirectMask | SubstructureNotifyMask,
13198 &message))
dc6f92b8
JB
13199 {
13200 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13201 error ("Can't notify window manager of iconification");
dc6f92b8 13202 }
16bd92ea 13203 }
dc6f92b8 13204
58769bee 13205 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
13206 IconicState. */
13207 x_wm_set_window_state (f, IconicState);
dc6f92b8 13208
a9c00105
RS
13209 if (!FRAME_VISIBLE_P (f))
13210 {
13211 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 13212 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
13213 }
13214
3a88c238 13215 f->async_iconified = 1;
1e6bc770 13216 f->async_visible = 0;
dc6f92b8 13217
334208b7 13218 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 13219 UNBLOCK_INPUT;
8c002a25 13220#endif /* not USE_X_TOOLKIT */
dc6f92b8 13221}
19f71add 13222
d047c4eb 13223\f
19f71add 13224/* Free X resources of frame F. */
dc6f92b8 13225
dfcf069d 13226void
19f71add 13227x_free_frame_resources (f)
f676886a 13228 struct frame *f;
dc6f92b8 13229{
7f9c7f94 13230 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
c6ea2775
EZ
13231 Lisp_Object bar;
13232 struct scroll_bar *b;
7f9c7f94 13233
dc6f92b8 13234 BLOCK_INPUT;
c0ff3fab 13235
6186a4a0
RS
13236 /* If a display connection is dead, don't try sending more
13237 commands to the X server. */
19f71add 13238 if (dpyinfo->display)
6186a4a0 13239 {
19f71add 13240 if (f->output_data.x->icon_desc)
6186a4a0 13241 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
c6ea2775
EZ
13242
13243#ifdef USE_X_TOOLKIT
13244 /* Explicitly destroy the scroll bars of the frame. Without
13245 this, we get "BadDrawable" errors from the toolkit later on,
13246 presumably from expose events generated for the disappearing
13247 toolkit scroll bars. */
13248 for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next)
13249 {
13250 b = XSCROLL_BAR (bar);
13251 x_scroll_bar_remove (b);
13252 }
13253#endif
13254
31f41daf 13255#ifdef HAVE_X_I18N
f5d11644
GM
13256 if (FRAME_XIC (f))
13257 free_frame_xic (f);
31f41daf 13258#endif
c6ea2775 13259
3afe33e7 13260#ifdef USE_X_TOOLKIT
06a2c219 13261 if (f->output_data.x->widget)
30ca89f5
GM
13262 {
13263 XtDestroyWidget (f->output_data.x->widget);
13264 f->output_data.x->widget = NULL;
13265 }
c6ea2775
EZ
13266 /* Tooltips don't have widgets, only a simple X window, even if
13267 we are using a toolkit. */
13268 else if (FRAME_X_WINDOW (f))
13269 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13270
6186a4a0 13271 free_frame_menubar (f);
c6ea2775
EZ
13272#else /* !USE_X_TOOLKIT */
13273 if (FRAME_X_WINDOW (f))
13274 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13275#endif /* !USE_X_TOOLKIT */
3afe33e7 13276
3e71d8f2
GM
13277 unload_color (f, f->output_data.x->foreground_pixel);
13278 unload_color (f, f->output_data.x->background_pixel);
13279 unload_color (f, f->output_data.x->cursor_pixel);
13280 unload_color (f, f->output_data.x->cursor_foreground_pixel);
13281 unload_color (f, f->output_data.x->border_pixel);
13282 unload_color (f, f->output_data.x->mouse_pixel);
c6ea2775 13283
3e71d8f2
GM
13284 if (f->output_data.x->scroll_bar_background_pixel != -1)
13285 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
13286 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
13287 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
7c1bef7a
MB
13288#ifdef USE_TOOLKIT_SCROLL_BARS
13289 /* Scrollbar shadow colors. */
13290 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
13291 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
13292 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
13293 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
13294#endif /* USE_TOOLKIT_SCROLL_BARS */
3e71d8f2
GM
13295 if (f->output_data.x->white_relief.allocated_p)
13296 unload_color (f, f->output_data.x->white_relief.pixel);
13297 if (f->output_data.x->black_relief.allocated_p)
13298 unload_color (f, f->output_data.x->black_relief.pixel);
4ca78676 13299
19f71add
GM
13300 if (FRAME_FACE_CACHE (f))
13301 free_frame_faces (f);
13302
4ca78676 13303 x_free_gcs (f);
6186a4a0
RS
13304 XFlush (FRAME_X_DISPLAY (f));
13305 }
dc6f92b8 13306
df89d8a4 13307 if (f->output_data.x->saved_menu_event)
06a2c219 13308 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 13309
7556890b 13310 xfree (f->output_data.x);
19f71add
GM
13311 f->output_data.x = NULL;
13312
0f941935
KH
13313 if (f == dpyinfo->x_focus_frame)
13314 dpyinfo->x_focus_frame = 0;
13315 if (f == dpyinfo->x_focus_event_frame)
13316 dpyinfo->x_focus_event_frame = 0;
13317 if (f == dpyinfo->x_highlight_frame)
13318 dpyinfo->x_highlight_frame = 0;
c0ff3fab 13319
7f9c7f94 13320 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 13321 {
7f9c7f94
RS
13322 dpyinfo->mouse_face_beg_row
13323 = dpyinfo->mouse_face_beg_col = -1;
13324 dpyinfo->mouse_face_end_row
13325 = dpyinfo->mouse_face_end_col = -1;
13326 dpyinfo->mouse_face_window = Qnil;
21323706
RS
13327 dpyinfo->mouse_face_deferred_gc = 0;
13328 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 13329 }
0134a210 13330
c0ff3fab 13331 UNBLOCK_INPUT;
dc6f92b8 13332}
19f71add
GM
13333
13334
13335/* Destroy the X window of frame F. */
13336
13337void
13338x_destroy_window (f)
13339 struct frame *f;
13340{
13341 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13342
13343 /* If a display connection is dead, don't try sending more
13344 commands to the X server. */
13345 if (dpyinfo->display != 0)
13346 x_free_frame_resources (f);
13347
13348 dpyinfo->reference_count--;
13349}
13350
dc6f92b8 13351\f
f451eb13
JB
13352/* Setting window manager hints. */
13353
af31d76f
RS
13354/* Set the normal size hints for the window manager, for frame F.
13355 FLAGS is the flags word to use--or 0 meaning preserve the flags
13356 that the window now has.
13357 If USER_POSITION is nonzero, we set the USPosition
13358 flag (this is useful when FLAGS is 0). */
6dba1858 13359
dfcf069d 13360void
af31d76f 13361x_wm_set_size_hint (f, flags, user_position)
f676886a 13362 struct frame *f;
af31d76f
RS
13363 long flags;
13364 int user_position;
dc6f92b8
JB
13365{
13366 XSizeHints size_hints;
3afe33e7
RS
13367
13368#ifdef USE_X_TOOLKIT
7e4f2521
FP
13369 Arg al[2];
13370 int ac = 0;
13371 Dimension widget_width, widget_height;
7556890b 13372 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 13373#else /* not USE_X_TOOLKIT */
c118dd06 13374 Window window = FRAME_X_WINDOW (f);
3afe33e7 13375#endif /* not USE_X_TOOLKIT */
dc6f92b8 13376
b72a58fd
RS
13377 /* Setting PMaxSize caused various problems. */
13378 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 13379
7556890b
RS
13380 size_hints.x = f->output_data.x->left_pos;
13381 size_hints.y = f->output_data.x->top_pos;
7553a6b7 13382
7e4f2521
FP
13383#ifdef USE_X_TOOLKIT
13384 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
13385 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 13386 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
13387 size_hints.height = widget_height;
13388 size_hints.width = widget_width;
13389#else /* not USE_X_TOOLKIT */
f676886a
JB
13390 size_hints.height = PIXEL_HEIGHT (f);
13391 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 13392#endif /* not USE_X_TOOLKIT */
7553a6b7 13393
7556890b
RS
13394 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
13395 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
13396 size_hints.max_width
13397 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
13398 size_hints.max_height
13399 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 13400
d067ea8b
KH
13401 /* Calculate the base and minimum sizes.
13402
13403 (When we use the X toolkit, we don't do it here.
13404 Instead we copy the values that the widgets are using, below.) */
13405#ifndef USE_X_TOOLKIT
b1c884c3 13406 {
b0342f17 13407 int base_width, base_height;
0134a210 13408 int min_rows = 0, min_cols = 0;
b0342f17 13409
f451eb13
JB
13410 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
13411 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 13412
0134a210 13413 check_frame_size (f, &min_rows, &min_cols);
b0342f17 13414
0134a210
RS
13415 /* The window manager uses the base width hints to calculate the
13416 current number of rows and columns in the frame while
13417 resizing; min_width and min_height aren't useful for this
13418 purpose, since they might not give the dimensions for a
13419 zero-row, zero-column frame.
58769bee 13420
0134a210
RS
13421 We use the base_width and base_height members if we have
13422 them; otherwise, we set the min_width and min_height members
13423 to the size for a zero x zero frame. */
b0342f17
JB
13424
13425#ifdef HAVE_X11R4
0134a210
RS
13426 size_hints.flags |= PBaseSize;
13427 size_hints.base_width = base_width;
13428 size_hints.base_height = base_height;
13429 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
13430 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 13431#else
0134a210
RS
13432 size_hints.min_width = base_width;
13433 size_hints.min_height = base_height;
b0342f17 13434#endif
b1c884c3 13435 }
dc6f92b8 13436
d067ea8b 13437 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 13438 if (flags)
dc6f92b8 13439 {
d067ea8b
KH
13440 size_hints.flags |= flags;
13441 goto no_read;
13442 }
13443#endif /* not USE_X_TOOLKIT */
13444
13445 {
13446 XSizeHints hints; /* Sometimes I hate X Windows... */
13447 long supplied_return;
13448 int value;
af31d76f
RS
13449
13450#ifdef HAVE_X11R4
d067ea8b
KH
13451 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
13452 &supplied_return);
af31d76f 13453#else
d067ea8b 13454 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 13455#endif
58769bee 13456
d067ea8b
KH
13457#ifdef USE_X_TOOLKIT
13458 size_hints.base_height = hints.base_height;
13459 size_hints.base_width = hints.base_width;
13460 size_hints.min_height = hints.min_height;
13461 size_hints.min_width = hints.min_width;
13462#endif
13463
13464 if (flags)
13465 size_hints.flags |= flags;
13466 else
13467 {
13468 if (value == 0)
13469 hints.flags = 0;
13470 if (hints.flags & PSize)
13471 size_hints.flags |= PSize;
13472 if (hints.flags & PPosition)
13473 size_hints.flags |= PPosition;
13474 if (hints.flags & USPosition)
13475 size_hints.flags |= USPosition;
13476 if (hints.flags & USSize)
13477 size_hints.flags |= USSize;
13478 }
13479 }
13480
06a2c219 13481#ifndef USE_X_TOOLKIT
d067ea8b 13482 no_read:
06a2c219 13483#endif
0134a210 13484
af31d76f 13485#ifdef PWinGravity
7556890b 13486 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 13487 size_hints.flags |= PWinGravity;
dc05a16b 13488
af31d76f 13489 if (user_position)
6dba1858 13490 {
af31d76f
RS
13491 size_hints.flags &= ~ PPosition;
13492 size_hints.flags |= USPosition;
6dba1858 13493 }
2554751d 13494#endif /* PWinGravity */
6dba1858 13495
b0342f17 13496#ifdef HAVE_X11R4
334208b7 13497 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13498#else
334208b7 13499 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13500#endif
dc6f92b8
JB
13501}
13502
13503/* Used for IconicState or NormalState */
06a2c219 13504
dfcf069d 13505void
f676886a
JB
13506x_wm_set_window_state (f, state)
13507 struct frame *f;
dc6f92b8
JB
13508 int state;
13509{
3afe33e7 13510#ifdef USE_X_TOOLKIT
546e6d5b
RS
13511 Arg al[1];
13512
13513 XtSetArg (al[0], XtNinitialState, state);
7556890b 13514 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 13515#else /* not USE_X_TOOLKIT */
c118dd06 13516 Window window = FRAME_X_WINDOW (f);
dc6f92b8 13517
7556890b
RS
13518 f->output_data.x->wm_hints.flags |= StateHint;
13519 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 13520
7556890b 13521 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 13522#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13523}
13524
dfcf069d 13525void
7f2ae036 13526x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 13527 struct frame *f;
7f2ae036 13528 int pixmap_id;
dc6f92b8 13529{
d2bd6bc4
RS
13530 Pixmap icon_pixmap;
13531
06a2c219 13532#ifndef USE_X_TOOLKIT
c118dd06 13533 Window window = FRAME_X_WINDOW (f);
75231bad 13534#endif
dc6f92b8 13535
7f2ae036 13536 if (pixmap_id > 0)
dbc4e1c1 13537 {
d2bd6bc4 13538 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 13539 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
13540 }
13541 else
68568555
RS
13542 {
13543 /* It seems there is no way to turn off use of an icon pixmap.
13544 The following line does it, only if no icon has yet been created,
13545 for some window managers. But with mwm it crashes.
13546 Some people say it should clear the IconPixmapHint bit in this case,
13547 but that doesn't work, and the X consortium said it isn't the
13548 right thing at all. Since there is no way to win,
13549 best to explicitly give up. */
13550#if 0
13551 f->output_data.x->wm_hints.icon_pixmap = None;
13552#else
13553 return;
13554#endif
13555 }
b1c884c3 13556
d2bd6bc4
RS
13557#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
13558
13559 {
13560 Arg al[1];
13561 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
13562 XtSetValues (f->output_data.x->widget, al, 1);
13563 }
13564
13565#else /* not USE_X_TOOLKIT */
13566
7556890b
RS
13567 f->output_data.x->wm_hints.flags |= IconPixmapHint;
13568 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
13569
13570#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13571}
13572
dfcf069d 13573void
f676886a
JB
13574x_wm_set_icon_position (f, icon_x, icon_y)
13575 struct frame *f;
dc6f92b8
JB
13576 int icon_x, icon_y;
13577{
75231bad 13578#ifdef USE_X_TOOLKIT
7556890b 13579 Window window = XtWindow (f->output_data.x->widget);
75231bad 13580#else
c118dd06 13581 Window window = FRAME_X_WINDOW (f);
75231bad 13582#endif
dc6f92b8 13583
7556890b
RS
13584 f->output_data.x->wm_hints.flags |= IconPositionHint;
13585 f->output_data.x->wm_hints.icon_x = icon_x;
13586 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 13587
7556890b 13588 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
13589}
13590
13591\f
06a2c219
GM
13592/***********************************************************************
13593 Fonts
13594 ***********************************************************************/
dc43ef94
KH
13595
13596/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 13597
dc43ef94
KH
13598struct font_info *
13599x_get_font_info (f, font_idx)
13600 FRAME_PTR f;
13601 int font_idx;
13602{
13603 return (FRAME_X_FONT_TABLE (f) + font_idx);
13604}
13605
13606
9c11f79e
GM
13607/* Return a list of names of available fonts matching PATTERN on frame F.
13608
13609 If SIZE is > 0, it is the size (maximum bounds width) of fonts
13610 to be listed.
13611
13612 SIZE < 0 means include scalable fonts.
13613
13614 Frame F null means we have not yet created any frame on X, and
13615 consult the first display in x_display_list. MAXNAMES sets a limit
13616 on how many fonts to match. */
dc43ef94
KH
13617
13618Lisp_Object
13619x_list_fonts (f, pattern, size, maxnames)
9c11f79e 13620 struct frame *f;
dc43ef94
KH
13621 Lisp_Object pattern;
13622 int size;
13623 int maxnames;
13624{
06a2c219
GM
13625 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
13626 Lisp_Object tem, second_best;
9c11f79e
GM
13627 struct x_display_info *dpyinfo
13628 = f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
13629 Display *dpy = dpyinfo->display;
09c6077f 13630 int try_XLoadQueryFont = 0;
53ca4657 13631 int count;
9c11f79e
GM
13632 int allow_scalable_fonts_p = 0;
13633
13634 if (size < 0)
13635 {
13636 allow_scalable_fonts_p = 1;
13637 size = 0;
13638 }
dc43ef94 13639
6b0efe73 13640 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
13641 if (NILP (patterns))
13642 patterns = Fcons (pattern, Qnil);
81ba44e5 13643
09c6077f
KH
13644 if (maxnames == 1 && !size)
13645 /* We can return any single font matching PATTERN. */
13646 try_XLoadQueryFont = 1;
9a32686f 13647
8e713be6 13648 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 13649 {
dc43ef94 13650 int num_fonts;
3e71d8f2 13651 char **names = NULL;
dc43ef94 13652
8e713be6 13653 pattern = XCAR (patterns);
536f4067
RS
13654 /* See if we cached the result for this particular query.
13655 The cache is an alist of the form:
9c11f79e
GM
13656 ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */
13657 tem = XCDR (dpyinfo->name_list_element);
13658 key = Fcons (Fcons (pattern, make_number (maxnames)),
13659 allow_scalable_fonts_p ? Qt : Qnil);
13660 list = Fassoc (key, tem);
13661 if (!NILP (list))
b5210ea7
KH
13662 {
13663 list = Fcdr_safe (list);
13664 /* We have a cashed list. Don't have to get the list again. */
13665 goto label_cached;
13666 }
13667
13668 /* At first, put PATTERN in the cache. */
09c6077f 13669
dc43ef94 13670 BLOCK_INPUT;
17d85edc
KH
13671 count = x_catch_errors (dpy);
13672
09c6077f
KH
13673 if (try_XLoadQueryFont)
13674 {
13675 XFontStruct *font;
13676 unsigned long value;
13677
13678 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
13679 if (x_had_errors_p (dpy))
13680 {
13681 /* This error is perhaps due to insufficient memory on X
13682 server. Let's just ignore it. */
13683 font = NULL;
13684 x_clear_errors (dpy);
13685 }
13686
09c6077f
KH
13687 if (font
13688 && XGetFontProperty (font, XA_FONT, &value))
13689 {
13690 char *name = (char *) XGetAtomName (dpy, (Atom) value);
13691 int len = strlen (name);
01c752b5 13692 char *tmp;
09c6077f 13693
6f6512e8
KH
13694 /* If DXPC (a Differential X Protocol Compressor)
13695 Ver.3.7 is running, XGetAtomName will return null
13696 string. We must avoid such a name. */
13697 if (len == 0)
13698 try_XLoadQueryFont = 0;
13699 else
13700 {
13701 num_fonts = 1;
13702 names = (char **) alloca (sizeof (char *));
13703 /* Some systems only allow alloca assigned to a
13704 simple var. */
13705 tmp = (char *) alloca (len + 1); names[0] = tmp;
13706 bcopy (name, names[0], len + 1);
13707 XFree (name);
13708 }
09c6077f
KH
13709 }
13710 else
13711 try_XLoadQueryFont = 0;
a083fd23
RS
13712
13713 if (font)
13714 XFreeFont (dpy, font);
09c6077f
KH
13715 }
13716
13717 if (!try_XLoadQueryFont)
17d85edc
KH
13718 {
13719 /* We try at least 10 fonts because XListFonts will return
13720 auto-scaled fonts at the head. */
13721 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
13722 &num_fonts);
13723 if (x_had_errors_p (dpy))
13724 {
13725 /* This error is perhaps due to insufficient memory on X
13726 server. Let's just ignore it. */
13727 names = NULL;
13728 x_clear_errors (dpy);
13729 }
13730 }
13731
13732 x_uncatch_errors (dpy, count);
dc43ef94
KH
13733 UNBLOCK_INPUT;
13734
13735 if (names)
13736 {
13737 int i;
dc43ef94
KH
13738
13739 /* Make a list of all the fonts we got back.
13740 Store that in the font cache for the display. */
13741 for (i = 0; i < num_fonts; i++)
13742 {
06a2c219 13743 int width = 0;
dc43ef94 13744 char *p = names[i];
06a2c219
GM
13745 int average_width = -1, dashes = 0;
13746
dc43ef94 13747 /* Count the number of dashes in NAMES[I]. If there are
9c11f79e
GM
13748 14 dashes, and the field value following 12th dash
13749 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
13750 is usually too ugly to be used for editing. Let's
13751 ignore it. */
dc43ef94
KH
13752 while (*p)
13753 if (*p++ == '-')
13754 {
13755 dashes++;
13756 if (dashes == 7) /* PIXEL_SIZE field */
13757 width = atoi (p);
13758 else if (dashes == 12) /* AVERAGE_WIDTH field */
13759 average_width = atoi (p);
13760 }
9c11f79e
GM
13761
13762 if (allow_scalable_fonts_p
13763 || dashes < 14 || average_width != 0)
dc43ef94
KH
13764 {
13765 tem = build_string (names[i]);
13766 if (NILP (Fassoc (tem, list)))
13767 {
13768 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
13769 && ((fast_c_string_match_ignore_case
13770 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
13771 >= 0))
13772 /* We can set the value of PIXEL_SIZE to the
b5210ea7 13773 width of this font. */
dc43ef94
KH
13774 list = Fcons (Fcons (tem, make_number (width)), list);
13775 else
13776 /* For the moment, width is not known. */
13777 list = Fcons (Fcons (tem, Qnil), list);
13778 }
13779 }
13780 }
e38f4136 13781
09c6077f 13782 if (!try_XLoadQueryFont)
e38f4136
GM
13783 {
13784 BLOCK_INPUT;
13785 XFreeFontNames (names);
13786 UNBLOCK_INPUT;
13787 }
dc43ef94
KH
13788 }
13789
b5210ea7 13790 /* Now store the result in the cache. */
f3fbd155
KR
13791 XSETCDR (dpyinfo->name_list_element,
13792 Fcons (Fcons (key, list), XCDR (dpyinfo->name_list_element)));
dc43ef94 13793
b5210ea7
KH
13794 label_cached:
13795 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 13796
b5210ea7
KH
13797 newlist = second_best = Qnil;
13798 /* Make a list of the fonts that have the right width. */
8e713be6 13799 for (; CONSP (list); list = XCDR (list))
b5210ea7 13800 {
536f4067
RS
13801 int found_size;
13802
8e713be6 13803 tem = XCAR (list);
dc43ef94 13804
8e713be6 13805 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
13806 continue;
13807 if (!size)
13808 {
8e713be6 13809 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
13810 continue;
13811 }
dc43ef94 13812
8e713be6 13813 if (!INTEGERP (XCDR (tem)))
dc43ef94 13814 {
b5210ea7 13815 /* Since we have not yet known the size of this font, we
9c11f79e 13816 must try slow function call XLoadQueryFont. */
dc43ef94
KH
13817 XFontStruct *thisinfo;
13818
13819 BLOCK_INPUT;
17d85edc 13820 count = x_catch_errors (dpy);
dc43ef94 13821 thisinfo = XLoadQueryFont (dpy,
8e713be6 13822 XSTRING (XCAR (tem))->data);
17d85edc
KH
13823 if (x_had_errors_p (dpy))
13824 {
13825 /* This error is perhaps due to insufficient memory on X
13826 server. Let's just ignore it. */
13827 thisinfo = NULL;
13828 x_clear_errors (dpy);
13829 }
13830 x_uncatch_errors (dpy, count);
dc43ef94
KH
13831 UNBLOCK_INPUT;
13832
13833 if (thisinfo)
13834 {
f3fbd155
KR
13835 XSETCDR (tem,
13836 (thisinfo->min_bounds.width == 0
13837 ? make_number (0)
13838 : make_number (thisinfo->max_bounds.width)));
e38f4136 13839 BLOCK_INPUT;
dc43ef94 13840 XFreeFont (dpy, thisinfo);
e38f4136 13841 UNBLOCK_INPUT;
dc43ef94
KH
13842 }
13843 else
b5210ea7 13844 /* For unknown reason, the previous call of XListFont had
06a2c219 13845 returned a font which can't be opened. Record the size
b5210ea7 13846 as 0 not to try to open it again. */
f3fbd155 13847 XSETCDR (tem, make_number (0));
dc43ef94 13848 }
536f4067 13849
8e713be6 13850 found_size = XINT (XCDR (tem));
536f4067 13851 if (found_size == size)
8e713be6 13852 newlist = Fcons (XCAR (tem), newlist);
536f4067 13853 else if (found_size > 0)
b5210ea7 13854 {
536f4067 13855 if (NILP (second_best))
b5210ea7 13856 second_best = tem;
536f4067
RS
13857 else if (found_size < size)
13858 {
8e713be6
KR
13859 if (XINT (XCDR (second_best)) > size
13860 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
13861 second_best = tem;
13862 }
13863 else
13864 {
8e713be6
KR
13865 if (XINT (XCDR (second_best)) > size
13866 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
13867 second_best = tem;
13868 }
b5210ea7
KH
13869 }
13870 }
13871 if (!NILP (newlist))
13872 break;
13873 else if (!NILP (second_best))
13874 {
8e713be6 13875 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 13876 break;
dc43ef94 13877 }
dc43ef94
KH
13878 }
13879
13880 return newlist;
13881}
13882
06a2c219
GM
13883
13884#if GLYPH_DEBUG
13885
13886/* Check that FONT is valid on frame F. It is if it can be found in F's
13887 font table. */
13888
13889static void
13890x_check_font (f, font)
13891 struct frame *f;
13892 XFontStruct *font;
13893{
13894 int i;
13895 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13896
13897 xassert (font != NULL);
13898
13899 for (i = 0; i < dpyinfo->n_fonts; i++)
13900 if (dpyinfo->font_table[i].name
13901 && font == dpyinfo->font_table[i].font)
13902 break;
13903
13904 xassert (i < dpyinfo->n_fonts);
13905}
13906
13907#endif /* GLYPH_DEBUG != 0 */
13908
13909/* Set *W to the minimum width, *H to the minimum font height of FONT.
13910 Note: There are (broken) X fonts out there with invalid XFontStruct
13911 min_bounds contents. For example, handa@etl.go.jp reports that
13912 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
13913 have font->min_bounds.width == 0. */
13914
13915static INLINE void
13916x_font_min_bounds (font, w, h)
13917 XFontStruct *font;
13918 int *w, *h;
13919{
13920 *h = FONT_HEIGHT (font);
13921 *w = font->min_bounds.width;
13922
13923 /* Try to handle the case where FONT->min_bounds has invalid
13924 contents. Since the only font known to have invalid min_bounds
13925 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
13926 if (*w <= 0)
13927 *w = font->max_bounds.width;
13928}
13929
13930
13931/* Compute the smallest character width and smallest font height over
13932 all fonts available on frame F. Set the members smallest_char_width
13933 and smallest_font_height in F's x_display_info structure to
13934 the values computed. Value is non-zero if smallest_font_height or
13935 smallest_char_width become smaller than they were before. */
13936
13937static int
13938x_compute_min_glyph_bounds (f)
13939 struct frame *f;
13940{
13941 int i;
13942 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13943 XFontStruct *font;
13944 int old_width = dpyinfo->smallest_char_width;
13945 int old_height = dpyinfo->smallest_font_height;
13946
13947 dpyinfo->smallest_font_height = 100000;
13948 dpyinfo->smallest_char_width = 100000;
13949
13950 for (i = 0; i < dpyinfo->n_fonts; ++i)
13951 if (dpyinfo->font_table[i].name)
13952 {
13953 struct font_info *fontp = dpyinfo->font_table + i;
13954 int w, h;
13955
13956 font = (XFontStruct *) fontp->font;
13957 xassert (font != (XFontStruct *) ~0);
13958 x_font_min_bounds (font, &w, &h);
13959
13960 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
13961 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
13962 }
13963
13964 xassert (dpyinfo->smallest_char_width > 0
13965 && dpyinfo->smallest_font_height > 0);
13966
13967 return (dpyinfo->n_fonts == 1
13968 || dpyinfo->smallest_char_width < old_width
13969 || dpyinfo->smallest_font_height < old_height);
13970}
13971
13972
dc43ef94
KH
13973/* Load font named FONTNAME of the size SIZE for frame F, and return a
13974 pointer to the structure font_info while allocating it dynamically.
13975 If SIZE is 0, load any size of font.
13976 If loading is failed, return NULL. */
13977
13978struct font_info *
13979x_load_font (f, fontname, size)
13980 struct frame *f;
13981 register char *fontname;
13982 int size;
13983{
13984 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13985 Lisp_Object font_names;
d645aaa4 13986 int count;
dc43ef94
KH
13987
13988 /* Get a list of all the fonts that match this name. Once we
13989 have a list of matching fonts, we compare them against the fonts
13990 we already have by comparing names. */
09c6077f 13991 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
13992
13993 if (!NILP (font_names))
13994 {
13995 Lisp_Object tail;
13996 int i;
13997
13998 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 13999 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
14000 if (dpyinfo->font_table[i].name
14001 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 14002 XSTRING (XCAR (tail))->data)
06a2c219 14003 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 14004 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
14005 return (dpyinfo->font_table + i);
14006 }
14007
14008 /* Load the font and add it to the table. */
14009 {
14010 char *full_name;
14011 XFontStruct *font;
14012 struct font_info *fontp;
14013 unsigned long value;
06a2c219 14014 int i;
dc43ef94 14015
2da424f1
KH
14016 /* If we have found fonts by x_list_font, load one of them. If
14017 not, we still try to load a font by the name given as FONTNAME
14018 because XListFonts (called in x_list_font) of some X server has
14019 a bug of not finding a font even if the font surely exists and
14020 is loadable by XLoadQueryFont. */
e1d6d5b9 14021 if (size > 0 && !NILP (font_names))
8e713be6 14022 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
14023
14024 BLOCK_INPUT;
d645aaa4 14025 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 14026 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
14027 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
14028 {
14029 /* This error is perhaps due to insufficient memory on X
14030 server. Let's just ignore it. */
14031 font = NULL;
14032 x_clear_errors (FRAME_X_DISPLAY (f));
14033 }
14034 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 14035 UNBLOCK_INPUT;
b5210ea7 14036 if (!font)
dc43ef94
KH
14037 return NULL;
14038
06a2c219
GM
14039 /* Find a free slot in the font table. */
14040 for (i = 0; i < dpyinfo->n_fonts; ++i)
14041 if (dpyinfo->font_table[i].name == NULL)
14042 break;
14043
14044 /* If no free slot found, maybe enlarge the font table. */
14045 if (i == dpyinfo->n_fonts
14046 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 14047 {
06a2c219
GM
14048 int sz;
14049 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
14050 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 14051 dpyinfo->font_table
06a2c219 14052 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
14053 }
14054
06a2c219
GM
14055 fontp = dpyinfo->font_table + i;
14056 if (i == dpyinfo->n_fonts)
14057 ++dpyinfo->n_fonts;
dc43ef94
KH
14058
14059 /* Now fill in the slots of *FONTP. */
14060 BLOCK_INPUT;
14061 fontp->font = font;
06a2c219 14062 fontp->font_idx = i;
dc43ef94
KH
14063 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
14064 bcopy (fontname, fontp->name, strlen (fontname) + 1);
14065
14066 /* Try to get the full name of FONT. Put it in FULL_NAME. */
14067 full_name = 0;
14068 if (XGetFontProperty (font, XA_FONT, &value))
14069 {
14070 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
14071 char *p = name;
14072 int dashes = 0;
14073
14074 /* Count the number of dashes in the "full name".
14075 If it is too few, this isn't really the font's full name,
14076 so don't use it.
14077 In X11R4, the fonts did not come with their canonical names
14078 stored in them. */
14079 while (*p)
14080 {
14081 if (*p == '-')
14082 dashes++;
14083 p++;
14084 }
14085
14086 if (dashes >= 13)
14087 {
14088 full_name = (char *) xmalloc (p - name + 1);
14089 bcopy (name, full_name, p - name + 1);
14090 }
14091
14092 XFree (name);
14093 }
14094
14095 if (full_name != 0)
14096 fontp->full_name = full_name;
14097 else
14098 fontp->full_name = fontp->name;
14099
14100 fontp->size = font->max_bounds.width;
d5749adb 14101 fontp->height = FONT_HEIGHT (font);
dc43ef94 14102
2da424f1
KH
14103 if (NILP (font_names))
14104 {
14105 /* We come here because of a bug of XListFonts mentioned at
14106 the head of this block. Let's store this information in
14107 the cache for x_list_fonts. */
14108 Lisp_Object lispy_name = build_string (fontname);
14109 Lisp_Object lispy_full_name = build_string (fontp->full_name);
9c11f79e
GM
14110 Lisp_Object key = Fcons (Fcons (lispy_name, make_number (256)),
14111 Qnil);
2da424f1 14112
f3fbd155
KR
14113 XSETCDR (dpyinfo->name_list_element,
14114 Fcons (Fcons (key,
14115 Fcons (Fcons (lispy_full_name,
14116 make_number (fontp->size)),
14117 Qnil)),
14118 XCDR (dpyinfo->name_list_element)));
2da424f1 14119 if (full_name)
9c11f79e
GM
14120 {
14121 key = Fcons (Fcons (lispy_full_name, make_number (256)),
14122 Qnil);
f3fbd155
KR
14123 XSETCDR (dpyinfo->name_list_element,
14124 Fcons (Fcons (key,
14125 Fcons (Fcons (lispy_full_name,
14126 make_number (fontp->size)),
14127 Qnil)),
14128 XCDR (dpyinfo->name_list_element)));
9c11f79e 14129 }
2da424f1
KH
14130 }
14131
dc43ef94
KH
14132 /* The slot `encoding' specifies how to map a character
14133 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
14134 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
14135 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 14136 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 14137 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
14138 which is never used by any charset. If mapping can't be
14139 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
14140 fontp->encoding[1]
14141 = (font->max_byte1 == 0
14142 /* 1-byte font */
14143 ? (font->min_char_or_byte2 < 0x80
14144 ? (font->max_char_or_byte2 < 0x80
14145 ? 0 /* 0x20..0x7F */
8ff102bd 14146 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
14147 : 1) /* 0xA0..0xFF */
14148 /* 2-byte font */
14149 : (font->min_byte1 < 0x80
14150 ? (font->max_byte1 < 0x80
14151 ? (font->min_char_or_byte2 < 0x80
14152 ? (font->max_char_or_byte2 < 0x80
14153 ? 0 /* 0x2020..0x7F7F */
8ff102bd 14154 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 14155 : 3) /* 0x20A0..0x7FFF */
8ff102bd 14156 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
14157 : (font->min_char_or_byte2 < 0x80
14158 ? (font->max_char_or_byte2 < 0x80
14159 ? 2 /* 0xA020..0xFF7F */
8ff102bd 14160 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
14161 : 1))); /* 0xA0A0..0xFFFF */
14162
14163 fontp->baseline_offset
14164 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
14165 ? (long) value : 0);
14166 fontp->relative_compose
14167 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
14168 ? (long) value : 0);
f78798df
KH
14169 fontp->default_ascent
14170 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
14171 ? (long) value : 0);
dc43ef94 14172
06a2c219
GM
14173 /* Set global flag fonts_changed_p to non-zero if the font loaded
14174 has a character with a smaller width than any other character
14175 before, or if the font loaded has a smalle>r height than any
14176 other font loaded before. If this happens, it will make a
14177 glyph matrix reallocation necessary. */
14178 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 14179 UNBLOCK_INPUT;
dc43ef94
KH
14180 return fontp;
14181 }
14182}
14183
06a2c219
GM
14184
14185/* Return a pointer to struct font_info of a font named FONTNAME for
14186 frame F. If no such font is loaded, return NULL. */
14187
dc43ef94
KH
14188struct font_info *
14189x_query_font (f, fontname)
14190 struct frame *f;
14191 register char *fontname;
14192{
14193 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14194 int i;
14195
14196 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
14197 if (dpyinfo->font_table[i].name
14198 && (!strcmp (dpyinfo->font_table[i].name, fontname)
14199 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
14200 return (dpyinfo->font_table + i);
14201 return NULL;
14202}
14203
06a2c219
GM
14204
14205/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
14206 `encoder' of the structure. */
14207
14208void
14209x_find_ccl_program (fontp)
14210 struct font_info *fontp;
14211{
a42f54e6 14212 Lisp_Object list, elt;
a6582676 14213
f9b5db02 14214 elt = Qnil;
8e713be6 14215 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 14216 {
8e713be6 14217 elt = XCAR (list);
a6582676 14218 if (CONSP (elt)
8e713be6 14219 && STRINGP (XCAR (elt))
9f2feff6
KH
14220 && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
14221 >= 0)
14222 || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
14223 >= 0)))
a42f54e6
KH
14224 break;
14225 }
f9b5db02 14226
a42f54e6
KH
14227 if (! NILP (list))
14228 {
d27f8ca7
KH
14229 struct ccl_program *ccl
14230 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 14231
8e713be6 14232 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
14233 xfree (ccl);
14234 else
14235 fontp->font_encoder = ccl;
a6582676
KH
14236 }
14237}
14238
06a2c219 14239
dc43ef94 14240\f
06a2c219
GM
14241/***********************************************************************
14242 Initialization
14243 ***********************************************************************/
f451eb13 14244
3afe33e7
RS
14245#ifdef USE_X_TOOLKIT
14246static XrmOptionDescRec emacs_options[] = {
14247 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
14248 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
14249
14250 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
14251 XrmoptionSepArg, NULL},
14252 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
14253
14254 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14255 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14256 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14257 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14258 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14259 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
14260 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
14261};
14262#endif /* USE_X_TOOLKIT */
14263
7a13e894
RS
14264static int x_initialized;
14265
29b38361
KH
14266#ifdef MULTI_KBOARD
14267/* Test whether two display-name strings agree up to the dot that separates
14268 the screen number from the server number. */
14269static int
14270same_x_server (name1, name2)
14271 char *name1, *name2;
14272{
14273 int seen_colon = 0;
cf591cc1
RS
14274 unsigned char *system_name = XSTRING (Vsystem_name)->data;
14275 int system_name_length = strlen (system_name);
14276 int length_until_period = 0;
14277
14278 while (system_name[length_until_period] != 0
14279 && system_name[length_until_period] != '.')
14280 length_until_period++;
14281
14282 /* Treat `unix' like an empty host name. */
14283 if (! strncmp (name1, "unix:", 5))
14284 name1 += 4;
14285 if (! strncmp (name2, "unix:", 5))
14286 name2 += 4;
14287 /* Treat this host's name like an empty host name. */
14288 if (! strncmp (name1, system_name, system_name_length)
14289 && name1[system_name_length] == ':')
14290 name1 += system_name_length;
14291 if (! strncmp (name2, system_name, system_name_length)
14292 && name2[system_name_length] == ':')
14293 name2 += system_name_length;
14294 /* Treat this host's domainless name like an empty host name. */
14295 if (! strncmp (name1, system_name, length_until_period)
14296 && name1[length_until_period] == ':')
14297 name1 += length_until_period;
14298 if (! strncmp (name2, system_name, length_until_period)
14299 && name2[length_until_period] == ':')
14300 name2 += length_until_period;
14301
29b38361
KH
14302 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
14303 {
14304 if (*name1 == ':')
14305 seen_colon++;
14306 if (seen_colon && *name1 == '.')
14307 return 1;
14308 }
14309 return (seen_colon
14310 && (*name1 == '.' || *name1 == '\0')
14311 && (*name2 == '.' || *name2 == '\0'));
14312}
14313#endif
14314
334208b7 14315struct x_display_info *
1f8255f2 14316x_term_init (display_name, xrm_option, resource_name)
334208b7 14317 Lisp_Object display_name;
1f8255f2
RS
14318 char *xrm_option;
14319 char *resource_name;
dc6f92b8 14320{
334208b7 14321 int connection;
7a13e894 14322 Display *dpy;
334208b7
RS
14323 struct x_display_info *dpyinfo;
14324 XrmDatabase xrdb;
14325
60439948
KH
14326 BLOCK_INPUT;
14327
7a13e894
RS
14328 if (!x_initialized)
14329 {
14330 x_initialize ();
14331 x_initialized = 1;
14332 }
dc6f92b8 14333
3afe33e7 14334#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
14335 /* weiner@footloose.sps.mot.com reports that this causes
14336 errors with X11R5:
14337 X protocol error: BadAtom (invalid Atom parameter)
14338 on protocol request 18skiloaf.
14339 So let's not use it until R6. */
14340#ifdef HAVE_X11XTR6
bdcd49ba
RS
14341 XtSetLanguageProc (NULL, NULL, NULL);
14342#endif
14343
7f9c7f94
RS
14344 {
14345 int argc = 0;
14346 char *argv[3];
14347
14348 argv[0] = "";
14349 argc = 1;
14350 if (xrm_option)
14351 {
14352 argv[argc++] = "-xrm";
14353 argv[argc++] = xrm_option;
14354 }
14355 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
14356 resource_name, EMACS_CLASS,
14357 emacs_options, XtNumber (emacs_options),
14358 &argc, argv);
39d8bb4d
KH
14359
14360#ifdef HAVE_X11XTR6
10537cb1 14361 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 14362 fixup_locale ();
39d8bb4d 14363#endif
7f9c7f94 14364 }
3afe33e7
RS
14365
14366#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
14367#ifdef HAVE_X11R5
14368 XSetLocaleModifiers ("");
14369#endif
7a13e894 14370 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 14371#endif /* not USE_X_TOOLKIT */
334208b7 14372
7a13e894
RS
14373 /* Detect failure. */
14374 if (dpy == 0)
60439948
KH
14375 {
14376 UNBLOCK_INPUT;
14377 return 0;
14378 }
7a13e894
RS
14379
14380 /* We have definitely succeeded. Record the new connection. */
14381
14382 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
f04e1297 14383 bzero (dpyinfo, sizeof *dpyinfo);
7a13e894 14384
29b38361
KH
14385#ifdef MULTI_KBOARD
14386 {
14387 struct x_display_info *share;
14388 Lisp_Object tail;
14389
14390 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
14391 share = share->next, tail = XCDR (tail))
14392 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
14393 XSTRING (display_name)->data))
14394 break;
14395 if (share)
14396 dpyinfo->kboard = share->kboard;
14397 else
14398 {
14399 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
14400 init_kboard (dpyinfo->kboard);
59e755be
KH
14401 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
14402 {
14403 char *vendor = ServerVendor (dpy);
9b6ed9f3 14404 UNBLOCK_INPUT;
59e755be
KH
14405 dpyinfo->kboard->Vsystem_key_alist
14406 = call1 (Qvendor_specific_keysyms,
14407 build_string (vendor ? vendor : ""));
9b6ed9f3 14408 BLOCK_INPUT;
59e755be
KH
14409 }
14410
29b38361
KH
14411 dpyinfo->kboard->next_kboard = all_kboards;
14412 all_kboards = dpyinfo->kboard;
0ad5446c
KH
14413 /* Don't let the initial kboard remain current longer than necessary.
14414 That would cause problems if a file loaded on startup tries to
06a2c219 14415 prompt in the mini-buffer. */
0ad5446c
KH
14416 if (current_kboard == initial_kboard)
14417 current_kboard = dpyinfo->kboard;
29b38361
KH
14418 }
14419 dpyinfo->kboard->reference_count++;
14420 }
b9737ad3
KH
14421#endif
14422
7a13e894
RS
14423 /* Put this display on the chain. */
14424 dpyinfo->next = x_display_list;
14425 x_display_list = dpyinfo;
14426
14427 /* Put it on x_display_name_list as well, to keep them parallel. */
14428 x_display_name_list = Fcons (Fcons (display_name, Qnil),
14429 x_display_name_list);
8e713be6 14430 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
14431
14432 dpyinfo->display = dpy;
dc6f92b8 14433
dc6f92b8 14434#if 0
7a13e894 14435 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 14436#endif /* ! 0 */
7a13e894
RS
14437
14438 dpyinfo->x_id_name
fc932ac6
RS
14439 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
14440 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
14441 + 2);
14442 sprintf (dpyinfo->x_id_name, "%s@%s",
14443 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
14444
14445 /* Figure out which modifier bits mean what. */
334208b7 14446 x_find_modifier_meanings (dpyinfo);
f451eb13 14447
ab648270 14448 /* Get the scroll bar cursor. */
7a13e894 14449 dpyinfo->vertical_scroll_bar_cursor
334208b7 14450 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 14451
334208b7
RS
14452 xrdb = x_load_resources (dpyinfo->display, xrm_option,
14453 resource_name, EMACS_CLASS);
14454#ifdef HAVE_XRMSETDATABASE
14455 XrmSetDatabase (dpyinfo->display, xrdb);
14456#else
14457 dpyinfo->display->db = xrdb;
14458#endif
547d9db8 14459 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
14460 all versions. */
14461 dpyinfo->xrdb = xrdb;
334208b7
RS
14462
14463 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
14464 DefaultScreen (dpyinfo->display));
5ff67d81 14465 select_visual (dpyinfo);
43bd1b2b 14466 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
14467 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
14468 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
14469 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
14470 dpyinfo->grabbed = 0;
14471 dpyinfo->reference_count = 0;
14472 dpyinfo->icon_bitmap_id = -1;
06a2c219 14473 dpyinfo->font_table = NULL;
7a13e894
RS
14474 dpyinfo->n_fonts = 0;
14475 dpyinfo->font_table_size = 0;
14476 dpyinfo->bitmaps = 0;
14477 dpyinfo->bitmaps_size = 0;
14478 dpyinfo->bitmaps_last = 0;
14479 dpyinfo->scratch_cursor_gc = 0;
14480 dpyinfo->mouse_face_mouse_frame = 0;
14481 dpyinfo->mouse_face_deferred_gc = 0;
14482 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
14483 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 14484 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894 14485 dpyinfo->mouse_face_window = Qnil;
0a61c667 14486 dpyinfo->mouse_face_overlay = Qnil;
7a13e894
RS
14487 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
14488 dpyinfo->mouse_face_defer = 0;
0f941935
KH
14489 dpyinfo->x_focus_frame = 0;
14490 dpyinfo->x_focus_event_frame = 0;
14491 dpyinfo->x_highlight_frame = 0;
06a2c219 14492 dpyinfo->image_cache = make_image_cache ();
334208b7 14493
43bd1b2b 14494 /* See if a private colormap is requested. */
5ff67d81
GM
14495 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
14496 {
14497 if (dpyinfo->visual->class == PseudoColor)
14498 {
14499 Lisp_Object value;
14500 value = display_x_get_resource (dpyinfo,
14501 build_string ("privateColormap"),
14502 build_string ("PrivateColormap"),
14503 Qnil, Qnil);
14504 if (STRINGP (value)
14505 && (!strcmp (XSTRING (value)->data, "true")
14506 || !strcmp (XSTRING (value)->data, "on")))
14507 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
14508 }
43bd1b2b 14509 }
5ff67d81
GM
14510 else
14511 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
14512 dpyinfo->visual, AllocNone);
43bd1b2b 14513
06a2c219
GM
14514 {
14515 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
14516 double pixels = DisplayHeight (dpyinfo->display, screen_number);
14517 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
14518 dpyinfo->resy = pixels * 25.4 / mm;
14519 pixels = DisplayWidth (dpyinfo->display, screen_number);
14520 mm = DisplayWidthMM (dpyinfo->display, screen_number);
14521 dpyinfo->resx = pixels * 25.4 / mm;
14522 }
14523
334208b7
RS
14524 dpyinfo->Xatom_wm_protocols
14525 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
14526 dpyinfo->Xatom_wm_take_focus
14527 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
14528 dpyinfo->Xatom_wm_save_yourself
14529 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
14530 dpyinfo->Xatom_wm_delete_window
14531 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
14532 dpyinfo->Xatom_wm_change_state
14533 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
14534 dpyinfo->Xatom_wm_configure_denied
14535 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
14536 dpyinfo->Xatom_wm_window_moved
14537 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
14538 dpyinfo->Xatom_editres
14539 = XInternAtom (dpyinfo->display, "Editres", False);
14540 dpyinfo->Xatom_CLIPBOARD
14541 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
14542 dpyinfo->Xatom_TIMESTAMP
14543 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
14544 dpyinfo->Xatom_TEXT
14545 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
14546 dpyinfo->Xatom_COMPOUND_TEXT
14547 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
14548 dpyinfo->Xatom_DELETE
14549 = XInternAtom (dpyinfo->display, "DELETE", False);
14550 dpyinfo->Xatom_MULTIPLE
14551 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
14552 dpyinfo->Xatom_INCR
14553 = XInternAtom (dpyinfo->display, "INCR", False);
14554 dpyinfo->Xatom_EMACS_TMP
14555 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
14556 dpyinfo->Xatom_TARGETS
14557 = XInternAtom (dpyinfo->display, "TARGETS", False);
14558 dpyinfo->Xatom_NULL
14559 = XInternAtom (dpyinfo->display, "NULL", False);
14560 dpyinfo->Xatom_ATOM_PAIR
14561 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
14562 /* For properties of font. */
14563 dpyinfo->Xatom_PIXEL_SIZE
14564 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
14565 dpyinfo->Xatom_MULE_BASELINE_OFFSET
14566 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
14567 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
14568 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
14569 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
14570 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 14571
06a2c219
GM
14572 /* Ghostscript support. */
14573 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
14574 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
14575
14576 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
14577 False);
14578
547d9db8
KH
14579 dpyinfo->cut_buffers_initialized = 0;
14580
334208b7
RS
14581 connection = ConnectionNumber (dpyinfo->display);
14582 dpyinfo->connection = connection;
14583
dc43ef94 14584 {
5d7cc324
RS
14585 char null_bits[1];
14586
14587 null_bits[0] = 0x00;
dc43ef94
KH
14588
14589 dpyinfo->null_pixel
14590 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14591 null_bits, 1, 1, (long) 0, (long) 0,
14592 1);
14593 }
14594
06a2c219
GM
14595 {
14596 extern int gray_bitmap_width, gray_bitmap_height;
10659c77 14597 extern char *gray_bitmap_bits;
06a2c219
GM
14598 dpyinfo->gray
14599 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14600 gray_bitmap_bits,
14601 gray_bitmap_width, gray_bitmap_height,
14602 (unsigned long) 1, (unsigned long) 0, 1);
14603 }
14604
f5d11644
GM
14605#ifdef HAVE_X_I18N
14606 xim_initialize (dpyinfo, resource_name);
14607#endif
14608
87485d6f
MW
14609#ifdef subprocesses
14610 /* This is only needed for distinguishing keyboard and process input. */
334208b7 14611 if (connection != 0)
7a13e894 14612 add_keyboard_wait_descriptor (connection);
87485d6f 14613#endif
6d4238f3 14614
041b69ac 14615#ifndef F_SETOWN_BUG
dc6f92b8 14616#ifdef F_SETOWN
dc6f92b8 14617#ifdef F_SETOWN_SOCK_NEG
61c3ce62 14618 /* stdin is a socket here */
334208b7 14619 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 14620#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 14621 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
14622#endif /* ! defined (F_SETOWN_SOCK_NEG) */
14623#endif /* ! defined (F_SETOWN) */
041b69ac 14624#endif /* F_SETOWN_BUG */
dc6f92b8
JB
14625
14626#ifdef SIGIO
eee20f6a
KH
14627 if (interrupt_input)
14628 init_sigio (connection);
c118dd06 14629#endif /* ! defined (SIGIO) */
dc6f92b8 14630
51b592fb 14631#ifdef USE_LUCID
f8c39f51 14632#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
14633 /* Make sure that we have a valid font for dialog boxes
14634 so that Xt does not crash. */
14635 {
14636 Display *dpy = dpyinfo->display;
14637 XrmValue d, fr, to;
14638 Font font;
e99db5a1 14639 int count;
51b592fb
RS
14640
14641 d.addr = (XPointer)&dpy;
14642 d.size = sizeof (Display *);
14643 fr.addr = XtDefaultFont;
14644 fr.size = sizeof (XtDefaultFont);
14645 to.size = sizeof (Font *);
14646 to.addr = (XPointer)&font;
e99db5a1 14647 count = x_catch_errors (dpy);
51b592fb
RS
14648 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
14649 abort ();
14650 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
14651 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 14652 x_uncatch_errors (dpy, count);
51b592fb
RS
14653 }
14654#endif
f8c39f51 14655#endif
51b592fb 14656
34e23e5a
GM
14657 /* See if we should run in synchronous mode. This is useful
14658 for debugging X code. */
14659 {
14660 Lisp_Object value;
14661 value = display_x_get_resource (dpyinfo,
14662 build_string ("synchronous"),
14663 build_string ("Synchronous"),
14664 Qnil, Qnil);
14665 if (STRINGP (value)
14666 && (!strcmp (XSTRING (value)->data, "true")
14667 || !strcmp (XSTRING (value)->data, "on")))
14668 XSynchronize (dpyinfo->display, True);
14669 }
14670
60439948
KH
14671 UNBLOCK_INPUT;
14672
7a13e894
RS
14673 return dpyinfo;
14674}
14675\f
14676/* Get rid of display DPYINFO, assuming all frames are already gone,
14677 and without sending any more commands to the X server. */
dc6f92b8 14678
7a13e894
RS
14679void
14680x_delete_display (dpyinfo)
14681 struct x_display_info *dpyinfo;
14682{
14683 delete_keyboard_wait_descriptor (dpyinfo->connection);
14684
14685 /* Discard this display from x_display_name_list and x_display_list.
14686 We can't use Fdelq because that can quit. */
14687 if (! NILP (x_display_name_list)
8e713be6
KR
14688 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
14689 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
14690 else
14691 {
14692 Lisp_Object tail;
14693
14694 tail = x_display_name_list;
8e713be6 14695 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 14696 {
bffcfca9 14697 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 14698 {
f3fbd155 14699 XSETCDR (tail, XCDR (XCDR (tail)));
7a13e894
RS
14700 break;
14701 }
8e713be6 14702 tail = XCDR (tail);
7a13e894
RS
14703 }
14704 }
14705
9bda743f
GM
14706 if (next_noop_dpyinfo == dpyinfo)
14707 next_noop_dpyinfo = dpyinfo->next;
14708
7a13e894
RS
14709 if (x_display_list == dpyinfo)
14710 x_display_list = dpyinfo->next;
7f9c7f94
RS
14711 else
14712 {
14713 struct x_display_info *tail;
7a13e894 14714
7f9c7f94
RS
14715 for (tail = x_display_list; tail; tail = tail->next)
14716 if (tail->next == dpyinfo)
14717 tail->next = tail->next->next;
14718 }
7a13e894 14719
0d777288
RS
14720#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
14721#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
14722 XrmDestroyDatabase (dpyinfo->xrdb);
14723#endif
0d777288 14724#endif
29b38361
KH
14725#ifdef MULTI_KBOARD
14726 if (--dpyinfo->kboard->reference_count == 0)
39f79001 14727 delete_kboard (dpyinfo->kboard);
b9737ad3 14728#endif
f5d11644
GM
14729#ifdef HAVE_X_I18N
14730 if (dpyinfo->xim)
14731 xim_close_dpy (dpyinfo);
14732#endif
14733
b9737ad3
KH
14734 xfree (dpyinfo->font_table);
14735 xfree (dpyinfo->x_id_name);
f04e1297 14736 xfree (dpyinfo->color_cells);
b9737ad3 14737 xfree (dpyinfo);
7a13e894 14738}
f04e1297 14739
7a13e894
RS
14740\f
14741/* Set up use of X before we make the first connection. */
14742
06a2c219
GM
14743static struct redisplay_interface x_redisplay_interface =
14744{
14745 x_produce_glyphs,
14746 x_write_glyphs,
14747 x_insert_glyphs,
14748 x_clear_end_of_line,
14749 x_scroll_run,
14750 x_after_update_window_line,
14751 x_update_window_begin,
14752 x_update_window_end,
14753 XTcursor_to,
14754 x_flush,
71b8321e 14755 x_clear_mouse_face,
66ac4b0e
GM
14756 x_get_glyph_overhangs,
14757 x_fix_overlapping_area
06a2c219
GM
14758};
14759
dfcf069d 14760void
7a13e894
RS
14761x_initialize ()
14762{
06a2c219
GM
14763 rif = &x_redisplay_interface;
14764
14765 clear_frame_hook = x_clear_frame;
14766 ins_del_lines_hook = x_ins_del_lines;
06a2c219 14767 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
14768 ring_bell_hook = XTring_bell;
14769 reset_terminal_modes_hook = XTreset_terminal_modes;
14770 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
14771 update_begin_hook = x_update_begin;
14772 update_end_hook = x_update_end;
dc6f92b8
JB
14773 set_terminal_window_hook = XTset_terminal_window;
14774 read_socket_hook = XTread_socket;
b8009dd1 14775 frame_up_to_date_hook = XTframe_up_to_date;
90e65f07 14776 mouse_position_hook = XTmouse_position;
f451eb13 14777 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 14778 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
14779 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
14780 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
14781 redeem_scroll_bar_hook = XTredeem_scroll_bar;
14782 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 14783 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 14784
f676886a 14785 scroll_region_ok = 1; /* we'll scroll partial frames */
9017309f 14786 char_ins_del_ok = 1;
dc6f92b8
JB
14787 line_ins_del_ok = 1; /* we'll just blt 'em */
14788 fast_clear_end_of_line = 1; /* X does this well */
58769bee 14789 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
14790 off the bottom */
14791 baud_rate = 19200;
14792
7a13e894 14793 x_noop_count = 0;
9ea173e8 14794 last_tool_bar_item = -1;
06a2c219
GM
14795 any_help_event_p = 0;
14796
b30b24cb
RS
14797 /* Try to use interrupt input; if we can't, then start polling. */
14798 Fset_input_mode (Qt, Qnil, Qt, Qnil);
14799
7f9c7f94
RS
14800#ifdef USE_X_TOOLKIT
14801 XtToolkitInitialize ();
651f03b6 14802
7f9c7f94 14803 Xt_app_con = XtCreateApplicationContext ();
651f03b6
GM
14804
14805 /* Register a converter from strings to pixels, which uses
14806 Emacs' color allocation infrastructure. */
14807 XtAppSetTypeConverter (Xt_app_con,
14808 XtRString, XtRPixel, cvt_string_to_pixel,
14809 cvt_string_to_pixel_args,
14810 XtNumber (cvt_string_to_pixel_args),
14811 XtCacheByDisplay, cvt_pixel_dtor);
14812
665881ad 14813 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
14814
14815 /* Install an asynchronous timer that processes Xt timeout events
14816 every 0.1s. This is necessary because some widget sets use
14817 timeouts internally, for example the LessTif menu bar, or the
14818 Xaw3d scroll bar. When Xt timouts aren't processed, these
14819 widgets don't behave normally. */
14820 {
14821 EMACS_TIME interval;
14822 EMACS_SET_SECS_USECS (interval, 0, 100000);
14823 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
14824 }
db74249b 14825#endif
bffcfca9 14826
eccc05db 14827#ifdef USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
14828 xaw3d_arrow_scroll = False;
14829 xaw3d_pick_top = True;
7f9c7f94
RS
14830#endif
14831
58769bee 14832 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 14833 original error handler. */
e99db5a1 14834 XSetErrorHandler (x_error_handler);
334208b7 14835 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 14836
06a2c219 14837 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
14838#ifdef SIGWINCH
14839 signal (SIGWINCH, SIG_DFL);
c118dd06 14840#endif /* ! defined (SIGWINCH) */
dc6f92b8 14841
92e2441b 14842 signal (SIGPIPE, x_connection_signal);
dc6f92b8 14843}
55123275 14844
06a2c219 14845
55123275
JB
14846void
14847syms_of_xterm ()
14848{
e99db5a1
RS
14849 staticpro (&x_error_message_string);
14850 x_error_message_string = Qnil;
14851
7a13e894
RS
14852 staticpro (&x_display_name_list);
14853 x_display_name_list = Qnil;
334208b7 14854
ab648270 14855 staticpro (&last_mouse_scroll_bar);
e53cb100 14856 last_mouse_scroll_bar = Qnil;
59e755be
KH
14857
14858 staticpro (&Qvendor_specific_keysyms);
14859 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
14860
14861 staticpro (&last_mouse_press_frame);
14862 last_mouse_press_frame = Qnil;
06a2c219 14863
06a2c219 14864 help_echo = Qnil;
be010514
GM
14865 staticpro (&help_echo);
14866 help_echo_object = Qnil;
14867 staticpro (&help_echo_object);
7cea38bc
GM
14868 help_echo_window = Qnil;
14869 staticpro (&help_echo_window);
06a2c219 14870 previous_help_echo = Qnil;
be010514
GM
14871 staticpro (&previous_help_echo);
14872 help_echo_pos = -1;
06a2c219 14873
7ee72033
MB
14874 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
14875 doc: /* *Non-nil means draw block cursor as wide as the glyph under it.
228299fa
GM
14876For example, if a block cursor is over a tab, it will be drawn as
14877wide as that tab on the display. */);
06a2c219
GM
14878 x_stretch_cursor_p = 0;
14879
a72d5ce5 14880 DEFVAR_BOOL ("x-use-underline-position-properties",
7ee72033
MB
14881 &x_use_underline_position_properties,
14882 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
f0529b5b 14883nil means ignore them. If you encounter fonts with bogus
228299fa
GM
14884UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
14885to 4.1, set this to nil. */);
a72d5ce5
GM
14886 x_use_underline_position_properties = 1;
14887
7ee72033
MB
14888 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
14889 doc: /* What X toolkit scroll bars Emacs uses.
228299fa
GM
14890A value of nil means Emacs doesn't use X toolkit scroll bars.
14891Otherwise, value is a symbol describing the X toolkit. */);
eccc05db 14892#ifdef USE_TOOLKIT_SCROLL_BARS
5bf04520
GM
14893#ifdef USE_MOTIF
14894 Vx_toolkit_scroll_bars = intern ("motif");
14895#elif defined HAVE_XAW3D
14896 Vx_toolkit_scroll_bars = intern ("xaw3d");
14897#else
14898 Vx_toolkit_scroll_bars = intern ("xaw");
14899#endif
06a2c219 14900#else
5bf04520 14901 Vx_toolkit_scroll_bars = Qnil;
06a2c219
GM
14902#endif
14903
06a2c219
GM
14904 staticpro (&last_mouse_motion_frame);
14905 last_mouse_motion_frame = Qnil;
55123275 14906}
6cf0ae86 14907
1d6c120a 14908#endif /* HAVE_X_WINDOWS */