Restore the quote in the `silly' example.
[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
269b7745 1611 5. `:relative-height FACTOR' specifies that the height of the
06a2c219
GM
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 3839 else if (s->first_glyph->type == IMAGE_GLYPH
0cb8bb48 3840 && s->img->pixmap
e2a57b34
MB
3841 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3842 color = IMAGE_BACKGROUND (s->img, s->f, 0);
06a2c219
GM
3843 else
3844 {
3845 XGCValues xgcv;
3846
3847 /* Get the background color of the face. */
3848 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3849 color = xgcv.background;
3850 }
3851
3852 if (di->white_relief.gc == 0
3853 || color != di->relief_background)
3854 {
3855 di->relief_background = color;
3856 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3857 WHITE_PIX_DEFAULT (s->f));
3858 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3859 BLACK_PIX_DEFAULT (s->f));
3860 }
3861}
3862
3863
3864/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3865 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3866 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3867 relief. LEFT_P non-zero means draw a relief on the left side of
3868 the rectangle. RIGHT_P non-zero means draw a relief on the right
3869 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3870 when drawing. */
3871
3872static void
3873x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3874 raised_p, left_p, right_p, clip_rect)
3875 struct frame *f;
3876 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3877 XRectangle *clip_rect;
3878{
de507556
GM
3879 Display *dpy = FRAME_X_DISPLAY (f);
3880 Window window = FRAME_X_WINDOW (f);
06a2c219
GM
3881 int i;
3882 GC gc;
3883
3884 if (raised_p)
3885 gc = f->output_data.x->white_relief.gc;
3886 else
3887 gc = f->output_data.x->black_relief.gc;
de507556 3888 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3889
3890 /* Top. */
3891 for (i = 0; i < width; ++i)
de507556 3892 XDrawLine (dpy, window, gc,
06a2c219
GM
3893 left_x + i * left_p, top_y + i,
3894 right_x + 1 - i * right_p, top_y + i);
3895
3896 /* Left. */
3897 if (left_p)
3898 for (i = 0; i < width; ++i)
de507556 3899 XDrawLine (dpy, window, gc,
44655e77 3900 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
06a2c219 3901
de507556 3902 XSetClipMask (dpy, gc, None);
06a2c219
GM
3903 if (raised_p)
3904 gc = f->output_data.x->black_relief.gc;
3905 else
3906 gc = f->output_data.x->white_relief.gc;
de507556 3907 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3908
3909 /* Bottom. */
3910 for (i = 0; i < width; ++i)
de507556
GM
3911 XDrawLine (dpy, window, gc,
3912 left_x + i * left_p, bottom_y - i,
327f42ee 3913 right_x + 1 - i * right_p, bottom_y - i);
06a2c219
GM
3914
3915 /* Right. */
3916 if (right_p)
3917 for (i = 0; i < width; ++i)
de507556 3918 XDrawLine (dpy, window, gc,
06a2c219
GM
3919 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3920
de507556 3921 XSetClipMask (dpy, gc, None);
06a2c219
GM
3922}
3923
3924
3925/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3926 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3927 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3928 left side of the rectangle. RIGHT_P non-zero means draw a line
3929 on the right side of the rectangle. CLIP_RECT is the clipping
3930 rectangle to use when drawing. */
3931
3932static void
3933x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3934 left_p, right_p, clip_rect)
3935 struct glyph_string *s;
3936 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3937 XRectangle *clip_rect;
3938{
3939 XGCValues xgcv;
3940
3941 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3942 XSetForeground (s->display, s->gc, s->face->box_color);
3943 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3944
3945 /* Top. */
3946 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3947 left_x, top_y, right_x - left_x + 1, width);
06a2c219
GM
3948
3949 /* Left. */
3950 if (left_p)
3951 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3952 left_x, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3953
3954 /* Bottom. */
3955 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3956 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
06a2c219
GM
3957
3958 /* Right. */
3959 if (right_p)
3960 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3961 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3962
3963 XSetForeground (s->display, s->gc, xgcv.foreground);
3964 XSetClipMask (s->display, s->gc, None);
3965}
3966
3967
3968/* Draw a box around glyph string S. */
3969
3970static void
3971x_draw_glyph_string_box (s)
3972 struct glyph_string *s;
3973{
3974 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3975 int left_p, right_p;
3976 struct glyph *last_glyph;
3977 XRectangle clip_rect;
3978
3979 last_x = window_box_right (s->w, s->area);
3980 if (s->row->full_width_p
3981 && !s->w->pseudo_window_p)
3982 {
3f332ef3 3983 last_x += FRAME_X_RIGHT_FRINGE_WIDTH (s->f);
06a2c219
GM
3984 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3985 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3986 }
3987
3988 /* The glyph that may have a right box line. */
b4192550 3989 last_glyph = (s->cmp || s->img
06a2c219
GM
3990 ? s->first_glyph
3991 : s->first_glyph + s->nchars - 1);
3992
ea2ba0d4 3993 width = abs (s->face->box_line_width);
06a2c219
GM
3994 raised_p = s->face->box == FACE_RAISED_BOX;
3995 left_x = s->x;
57ac7c81
GM
3996 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
3997 ? last_x - 1
3998 : min (last_x, s->x + s->background_width) - 1);
06a2c219
GM
3999 top_y = s->y;
4000 bottom_y = top_y + s->height - 1;
4001
4002 left_p = (s->first_glyph->left_box_line_p
4003 || (s->hl == DRAW_MOUSE_FACE
4004 && (s->prev == NULL
4005 || s->prev->hl != s->hl)));
4006 right_p = (last_glyph->right_box_line_p
4007 || (s->hl == DRAW_MOUSE_FACE
4008 && (s->next == NULL
4009 || s->next->hl != s->hl)));
327f42ee 4010
06a2c219
GM
4011 x_get_glyph_string_clip_rect (s, &clip_rect);
4012
4013 if (s->face->box == FACE_SIMPLE_BOX)
4014 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4015 left_p, right_p, &clip_rect);
4016 else
4017 {
4018 x_setup_relief_colors (s);
4019 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
4020 width, raised_p, left_p, right_p, &clip_rect);
4021 }
4022}
4023
4024
4025/* Draw foreground of image glyph string S. */
4026
4027static void
4028x_draw_image_foreground (s)
4029 struct glyph_string *s;
4030{
4031 int x;
95af8492 4032 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4033
4034 /* If first glyph of S has a left box line, start drawing it to the
4035 right of that line. */
4036 if (s->face->box != FACE_NO_BOX
4037 && s->first_glyph->left_box_line_p)
ea2ba0d4 4038 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4039 else
4040 x = s->x;
4041
4042 /* If there is a margin around the image, adjust x- and y-position
4043 by that margin. */
22d650b8
GM
4044 x += s->img->hmargin;
4045 y += s->img->vmargin;
06a2c219
GM
4046
4047 if (s->img->pixmap)
4048 {
4049 if (s->img->mask)
4050 {
4051 /* We can't set both a clip mask and use XSetClipRectangles
4052 because the latter also sets a clip mask. We also can't
4053 trust on the shape extension to be available
4054 (XShapeCombineRegion). So, compute the rectangle to draw
4055 manually. */
4056 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4057 | GCFunction);
4058 XGCValues xgcv;
4059 XRectangle clip_rect, image_rect, r;
4060
4061 xgcv.clip_mask = s->img->mask;
4062 xgcv.clip_x_origin = x;
4063 xgcv.clip_y_origin = y;
4064 xgcv.function = GXcopy;
4065 XChangeGC (s->display, s->gc, mask, &xgcv);
4066
4067 x_get_glyph_string_clip_rect (s, &clip_rect);
4068 image_rect.x = x;
4069 image_rect.y = y;
4070 image_rect.width = s->img->width;
4071 image_rect.height = s->img->height;
4072 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4073 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4074 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
4075 }
4076 else
4077 {
49ad1d99
GM
4078 XRectangle clip_rect, image_rect, r;
4079
4080 x_get_glyph_string_clip_rect (s, &clip_rect);
4081 image_rect.x = x;
4082 image_rect.y = y;
4083 image_rect.width = s->img->width;
4084 image_rect.height = s->img->height;
4085 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4086 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4087 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
06a2c219
GM
4088
4089 /* When the image has a mask, we can expect that at
4090 least part of a mouse highlight or a block cursor will
4091 be visible. If the image doesn't have a mask, make
4092 a block cursor visible by drawing a rectangle around
4093 the image. I believe it's looking better if we do
4094 nothing here for mouse-face. */
4095 if (s->hl == DRAW_CURSOR)
4096 XDrawRectangle (s->display, s->window, s->gc, x, y,
4097 s->img->width - 1, s->img->height - 1);
4098 }
4099 }
4100 else
4101 /* Draw a rectangle if image could not be loaded. */
4102 XDrawRectangle (s->display, s->window, s->gc, x, y,
4103 s->img->width - 1, s->img->height - 1);
4104}
4105
4106
4107/* Draw a relief around the image glyph string S. */
4108
4109static void
4110x_draw_image_relief (s)
4111 struct glyph_string *s;
4112{
4113 int x0, y0, x1, y1, thick, raised_p;
4114 XRectangle r;
4115 int x;
95af8492 4116 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4117
4118 /* If first glyph of S has a left box line, start drawing it to the
4119 right of that line. */
4120 if (s->face->box != FACE_NO_BOX
4121 && s->first_glyph->left_box_line_p)
ea2ba0d4 4122 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4123 else
4124 x = s->x;
4125
4126 /* If there is a margin around the image, adjust x- and y-position
4127 by that margin. */
22d650b8
GM
4128 x += s->img->hmargin;
4129 y += s->img->vmargin;
06a2c219
GM
4130
4131 if (s->hl == DRAW_IMAGE_SUNKEN
4132 || s->hl == DRAW_IMAGE_RAISED)
4133 {
62854fe2 4134 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
06a2c219
GM
4135 raised_p = s->hl == DRAW_IMAGE_RAISED;
4136 }
4137 else
4138 {
4139 thick = abs (s->img->relief);
4140 raised_p = s->img->relief > 0;
4141 }
4142
4143 x0 = x - thick;
4144 y0 = y - thick;
4145 x1 = x + s->img->width + thick - 1;
4146 y1 = y + s->img->height + thick - 1;
4147
4148 x_setup_relief_colors (s);
4149 x_get_glyph_string_clip_rect (s, &r);
4150 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
4151}
4152
4153
4154/* Draw the foreground of image glyph string S to PIXMAP. */
4155
4156static void
4157x_draw_image_foreground_1 (s, pixmap)
4158 struct glyph_string *s;
4159 Pixmap pixmap;
4160{
4161 int x;
95af8492 4162 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
4163
4164 /* If first glyph of S has a left box line, start drawing it to the
4165 right of that line. */
4166 if (s->face->box != FACE_NO_BOX
4167 && s->first_glyph->left_box_line_p)
ea2ba0d4 4168 x = abs (s->face->box_line_width);
06a2c219
GM
4169 else
4170 x = 0;
4171
4172 /* If there is a margin around the image, adjust x- and y-position
4173 by that margin. */
22d650b8
GM
4174 x += s->img->hmargin;
4175 y += s->img->vmargin;
dc43ef94 4176
06a2c219
GM
4177 if (s->img->pixmap)
4178 {
4179 if (s->img->mask)
4180 {
4181 /* We can't set both a clip mask and use XSetClipRectangles
4182 because the latter also sets a clip mask. We also can't
4183 trust on the shape extension to be available
4184 (XShapeCombineRegion). So, compute the rectangle to draw
4185 manually. */
4186 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4187 | GCFunction);
4188 XGCValues xgcv;
4189
4190 xgcv.clip_mask = s->img->mask;
4191 xgcv.clip_x_origin = x;
4192 xgcv.clip_y_origin = y;
4193 xgcv.function = GXcopy;
4194 XChangeGC (s->display, s->gc, mask, &xgcv);
4195
4196 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4197 0, 0, s->img->width, s->img->height, x, y);
4198 XSetClipMask (s->display, s->gc, None);
4199 }
4200 else
4201 {
4202 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4203 0, 0, s->img->width, s->img->height, x, y);
4204
4205 /* When the image has a mask, we can expect that at
4206 least part of a mouse highlight or a block cursor will
4207 be visible. If the image doesn't have a mask, make
4208 a block cursor visible by drawing a rectangle around
4209 the image. I believe it's looking better if we do
4210 nothing here for mouse-face. */
4211 if (s->hl == DRAW_CURSOR)
4212 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4213 s->img->width - 1, s->img->height - 1);
4214 }
4215 }
4216 else
4217 /* Draw a rectangle if image could not be loaded. */
4218 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4219 s->img->width - 1, s->img->height - 1);
4220}
dc43ef94 4221
990ba854 4222
06a2c219
GM
4223/* Draw part of the background of glyph string S. X, Y, W, and H
4224 give the rectangle to draw. */
a9a5b0a5 4225
06a2c219
GM
4226static void
4227x_draw_glyph_string_bg_rect (s, x, y, w, h)
4228 struct glyph_string *s;
4229 int x, y, w, h;
4230{
4231 if (s->stippled_p)
4232 {
4233 /* Fill background with a stipple pattern. */
4234 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4235 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4236 XSetFillStyle (s->display, s->gc, FillSolid);
4237 }
4238 else
4239 x_clear_glyph_string_rect (s, x, y, w, h);
4240}
07e34cb0 4241
b5210ea7 4242
06a2c219 4243/* Draw image glyph string S.
dc43ef94 4244
06a2c219
GM
4245 s->y
4246 s->x +-------------------------
4247 | s->face->box
4248 |
4249 | +-------------------------
4250 | | s->img->margin
4251 | |
4252 | | +-------------------
4253 | | | the image
dc43ef94 4254
06a2c219 4255 */
dc43ef94 4256
06a2c219
GM
4257static void
4258x_draw_image_glyph_string (s)
4259 struct glyph_string *s;
4260{
4261 int x, y;
ea2ba0d4
KH
4262 int box_line_hwidth = abs (s->face->box_line_width);
4263 int box_line_vwidth = max (s->face->box_line_width, 0);
06a2c219
GM
4264 int height;
4265 Pixmap pixmap = None;
4266
ea2ba0d4 4267 height = s->height - 2 * box_line_vwidth;
06a2c219
GM
4268
4269 /* Fill background with face under the image. Do it only if row is
4270 taller than image or if image has a clip mask to reduce
4271 flickering. */
4272 s->stippled_p = s->face->stipple != 0;
4273 if (height > s->img->height
22d650b8
GM
4274 || s->img->hmargin
4275 || s->img->vmargin
06a2c219
GM
4276 || s->img->mask
4277 || s->img->pixmap == 0
4278 || s->width != s->background_width)
4279 {
ea2ba0d4
KH
4280 if (box_line_hwidth && s->first_glyph->left_box_line_p)
4281 x = s->x + box_line_hwidth;
06a2c219
GM
4282 else
4283 x = s->x;
4284
ea2ba0d4 4285 y = s->y + box_line_vwidth;
06a2c219
GM
4286
4287 if (s->img->mask)
4288 {
f9b5db02
GM
4289 /* Create a pixmap as large as the glyph string. Fill it
4290 with the background color. Copy the image to it, using
4291 its mask. Copy the temporary pixmap to the display. */
06a2c219
GM
4292 Screen *screen = FRAME_X_SCREEN (s->f);
4293 int depth = DefaultDepthOfScreen (screen);
4294
4295 /* Create a pixmap as large as the glyph string. */
4296 pixmap = XCreatePixmap (s->display, s->window,
4297 s->background_width,
4298 s->height, depth);
4299
4300 /* Don't clip in the following because we're working on the
4301 pixmap. */
4302 XSetClipMask (s->display, s->gc, None);
4303
4304 /* Fill the pixmap with the background color/stipple. */
4305 if (s->stippled_p)
4306 {
4307 /* Fill background with a stipple pattern. */
4308 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4309 XFillRectangle (s->display, pixmap, s->gc,
4310 0, 0, s->background_width, s->height);
4311 XSetFillStyle (s->display, s->gc, FillSolid);
4312 }
4313 else
4314 {
4315 XGCValues xgcv;
4316 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4317 &xgcv);
4318 XSetForeground (s->display, s->gc, xgcv.background);
4319 XFillRectangle (s->display, pixmap, s->gc,
4320 0, 0, s->background_width, s->height);
4321 XSetForeground (s->display, s->gc, xgcv.foreground);
4322 }
4323 }
4324 else
06a2c219
GM
4325 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
4326
4327 s->background_filled_p = 1;
4328 }
dc43ef94 4329
06a2c219
GM
4330 /* Draw the foreground. */
4331 if (pixmap != None)
4332 {
4333 x_draw_image_foreground_1 (s, pixmap);
4334 x_set_glyph_string_clipping (s);
4335 XCopyArea (s->display, pixmap, s->window, s->gc,
4336 0, 0, s->background_width, s->height, s->x, s->y);
4337 XFreePixmap (s->display, pixmap);
4338 }
4339 else
4340 x_draw_image_foreground (s);
b5210ea7 4341
06a2c219
GM
4342 /* If we must draw a relief around the image, do it. */
4343 if (s->img->relief
4344 || s->hl == DRAW_IMAGE_RAISED
4345 || s->hl == DRAW_IMAGE_SUNKEN)
4346 x_draw_image_relief (s);
4347}
8c1a6a84 4348
990ba854 4349
06a2c219 4350/* Draw stretch glyph string S. */
dc43ef94 4351
06a2c219
GM
4352static void
4353x_draw_stretch_glyph_string (s)
4354 struct glyph_string *s;
4355{
4356 xassert (s->first_glyph->type == STRETCH_GLYPH);
4357 s->stippled_p = s->face->stipple != 0;
990ba854 4358
06a2c219
GM
4359 if (s->hl == DRAW_CURSOR
4360 && !x_stretch_cursor_p)
4361 {
4362 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4363 as wide as the stretch glyph. */
4364 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4365
06a2c219
GM
4366 /* Draw cursor. */
4367 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4368
06a2c219
GM
4369 /* Clear rest using the GC of the original non-cursor face. */
4370 if (width < s->background_width)
4371 {
06a2c219
GM
4372 int x = s->x + width, y = s->y;
4373 int w = s->background_width - width, h = s->height;
4374 XRectangle r;
b7f83f9e 4375 GC gc;
dc43ef94 4376
b7f83f9e
GM
4377 if (s->row->mouse_face_p
4378 && cursor_in_mouse_face_p (s->w))
4379 {
4380 x_set_mouse_face_gc (s);
4381 gc = s->gc;
4382 }
4383 else
4384 gc = s->face->gc;
4385
06a2c219
GM
4386 x_get_glyph_string_clip_rect (s, &r);
4387 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
b7f83f9e 4388
06a2c219
GM
4389 if (s->face->stipple)
4390 {
4391 /* Fill background with a stipple pattern. */
4392 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4393 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4394 XSetFillStyle (s->display, gc, FillSolid);
4395 }
4396 else
4397 {
4398 XGCValues xgcv;
4399 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4400 XSetForeground (s->display, gc, xgcv.background);
4401 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4402 XSetForeground (s->display, gc, xgcv.foreground);
4403 }
4404 }
4405 }
61e9f9f3 4406 else if (!s->background_filled_p)
06a2c219
GM
4407 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4408 s->height);
4409
4410 s->background_filled_p = 1;
4411}
4412
4413
4414/* Draw glyph string S. */
4415
4416static void
4417x_draw_glyph_string (s)
4418 struct glyph_string *s;
4419{
4458cf11
KH
4420 int relief_drawn_p = 0;
4421
06a2c219
GM
4422 /* If S draws into the background of its successor, draw the
4423 background of the successor first so that S can draw into it.
4424 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4425 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4426 {
4427 xassert (s->next->img == NULL);
4428 x_set_glyph_string_gc (s->next);
4429 x_set_glyph_string_clipping (s->next);
4430 x_draw_glyph_string_background (s->next, 1);
4431 }
97210f4e 4432
06a2c219
GM
4433 /* Set up S->gc, set clipping and draw S. */
4434 x_set_glyph_string_gc (s);
06a2c219 4435
4458cf11
KH
4436 /* Draw relief (if any) in advance for char/composition so that the
4437 glyph string can be drawn over it. */
4438 if (!s->for_overlaps_p
4439 && s->face->box != FACE_NO_BOX
4440 && (s->first_glyph->type == CHAR_GLYPH
4441 || s->first_glyph->type == COMPOSITE_GLYPH))
4442
4443 {
e6269cbb 4444 x_set_glyph_string_clipping (s);
4458cf11
KH
4445 x_draw_glyph_string_background (s, 1);
4446 x_draw_glyph_string_box (s);
e6269cbb 4447 x_set_glyph_string_clipping (s);
4458cf11
KH
4448 relief_drawn_p = 1;
4449 }
e6269cbb
GM
4450 else
4451 x_set_glyph_string_clipping (s);
4458cf11 4452
06a2c219
GM
4453 switch (s->first_glyph->type)
4454 {
4455 case IMAGE_GLYPH:
4456 x_draw_image_glyph_string (s);
4457 break;
4458
4459 case STRETCH_GLYPH:
4460 x_draw_stretch_glyph_string (s);
4461 break;
4462
4463 case CHAR_GLYPH:
66ac4b0e
GM
4464 if (s->for_overlaps_p)
4465 s->background_filled_p = 1;
4466 else
4467 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4468 x_draw_glyph_string_foreground (s);
4469 break;
4470
b4192550
KH
4471 case COMPOSITE_GLYPH:
4472 if (s->for_overlaps_p || s->gidx > 0)
4473 s->background_filled_p = 1;
4474 else
4475 x_draw_glyph_string_background (s, 1);
4476 x_draw_composite_glyph_string_foreground (s);
4477 break;
4478
06a2c219
GM
4479 default:
4480 abort ();
4481 }
4482
66ac4b0e 4483 if (!s->for_overlaps_p)
06a2c219 4484 {
66ac4b0e
GM
4485 /* Draw underline. */
4486 if (s->face->underline_p)
4487 {
e24e84cc
GM
4488 unsigned long tem, h;
4489 int y;
06a2c219 4490
e24e84cc 4491 /* Get the underline thickness. Default is 1 pixel. */
66ac4b0e
GM
4492 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4493 h = 1;
e24e84cc
GM
4494
4495 /* Get the underline position. This is the recommended
4496 vertical offset in pixels from the baseline to the top of
4497 the underline. This is a signed value according to the
4498 specs, and its default is
4499
4500 ROUND ((maximum descent) / 2), with
4501 ROUND(x) = floor (x + 0.5) */
4502
a72d5ce5
GM
4503 if (x_use_underline_position_properties
4504 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
e24e84cc
GM
4505 y = s->ybase + (long) tem;
4506 else if (s->face->font)
4507 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4508 else
a02f1be0 4509 y = s->y + s->height - h;
06a2c219 4510
66ac4b0e 4511 if (s->face->underline_defaulted_p)
e24e84cc
GM
4512 XFillRectangle (s->display, s->window, s->gc,
4513 s->x, y, s->width, h);
66ac4b0e
GM
4514 else
4515 {
4516 XGCValues xgcv;
4517 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4518 XSetForeground (s->display, s->gc, s->face->underline_color);
e24e84cc
GM
4519 XFillRectangle (s->display, s->window, s->gc,
4520 s->x, y, s->width, h);
66ac4b0e
GM
4521 XSetForeground (s->display, s->gc, xgcv.foreground);
4522 }
dc6f92b8 4523 }
07e34cb0 4524
66ac4b0e
GM
4525 /* Draw overline. */
4526 if (s->face->overline_p)
06a2c219 4527 {
66ac4b0e
GM
4528 unsigned long dy = 0, h = 1;
4529
4530 if (s->face->overline_color_defaulted_p)
4531 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4532 s->width, h);
4533 else
4534 {
4535 XGCValues xgcv;
4536 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4537 XSetForeground (s->display, s->gc, s->face->overline_color);
4538 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4539 s->width, h);
4540 XSetForeground (s->display, s->gc, xgcv.foreground);
4541 }
06a2c219 4542 }
06a2c219 4543
66ac4b0e
GM
4544 /* Draw strike-through. */
4545 if (s->face->strike_through_p)
06a2c219 4546 {
66ac4b0e
GM
4547 unsigned long h = 1;
4548 unsigned long dy = (s->height - h) / 2;
4549
4550 if (s->face->strike_through_color_defaulted_p)
4551 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4552 s->width, h);
4553 else
4554 {
4555 XGCValues xgcv;
4556 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4557 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4558 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4559 s->width, h);
4560 XSetForeground (s->display, s->gc, xgcv.foreground);
4561 }
06a2c219 4562 }
06a2c219 4563
4458cf11
KH
4564 /* Draw relief if not yet drawn. */
4565 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
66ac4b0e
GM
4566 x_draw_glyph_string_box (s);
4567 }
06a2c219
GM
4568
4569 /* Reset clipping. */
4570 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4571}
07e34cb0 4572
06a2c219 4573
b4192550
KH
4574static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4575 struct face **, int));
06a2c219 4576
06a2c219 4577
209f68d9
GM
4578/* Fill glyph string S with composition components specified by S->cmp.
4579
b4192550
KH
4580 FACES is an array of faces for all components of this composition.
4581 S->gidx is the index of the first component for S.
4582 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4583 use its physical height for clipping.
06a2c219 4584
b4192550 4585 Value is the index of a component not in S. */
07e34cb0 4586
b4192550
KH
4587static int
4588x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4589 struct glyph_string *s;
b4192550 4590 struct face **faces;
66ac4b0e 4591 int overlaps_p;
07e34cb0 4592{
b4192550 4593 int i;
06a2c219 4594
b4192550 4595 xassert (s);
06a2c219 4596
b4192550 4597 s->for_overlaps_p = overlaps_p;
06a2c219 4598
b4192550
KH
4599 s->face = faces[s->gidx];
4600 s->font = s->face->font;
4601 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4602
b4192550
KH
4603 /* For all glyphs of this composition, starting at the offset
4604 S->gidx, until we reach the end of the definition or encounter a
4605 glyph that requires the different face, add it to S. */
4606 ++s->nchars;
4607 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4608 ++s->nchars;
06a2c219 4609
b4192550
KH
4610 /* All glyph strings for the same composition has the same width,
4611 i.e. the width set for the first component of the composition. */
06a2c219 4612
06a2c219
GM
4613 s->width = s->first_glyph->pixel_width;
4614
4615 /* If the specified font could not be loaded, use the frame's
4616 default font, but record the fact that we couldn't load it in
4617 the glyph string so that we can draw rectangles for the
4618 characters of the glyph string. */
4619 if (s->font == NULL)
4620 {
4621 s->font_not_found_p = 1;
4622 s->font = FRAME_FONT (s->f);
4623 }
4624
4625 /* Adjust base line for subscript/superscript text. */
4626 s->ybase += s->first_glyph->voffset;
4627
4628 xassert (s->face && s->face->gc);
4629
4630 /* This glyph string must always be drawn with 16-bit functions. */
4631 s->two_byte_p = 1;
b4192550
KH
4632
4633 return s->gidx + s->nchars;
06a2c219
GM
4634}
4635
4636
209f68d9
GM
4637/* Fill glyph string S from a sequence of character glyphs.
4638
06a2c219 4639 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4640 first glyph to consider, END is the index of the last + 1.
4641 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4642 use its physical height for clipping.
66ac4b0e
GM
4643
4644 Value is the index of the first glyph not in S. */
06a2c219
GM
4645
4646static int
66ac4b0e 4647x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4648 struct glyph_string *s;
4649 int face_id;
66ac4b0e 4650 int start, end, overlaps_p;
06a2c219
GM
4651{
4652 struct glyph *glyph, *last;
4653 int voffset;
ee569018 4654 int glyph_not_available_p;
06a2c219 4655
06a2c219
GM
4656 xassert (s->f == XFRAME (s->w->frame));
4657 xassert (s->nchars == 0);
4658 xassert (start >= 0 && end > start);
4659
66ac4b0e 4660 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4661 glyph = s->row->glyphs[s->area] + start;
4662 last = s->row->glyphs[s->area] + end;
4663 voffset = glyph->voffset;
4664
ee569018
KH
4665 glyph_not_available_p = glyph->glyph_not_available_p;
4666
06a2c219
GM
4667 while (glyph < last
4668 && glyph->type == CHAR_GLYPH
4669 && glyph->voffset == voffset
ee569018
KH
4670 /* Same face id implies same font, nowadays. */
4671 && glyph->face_id == face_id
4672 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4673 {
ee569018
KH
4674 int two_byte_p;
4675
06a2c219 4676 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4677 s->char2b + s->nchars,
4678 &two_byte_p);
4679 s->two_byte_p = two_byte_p;
06a2c219
GM
4680 ++s->nchars;
4681 xassert (s->nchars <= end - start);
4682 s->width += glyph->pixel_width;
4683 ++glyph;
4684 }
4685
4686 s->font = s->face->font;
4687 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4688
4689 /* If the specified font could not be loaded, use the frame's font,
4690 but record the fact that we couldn't load it in
4691 S->font_not_found_p so that we can draw rectangles for the
4692 characters of the glyph string. */
ee569018 4693 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4694 {
4695 s->font_not_found_p = 1;
4696 s->font = FRAME_FONT (s->f);
4697 }
4698
4699 /* Adjust base line for subscript/superscript text. */
4700 s->ybase += voffset;
66ac4b0e 4701
06a2c219
GM
4702 xassert (s->face && s->face->gc);
4703 return glyph - s->row->glyphs[s->area];
07e34cb0 4704}
dc6f92b8 4705
06a2c219
GM
4706
4707/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4708
dfcf069d 4709static void
06a2c219
GM
4710x_fill_image_glyph_string (s)
4711 struct glyph_string *s;
4712{
4713 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4714 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4715 xassert (s->img);
43d120d8 4716 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4717 s->font = s->face->font;
4718 s->width = s->first_glyph->pixel_width;
4719
4720 /* Adjust base line for subscript/superscript text. */
4721 s->ybase += s->first_glyph->voffset;
4722}
4723
4724
209f68d9 4725/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4726
209f68d9
GM
4727 ROW is the glyph row in which the glyphs are found, AREA is the
4728 area within the row. START is the index of the first glyph to
4729 consider, END is the index of the last + 1.
4730
4731 Value is the index of the first glyph not in S. */
4732
4733static int
4734x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4735 struct glyph_string *s;
209f68d9
GM
4736 struct glyph_row *row;
4737 enum glyph_row_area area;
4738 int start, end;
06a2c219 4739{
209f68d9
GM
4740 struct glyph *glyph, *last;
4741 int voffset, face_id;
4742
06a2c219 4743 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4744
4745 glyph = s->row->glyphs[s->area] + start;
4746 last = s->row->glyphs[s->area] + end;
4747 face_id = glyph->face_id;
4748 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4749 s->font = s->face->font;
209f68d9
GM
4750 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4751 s->width = glyph->pixel_width;
4752 voffset = glyph->voffset;
4753
4754 for (++glyph;
4755 (glyph < last
4756 && glyph->type == STRETCH_GLYPH
4757 && glyph->voffset == voffset
4758 && glyph->face_id == face_id);
4759 ++glyph)
4760 s->width += glyph->pixel_width;
06a2c219
GM
4761
4762 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4763 s->ybase += voffset;
4764
c296fc01
GM
4765 /* The case that face->gc == 0 is handled when drawing the glyph
4766 string by calling PREPARE_FACE_FOR_DISPLAY. */
4767 xassert (s->face);
209f68d9 4768 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4769}
4770
4771
4772/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4773 of XChar2b structures for S; it can't be allocated in
4774 x_init_glyph_string because it must be allocated via `alloca'. W
4775 is the window on which S is drawn. ROW and AREA are the glyph row
4776 and area within the row from which S is constructed. START is the
4777 index of the first glyph structure covered by S. HL is a
4778 face-override for drawing S. */
4779
4780static void
4781x_init_glyph_string (s, char2b, w, row, area, start, hl)
4782 struct glyph_string *s;
4783 XChar2b *char2b;
4784 struct window *w;
4785 struct glyph_row *row;
4786 enum glyph_row_area area;
4787 int start;
4788 enum draw_glyphs_face hl;
4789{
4790 bzero (s, sizeof *s);
4791 s->w = w;
4792 s->f = XFRAME (w->frame);
4793 s->display = FRAME_X_DISPLAY (s->f);
4794 s->window = FRAME_X_WINDOW (s->f);
4795 s->char2b = char2b;
4796 s->hl = hl;
4797 s->row = row;
4798 s->area = area;
4799 s->first_glyph = row->glyphs[area] + start;
4800 s->height = row->height;
4801 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4802
9ea173e8
GM
4803 /* Display the internal border below the tool-bar window. */
4804 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4805 s->y -= s->f->output_data.x->internal_border_width;
4806
4807 s->ybase = s->y + row->ascent;
4808}
4809
4810
4811/* Set background width of glyph string S. START is the index of the
4812 first glyph following S. LAST_X is the right-most x-position + 1
4813 in the drawing area. */
4814
4815static INLINE void
4816x_set_glyph_string_background_width (s, start, last_x)
4817 struct glyph_string *s;
4818 int start;
4819 int last_x;
4820{
4821 /* If the face of this glyph string has to be drawn to the end of
4822 the drawing area, set S->extends_to_end_of_line_p. */
4823 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4824
4825 if (start == s->row->used[s->area]
eb79f5cc 4826 && s->area == TEXT_AREA
7b0870b2
GM
4827 && ((s->hl == DRAW_NORMAL_TEXT
4828 && (s->row->fill_line_p
4829 || s->face->background != default_face->background
4830 || s->face->stipple != default_face->stipple
4831 || s->row->mouse_face_p))
327f42ee
GM
4832 || s->hl == DRAW_MOUSE_FACE
4833 || ((s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN)
4834 && s->row->fill_line_p)))
7b0870b2 4835 s->extends_to_end_of_line_p = 1;
06a2c219
GM
4836
4837 /* If S extends its face to the end of the line, set its
4838 background_width to the distance to the right edge of the drawing
4839 area. */
4840 if (s->extends_to_end_of_line_p)
1da3fd71 4841 s->background_width = last_x - s->x + 1;
06a2c219
GM
4842 else
4843 s->background_width = s->width;
4844}
4845
4846
4847/* Add a glyph string for a stretch glyph to the list of strings
4848 between HEAD and TAIL. START is the index of the stretch glyph in
4849 row area AREA of glyph row ROW. END is the index of the last glyph
4850 in that glyph row area. X is the current output position assigned
4851 to the new glyph string constructed. HL overrides that face of the
4852 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4853 is the right-most x-position of the drawing area. */
4854
8abee2e1
DL
4855/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4856 and below -- keep them on one line. */
4857#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4858 do \
4859 { \
4860 s = (struct glyph_string *) alloca (sizeof *s); \
4861 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4862 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4863 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4864 s->x = (X); \
4865 } \
4866 while (0)
4867
4868
4869/* Add a glyph string for an image glyph to the list of strings
4870 between HEAD and TAIL. START is the index of the image glyph in
4871 row area AREA of glyph row ROW. END is the index of the last glyph
4872 in that glyph row area. X is the current output position assigned
4873 to the new glyph string constructed. HL overrides that face of the
4874 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4875 is the right-most x-position of the drawing area. */
4876
8abee2e1 4877#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4878 do \
4879 { \
4880 s = (struct glyph_string *) alloca (sizeof *s); \
4881 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4882 x_fill_image_glyph_string (s); \
4883 x_append_glyph_string (&HEAD, &TAIL, s); \
4884 ++START; \
4885 s->x = (X); \
4886 } \
4887 while (0)
4888
4889
4890/* Add a glyph string for a sequence of character glyphs to the list
4891 of strings between HEAD and TAIL. START is the index of the first
4892 glyph in row area AREA of glyph row ROW that is part of the new
4893 glyph string. END is the index of the last glyph in that glyph row
4894 area. X is the current output position assigned to the new glyph
4895 string constructed. HL overrides that face of the glyph; e.g. it
4896 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4897 right-most x-position of the drawing area. */
4898
8abee2e1 4899#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4900 do \
4901 { \
3e71d8f2 4902 int c, face_id; \
06a2c219
GM
4903 XChar2b *char2b; \
4904 \
43d120d8 4905 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4906 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4907 \
b4192550
KH
4908 s = (struct glyph_string *) alloca (sizeof *s); \
4909 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4910 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4911 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4912 s->x = (X); \
4913 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4914 OVERLAPS_P); \
06a2c219
GM
4915 } \
4916 while (0)
4917
4918
b4192550
KH
4919/* Add a glyph string for a composite sequence to the list of strings
4920 between HEAD and TAIL. START is the index of the first glyph in
4921 row area AREA of glyph row ROW that is part of the new glyph
4922 string. END is the index of the last glyph in that glyph row area.
4923 X is the current output position assigned to the new glyph string
4924 constructed. HL overrides that face of the glyph; e.g. it is
4925 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4926 x-position of the drawing area. */
4927
6c27ec25 4928#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4929 do { \
43d120d8
KH
4930 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4931 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4932 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4933 struct composition *cmp = composition_table[cmp_id]; \
4934 int glyph_len = cmp->glyph_len; \
4935 XChar2b *char2b; \
4936 struct face **faces; \
4937 struct glyph_string *first_s = NULL; \
4938 int n; \
4939 \
ee569018 4940 base_face = base_face->ascii_face; \
b4192550
KH
4941 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4942 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4943 /* At first, fill in `char2b' and `faces'. */ \
4944 for (n = 0; n < glyph_len; n++) \
4945 { \
43d120d8 4946 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4947 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4948 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4949 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4950 this_face_id, char2b + n, 1); \
b4192550
KH
4951 } \
4952 \
4953 /* Make glyph_strings for each glyph sequence that is drawable by \
4954 the same face, and append them to HEAD/TAIL. */ \
4955 for (n = 0; n < cmp->glyph_len;) \
4956 { \
4957 s = (struct glyph_string *) alloca (sizeof *s); \
4958 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4959 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4960 s->cmp = cmp; \
4961 s->gidx = n; \
b4192550
KH
4962 s->x = (X); \
4963 \
4964 if (n == 0) \
4965 first_s = s; \
4966 \
4967 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4968 } \
4969 \
4970 ++START; \
4971 s = first_s; \
4972 } while (0)
4973
4974
06a2c219
GM
4975/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4976 of AREA of glyph row ROW on window W between indices START and END.
4977 HL overrides the face for drawing glyph strings, e.g. it is
4978 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4979 x-positions of the drawing area.
4980
4981 This is an ugly monster macro construct because we must use alloca
4982 to allocate glyph strings (because x_draw_glyphs can be called
4983 asynchronously). */
4984
8abee2e1 4985#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4986 do \
4987 { \
4988 HEAD = TAIL = NULL; \
4989 while (START < END) \
4990 { \
4991 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4992 switch (first_glyph->type) \
4993 { \
4994 case CHAR_GLYPH: \
4995 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
4996 TAIL, HL, X, LAST_X, \
4997 OVERLAPS_P); \
06a2c219
GM
4998 break; \
4999 \
b4192550
KH
5000 case COMPOSITE_GLYPH: \
5001 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
5002 HEAD, TAIL, HL, X, LAST_X,\
5003 OVERLAPS_P); \
5004 break; \
5005 \
06a2c219
GM
5006 case STRETCH_GLYPH: \
5007 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
5008 HEAD, TAIL, HL, X, LAST_X); \
5009 break; \
5010 \
5011 case IMAGE_GLYPH: \
5012 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
5013 TAIL, HL, X, LAST_X); \
5014 break; \
5015 \
5016 default: \
5017 abort (); \
5018 } \
5019 \
5020 x_set_glyph_string_background_width (s, START, LAST_X); \
5021 (X) += s->width; \
5022 } \
5023 } \
5024 while (0)
5025
5026
5027/* Draw glyphs between START and END in AREA of ROW on window W,
5028 starting at x-position X. X is relative to AREA in W. HL is a
5029 face-override with the following meaning:
5030
5031 DRAW_NORMAL_TEXT draw normally
5032 DRAW_CURSOR draw in cursor face
5033 DRAW_MOUSE_FACE draw in mouse face.
5034 DRAW_INVERSE_VIDEO draw in mode line face
5035 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
5036 DRAW_IMAGE_RAISED draw an image with a raised relief around it
5037
66ac4b0e
GM
5038 If OVERLAPS_P is non-zero, draw only the foreground of characters
5039 and clip to the physical height of ROW.
5040
06a2c219
GM
5041 Value is the x-position reached, relative to AREA of W. */
5042
5043static int
f0a48a01 5044x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
06a2c219
GM
5045 struct window *w;
5046 int x;
5047 struct glyph_row *row;
5048 enum glyph_row_area area;
5049 int start, end;
5050 enum draw_glyphs_face hl;
66ac4b0e 5051 int overlaps_p;
dc6f92b8 5052{
06a2c219
GM
5053 struct glyph_string *head, *tail;
5054 struct glyph_string *s;
5055 int last_x, area_width;
5056 int x_reached;
5057 int i, j;
5058
5059 /* Let's rather be paranoid than getting a SEGV. */
06a2c219 5060 end = min (end, row->used[area]);
a8710abf
GM
5061 start = max (0, start);
5062 start = min (end, start);
06a2c219
GM
5063
5064 /* Translate X to frame coordinates. Set last_x to the right
5065 end of the drawing area. */
5066 if (row->full_width_p)
5067 {
5068 /* X is relative to the left edge of W, without scroll bars
3f332ef3 5069 or fringes. */
06a2c219 5070 struct frame *f = XFRAME (w->frame);
06a2c219 5071 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 5072
06a2c219
GM
5073 x += window_left_x;
5074 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
5075 last_x = window_left_x + area_width;
5076
5077 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5078 {
110859fc 5079 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
5080 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
5081 last_x += width;
5082 else
5083 x -= width;
5084 }
dc6f92b8 5085
b9432a85 5086 x += FRAME_INTERNAL_BORDER_WIDTH (f);
98fedd97 5087 last_x += FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
5088 }
5089 else
dc6f92b8 5090 {
06a2c219
GM
5091 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
5092 area_width = window_box_width (w, area);
5093 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
5094 }
5095
06a2c219
GM
5096 /* Build a doubly-linked list of glyph_string structures between
5097 head and tail from what we have to draw. Note that the macro
5098 BUILD_GLYPH_STRINGS will modify its start parameter. That's
5099 the reason we use a separate variable `i'. */
5100 i = start;
66ac4b0e
GM
5101 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
5102 overlaps_p);
06a2c219
GM
5103 if (tail)
5104 x_reached = tail->x + tail->background_width;
5105 else
5106 x_reached = x;
90e65f07 5107
06a2c219
GM
5108 /* If there are any glyphs with lbearing < 0 or rbearing > width in
5109 the row, redraw some glyphs in front or following the glyph
5110 strings built above. */
a8710abf 5111 if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
5112 {
5113 int dummy_x = 0;
5114 struct glyph_string *h, *t;
5115
5116 /* Compute overhangs for all glyph strings. */
5117 for (s = head; s; s = s->next)
5118 x_compute_glyph_string_overhangs (s);
5119
5120 /* Prepend glyph strings for glyphs in front of the first glyph
5121 string that are overwritten because of the first glyph
5122 string's left overhang. The background of all strings
5123 prepended must be drawn because the first glyph string
5124 draws over it. */
5125 i = x_left_overwritten (head);
5126 if (i >= 0)
5127 {
5128 j = i;
5129 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
5130 DRAW_NORMAL_TEXT, dummy_x, last_x,
5131 overlaps_p);
06a2c219 5132 start = i;
06a2c219
GM
5133 x_compute_overhangs_and_x (t, head->x, 1);
5134 x_prepend_glyph_string_lists (&head, &tail, h, t);
5135 }
58769bee 5136
06a2c219
GM
5137 /* Prepend glyph strings for glyphs in front of the first glyph
5138 string that overwrite that glyph string because of their
5139 right overhang. For these strings, only the foreground must
5140 be drawn, because it draws over the glyph string at `head'.
5141 The background must not be drawn because this would overwrite
5142 right overhangs of preceding glyphs for which no glyph
5143 strings exist. */
5144 i = x_left_overwriting (head);
5145 if (i >= 0)
5146 {
5147 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
5148 DRAW_NORMAL_TEXT, dummy_x, last_x,
5149 overlaps_p);
06a2c219
GM
5150 for (s = h; s; s = s->next)
5151 s->background_filled_p = 1;
06a2c219
GM
5152 x_compute_overhangs_and_x (t, head->x, 1);
5153 x_prepend_glyph_string_lists (&head, &tail, h, t);
5154 }
dbcb258a 5155
06a2c219
GM
5156 /* Append glyphs strings for glyphs following the last glyph
5157 string tail that are overwritten by tail. The background of
5158 these strings has to be drawn because tail's foreground draws
5159 over it. */
5160 i = x_right_overwritten (tail);
5161 if (i >= 0)
5162 {
5163 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5164 DRAW_NORMAL_TEXT, x, last_x,
5165 overlaps_p);
06a2c219
GM
5166 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5167 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219 5168 }
dc6f92b8 5169
06a2c219
GM
5170 /* Append glyph strings for glyphs following the last glyph
5171 string tail that overwrite tail. The foreground of such
5172 glyphs has to be drawn because it writes into the background
5173 of tail. The background must not be drawn because it could
5174 paint over the foreground of following glyphs. */
5175 i = x_right_overwriting (tail);
5176 if (i >= 0)
5177 {
5178 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5179 DRAW_NORMAL_TEXT, x, last_x,
5180 overlaps_p);
06a2c219
GM
5181 for (s = h; s; s = s->next)
5182 s->background_filled_p = 1;
5183 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5184 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219
GM
5185 }
5186 }
58769bee 5187
06a2c219
GM
5188 /* Draw all strings. */
5189 for (s = head; s; s = s->next)
5190 x_draw_glyph_string (s);
dc6f92b8 5191
bb313871
GM
5192 if (area == TEXT_AREA
5193 && !row->full_width_p
5194 /* When drawing overlapping rows, only the glyph strings'
5195 foreground is drawn, which doesn't erase a cursor
5196 completely. */
5197 && !overlaps_p)
f0a48a01
GM
5198 {
5199 int x0 = head ? head->x : x;
5200 int x1 = tail ? tail->x + tail->background_width : x;
5201
5202 x0 = FRAME_TO_WINDOW_PIXEL_X (w, x0);
5203 x1 = FRAME_TO_WINDOW_PIXEL_X (w, x1);
5204
bb313871 5205 if (XFASTINT (w->left_margin_width) != 0)
f0a48a01
GM
5206 {
5207 int left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
5208 x0 -= left_area_width;
5209 x1 -= left_area_width;
5210 }
5211
60626bab
GM
5212 notice_overwritten_cursor (w, area, x0, x1,
5213 row->y, MATRIX_ROW_BOTTOM_Y (row));
f0a48a01
GM
5214 }
5215
06a2c219
GM
5216 /* Value is the x-position up to which drawn, relative to AREA of W.
5217 This doesn't include parts drawn because of overhangs. */
5218 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
5219 if (!row->full_width_p)
5220 {
f0a48a01 5221 if (area > LEFT_MARGIN_AREA && XFASTINT (w->left_margin_width) != 0)
06a2c219
GM
5222 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
5223 if (area > TEXT_AREA)
5224 x_reached -= window_box_width (w, TEXT_AREA);
5225 }
a8710abf 5226
06a2c219
GM
5227 return x_reached;
5228}
dc6f92b8 5229
dc6f92b8 5230
66ac4b0e
GM
5231/* Fix the display of area AREA of overlapping row ROW in window W. */
5232
5233static void
5234x_fix_overlapping_area (w, row, area)
5235 struct window *w;
5236 struct glyph_row *row;
5237 enum glyph_row_area area;
5238{
5239 int i, x;
5240
5241 BLOCK_INPUT;
5242
5243 if (area == LEFT_MARGIN_AREA)
5244 x = 0;
5245 else if (area == TEXT_AREA)
5246 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5247 else
5248 x = (window_box_width (w, LEFT_MARGIN_AREA)
5249 + window_box_width (w, TEXT_AREA));
5250
5251 for (i = 0; i < row->used[area];)
5252 {
5253 if (row->glyphs[area][i].overlaps_vertically_p)
5254 {
5255 int start = i, start_x = x;
5256
5257 do
5258 {
5259 x += row->glyphs[area][i].pixel_width;
5260 ++i;
5261 }
5262 while (i < row->used[area]
5263 && row->glyphs[area][i].overlaps_vertically_p);
5264
5265 x_draw_glyphs (w, start_x, row, area, start, i,
f0a48a01 5266 DRAW_NORMAL_TEXT, 1);
66ac4b0e
GM
5267 }
5268 else
5269 {
5270 x += row->glyphs[area][i].pixel_width;
5271 ++i;
5272 }
5273 }
5274
5275 UNBLOCK_INPUT;
5276}
5277
5278
06a2c219
GM
5279/* Output LEN glyphs starting at START at the nominal cursor position.
5280 Advance the nominal cursor over the text. The global variable
5281 updated_window contains the window being updated, updated_row is
5282 the glyph row being updated, and updated_area is the area of that
5283 row being updated. */
dc6f92b8 5284
06a2c219
GM
5285static void
5286x_write_glyphs (start, len)
5287 struct glyph *start;
5288 int len;
5289{
f0a48a01 5290 int x, hpos;
d9cdbb3d 5291
06a2c219 5292 xassert (updated_window && updated_row);
dc6f92b8 5293 BLOCK_INPUT;
06a2c219
GM
5294
5295 /* Write glyphs. */
dc6f92b8 5296
06a2c219
GM
5297 hpos = start - updated_row->glyphs[updated_area];
5298 x = x_draw_glyphs (updated_window, output_cursor.x,
5299 updated_row, updated_area,
5300 hpos, hpos + len,
f0a48a01 5301 DRAW_NORMAL_TEXT, 0);
dc6f92b8
JB
5302
5303 UNBLOCK_INPUT;
06a2c219
GM
5304
5305 /* Advance the output cursor. */
5306 output_cursor.hpos += len;
5307 output_cursor.x = x;
dc6f92b8
JB
5308}
5309
0cdd0c9f 5310
06a2c219 5311/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 5312
06a2c219
GM
5313static void
5314x_insert_glyphs (start, len)
5315 struct glyph *start;
5316 register int len;
5317{
5318 struct frame *f;
5319 struct window *w;
5320 int line_height, shift_by_width, shifted_region_width;
5321 struct glyph_row *row;
5322 struct glyph *glyph;
2beb36f9 5323 int frame_x, frame_y, hpos;
58769bee 5324
06a2c219 5325 xassert (updated_window && updated_row);
0cdd0c9f 5326 BLOCK_INPUT;
06a2c219
GM
5327 w = updated_window;
5328 f = XFRAME (WINDOW_FRAME (w));
5329
5330 /* Get the height of the line we are in. */
5331 row = updated_row;
5332 line_height = row->height;
5333
5334 /* Get the width of the glyphs to insert. */
5335 shift_by_width = 0;
5336 for (glyph = start; glyph < start + len; ++glyph)
5337 shift_by_width += glyph->pixel_width;
5338
5339 /* Get the width of the region to shift right. */
5340 shifted_region_width = (window_box_width (w, updated_area)
5341 - output_cursor.x
5342 - shift_by_width);
5343
5344 /* Shift right. */
bf0ab8a2 5345 frame_x = window_box_left (w, updated_area) + output_cursor.x;
06a2c219
GM
5346 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
5347 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5348 f->output_data.x->normal_gc,
5349 frame_x, frame_y,
5350 shifted_region_width, line_height,
5351 frame_x + shift_by_width, frame_y);
5352
5353 /* Write the glyphs. */
5354 hpos = start - row->glyphs[updated_area];
5355 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
f0a48a01 5356 DRAW_NORMAL_TEXT, 0);
06a2c219
GM
5357
5358 /* Advance the output cursor. */
5359 output_cursor.hpos += len;
5360 output_cursor.x += shift_by_width;
0cdd0c9f
RS
5361 UNBLOCK_INPUT;
5362}
0cdd0c9f 5363
0cdd0c9f 5364
06a2c219
GM
5365/* Delete N glyphs at the nominal cursor position. Not implemented
5366 for X frames. */
c83febd7
RS
5367
5368static void
06a2c219
GM
5369x_delete_glyphs (n)
5370 register int n;
c83febd7 5371{
06a2c219 5372 abort ();
c83febd7
RS
5373}
5374
0cdd0c9f 5375
c5e6e06b
GM
5376/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
5377 If they are <= 0, this is probably an error. */
5378
5379void
5380x_clear_area (dpy, window, x, y, width, height, exposures)
5381 Display *dpy;
5382 Window window;
5383 int x, y;
5384 int width, height;
5385 int exposures;
5386{
5387 xassert (width > 0 && height > 0);
5388 XClearArea (dpy, window, x, y, width, height, exposures);
5389}
5390
5391
06a2c219
GM
5392/* Erase the current text line from the nominal cursor position
5393 (inclusive) to pixel column TO_X (exclusive). The idea is that
5394 everything from TO_X onward is already erased.
5395
5396 TO_X is a pixel position relative to updated_area of
5397 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 5398
06a2c219
GM
5399static void
5400x_clear_end_of_line (to_x)
5401 int to_x;
5402{
5403 struct frame *f;
5404 struct window *w = updated_window;
5405 int max_x, min_y, max_y;
5406 int from_x, from_y, to_y;
5407
5408 xassert (updated_window && updated_row);
5409 f = XFRAME (w->frame);
5410
5411 if (updated_row->full_width_p)
5412 {
5413 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
5414 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5415 && !w->pseudo_window_p)
5416 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 5417 }
06a2c219
GM
5418 else
5419 max_x = window_box_width (w, updated_area);
5420 max_y = window_text_bottom_y (w);
dc6f92b8 5421
06a2c219
GM
5422 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5423 of window. For TO_X > 0, truncate to end of drawing area. */
5424 if (to_x == 0)
5425 return;
5426 else if (to_x < 0)
5427 to_x = max_x;
5428 else
5429 to_x = min (to_x, max_x);
dbc4e1c1 5430
06a2c219
GM
5431 to_y = min (max_y, output_cursor.y + updated_row->height);
5432
5433 /* Notice if the cursor will be cleared by this operation. */
5434 if (!updated_row->full_width_p)
60626bab
GM
5435 notice_overwritten_cursor (w, updated_area,
5436 output_cursor.x, -1,
5437 updated_row->y,
5438 MATRIX_ROW_BOTTOM_Y (updated_row));
dbc4e1c1 5439
06a2c219
GM
5440 from_x = output_cursor.x;
5441
5442 /* Translate to frame coordinates. */
5443 if (updated_row->full_width_p)
5444 {
5445 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5446 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5447 }
0cdd0c9f
RS
5448 else
5449 {
06a2c219
GM
5450 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5451 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5452 }
5453
045dee35 5454 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5455 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5456 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5457
5458 /* Prevent inadvertently clearing to end of the X window. */
5459 if (to_x > from_x && to_y > from_y)
5460 {
5461 BLOCK_INPUT;
c5e6e06b
GM
5462 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5463 from_x, from_y, to_x - from_x, to_y - from_y,
5464 False);
06a2c219 5465 UNBLOCK_INPUT;
0cdd0c9f 5466 }
0cdd0c9f 5467}
dbc4e1c1 5468
0cdd0c9f 5469
06a2c219 5470/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5471 frame. Otherwise clear the selected frame. */
06a2c219
GM
5472
5473static void
5474x_clear_frame ()
0cdd0c9f 5475{
06a2c219 5476 struct frame *f;
0cdd0c9f 5477
06a2c219
GM
5478 if (updating_frame)
5479 f = updating_frame;
0cdd0c9f 5480 else
b86bd3dd 5481 f = SELECTED_FRAME ();
58769bee 5482
06a2c219
GM
5483 /* Clearing the frame will erase any cursor, so mark them all as no
5484 longer visible. */
5485 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5486 output_cursor.hpos = output_cursor.vpos = 0;
5487 output_cursor.x = -1;
5488
5489 /* We don't set the output cursor here because there will always
5490 follow an explicit cursor_to. */
5491 BLOCK_INPUT;
5492 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5493
5494 /* We have to clear the scroll bars, too. If we have changed
5495 colors or something like that, then they should be notified. */
5496 x_scroll_bar_clear (f);
0cdd0c9f 5497
06a2c219
GM
5498 XFlush (FRAME_X_DISPLAY (f));
5499 UNBLOCK_INPUT;
dc6f92b8 5500}
06a2c219
GM
5501
5502
dc6f92b8 5503\f
dbc4e1c1
JB
5504/* Invert the middle quarter of the frame for .15 sec. */
5505
06a2c219
GM
5506/* We use the select system call to do the waiting, so we have to make
5507 sure it's available. If it isn't, we just won't do visual bells. */
5508
dbc4e1c1
JB
5509#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5510
06a2c219
GM
5511
5512/* Subtract the `struct timeval' values X and Y, storing the result in
5513 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5514
5515static int
5516timeval_subtract (result, x, y)
5517 struct timeval *result, x, y;
5518{
06a2c219
GM
5519 /* Perform the carry for the later subtraction by updating y. This
5520 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5521 if (x.tv_usec < y.tv_usec)
5522 {
5523 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5524 y.tv_usec -= 1000000 * nsec;
5525 y.tv_sec += nsec;
5526 }
06a2c219 5527
dbc4e1c1
JB
5528 if (x.tv_usec - y.tv_usec > 1000000)
5529 {
5530 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5531 y.tv_usec += 1000000 * nsec;
5532 y.tv_sec -= nsec;
5533 }
5534
06a2c219
GM
5535 /* Compute the time remaining to wait. tv_usec is certainly
5536 positive. */
dbc4e1c1
JB
5537 result->tv_sec = x.tv_sec - y.tv_sec;
5538 result->tv_usec = x.tv_usec - y.tv_usec;
5539
06a2c219
GM
5540 /* Return indication of whether the result should be considered
5541 negative. */
dbc4e1c1
JB
5542 return x.tv_sec < y.tv_sec;
5543}
dc6f92b8 5544
dfcf069d 5545void
f676886a
JB
5546XTflash (f)
5547 struct frame *f;
dc6f92b8 5548{
dbc4e1c1 5549 BLOCK_INPUT;
dc6f92b8 5550
dbc4e1c1
JB
5551 {
5552 GC gc;
dc6f92b8 5553
06a2c219
GM
5554 /* Create a GC that will use the GXxor function to flip foreground
5555 pixels into background pixels. */
dbc4e1c1
JB
5556 {
5557 XGCValues values;
dc6f92b8 5558
dbc4e1c1 5559 values.function = GXxor;
7556890b
RS
5560 values.foreground = (f->output_data.x->foreground_pixel
5561 ^ f->output_data.x->background_pixel);
58769bee 5562
334208b7 5563 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5564 GCFunction | GCForeground, &values);
5565 }
dc6f92b8 5566
dbc4e1c1 5567 {
e84e14c3
RS
5568 /* Get the height not including a menu bar widget. */
5569 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5570 /* Height of each line to flash. */
5571 int flash_height = FRAME_LINE_HEIGHT (f);
5572 /* These will be the left and right margins of the rectangles. */
5573 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5574 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5575
5576 int width;
5577
5578 /* Don't flash the area between a scroll bar and the frame
5579 edge it is next to. */
5580 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5581 {
5582 case vertical_scroll_bar_left:
5583 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5584 break;
5585
5586 case vertical_scroll_bar_right:
5587 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5588 break;
06a2c219
GM
5589
5590 default:
5591 break;
e84e14c3
RS
5592 }
5593
5594 width = flash_right - flash_left;
5595
5596 /* If window is tall, flash top and bottom line. */
5597 if (height > 3 * FRAME_LINE_HEIGHT (f))
5598 {
5599 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5600 flash_left,
5601 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5602 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5603 width, flash_height);
5604 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5605 flash_left,
5606 (height - flash_height
5607 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5608 width, flash_height);
5609 }
5610 else
5611 /* If it is short, flash it all. */
5612 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5613 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5614 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5615
06a2c219 5616 x_flush (f);
dc6f92b8 5617
dbc4e1c1 5618 {
06a2c219 5619 struct timeval wakeup;
dc6f92b8 5620
66c30ea1 5621 EMACS_GET_TIME (wakeup);
dc6f92b8 5622
dbc4e1c1
JB
5623 /* Compute time to wait until, propagating carry from usecs. */
5624 wakeup.tv_usec += 150000;
5625 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5626 wakeup.tv_usec %= 1000000;
5627
101922c3
GM
5628 /* Keep waiting until past the time wakeup or any input gets
5629 available. */
5630 while (! detect_input_pending ())
dbc4e1c1 5631 {
101922c3 5632 struct timeval current;
dbc4e1c1
JB
5633 struct timeval timeout;
5634
101922c3 5635 EMACS_GET_TIME (current);
dbc4e1c1 5636
101922c3
GM
5637 /* Break if result would be negative. */
5638 if (timeval_subtract (&current, wakeup, current))
dbc4e1c1
JB
5639 break;
5640
101922c3
GM
5641 /* How long `select' should wait. */
5642 timeout.tv_sec = 0;
5643 timeout.tv_usec = 10000;
5644
dbc4e1c1 5645 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5646 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5647 }
5648 }
58769bee 5649
e84e14c3
RS
5650 /* If window is tall, flash top and bottom line. */
5651 if (height > 3 * FRAME_LINE_HEIGHT (f))
5652 {
5653 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5654 flash_left,
5655 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5656 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5657 width, flash_height);
5658 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5659 flash_left,
5660 (height - flash_height
5661 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5662 width, flash_height);
5663 }
5664 else
5665 /* If it is short, flash it all. */
5666 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5667 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5668 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5669
334208b7 5670 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5671 x_flush (f);
dc6f92b8 5672 }
dbc4e1c1
JB
5673 }
5674
5675 UNBLOCK_INPUT;
dc6f92b8
JB
5676}
5677
06a2c219 5678#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5679
5680
dc6f92b8
JB
5681/* Make audible bell. */
5682
dfcf069d 5683void
dc6f92b8
JB
5684XTring_bell ()
5685{
b86bd3dd
GM
5686 struct frame *f = SELECTED_FRAME ();
5687
5688 if (FRAME_X_DISPLAY (f))
5689 {
dbc4e1c1 5690#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5691 if (visible_bell)
5692 XTflash (f);
5693 else
dbc4e1c1 5694#endif
b86bd3dd
GM
5695 {
5696 BLOCK_INPUT;
5697 XBell (FRAME_X_DISPLAY (f), 0);
5698 XFlush (FRAME_X_DISPLAY (f));
5699 UNBLOCK_INPUT;
5700 }
dc6f92b8
JB
5701 }
5702}
06a2c219 5703
dc6f92b8 5704\f
06a2c219
GM
5705/* Specify how many text lines, from the top of the window,
5706 should be affected by insert-lines and delete-lines operations.
5707 This, and those operations, are used only within an update
5708 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5709
dfcf069d 5710static void
06a2c219
GM
5711XTset_terminal_window (n)
5712 register int n;
dc6f92b8 5713{
06a2c219 5714 /* This function intentionally left blank. */
dc6f92b8
JB
5715}
5716
06a2c219
GM
5717
5718\f
5719/***********************************************************************
5720 Line Dance
5721 ***********************************************************************/
5722
5723/* Perform an insert-lines or delete-lines operation, inserting N
5724 lines or deleting -N lines at vertical position VPOS. */
5725
dfcf069d 5726static void
06a2c219
GM
5727x_ins_del_lines (vpos, n)
5728 int vpos, n;
dc6f92b8
JB
5729{
5730 abort ();
5731}
06a2c219
GM
5732
5733
5734/* Scroll part of the display as described by RUN. */
dc6f92b8 5735
dfcf069d 5736static void
06a2c219
GM
5737x_scroll_run (w, run)
5738 struct window *w;
5739 struct run *run;
dc6f92b8 5740{
06a2c219
GM
5741 struct frame *f = XFRAME (w->frame);
5742 int x, y, width, height, from_y, to_y, bottom_y;
5743
5744 /* Get frame-relative bounding box of the text display area of W,
3f332ef3
KS
5745 without mode lines. Include in this box the left and right
5746 fringe of W. */
06a2c219 5747 window_box (w, -1, &x, &y, &width, &height);
3f332ef3
KS
5748 width += FRAME_X_FRINGE_WIDTH (f);
5749 x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
06a2c219
GM
5750
5751 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5752 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5753 bottom_y = y + height;
dc6f92b8 5754
06a2c219
GM
5755 if (to_y < from_y)
5756 {
5757 /* Scrolling up. Make sure we don't copy part of the mode
5758 line at the bottom. */
5759 if (from_y + run->height > bottom_y)
5760 height = bottom_y - from_y;
5761 else
5762 height = run->height;
5763 }
dc6f92b8 5764 else
06a2c219
GM
5765 {
5766 /* Scolling down. Make sure we don't copy over the mode line.
5767 at the bottom. */
5768 if (to_y + run->height > bottom_y)
5769 height = bottom_y - to_y;
5770 else
5771 height = run->height;
5772 }
7a13e894 5773
06a2c219
GM
5774 BLOCK_INPUT;
5775
5776 /* Cursor off. Will be switched on again in x_update_window_end. */
5777 updated_window = w;
5778 x_clear_cursor (w);
5779
5780 XCopyArea (FRAME_X_DISPLAY (f),
5781 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5782 f->output_data.x->normal_gc,
5783 x, from_y,
5784 width, height,
5785 x, to_y);
5786
5787 UNBLOCK_INPUT;
5788}
dc6f92b8 5789
dc6f92b8 5790
06a2c219
GM
5791\f
5792/***********************************************************************
5793 Exposure Events
5794 ***********************************************************************/
5795
5796/* Redisplay an exposed area of frame F. X and Y are the upper-left
5797 corner of the exposed rectangle. W and H are width and height of
5798 the exposed area. All are pixel values. W or H zero means redraw
5799 the entire frame. */
dc6f92b8 5800
06a2c219
GM
5801static void
5802expose_frame (f, x, y, w, h)
5803 struct frame *f;
5804 int x, y, w, h;
dc6f92b8 5805{
06a2c219 5806 XRectangle r;
82f053ab 5807 int mouse_face_overwritten_p = 0;
dc6f92b8 5808
06a2c219 5809 TRACE ((stderr, "expose_frame "));
dc6f92b8 5810
06a2c219
GM
5811 /* No need to redraw if frame will be redrawn soon. */
5812 if (FRAME_GARBAGED_P (f))
dc6f92b8 5813 {
06a2c219
GM
5814 TRACE ((stderr, " garbaged\n"));
5815 return;
5816 }
5817
5818 /* If basic faces haven't been realized yet, there is no point in
5819 trying to redraw anything. This can happen when we get an expose
5820 event while Emacs is starting, e.g. by moving another window. */
5821 if (FRAME_FACE_CACHE (f) == NULL
5822 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5823 {
5824 TRACE ((stderr, " no faces\n"));
5825 return;
58769bee 5826 }
06a2c219
GM
5827
5828 if (w == 0 || h == 0)
58769bee 5829 {
06a2c219
GM
5830 r.x = r.y = 0;
5831 r.width = CANON_X_UNIT (f) * f->width;
5832 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5833 }
5834 else
5835 {
06a2c219
GM
5836 r.x = x;
5837 r.y = y;
5838 r.width = w;
5839 r.height = h;
5840 }
5841
5842 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
82f053ab 5843 mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
06a2c219 5844
9ea173e8 5845 if (WINDOWP (f->tool_bar_window))
82f053ab
GM
5846 mouse_face_overwritten_p
5847 |= expose_window (XWINDOW (f->tool_bar_window), &r);
06a2c219
GM
5848
5849#ifndef USE_X_TOOLKIT
5850 if (WINDOWP (f->menu_bar_window))
82f053ab
GM
5851 mouse_face_overwritten_p
5852 |= expose_window (XWINDOW (f->menu_bar_window), &r);
06a2c219 5853#endif /* not USE_X_TOOLKIT */
82f053ab
GM
5854
5855 /* Some window managers support a focus-follows-mouse style with
5856 delayed raising of frames. Imagine a partially obscured frame,
5857 and moving the mouse into partially obscured mouse-face on that
5858 frame. The visible part of the mouse-face will be highlighted,
5859 then the WM raises the obscured frame. With at least one WM, KDE
5860 2.1, Emacs is not getting any event for the raising of the frame
5861 (even tried with SubstructureRedirectMask), only Expose events.
5862 These expose events will draw text normally, i.e. not
5863 highlighted. Which means we must redo the highlight here.
5864 Subsume it under ``we love X''. --gerd 2001-08-15 */
5865 if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
5866 {
5867 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5868 if (f == dpyinfo->mouse_face_mouse_frame)
5869 {
5870 int x = dpyinfo->mouse_face_mouse_x;
5871 int y = dpyinfo->mouse_face_mouse_y;
5872 clear_mouse_face (dpyinfo);
5873 note_mouse_highlight (f, x, y);
5874 }
5875 }
dc6f92b8
JB
5876}
5877
06a2c219
GM
5878
5879/* Redraw (parts) of all windows in the window tree rooted at W that
82f053ab
GM
5880 intersect R. R contains frame pixel coordinates. Value is
5881 non-zero if the exposure overwrites mouse-face. */
06a2c219 5882
82f053ab 5883static int
06a2c219
GM
5884expose_window_tree (w, r)
5885 struct window *w;
5886 XRectangle *r;
dc6f92b8 5887{
82f053ab
GM
5888 struct frame *f = XFRAME (w->frame);
5889 int mouse_face_overwritten_p = 0;
5890
5891 while (w && !FRAME_GARBAGED_P (f))
06a2c219
GM
5892 {
5893 if (!NILP (w->hchild))
82f053ab
GM
5894 mouse_face_overwritten_p
5895 |= expose_window_tree (XWINDOW (w->hchild), r);
06a2c219 5896 else if (!NILP (w->vchild))
82f053ab
GM
5897 mouse_face_overwritten_p
5898 |= expose_window_tree (XWINDOW (w->vchild), r);
5899 else
5900 mouse_face_overwritten_p |= expose_window (w, r);
5901
a02f1be0 5902 w = NILP (w->next) ? NULL : XWINDOW (w->next);
06a2c219 5903 }
82f053ab
GM
5904
5905 return mouse_face_overwritten_p;
06a2c219 5906}
58769bee 5907
dc6f92b8 5908
06a2c219
GM
5909/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5910 which intersects rectangle R. R is in window-relative coordinates. */
5911
5912static void
5913expose_area (w, row, r, area)
5914 struct window *w;
5915 struct glyph_row *row;
5916 XRectangle *r;
5917 enum glyph_row_area area;
5918{
06a2c219
GM
5919 struct glyph *first = row->glyphs[area];
5920 struct glyph *end = row->glyphs[area] + row->used[area];
5921 struct glyph *last;
4bc6dcc7 5922 int first_x, start_x, x;
06a2c219 5923
6fb13182
GM
5924 if (area == TEXT_AREA && row->fill_line_p)
5925 /* If row extends face to end of line write the whole line. */
153f5ed7 5926 x_draw_glyphs (w, 0, row, area, 0, row->used[area],
f0a48a01 5927 DRAW_NORMAL_TEXT, 0);
6fb13182
GM
5928 else
5929 {
4bc6dcc7
GM
5930 /* Set START_X to the window-relative start position for drawing glyphs of
5931 AREA. The first glyph of the text area can be partially visible.
5932 The first glyphs of other areas cannot. */
5933 if (area == LEFT_MARGIN_AREA)
5934 start_x = 0;
5935 else if (area == TEXT_AREA)
5936 start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5937 else
5938 start_x = (window_box_width (w, LEFT_MARGIN_AREA)
5939 + window_box_width (w, TEXT_AREA));
5940 x = start_x;
5941
6fb13182
GM
5942 /* Find the first glyph that must be redrawn. */
5943 while (first < end
5944 && x + first->pixel_width < r->x)
5945 {
5946 x += first->pixel_width;
5947 ++first;
5948 }
5949
5950 /* Find the last one. */
5951 last = first;
5952 first_x = x;
5953 while (last < end
5954 && x < r->x + r->width)
5955 {
5956 x += last->pixel_width;
5957 ++last;
5958 }
5959
5960 /* Repaint. */
5961 if (last > first)
4bc6dcc7 5962 x_draw_glyphs (w, first_x - start_x, row, area,
6fb13182
GM
5963 first - row->glyphs[area],
5964 last - row->glyphs[area],
f0a48a01 5965 DRAW_NORMAL_TEXT, 0);
6fb13182 5966 }
06a2c219
GM
5967}
5968
58769bee 5969
06a2c219 5970/* Redraw the parts of the glyph row ROW on window W intersecting
82f053ab
GM
5971 rectangle R. R is in window-relative coordinates. Value is
5972 non-zero if mouse-face was overwritten. */
dc6f92b8 5973
82f053ab 5974static int
06a2c219
GM
5975expose_line (w, row, r)
5976 struct window *w;
5977 struct glyph_row *row;
5978 XRectangle *r;
5979{
5980 xassert (row->enabled_p);
5981
5982 if (row->mode_line_p || w->pseudo_window_p)
5983 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
f0a48a01 5984 DRAW_NORMAL_TEXT, 0);
06a2c219
GM
5985 else
5986 {
5987 if (row->used[LEFT_MARGIN_AREA])
5988 expose_area (w, row, r, LEFT_MARGIN_AREA);
5989 if (row->used[TEXT_AREA])
5990 expose_area (w, row, r, TEXT_AREA);
5991 if (row->used[RIGHT_MARGIN_AREA])
5992 expose_area (w, row, r, RIGHT_MARGIN_AREA);
3f332ef3 5993 x_draw_row_fringe_bitmaps (w, row);
06a2c219 5994 }
82f053ab
GM
5995
5996 return row->mouse_face_p;
06a2c219 5997}
dc6f92b8 5998
58769bee 5999
06a2c219
GM
6000/* Return non-zero if W's cursor intersects rectangle R. */
6001
6002static int
6003x_phys_cursor_in_rect_p (w, r)
6004 struct window *w;
6005 XRectangle *r;
6006{
6007 XRectangle cr, result;
6008 struct glyph *cursor_glyph;
6009
6010 cursor_glyph = get_phys_cursor_glyph (w);
6011 if (cursor_glyph)
6012 {
6013 cr.x = w->phys_cursor.x;
6014 cr.y = w->phys_cursor.y;
6015 cr.width = cursor_glyph->pixel_width;
6016 cr.height = w->phys_cursor_height;
6017 return x_intersect_rectangles (&cr, r, &result);
6018 }
6019 else
6020 return 0;
dc6f92b8 6021}
dc6f92b8 6022
06a2c219 6023
a02f1be0
GM
6024/* Redraw the part of window W intersection rectangle FR. Pixel
6025 coordinates in FR are frame-relative. Call this function with
82f053ab
GM
6026 input blocked. Value is non-zero if the exposure overwrites
6027 mouse-face. */
dc6f92b8 6028
a39202f6 6029static int
a02f1be0 6030expose_window (w, fr)
06a2c219 6031 struct window *w;
a02f1be0 6032 XRectangle *fr;
dc6f92b8 6033{
a02f1be0 6034 struct frame *f = XFRAME (w->frame);
a02f1be0 6035 XRectangle wr, r;
82f053ab 6036 int mouse_face_overwritten_p = 0;
dc6f92b8 6037
80c32bcc
GM
6038 /* If window is not yet fully initialized, do nothing. This can
6039 happen when toolkit scroll bars are used and a window is split.
6040 Reconfiguring the scroll bar will generate an expose for a newly
6041 created window. */
a39202f6 6042 if (w->current_matrix == NULL)
82f053ab 6043 return 0;
a39202f6
GM
6044
6045 /* When we're currently updating the window, display and current
6046 matrix usually don't agree. Arrange for a thorough display
6047 later. */
6048 if (w == updated_window)
6049 {
6050 SET_FRAME_GARBAGED (f);
6051 return 0;
6052 }
80c32bcc 6053
a39202f6 6054 /* Frame-relative pixel rectangle of W. */
a02f1be0
GM
6055 wr.x = XFASTINT (w->left) * CANON_X_UNIT (f);
6056 wr.y = XFASTINT (w->top) * CANON_Y_UNIT (f);
6057 wr.width = XFASTINT (w->width) * CANON_X_UNIT (f);
6058 wr.height = XFASTINT (w->height) * CANON_Y_UNIT (f);
6059
a39202f6
GM
6060 if (x_intersect_rectangles (fr, &wr, &r))
6061 {
6062 int yb = window_text_bottom_y (w);
6063 struct glyph_row *row;
6064 int cursor_cleared_p;
a02f1be0 6065
a39202f6
GM
6066 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
6067 r.x, r.y, r.width, r.height));
dc6f92b8 6068
a39202f6
GM
6069 /* Convert to window coordinates. */
6070 r.x = FRAME_TO_WINDOW_PIXEL_X (w, r.x);
6071 r.y = FRAME_TO_WINDOW_PIXEL_Y (w, r.y);
dc6f92b8 6072
a39202f6
GM
6073 /* Turn off the cursor. */
6074 if (!w->pseudo_window_p
6075 && x_phys_cursor_in_rect_p (w, &r))
6076 {
6077 x_clear_cursor (w);
6078 cursor_cleared_p = 1;
6079 }
6080 else
6081 cursor_cleared_p = 0;
06a2c219 6082
a39202f6
GM
6083 /* Find the first row intersecting the rectangle R. */
6084 for (row = w->current_matrix->rows;
6085 row->enabled_p;
6086 ++row)
6087 {
6088 int y0 = row->y;
6089 int y1 = MATRIX_ROW_BOTTOM_Y (row);
6090
6091 if ((y0 >= r.y && y0 < r.y + r.height)
6092 || (y1 > r.y && y1 < r.y + r.height)
6093 || (r.y >= y0 && r.y < y1)
6094 || (r.y + r.height > y0 && r.y + r.height < y1))
82f053ab
GM
6095 {
6096 if (expose_line (w, row, &r))
6097 mouse_face_overwritten_p = 1;
6098 }
6099
a39202f6
GM
6100 if (y1 >= yb)
6101 break;
6102 }
dc6f92b8 6103
a39202f6
GM
6104 /* Display the mode line if there is one. */
6105 if (WINDOW_WANTS_MODELINE_P (w)
6106 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
6107 row->enabled_p)
6108 && row->y < r.y + r.height)
82f053ab
GM
6109 {
6110 if (expose_line (w, row, &r))
6111 mouse_face_overwritten_p = 1;
6112 }
a39202f6
GM
6113
6114 if (!w->pseudo_window_p)
6115 {
6116 /* Draw border between windows. */
6117 x_draw_vertical_border (w);
06a2c219 6118
a39202f6
GM
6119 /* Turn the cursor on again. */
6120 if (cursor_cleared_p)
6121 x_update_window_cursor (w, 1);
6122 }
06a2c219 6123 }
82f053ab
GM
6124
6125 return mouse_face_overwritten_p;
06a2c219 6126}
dc6f92b8 6127
dc6f92b8 6128
06a2c219
GM
6129/* Determine the intersection of two rectangles R1 and R2. Return
6130 the intersection in *RESULT. Value is non-zero if RESULT is not
6131 empty. */
6132
6133static int
6134x_intersect_rectangles (r1, r2, result)
6135 XRectangle *r1, *r2, *result;
6136{
6137 XRectangle *left, *right;
6138 XRectangle *upper, *lower;
6139 int intersection_p = 0;
6140
6141 /* Rearrange so that R1 is the left-most rectangle. */
6142 if (r1->x < r2->x)
6143 left = r1, right = r2;
6144 else
6145 left = r2, right = r1;
6146
6147 /* X0 of the intersection is right.x0, if this is inside R1,
6148 otherwise there is no intersection. */
6149 if (right->x <= left->x + left->width)
6150 {
6151 result->x = right->x;
6152
6153 /* The right end of the intersection is the minimum of the
6154 the right ends of left and right. */
6155 result->width = (min (left->x + left->width, right->x + right->width)
6156 - result->x);
6157
6158 /* Same game for Y. */
6159 if (r1->y < r2->y)
6160 upper = r1, lower = r2;
6161 else
6162 upper = r2, lower = r1;
6163
6164 /* The upper end of the intersection is lower.y0, if this is inside
6165 of upper. Otherwise, there is no intersection. */
6166 if (lower->y <= upper->y + upper->height)
dc43ef94 6167 {
06a2c219
GM
6168 result->y = lower->y;
6169
6170 /* The lower end of the intersection is the minimum of the lower
6171 ends of upper and lower. */
6172 result->height = (min (lower->y + lower->height,
6173 upper->y + upper->height)
6174 - result->y);
6175 intersection_p = 1;
dc43ef94 6176 }
dc6f92b8
JB
6177 }
6178
06a2c219 6179 return intersection_p;
dc6f92b8 6180}
06a2c219
GM
6181
6182
6183
6184
dc6f92b8 6185\f
dc6f92b8 6186static void
334208b7
RS
6187frame_highlight (f)
6188 struct frame *f;
dc6f92b8 6189{
b3e1e05c
JB
6190 /* We used to only do this if Vx_no_window_manager was non-nil, but
6191 the ICCCM (section 4.1.6) says that the window's border pixmap
6192 and border pixel are window attributes which are "private to the
6193 client", so we can always change it to whatever we want. */
6194 BLOCK_INPUT;
334208b7 6195 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6196 f->output_data.x->border_pixel);
b3e1e05c 6197 UNBLOCK_INPUT;
5d46f928 6198 x_update_cursor (f, 1);
dc6f92b8
JB
6199}
6200
6201static void
334208b7
RS
6202frame_unhighlight (f)
6203 struct frame *f;
dc6f92b8 6204{
b3e1e05c
JB
6205 /* We used to only do this if Vx_no_window_manager was non-nil, but
6206 the ICCCM (section 4.1.6) says that the window's border pixmap
6207 and border pixel are window attributes which are "private to the
6208 client", so we can always change it to whatever we want. */
6209 BLOCK_INPUT;
334208b7 6210 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6211 f->output_data.x->border_tile);
b3e1e05c 6212 UNBLOCK_INPUT;
5d46f928 6213 x_update_cursor (f, 1);
dc6f92b8 6214}
dc6f92b8 6215
f676886a
JB
6216/* The focus has changed. Update the frames as necessary to reflect
6217 the new situation. Note that we can't change the selected frame
c5acd733 6218 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 6219 Each event gets marked with the frame in which it occurred, so the
c5acd733 6220 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 6221
6d4238f3 6222static void
0f941935
KH
6223x_new_focus_frame (dpyinfo, frame)
6224 struct x_display_info *dpyinfo;
f676886a 6225 struct frame *frame;
dc6f92b8 6226{
0f941935 6227 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 6228
0f941935 6229 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 6230 {
58769bee 6231 /* Set this before calling other routines, so that they see
f676886a 6232 the correct value of x_focus_frame. */
0f941935 6233 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
6234
6235 if (old_focus && old_focus->auto_lower)
f676886a 6236 x_lower_frame (old_focus);
dc6f92b8
JB
6237
6238#if 0
f676886a 6239 selected_frame = frame;
e0c1aef2
KH
6240 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6241 selected_frame);
f676886a
JB
6242 Fselect_window (selected_frame->selected_window);
6243 choose_minibuf_frame ();
c118dd06 6244#endif /* ! 0 */
dc6f92b8 6245
0f941935
KH
6246 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6247 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
6248 else
6249 pending_autoraise_frame = 0;
6d4238f3 6250 }
dc6f92b8 6251
0f941935 6252 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
6253}
6254
37c2c98b
RS
6255/* Handle an event saying the mouse has moved out of an Emacs frame. */
6256
6257void
0f941935
KH
6258x_mouse_leave (dpyinfo)
6259 struct x_display_info *dpyinfo;
37c2c98b 6260{
0f941935 6261 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 6262}
6d4238f3 6263
f451eb13
JB
6264/* The focus has changed, or we have redirected a frame's focus to
6265 another frame (this happens when a frame uses a surrogate
06a2c219 6266 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
6267
6268 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 6269 frame is being highlighted or un-highlighted; we only use it to find
0f941935 6270 the appropriate X display info. */
06a2c219 6271
6d4238f3 6272static void
0f941935
KH
6273XTframe_rehighlight (frame)
6274 struct frame *frame;
6d4238f3 6275{
0f941935
KH
6276 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6277}
6d4238f3 6278
0f941935
KH
6279static void
6280x_frame_rehighlight (dpyinfo)
6281 struct x_display_info *dpyinfo;
6282{
6283 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6284
6285 if (dpyinfo->x_focus_frame)
6d4238f3 6286 {
0f941935
KH
6287 dpyinfo->x_highlight_frame
6288 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6289 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6290 : dpyinfo->x_focus_frame);
6291 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 6292 {
0f941935
KH
6293 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6294 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 6295 }
dc6f92b8 6296 }
6d4238f3 6297 else
0f941935 6298 dpyinfo->x_highlight_frame = 0;
dc6f92b8 6299
0f941935 6300 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
6301 {
6302 if (old_highlight)
f676886a 6303 frame_unhighlight (old_highlight);
0f941935
KH
6304 if (dpyinfo->x_highlight_frame)
6305 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 6306 }
dc6f92b8 6307}
06a2c219
GM
6308
6309
dc6f92b8 6310\f
06a2c219 6311/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 6312
28430d3c
JB
6313/* Initialize mode_switch_bit and modifier_meaning. */
6314static void
334208b7
RS
6315x_find_modifier_meanings (dpyinfo)
6316 struct x_display_info *dpyinfo;
28430d3c 6317{
f689eb05 6318 int min_code, max_code;
28430d3c
JB
6319 KeySym *syms;
6320 int syms_per_code;
6321 XModifierKeymap *mods;
6322
334208b7
RS
6323 dpyinfo->meta_mod_mask = 0;
6324 dpyinfo->shift_lock_mask = 0;
6325 dpyinfo->alt_mod_mask = 0;
6326 dpyinfo->super_mod_mask = 0;
6327 dpyinfo->hyper_mod_mask = 0;
58769bee 6328
9658a521 6329#ifdef HAVE_X11R4
334208b7 6330 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 6331#else
4a60f8c5
RS
6332 min_code = dpyinfo->display->min_keycode;
6333 max_code = dpyinfo->display->max_keycode;
9658a521
JB
6334#endif
6335
334208b7 6336 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
6337 min_code, max_code - min_code + 1,
6338 &syms_per_code);
334208b7 6339 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 6340
58769bee 6341 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 6342 Alt keysyms are on. */
28430d3c 6343 {
06a2c219 6344 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
6345
6346 for (row = 3; row < 8; row++)
6347 for (col = 0; col < mods->max_keypermod; col++)
6348 {
0299d313
RS
6349 KeyCode code
6350 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 6351
af92970c
KH
6352 /* Zeroes are used for filler. Skip them. */
6353 if (code == 0)
6354 continue;
6355
28430d3c
JB
6356 /* Are any of this keycode's keysyms a meta key? */
6357 {
6358 int code_col;
6359
6360 for (code_col = 0; code_col < syms_per_code; code_col++)
6361 {
f689eb05 6362 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 6363
f689eb05 6364 switch (sym)
28430d3c 6365 {
f689eb05
JB
6366 case XK_Meta_L:
6367 case XK_Meta_R:
334208b7 6368 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 6369 break;
f689eb05
JB
6370
6371 case XK_Alt_L:
6372 case XK_Alt_R:
334208b7 6373 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
6374 break;
6375
6376 case XK_Hyper_L:
6377 case XK_Hyper_R:
334208b7 6378 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
6379 break;
6380
6381 case XK_Super_L:
6382 case XK_Super_R:
334208b7 6383 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 6384 break;
11edeb03
JB
6385
6386 case XK_Shift_Lock:
6387 /* Ignore this if it's not on the lock modifier. */
6388 if ((1 << row) == LockMask)
334208b7 6389 dpyinfo->shift_lock_mask = LockMask;
11edeb03 6390 break;
28430d3c
JB
6391 }
6392 }
6393 }
6394 }
6395 }
6396
f689eb05 6397 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 6398 if (! dpyinfo->meta_mod_mask)
a3c44b14 6399 {
334208b7
RS
6400 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6401 dpyinfo->alt_mod_mask = 0;
a3c44b14 6402 }
f689eb05 6403
148c4b70
RS
6404 /* If some keys are both alt and meta,
6405 make them just meta, not alt. */
334208b7 6406 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 6407 {
334208b7 6408 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 6409 }
58769bee 6410
28430d3c 6411 XFree ((char *) syms);
f689eb05 6412 XFreeModifiermap (mods);
28430d3c
JB
6413}
6414
dfeccd2d
JB
6415/* Convert between the modifier bits X uses and the modifier bits
6416 Emacs uses. */
06a2c219 6417
7c5283e4 6418static unsigned int
334208b7
RS
6419x_x_to_emacs_modifiers (dpyinfo, state)
6420 struct x_display_info *dpyinfo;
dc6f92b8
JB
6421 unsigned int state;
6422{
334208b7
RS
6423 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
6424 | ((state & ControlMask) ? ctrl_modifier : 0)
6425 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
6426 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
6427 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
6428 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
6429}
6430
dfeccd2d 6431static unsigned int
334208b7
RS
6432x_emacs_to_x_modifiers (dpyinfo, state)
6433 struct x_display_info *dpyinfo;
dfeccd2d
JB
6434 unsigned int state;
6435{
334208b7
RS
6436 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
6437 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6438 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6439 | ((state & shift_modifier) ? ShiftMask : 0)
6440 | ((state & ctrl_modifier) ? ControlMask : 0)
6441 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6442}
d047c4eb
KH
6443
6444/* Convert a keysym to its name. */
6445
6446char *
6447x_get_keysym_name (keysym)
6448 KeySym keysym;
6449{
6450 char *value;
6451
6452 BLOCK_INPUT;
6453 value = XKeysymToString (keysym);
6454 UNBLOCK_INPUT;
6455
6456 return value;
6457}
06a2c219
GM
6458
6459
e4571a43
JB
6460\f
6461/* Mouse clicks and mouse movement. Rah. */
e4571a43 6462
06a2c219
GM
6463/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6464 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6465 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6466 not force the value into range. */
69388238 6467
c8dba240 6468void
69388238 6469pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6470 FRAME_PTR f;
69388238 6471 register int pix_x, pix_y;
e4571a43
JB
6472 register int *x, *y;
6473 XRectangle *bounds;
69388238 6474 int noclip;
e4571a43 6475{
06a2c219 6476 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6477 even for negative values. */
6478 if (pix_x < 0)
7556890b 6479 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6480 if (pix_y < 0)
7556890b 6481 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6482
e4571a43
JB
6483 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6484 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6485
6486 if (bounds)
6487 {
7556890b
RS
6488 bounds->width = FONT_WIDTH (f->output_data.x->font);
6489 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6490 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6491 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6492 }
6493
69388238
RS
6494 if (!noclip)
6495 {
6496 if (pix_x < 0)
6497 pix_x = 0;
3cbd2e0b
RS
6498 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6499 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6500
6501 if (pix_y < 0)
6502 pix_y = 0;
6503 else if (pix_y > f->height)
6504 pix_y = f->height;
6505 }
e4571a43
JB
6506
6507 *x = pix_x;
6508 *y = pix_y;
6509}
6510
06a2c219
GM
6511
6512/* Given HPOS/VPOS in the current matrix of W, return corresponding
6513 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6514 can't tell the positions because W's display is not up to date,
6515 return 0. */
6516
6517int
6518glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6519 struct window *w;
6520 int hpos, vpos;
6521 int *frame_x, *frame_y;
2b5c9e71 6522{
06a2c219
GM
6523 int success_p;
6524
6525 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6526 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6527
6528 if (display_completed)
6529 {
6530 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6531 struct glyph *glyph = row->glyphs[TEXT_AREA];
6532 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6533
6534 *frame_y = row->y;
6535 *frame_x = row->x;
6536 while (glyph < end)
6537 {
6538 *frame_x += glyph->pixel_width;
6539 ++glyph;
6540 }
6541
6542 success_p = 1;
6543 }
6544 else
6545 {
6546 *frame_y = *frame_x = 0;
6547 success_p = 0;
6548 }
6549
6550 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6551 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6552 return success_p;
2b5c9e71
RS
6553}
6554
06a2c219 6555
dc6f92b8
JB
6556/* Prepare a mouse-event in *RESULT for placement in the input queue.
6557
6558 If the event is a button press, then note that we have grabbed
f451eb13 6559 the mouse. */
dc6f92b8
JB
6560
6561static Lisp_Object
f451eb13 6562construct_mouse_click (result, event, f)
dc6f92b8
JB
6563 struct input_event *result;
6564 XButtonEvent *event;
f676886a 6565 struct frame *f;
dc6f92b8 6566{
f451eb13 6567 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6568 otherwise. */
f451eb13 6569 result->kind = mouse_click;
69388238 6570 result->code = event->button - Button1;
1113d9db 6571 result->timestamp = event->time;
334208b7
RS
6572 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6573 event->state)
f689eb05 6574 | (event->type == ButtonRelease
58769bee 6575 ? up_modifier
f689eb05 6576 : down_modifier));
dc6f92b8 6577
06a2c219
GM
6578 XSETINT (result->x, event->x);
6579 XSETINT (result->y, event->y);
6580 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6581 result->arg = Qnil;
06a2c219 6582 return Qnil;
dc6f92b8 6583}
b849c413 6584
69388238 6585\f
90e65f07
JB
6586/* Function to report a mouse movement to the mainstream Emacs code.
6587 The input handler calls this.
6588
6589 We have received a mouse movement event, which is given in *event.
6590 If the mouse is over a different glyph than it was last time, tell
6591 the mainstream emacs code by setting mouse_moved. If not, ask for
6592 another motion event, so we can check again the next time it moves. */
b8009dd1 6593
06a2c219
GM
6594static XMotionEvent last_mouse_motion_event;
6595static Lisp_Object last_mouse_motion_frame;
6596
90e65f07 6597static void
12ba150f 6598note_mouse_movement (frame, event)
f676886a 6599 FRAME_PTR frame;
90e65f07 6600 XMotionEvent *event;
90e65f07 6601{
e5d77022 6602 last_mouse_movement_time = event->time;
06a2c219
GM
6603 last_mouse_motion_event = *event;
6604 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6605
27f338af
RS
6606 if (event->window != FRAME_X_WINDOW (frame))
6607 {
39d8bb4d 6608 frame->mouse_moved = 1;
27f338af 6609 last_mouse_scroll_bar = Qnil;
27f338af 6610 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6611 }
6612
90e65f07 6613 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6614 else if (event->x < last_mouse_glyph.x
6615 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6616 || event->y < last_mouse_glyph.y
6617 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6618 {
39d8bb4d 6619 frame->mouse_moved = 1;
ab648270 6620 last_mouse_scroll_bar = Qnil;
b8009dd1 6621 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6622 }
6623}
6624
bf1c0ba1 6625/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6626
06a2c219
GM
6627 int disable_mouse_highlight;
6628
6629
6630\f
6631/************************************************************************
6632 Mouse Face
6633 ************************************************************************/
6634
6635/* Find the glyph under window-relative coordinates X/Y in window W.
6636 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6637 strings. Return in *HPOS and *VPOS the row and column number of
6638 the glyph found. Return in *AREA the glyph area containing X.
6639 Value is a pointer to the glyph found or null if X/Y is not on
6640 text, or we can't tell because W's current matrix is not up to
6641 date. */
6642
6643static struct glyph *
f9db2310 6644x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
06a2c219
GM
6645 struct window *w;
6646 int x, y;
6647 int *hpos, *vpos, *area;
f9db2310 6648 int buffer_only_p;
06a2c219
GM
6649{
6650 struct glyph *glyph, *end;
3e71d8f2 6651 struct glyph_row *row = NULL;
06a2c219
GM
6652 int x0, i, left_area_width;
6653
6654 /* Find row containing Y. Give up if some row is not enabled. */
6655 for (i = 0; i < w->current_matrix->nrows; ++i)
6656 {
6657 row = MATRIX_ROW (w->current_matrix, i);
6658 if (!row->enabled_p)
6659 return NULL;
6660 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6661 break;
6662 }
6663
6664 *vpos = i;
6665 *hpos = 0;
6666
6667 /* Give up if Y is not in the window. */
6668 if (i == w->current_matrix->nrows)
6669 return NULL;
6670
6671 /* Get the glyph area containing X. */
6672 if (w->pseudo_window_p)
6673 {
6674 *area = TEXT_AREA;
6675 x0 = 0;
6676 }
6677 else
6678 {
6679 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6680 if (x < left_area_width)
6681 {
6682 *area = LEFT_MARGIN_AREA;
6683 x0 = 0;
6684 }
6685 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6686 {
6687 *area = TEXT_AREA;
6688 x0 = row->x + left_area_width;
6689 }
6690 else
6691 {
6692 *area = RIGHT_MARGIN_AREA;
6693 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6694 }
6695 }
6696
6697 /* Find glyph containing X. */
6698 glyph = row->glyphs[*area];
6699 end = glyph + row->used[*area];
6700 while (glyph < end)
6701 {
6702 if (x < x0 + glyph->pixel_width)
6703 {
6704 if (w->pseudo_window_p)
6705 break;
f9db2310 6706 else if (!buffer_only_p || BUFFERP (glyph->object))
06a2c219
GM
6707 break;
6708 }
6709
6710 x0 += glyph->pixel_width;
6711 ++glyph;
6712 }
6713
6714 if (glyph == end)
6715 return NULL;
6716
6717 *hpos = glyph - row->glyphs[*area];
6718 return glyph;
6719}
6720
6721
6722/* Convert frame-relative x/y to coordinates relative to window W.
6723 Takes pseudo-windows into account. */
6724
6725static void
6726frame_to_window_pixel_xy (w, x, y)
6727 struct window *w;
6728 int *x, *y;
6729{
6730 if (w->pseudo_window_p)
6731 {
6732 /* A pseudo-window is always full-width, and starts at the
6733 left edge of the frame, plus a frame border. */
6734 struct frame *f = XFRAME (w->frame);
6735 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6736 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6737 }
6738 else
6739 {
6740 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6741 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6742 }
6743}
6744
6745
e371a781 6746/* Take proper action when mouse has moved to the mode or header line of
06a2c219
GM
6747 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6748 mode line. X is relative to the start of the text display area of
3f332ef3 6749 W, so the width of fringes and scroll bars must be subtracted
06a2c219
GM
6750 to get a position relative to the start of the mode line. */
6751
6752static void
6753note_mode_line_highlight (w, x, mode_line_p)
6754 struct window *w;
6755 int x, mode_line_p;
6756{
6757 struct frame *f = XFRAME (w->frame);
6758 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6759 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6760 struct glyph_row *row;
6761
6762 if (mode_line_p)
6763 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6764 else
045dee35 6765 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
e371a781 6766
06a2c219
GM
6767 if (row->enabled_p)
6768 {
6769 struct glyph *glyph, *end;
6770 Lisp_Object help, map;
6771 int x0;
6772
6773 /* Find the glyph under X. */
6774 glyph = row->glyphs[TEXT_AREA];
6775 end = glyph + row->used[TEXT_AREA];
6776 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
3f332ef3 6777 + FRAME_X_LEFT_FRINGE_WIDTH (f));
e371a781 6778
06a2c219
GM
6779 while (glyph < end
6780 && x >= x0 + glyph->pixel_width)
6781 {
6782 x0 += glyph->pixel_width;
6783 ++glyph;
6784 }
6785
6786 if (glyph < end
6787 && STRINGP (glyph->object)
6788 && XSTRING (glyph->object)->intervals
6789 && glyph->charpos >= 0
6790 && glyph->charpos < XSTRING (glyph->object)->size)
6791 {
6792 /* If we're on a string with `help-echo' text property,
6793 arrange for the help to be displayed. This is done by
6794 setting the global variable help_echo to the help string. */
6795 help = Fget_text_property (make_number (glyph->charpos),
6796 Qhelp_echo, glyph->object);
b7e80413 6797 if (!NILP (help))
be010514
GM
6798 {
6799 help_echo = help;
7cea38bc 6800 XSETWINDOW (help_echo_window, w);
be010514
GM
6801 help_echo_object = glyph->object;
6802 help_echo_pos = glyph->charpos;
6803 }
06a2c219
GM
6804
6805 /* Change the mouse pointer according to what is under X/Y. */
6806 map = Fget_text_property (make_number (glyph->charpos),
6807 Qlocal_map, glyph->object);
02067692 6808 if (KEYMAPP (map))
06a2c219 6809 cursor = f->output_data.x->nontext_cursor;
be010514
GM
6810 else
6811 {
6812 map = Fget_text_property (make_number (glyph->charpos),
6813 Qkeymap, glyph->object);
02067692 6814 if (KEYMAPP (map))
be010514
GM
6815 cursor = f->output_data.x->nontext_cursor;
6816 }
06a2c219
GM
6817 }
6818 }
6819
6820 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6821}
6822
6823
6824/* Take proper action when the mouse has moved to position X, Y on
6825 frame F as regards highlighting characters that have mouse-face
6826 properties. Also de-highlighting chars where the mouse was before.
27f338af 6827 X and Y can be negative or out of range. */
b8009dd1
RS
6828
6829static void
6830note_mouse_highlight (f, x, y)
06a2c219 6831 struct frame *f;
c32cdd9a 6832 int x, y;
b8009dd1 6833{
06a2c219
GM
6834 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6835 int portion;
b8009dd1
RS
6836 Lisp_Object window;
6837 struct window *w;
0d487c52
GM
6838 Cursor cursor = None;
6839 struct buffer *b;
b8009dd1 6840
06a2c219
GM
6841 /* When a menu is active, don't highlight because this looks odd. */
6842#ifdef USE_X_TOOLKIT
6843 if (popup_activated ())
6844 return;
6845#endif
6846
04fff9c0
GM
6847 if (disable_mouse_highlight
6848 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6849 return;
6850
06a2c219
GM
6851 dpyinfo->mouse_face_mouse_x = x;
6852 dpyinfo->mouse_face_mouse_y = y;
6853 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6854
06a2c219 6855 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6856 return;
6857
514e4681
RS
6858 if (gc_in_progress)
6859 {
06a2c219 6860 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6861 return;
6862 }
6863
b8009dd1 6864 /* Which window is that in? */
06a2c219 6865 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6866
6867 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6868 if (! EQ (window, dpyinfo->mouse_face_window))
6869 clear_mouse_face (dpyinfo);
6870
6871 /* Not on a window -> return. */
6872 if (!WINDOWP (window))
6873 return;
6874
6875 /* Convert to window-relative pixel coordinates. */
6876 w = XWINDOW (window);
6877 frame_to_window_pixel_xy (w, &x, &y);
6878
9ea173e8 6879 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6880 buffer. */
9ea173e8 6881 if (EQ (window, f->tool_bar_window))
06a2c219 6882 {
9ea173e8 6883 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6884 return;
6885 }
6886
0d487c52 6887 /* Mouse is on the mode or header line? */
06a2c219
GM
6888 if (portion == 1 || portion == 3)
6889 {
06a2c219
GM
6890 note_mode_line_highlight (w, x, portion == 1);
6891 return;
6892 }
0d487c52
GM
6893
6894 if (portion == 2)
6895 cursor = f->output_data.x->horizontal_drag_cursor;
06a2c219 6896 else
0d487c52 6897 cursor = f->output_data.x->text_cursor;
b8009dd1 6898
0cdd0c9f
RS
6899 /* Are we in a window whose display is up to date?
6900 And verify the buffer's text has not changed. */
0d487c52 6901 b = XBUFFER (w->buffer);
06a2c219
GM
6902 if (/* Within text portion of the window. */
6903 portion == 0
0cdd0c9f 6904 && EQ (w->window_end_valid, w->buffer)
0d487c52
GM
6905 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
6906 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
b8009dd1 6907 {
06a2c219
GM
6908 int hpos, vpos, pos, i, area;
6909 struct glyph *glyph;
f9db2310 6910 Lisp_Object object;
0d487c52
GM
6911 Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
6912 Lisp_Object *overlay_vec = NULL;
6913 int len, noverlays;
6914 struct buffer *obuf;
6915 int obegv, ozv, same_region;
b8009dd1 6916
06a2c219 6917 /* Find the glyph under X/Y. */
f9db2310 6918 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
06a2c219
GM
6919
6920 /* Clear mouse face if X/Y not over text. */
6921 if (glyph == NULL
6922 || area != TEXT_AREA
6923 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6924 {
fa262c07
GM
6925 if (clear_mouse_face (dpyinfo))
6926 cursor = None;
6927 goto set_cursor;
06a2c219
GM
6928 }
6929
6930 pos = glyph->charpos;
f9db2310
GM
6931 object = glyph->object;
6932 if (!STRINGP (object) && !BUFFERP (object))
fa262c07 6933 goto set_cursor;
06a2c219 6934
0d487c52
GM
6935 /* If we get an out-of-range value, return now; avoid an error. */
6936 if (BUFFERP (object) && pos > BUF_Z (b))
fa262c07 6937 goto set_cursor;
06a2c219 6938
0d487c52
GM
6939 /* Make the window's buffer temporarily current for
6940 overlays_at and compute_char_face. */
6941 obuf = current_buffer;
6942 current_buffer = b;
6943 obegv = BEGV;
6944 ozv = ZV;
6945 BEGV = BEG;
6946 ZV = Z;
06a2c219 6947
0d487c52
GM
6948 /* Is this char mouse-active or does it have help-echo? */
6949 position = make_number (pos);
f9db2310 6950
0d487c52
GM
6951 if (BUFFERP (object))
6952 {
6953 /* Put all the overlays we want in a vector in overlay_vec.
6954 Store the length in len. If there are more than 10, make
6955 enough space for all, and try again. */
6956 len = 10;
6957 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6958 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
6959 if (noverlays > len)
6960 {
6961 len = noverlays;
6962 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6963 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
6964 }
f8349001 6965
0d487c52
GM
6966 /* Sort overlays into increasing priority order. */
6967 noverlays = sort_overlays (overlay_vec, noverlays, w);
6968 }
6969 else
6970 noverlays = 0;
6971
6972 same_region = (EQ (window, dpyinfo->mouse_face_window)
6973 && vpos >= dpyinfo->mouse_face_beg_row
6974 && vpos <= dpyinfo->mouse_face_end_row
6975 && (vpos > dpyinfo->mouse_face_beg_row
6976 || hpos >= dpyinfo->mouse_face_beg_col)
6977 && (vpos < dpyinfo->mouse_face_end_row
6978 || hpos < dpyinfo->mouse_face_end_col
6979 || dpyinfo->mouse_face_past_end));
6980
6981 if (same_region)
6982 cursor = None;
6983
6984 /* Check mouse-face highlighting. */
6985 if (! same_region
6986 /* If there exists an overlay with mouse-face overlapping
6987 the one we are currently highlighting, we have to
6988 check if we enter the overlapping overlay, and then
6989 highlight only that. */
6990 || (OVERLAYP (dpyinfo->mouse_face_overlay)
6991 && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
6992 {
0d487c52
GM
6993 /* Find the highest priority overlay that has a mouse-face
6994 property. */
6995 overlay = Qnil;
6996 for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
6997 {
6998 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6999 if (!NILP (mouse_face))
7000 overlay = overlay_vec[i];
7001 }
8bd189fb
GM
7002
7003 /* If we're actually highlighting the same overlay as
7004 before, there's no need to do that again. */
7005 if (!NILP (overlay)
7006 && EQ (overlay, dpyinfo->mouse_face_overlay))
7007 goto check_help_echo;
f9db2310 7008
8bd189fb
GM
7009 dpyinfo->mouse_face_overlay = overlay;
7010
7011 /* Clear the display of the old active region, if any. */
7012 if (clear_mouse_face (dpyinfo))
7013 cursor = None;
7014
0d487c52
GM
7015 /* If no overlay applies, get a text property. */
7016 if (NILP (overlay))
7017 mouse_face = Fget_text_property (position, Qmouse_face, object);
06a2c219 7018
0d487c52
GM
7019 /* Handle the overlay case. */
7020 if (!NILP (overlay))
7021 {
7022 /* Find the range of text around this char that
7023 should be active. */
7024 Lisp_Object before, after;
7025 int ignore;
7026
7027 before = Foverlay_start (overlay);
7028 after = Foverlay_end (overlay);
7029 /* Record this as the current active region. */
7030 fast_find_position (w, XFASTINT (before),
7031 &dpyinfo->mouse_face_beg_col,
7032 &dpyinfo->mouse_face_beg_row,
7033 &dpyinfo->mouse_face_beg_x,
7e376260
GM
7034 &dpyinfo->mouse_face_beg_y, Qnil);
7035
0d487c52
GM
7036 dpyinfo->mouse_face_past_end
7037 = !fast_find_position (w, XFASTINT (after),
7038 &dpyinfo->mouse_face_end_col,
7039 &dpyinfo->mouse_face_end_row,
7040 &dpyinfo->mouse_face_end_x,
7e376260 7041 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7042 dpyinfo->mouse_face_window = window;
7043 dpyinfo->mouse_face_face_id
7044 = face_at_buffer_position (w, pos, 0, 0,
7045 &ignore, pos + 1, 1);
7046
7047 /* Display it as active. */
7048 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7049 cursor = None;
0d487c52
GM
7050 }
7051 /* Handle the text property case. */
7052 else if (!NILP (mouse_face) && BUFFERP (object))
7053 {
7054 /* Find the range of text around this char that
7055 should be active. */
7056 Lisp_Object before, after, beginning, end;
7057 int ignore;
7058
7059 beginning = Fmarker_position (w->start);
7060 end = make_number (BUF_Z (XBUFFER (object))
7061 - XFASTINT (w->window_end_pos));
7062 before
7063 = Fprevious_single_property_change (make_number (pos + 1),
7064 Qmouse_face,
7065 object, beginning);
7066 after
7067 = Fnext_single_property_change (position, Qmouse_face,
7068 object, end);
7069
7070 /* Record this as the current active region. */
7071 fast_find_position (w, XFASTINT (before),
7072 &dpyinfo->mouse_face_beg_col,
7073 &dpyinfo->mouse_face_beg_row,
7074 &dpyinfo->mouse_face_beg_x,
7e376260 7075 &dpyinfo->mouse_face_beg_y, Qnil);
0d487c52
GM
7076 dpyinfo->mouse_face_past_end
7077 = !fast_find_position (w, XFASTINT (after),
7078 &dpyinfo->mouse_face_end_col,
7079 &dpyinfo->mouse_face_end_row,
7080 &dpyinfo->mouse_face_end_x,
7e376260 7081 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7082 dpyinfo->mouse_face_window = window;
7083
7084 if (BUFFERP (object))
06a2c219
GM
7085 dpyinfo->mouse_face_face_id
7086 = face_at_buffer_position (w, pos, 0, 0,
7087 &ignore, pos + 1, 1);
7088
0d487c52
GM
7089 /* Display it as active. */
7090 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7091 cursor = None;
0d487c52
GM
7092 }
7093 else if (!NILP (mouse_face) && STRINGP (object))
7094 {
7095 Lisp_Object b, e;
7096 int ignore;
f9db2310 7097
0d487c52
GM
7098 b = Fprevious_single_property_change (make_number (pos + 1),
7099 Qmouse_face,
7100 object, Qnil);
7101 e = Fnext_single_property_change (position, Qmouse_face,
7102 object, Qnil);
7103 if (NILP (b))
7104 b = make_number (0);
7105 if (NILP (e))
7106 e = make_number (XSTRING (object)->size - 1);
7107 fast_find_string_pos (w, XINT (b), object,
06a2c219
GM
7108 &dpyinfo->mouse_face_beg_col,
7109 &dpyinfo->mouse_face_beg_row,
7110 &dpyinfo->mouse_face_beg_x,
0d487c52
GM
7111 &dpyinfo->mouse_face_beg_y, 0);
7112 fast_find_string_pos (w, XINT (e), object,
7113 &dpyinfo->mouse_face_end_col,
7114 &dpyinfo->mouse_face_end_row,
7115 &dpyinfo->mouse_face_end_x,
7116 &dpyinfo->mouse_face_end_y, 1);
7117 dpyinfo->mouse_face_past_end = 0;
7118 dpyinfo->mouse_face_window = window;
7119 dpyinfo->mouse_face_face_id
7120 = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
7121 glyph->face_id, 1);
7122 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7123 cursor = None;
0d487c52 7124 }
7e376260
GM
7125 else if (STRINGP (object) && NILP (mouse_face))
7126 {
7127 /* A string which doesn't have mouse-face, but
7128 the text ``under'' it might have. */
7129 struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
7130 int start = MATRIX_ROW_START_CHARPOS (r);
7131
7132 pos = string_buffer_position (w, object, start);
7133 if (pos > 0)
7134 mouse_face = get_char_property_and_overlay (make_number (pos),
7135 Qmouse_face,
7136 w->buffer,
7137 &overlay);
7138 if (!NILP (mouse_face) && !NILP (overlay))
7139 {
7140 Lisp_Object before = Foverlay_start (overlay);
7141 Lisp_Object after = Foverlay_end (overlay);
91c153e2 7142 int ignore;
7e376260
GM
7143
7144 /* Note that we might not be able to find position
7145 BEFORE in the glyph matrix if the overlay is
7146 entirely covered by a `display' property. In
7147 this case, we overshoot. So let's stop in
7148 the glyph matrix before glyphs for OBJECT. */
7149 fast_find_position (w, XFASTINT (before),
7150 &dpyinfo->mouse_face_beg_col,
7151 &dpyinfo->mouse_face_beg_row,
7152 &dpyinfo->mouse_face_beg_x,
7153 &dpyinfo->mouse_face_beg_y,
7154 object);
7155
7156 dpyinfo->mouse_face_past_end
7157 = !fast_find_position (w, XFASTINT (after),
7158 &dpyinfo->mouse_face_end_col,
7159 &dpyinfo->mouse_face_end_row,
7160 &dpyinfo->mouse_face_end_x,
7161 &dpyinfo->mouse_face_end_y,
7162 Qnil);
7163 dpyinfo->mouse_face_window = window;
7164 dpyinfo->mouse_face_face_id
7165 = face_at_buffer_position (w, pos, 0, 0,
7166 &ignore, pos + 1, 1);
7167
7168 /* Display it as active. */
7169 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
7170 cursor = None;
7171 }
7172 }
0d487c52 7173 }
06a2c219 7174
8bd189fb
GM
7175 check_help_echo:
7176
0d487c52
GM
7177 /* Look for a `help-echo' property. */
7178 {
7179 Lisp_Object help, overlay;
06a2c219 7180
0d487c52
GM
7181 /* Check overlays first. */
7182 help = overlay = Qnil;
7183 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
7184 {
7185 overlay = overlay_vec[i];
7186 help = Foverlay_get (overlay, Qhelp_echo);
7187 }
be010514 7188
0d487c52
GM
7189 if (!NILP (help))
7190 {
7191 help_echo = help;
7192 help_echo_window = window;
7193 help_echo_object = overlay;
7194 help_echo_pos = pos;
7195 }
7196 else
7197 {
7198 Lisp_Object object = glyph->object;
7199 int charpos = glyph->charpos;
7177d86b 7200
0d487c52
GM
7201 /* Try text properties. */
7202 if (STRINGP (object)
7203 && charpos >= 0
7204 && charpos < XSTRING (object)->size)
7205 {
7206 help = Fget_text_property (make_number (charpos),
7207 Qhelp_echo, object);
7208 if (NILP (help))
7209 {
7210 /* If the string itself doesn't specify a help-echo,
7211 see if the buffer text ``under'' it does. */
7212 struct glyph_row *r
7213 = MATRIX_ROW (w->current_matrix, vpos);
7214 int start = MATRIX_ROW_START_CHARPOS (r);
7215 int pos = string_buffer_position (w, object, start);
7216 if (pos > 0)
7217 {
7e376260 7218 help = Fget_char_property (make_number (pos),
0d487c52
GM
7219 Qhelp_echo, w->buffer);
7220 if (!NILP (help))
7221 {
7222 charpos = pos;
7223 object = w->buffer;
7224 }
7225 }
7226 }
7227 }
7228 else if (BUFFERP (object)
7229 && charpos >= BEGV
7230 && charpos < ZV)
7231 help = Fget_text_property (make_number (charpos), Qhelp_echo,
7232 object);
06a2c219 7233
0d487c52
GM
7234 if (!NILP (help))
7235 {
7236 help_echo = help;
7237 help_echo_window = window;
7238 help_echo_object = object;
7239 help_echo_pos = charpos;
7240 }
7241 }
06a2c219 7242 }
0d487c52
GM
7243
7244 BEGV = obegv;
7245 ZV = ozv;
7246 current_buffer = obuf;
06a2c219 7247 }
0d487c52 7248
fa262c07
GM
7249 set_cursor:
7250
0d487c52
GM
7251 if (cursor != None)
7252 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
06a2c219
GM
7253}
7254
7255static void
7256redo_mouse_highlight ()
7257{
7258 if (!NILP (last_mouse_motion_frame)
7259 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
7260 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
7261 last_mouse_motion_event.x,
7262 last_mouse_motion_event.y);
7263}
7264
7265
7266\f
7267/***********************************************************************
9ea173e8 7268 Tool-bars
06a2c219
GM
7269 ***********************************************************************/
7270
9ea173e8
GM
7271static int x_tool_bar_item P_ ((struct frame *, int, int,
7272 struct glyph **, int *, int *, int *));
06a2c219 7273
9ea173e8 7274/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
7275 or -1. */
7276
9ea173e8 7277static int last_tool_bar_item;
06a2c219
GM
7278
7279
9ea173e8
GM
7280/* Get information about the tool-bar item at position X/Y on frame F.
7281 Return in *GLYPH a pointer to the glyph of the tool-bar item in
7282 the current matrix of the tool-bar window of F, or NULL if not
7283 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
8daf1204 7284 item in F->tool_bar_items. Value is
06a2c219 7285
9ea173e8 7286 -1 if X/Y is not on a tool-bar item
06a2c219
GM
7287 0 if X/Y is on the same item that was highlighted before.
7288 1 otherwise. */
7289
7290static int
9ea173e8 7291x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
7292 struct frame *f;
7293 int x, y;
7294 struct glyph **glyph;
7295 int *hpos, *vpos, *prop_idx;
7296{
7297 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7298 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7299 int area;
7300
7301 /* Find the glyph under X/Y. */
f9db2310 7302 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
06a2c219
GM
7303 if (*glyph == NULL)
7304 return -1;
7305
9ea173e8 7306 /* Get the start of this tool-bar item's properties in
8daf1204 7307 f->tool_bar_items. */
9ea173e8 7308 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
7309 return -1;
7310
7311 /* Is mouse on the highlighted item? */
9ea173e8 7312 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
7313 && *vpos >= dpyinfo->mouse_face_beg_row
7314 && *vpos <= dpyinfo->mouse_face_end_row
7315 && (*vpos > dpyinfo->mouse_face_beg_row
7316 || *hpos >= dpyinfo->mouse_face_beg_col)
7317 && (*vpos < dpyinfo->mouse_face_end_row
7318 || *hpos < dpyinfo->mouse_face_end_col
7319 || dpyinfo->mouse_face_past_end))
7320 return 0;
7321
7322 return 1;
7323}
7324
7325
9ea173e8 7326/* Handle mouse button event on the tool-bar of frame F, at
6c4a22e6 7327 frame-relative coordinates X/Y. EVENT_TYPE is either ButtonPress
06a2c219
GM
7328 or ButtonRelase. */
7329
7330static void
9ea173e8 7331x_handle_tool_bar_click (f, button_event)
06a2c219
GM
7332 struct frame *f;
7333 XButtonEvent *button_event;
7334{
7335 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7336 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7337 int hpos, vpos, prop_idx;
7338 struct glyph *glyph;
7339 Lisp_Object enabled_p;
7340 int x = button_event->x;
7341 int y = button_event->y;
7342
9ea173e8 7343 /* If not on the highlighted tool-bar item, return. */
06a2c219 7344 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 7345 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
7346 return;
7347
7348 /* If item is disabled, do nothing. */
8daf1204 7349 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7350 if (NILP (enabled_p))
7351 return;
7352
7353 if (button_event->type == ButtonPress)
7354 {
7355 /* Show item in pressed state. */
7356 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
7357 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 7358 last_tool_bar_item = prop_idx;
06a2c219
GM
7359 }
7360 else
7361 {
7362 Lisp_Object key, frame;
7363 struct input_event event;
7364
7365 /* Show item in released state. */
7366 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
7367 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
7368
8daf1204 7369 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
06a2c219
GM
7370
7371 XSETFRAME (frame, f);
9ea173e8 7372 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7373 event.frame_or_window = frame;
7374 event.arg = frame;
06a2c219
GM
7375 kbd_buffer_store_event (&event);
7376
9ea173e8 7377 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7378 event.frame_or_window = frame;
7379 event.arg = key;
06a2c219
GM
7380 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7381 button_event->state);
7382 kbd_buffer_store_event (&event);
9ea173e8 7383 last_tool_bar_item = -1;
06a2c219
GM
7384 }
7385}
7386
7387
9ea173e8
GM
7388/* Possibly highlight a tool-bar item on frame F when mouse moves to
7389 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
7390 note_mouse_highlight. */
7391
7392static void
9ea173e8 7393note_tool_bar_highlight (f, x, y)
06a2c219
GM
7394 struct frame *f;
7395 int x, y;
7396{
9ea173e8 7397 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
7398 struct window *w = XWINDOW (window);
7399 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7400 int hpos, vpos;
7401 struct glyph *glyph;
7402 struct glyph_row *row;
5c187dee 7403 int i;
06a2c219
GM
7404 Lisp_Object enabled_p;
7405 int prop_idx;
140330de 7406 enum draw_glyphs_face draw;
5c187dee 7407 int mouse_down_p, rc;
06a2c219
GM
7408
7409 /* Function note_mouse_highlight is called with negative x(y
7410 values when mouse moves outside of the frame. */
7411 if (x <= 0 || y <= 0)
7412 {
7413 clear_mouse_face (dpyinfo);
7414 return;
7415 }
7416
9ea173e8 7417 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
7418 if (rc < 0)
7419 {
9ea173e8 7420 /* Not on tool-bar item. */
06a2c219
GM
7421 clear_mouse_face (dpyinfo);
7422 return;
7423 }
7424 else if (rc == 0)
06a2c219 7425 goto set_help_echo;
b8009dd1 7426
06a2c219
GM
7427 clear_mouse_face (dpyinfo);
7428
9ea173e8 7429 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
7430 mouse_down_p = (dpyinfo->grabbed
7431 && f == last_mouse_frame
7432 && FRAME_LIVE_P (f));
7433 if (mouse_down_p
9ea173e8 7434 && last_tool_bar_item != prop_idx)
06a2c219
GM
7435 return;
7436
7437 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7438 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7439
9ea173e8 7440 /* If tool-bar item is not enabled, don't highlight it. */
8daf1204 7441 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7442 if (!NILP (enabled_p))
7443 {
7444 /* Compute the x-position of the glyph. In front and past the
7445 image is a space. We include this is the highlighted area. */
7446 row = MATRIX_ROW (w->current_matrix, vpos);
7447 for (i = x = 0; i < hpos; ++i)
7448 x += row->glyphs[TEXT_AREA][i].pixel_width;
7449
7450 /* Record this as the current active region. */
7451 dpyinfo->mouse_face_beg_col = hpos;
7452 dpyinfo->mouse_face_beg_row = vpos;
7453 dpyinfo->mouse_face_beg_x = x;
7454 dpyinfo->mouse_face_beg_y = row->y;
7455 dpyinfo->mouse_face_past_end = 0;
7456
7457 dpyinfo->mouse_face_end_col = hpos + 1;
7458 dpyinfo->mouse_face_end_row = vpos;
7459 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7460 dpyinfo->mouse_face_end_y = row->y;
7461 dpyinfo->mouse_face_window = window;
9ea173e8 7462 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
7463
7464 /* Display it as active. */
7465 show_mouse_face (dpyinfo, draw);
7466 dpyinfo->mouse_face_image_state = draw;
b8009dd1 7467 }
06a2c219
GM
7468
7469 set_help_echo:
7470
9ea173e8 7471 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 7472 XTread_socket does the rest. */
7cea38bc 7473 help_echo_object = help_echo_window = Qnil;
be010514 7474 help_echo_pos = -1;
8daf1204 7475 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
b7e80413 7476 if (NILP (help_echo))
8daf1204 7477 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
b8009dd1 7478}
4d73d038 7479
06a2c219
GM
7480
7481\f
9f8531e5
GM
7482/* Find the glyph matrix position of buffer position CHARPOS in window
7483 *W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7484 current glyphs must be up to date. If CHARPOS is above window
7485 start return (0, 0, 0, 0). If CHARPOS is after end of W, return end
7486 of last line in W. In the row containing CHARPOS, stop before glyphs
7e376260 7487 having STOP as object. */
b8009dd1 7488
9f8531e5
GM
7489#if 0 /* This is a version of fast_find_position that's more correct
7490 in the presence of hscrolling, for example. I didn't install
7491 it right away because the problem fixed is minor, it failed
7492 in 20.x as well, and I think it's too risky to install
7493 so near the release of 21.1. 2001-09-25 gerd. */
7494
7495static int
7496fast_find_position (w, charpos, hpos, vpos, x, y, stop)
7497 struct window *w;
7498 int charpos;
7499 int *hpos, *vpos, *x, *y;
7500 Lisp_Object stop;
7501{
7502 struct glyph_row *row, *first;
7503 struct glyph *glyph, *end;
7504 int i, past_end = 0;
7505
7506 first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
62e33982 7507 row = row_containing_pos (w, charpos, first, NULL, 0);
9f8531e5
GM
7508 if (row == NULL)
7509 {
7510 if (charpos < MATRIX_ROW_START_CHARPOS (first))
7511 {
7512 *x = *y = *hpos = *vpos = 0;
7513 return 0;
7514 }
7515 else
7516 {
7517 row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
7518 past_end = 1;
7519 }
7520 }
7521
7522 *x = row->x;
7523 *y = row->y;
7524 *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7525
7526 glyph = row->glyphs[TEXT_AREA];
7527 end = glyph + row->used[TEXT_AREA];
7528
7529 /* Skip over glyphs not having an object at the start of the row.
7530 These are special glyphs like truncation marks on terminal
7531 frames. */
7532 if (row->displays_text_p)
7533 while (glyph < end
7534 && INTEGERP (glyph->object)
7535 && !EQ (stop, glyph->object)
7536 && glyph->charpos < 0)
7537 {
7538 *x += glyph->pixel_width;
7539 ++glyph;
7540 }
7541
7542 while (glyph < end
7543 && !INTEGERP (glyph->object)
7544 && !EQ (stop, glyph->object)
7545 && (!BUFFERP (glyph->object)
7546 || glyph->charpos < charpos))
7547 {
7548 *x += glyph->pixel_width;
7549 ++glyph;
7550 }
7551
7552 *hpos = glyph - row->glyphs[TEXT_AREA];
7553 return past_end;
7554}
7555
7556#else /* not 0 */
7557
b8009dd1 7558static int
7e376260 7559fast_find_position (w, pos, hpos, vpos, x, y, stop)
06a2c219 7560 struct window *w;
b8009dd1 7561 int pos;
06a2c219 7562 int *hpos, *vpos, *x, *y;
7e376260 7563 Lisp_Object stop;
b8009dd1 7564{
b8009dd1 7565 int i;
bf1c0ba1 7566 int lastcol;
06a2c219
GM
7567 int maybe_next_line_p = 0;
7568 int line_start_position;
7569 int yb = window_text_bottom_y (w);
03d1a189
GM
7570 struct glyph_row *row, *best_row;
7571 int row_vpos, best_row_vpos;
06a2c219
GM
7572 int current_x;
7573
03d1a189
GM
7574 row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7575 row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7576
06a2c219 7577 while (row->y < yb)
b8009dd1 7578 {
06a2c219
GM
7579 if (row->used[TEXT_AREA])
7580 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7581 else
7582 line_start_position = 0;
7583
7584 if (line_start_position > pos)
b8009dd1 7585 break;
77b68646
RS
7586 /* If the position sought is the end of the buffer,
7587 don't include the blank lines at the bottom of the window. */
06a2c219
GM
7588 else if (line_start_position == pos
7589 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 7590 {
06a2c219 7591 maybe_next_line_p = 1;
77b68646
RS
7592 break;
7593 }
06a2c219
GM
7594 else if (line_start_position > 0)
7595 {
7596 best_row = row;
7597 best_row_vpos = row_vpos;
7598 }
4b0bb6f3
GM
7599
7600 if (row->y + row->height >= yb)
7601 break;
06a2c219
GM
7602
7603 ++row;
7604 ++row_vpos;
b8009dd1 7605 }
06a2c219
GM
7606
7607 /* Find the right column within BEST_ROW. */
7608 lastcol = 0;
7609 current_x = best_row->x;
7610 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 7611 {
06a2c219 7612 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7e376260 7613 int charpos = glyph->charpos;
06a2c219 7614
7e376260 7615 if (BUFFERP (glyph->object))
bf1c0ba1 7616 {
7e376260
GM
7617 if (charpos == pos)
7618 {
7619 *hpos = i;
7620 *vpos = best_row_vpos;
7621 *x = current_x;
7622 *y = best_row->y;
7623 return 1;
7624 }
7625 else if (charpos > pos)
7626 break;
bf1c0ba1 7627 }
7e376260 7628 else if (EQ (glyph->object, stop))
4d73d038 7629 break;
06a2c219 7630
7e376260
GM
7631 if (charpos > 0)
7632 lastcol = i;
06a2c219 7633 current_x += glyph->pixel_width;
bf1c0ba1 7634 }
b8009dd1 7635
77b68646
RS
7636 /* If we're looking for the end of the buffer,
7637 and we didn't find it in the line we scanned,
7638 use the start of the following line. */
06a2c219 7639 if (maybe_next_line_p)
77b68646 7640 {
06a2c219
GM
7641 ++best_row;
7642 ++best_row_vpos;
7643 lastcol = 0;
7644 current_x = best_row->x;
77b68646
RS
7645 }
7646
06a2c219
GM
7647 *vpos = best_row_vpos;
7648 *hpos = lastcol + 1;
7649 *x = current_x;
7650 *y = best_row->y;
b8009dd1
RS
7651 return 0;
7652}
7653
9f8531e5
GM
7654#endif /* not 0 */
7655
06a2c219 7656
269b7745 7657/* Find the position of the glyph for position POS in OBJECT in
f9db2310
GM
7658 window W's current matrix, and return in *X/*Y the pixel
7659 coordinates, and return in *HPOS/*VPOS the column/row of the glyph.
7660
7661 RIGHT_P non-zero means return the position of the right edge of the
7662 glyph, RIGHT_P zero means return the left edge position.
7663
7664 If no glyph for POS exists in the matrix, return the position of
7665 the glyph with the next smaller position that is in the matrix, if
7666 RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS
7667 exists in the matrix, return the position of the glyph with the
7668 next larger position in OBJECT.
7669
7670 Value is non-zero if a glyph was found. */
7671
7672static int
7673fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
7674 struct window *w;
7675 int pos;
7676 Lisp_Object object;
7677 int *hpos, *vpos, *x, *y;
7678 int right_p;
7679{
7680 int yb = window_text_bottom_y (w);
7681 struct glyph_row *r;
7682 struct glyph *best_glyph = NULL;
7683 struct glyph_row *best_row = NULL;
7684 int best_x = 0;
7685
7686 for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7687 r->enabled_p && r->y < yb;
7688 ++r)
7689 {
7690 struct glyph *g = r->glyphs[TEXT_AREA];
7691 struct glyph *e = g + r->used[TEXT_AREA];
7692 int gx;
7693
7694 for (gx = r->x; g < e; gx += g->pixel_width, ++g)
7695 if (EQ (g->object, object))
7696 {
7697 if (g->charpos == pos)
7698 {
7699 best_glyph = g;
7700 best_x = gx;
7701 best_row = r;
7702 goto found;
7703 }
7704 else if (best_glyph == NULL
7705 || ((abs (g->charpos - pos)
7706 < abs (best_glyph->charpos - pos))
7707 && (right_p
7708 ? g->charpos < pos
7709 : g->charpos > pos)))
7710 {
7711 best_glyph = g;
7712 best_x = gx;
7713 best_row = r;
7714 }
7715 }
7716 }
7717
7718 found:
7719
7720 if (best_glyph)
7721 {
7722 *x = best_x;
7723 *hpos = best_glyph - best_row->glyphs[TEXT_AREA];
7724
7725 if (right_p)
7726 {
7727 *x += best_glyph->pixel_width;
7728 ++*hpos;
7729 }
7730
7731 *y = best_row->y;
7732 *vpos = best_row - w->current_matrix->rows;
7733 }
7734
7735 return best_glyph != NULL;
7736}
7737
7738
b8009dd1
RS
7739/* Display the active region described by mouse_face_*
7740 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7741
7742static void
06a2c219 7743show_mouse_face (dpyinfo, draw)
7a13e894 7744 struct x_display_info *dpyinfo;
06a2c219 7745 enum draw_glyphs_face draw;
b8009dd1 7746{
7a13e894 7747 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7748 struct frame *f = XFRAME (WINDOW_FRAME (w));
06a2c219 7749
b2bbd509
GM
7750 if (/* If window is in the process of being destroyed, don't bother
7751 to do anything. */
7752 w->current_matrix != NULL
7753 /* Recognize when we are called to operate on rows that don't exist
7754 anymore. This can happen when a window is split. */
7755 && dpyinfo->mouse_face_end_row < w->current_matrix->nrows)
06a2c219 7756 {
b2bbd509
GM
7757 int phys_cursor_on_p = w->phys_cursor_on_p;
7758 struct glyph_row *row, *first, *last;
06a2c219 7759
b2bbd509
GM
7760 first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row);
7761 last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row);
7762
7763 for (row = first; row <= last && row->enabled_p; ++row)
06a2c219 7764 {
b2bbd509 7765 int start_hpos, end_hpos, start_x;
06a2c219 7766
b2bbd509
GM
7767 /* For all but the first row, the highlight starts at column 0. */
7768 if (row == first)
7769 {
7770 start_hpos = dpyinfo->mouse_face_beg_col;
7771 start_x = dpyinfo->mouse_face_beg_x;
7772 }
7773 else
7774 {
7775 start_hpos = 0;
7776 start_x = 0;
7777 }
06a2c219 7778
b2bbd509
GM
7779 if (row == last)
7780 end_hpos = dpyinfo->mouse_face_end_col;
7781 else
7782 end_hpos = row->used[TEXT_AREA];
b8009dd1 7783
b2bbd509
GM
7784 if (end_hpos > start_hpos)
7785 {
7786 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7787 start_hpos, end_hpos, draw, 0);
b8009dd1 7788
60626bab
GM
7789 row->mouse_face_p
7790 = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED;
b2bbd509
GM
7791 }
7792 }
2729a2b5 7793
b2bbd509
GM
7794 /* When we've written over the cursor, arrange for it to
7795 be displayed again. */
7796 if (phys_cursor_on_p && !w->phys_cursor_on_p)
7797 x_display_cursor (w, 1,
7798 w->phys_cursor.hpos, w->phys_cursor.vpos,
7799 w->phys_cursor.x, w->phys_cursor.y);
7800 }
fb3b7de5 7801
06a2c219
GM
7802 /* Change the mouse cursor. */
7803 if (draw == DRAW_NORMAL_TEXT)
7804 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7805 f->output_data.x->text_cursor);
7806 else if (draw == DRAW_MOUSE_FACE)
334208b7 7807 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7808 f->output_data.x->cross_cursor);
27ead1d5 7809 else
334208b7 7810 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7811 f->output_data.x->nontext_cursor);
b8009dd1
RS
7812}
7813
7814/* Clear out the mouse-highlighted active region.
fa262c07
GM
7815 Redraw it un-highlighted first. Value is non-zero if mouse
7816 face was actually drawn unhighlighted. */
b8009dd1 7817
fa262c07 7818static int
7a13e894
RS
7819clear_mouse_face (dpyinfo)
7820 struct x_display_info *dpyinfo;
b8009dd1 7821{
fa262c07 7822 int cleared = 0;
06a2c219 7823
fa262c07
GM
7824 if (!NILP (dpyinfo->mouse_face_window))
7825 {
7826 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
7827 cleared = 1;
7828 }
b8009dd1 7829
7a13e894
RS
7830 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7831 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7832 dpyinfo->mouse_face_window = Qnil;
1b85dc1c 7833 dpyinfo->mouse_face_overlay = Qnil;
fa262c07 7834 return cleared;
b8009dd1 7835}
e687d06e 7836
71b8321e
GM
7837
7838/* Clear any mouse-face on window W. This function is part of the
7839 redisplay interface, and is called from try_window_id and similar
7840 functions to ensure the mouse-highlight is off. */
7841
7842static void
7843x_clear_mouse_face (w)
7844 struct window *w;
7845{
7846 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7847 Lisp_Object window;
7848
2e636f9d 7849 BLOCK_INPUT;
71b8321e
GM
7850 XSETWINDOW (window, w);
7851 if (EQ (window, dpyinfo->mouse_face_window))
7852 clear_mouse_face (dpyinfo);
2e636f9d 7853 UNBLOCK_INPUT;
71b8321e
GM
7854}
7855
7856
e687d06e
RS
7857/* Just discard the mouse face information for frame F, if any.
7858 This is used when the size of F is changed. */
7859
dfcf069d 7860void
e687d06e
RS
7861cancel_mouse_face (f)
7862 FRAME_PTR f;
7863{
7864 Lisp_Object window;
7865 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7866
7867 window = dpyinfo->mouse_face_window;
7868 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7869 {
7870 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7871 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7872 dpyinfo->mouse_face_window = Qnil;
7873 }
7874}
b52b65bd 7875
b8009dd1 7876\f
b52b65bd
GM
7877static int glyph_rect P_ ((struct frame *f, int, int, XRectangle *));
7878
7879
7880/* Try to determine frame pixel position and size of the glyph under
7881 frame pixel coordinates X/Y on frame F . Return the position and
7882 size in *RECT. Value is non-zero if we could compute these
7883 values. */
7884
7885static int
7886glyph_rect (f, x, y, rect)
7887 struct frame *f;
7888 int x, y;
7889 XRectangle *rect;
7890{
7891 Lisp_Object window;
7892 int part, found = 0;
7893
7894 window = window_from_coordinates (f, x, y, &part, 0);
7895 if (!NILP (window))
7896 {
7897 struct window *w = XWINDOW (window);
7898 struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7899 struct glyph_row *end = r + w->current_matrix->nrows - 1;
b52b65bd
GM
7900
7901 frame_to_window_pixel_xy (w, &x, &y);
7902
7903 for (; !found && r < end && r->enabled_p; ++r)
7904 if (r->y >= y)
7905 {
7906 struct glyph *g = r->glyphs[TEXT_AREA];
7907 struct glyph *end = g + r->used[TEXT_AREA];
7908 int gx;
7909
7910 for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
7911 if (gx >= x)
7912 {
7913 rect->width = g->pixel_width;
7914 rect->height = r->height;
7915 rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
7916 rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
7917 found = 1;
7918 }
7919 }
7920 }
7921
7922 return found;
7923}
7924
12ba150f 7925
90e65f07 7926/* Return the current position of the mouse.
b52b65bd 7927 *FP should be a frame which indicates which display to ask about.
90e65f07 7928
b52b65bd
GM
7929 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
7930 and *PART to the frame, window, and scroll bar part that the mouse
7931 is over. Set *X and *Y to the portion and whole of the mouse's
ab648270 7932 position on the scroll bar.
12ba150f 7933
b52b65bd
GM
7934 If the mouse movement started elsewhere, set *FP to the frame the
7935 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
12ba150f
JB
7936 the mouse is over.
7937
b52b65bd 7938 Set *TIME to the server time-stamp for the time at which the mouse
12ba150f
JB
7939 was at this position.
7940
a135645a
RS
7941 Don't store anything if we don't have a valid set of values to report.
7942
90e65f07 7943 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7944 movement. */
90e65f07
JB
7945
7946static void
1cf412ec 7947XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7948 FRAME_PTR *fp;
1cf412ec 7949 int insist;
12ba150f 7950 Lisp_Object *bar_window;
ab648270 7951 enum scroll_bar_part *part;
90e65f07 7952 Lisp_Object *x, *y;
e5d77022 7953 unsigned long *time;
90e65f07 7954{
a135645a
RS
7955 FRAME_PTR f1;
7956
90e65f07
JB
7957 BLOCK_INPUT;
7958
8bcee03e 7959 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7960 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7961 else
7962 {
12ba150f
JB
7963 Window root;
7964 int root_x, root_y;
90e65f07 7965
12ba150f
JB
7966 Window dummy_window;
7967 int dummy;
7968
39d8bb4d
KH
7969 Lisp_Object frame, tail;
7970
7971 /* Clear the mouse-moved flag for every frame on this display. */
7972 FOR_EACH_FRAME (tail, frame)
7973 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7974 XFRAME (frame)->mouse_moved = 0;
7975
ab648270 7976 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7977
7978 /* Figure out which root window we're on. */
334208b7
RS
7979 XQueryPointer (FRAME_X_DISPLAY (*fp),
7980 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7981
7982 /* The root window which contains the pointer. */
7983 &root,
7984
7985 /* Trash which we can't trust if the pointer is on
7986 a different screen. */
7987 &dummy_window,
7988
7989 /* The position on that root window. */
58769bee 7990 &root_x, &root_y,
12ba150f
JB
7991
7992 /* More trash we can't trust. */
7993 &dummy, &dummy,
7994
7995 /* Modifier keys and pointer buttons, about which
7996 we don't care. */
7997 (unsigned int *) &dummy);
7998
7999 /* Now we have a position on the root; find the innermost window
8000 containing the pointer. */
8001 {
8002 Window win, child;
8003 int win_x, win_y;
06a2c219 8004 int parent_x = 0, parent_y = 0;
e99db5a1 8005 int count;
12ba150f
JB
8006
8007 win = root;
69388238 8008
2d7fc7e8
RS
8009 /* XTranslateCoordinates can get errors if the window
8010 structure is changing at the same time this function
8011 is running. So at least we must not crash from them. */
8012
e99db5a1 8013 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 8014
334208b7 8015 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 8016 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 8017 {
69388238
RS
8018 /* If mouse was grabbed on a frame, give coords for that frame
8019 even if the mouse is now outside it. */
334208b7 8020 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 8021
12ba150f 8022 /* From-window, to-window. */
69388238 8023 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
8024
8025 /* From-position, to-position. */
8026 root_x, root_y, &win_x, &win_y,
8027
8028 /* Child of win. */
8029 &child);
69388238
RS
8030 f1 = last_mouse_frame;
8031 }
8032 else
8033 {
8034 while (1)
8035 {
334208b7 8036 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 8037
69388238
RS
8038 /* From-window, to-window. */
8039 root, win,
12ba150f 8040
69388238
RS
8041 /* From-position, to-position. */
8042 root_x, root_y, &win_x, &win_y,
8043
8044 /* Child of win. */
8045 &child);
8046
9af3143a 8047 if (child == None || child == win)
69388238
RS
8048 break;
8049
8050 win = child;
8051 parent_x = win_x;
8052 parent_y = win_y;
8053 }
12ba150f 8054
69388238
RS
8055 /* Now we know that:
8056 win is the innermost window containing the pointer
8057 (XTC says it has no child containing the pointer),
8058 win_x and win_y are the pointer's position in it
8059 (XTC did this the last time through), and
8060 parent_x and parent_y are the pointer's position in win's parent.
8061 (They are what win_x and win_y were when win was child.
8062 If win is the root window, it has no parent, and
8063 parent_{x,y} are invalid, but that's okay, because we'll
8064 never use them in that case.) */
8065
8066 /* Is win one of our frames? */
19126e11 8067 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
aad0f6ab
GM
8068
8069#ifdef USE_X_TOOLKIT
8070 /* If we end up with the menu bar window, say it's not
8071 on the frame. */
8072 if (f1 != NULL
8073 && f1->output_data.x->menubar_widget
8074 && win == XtWindow (f1->output_data.x->menubar_widget))
8075 f1 = NULL;
8076#endif /* USE_X_TOOLKIT */
69388238 8077 }
58769bee 8078
2d7fc7e8
RS
8079 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
8080 f1 = 0;
8081
e99db5a1 8082 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 8083
ab648270 8084 /* If not, is it one of our scroll bars? */
a135645a 8085 if (! f1)
12ba150f 8086 {
ab648270 8087 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
8088
8089 if (bar)
8090 {
a135645a 8091 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
8092 win_x = parent_x;
8093 win_y = parent_y;
8094 }
8095 }
90e65f07 8096
8bcee03e 8097 if (f1 == 0 && insist > 0)
b86bd3dd 8098 f1 = SELECTED_FRAME ();
1cf412ec 8099
a135645a 8100 if (f1)
12ba150f 8101 {
06a2c219
GM
8102 /* Ok, we found a frame. Store all the values.
8103 last_mouse_glyph is a rectangle used to reduce the
8104 generation of mouse events. To not miss any motion
8105 events, we must divide the frame into rectangles of the
8106 size of the smallest character that could be displayed
8107 on it, i.e. into the same rectangles that matrices on
8108 the frame are divided into. */
8109
b52b65bd
GM
8110 int width, height, gx, gy;
8111 XRectangle rect;
8112
8113 if (glyph_rect (f1, win_x, win_y, &rect))
8114 last_mouse_glyph = rect;
8115 else
8116 {
8117 width = FRAME_SMALLEST_CHAR_WIDTH (f1);
8118 height = FRAME_SMALLEST_FONT_HEIGHT (f1);
8119 gx = win_x;
8120 gy = win_y;
06a2c219 8121
b52b65bd
GM
8122 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
8123 round down even for negative values. */
8124 if (gx < 0)
8125 gx -= width - 1;
4f00e84d 8126 if (gy < 0)
b52b65bd
GM
8127 gy -= height - 1;
8128 gx = (gx + width - 1) / width * width;
8129 gy = (gy + height - 1) / height * height;
8130
8131 last_mouse_glyph.width = width;
8132 last_mouse_glyph.height = height;
8133 last_mouse_glyph.x = gx;
8134 last_mouse_glyph.y = gy;
8135 }
12ba150f
JB
8136
8137 *bar_window = Qnil;
8138 *part = 0;
334208b7 8139 *fp = f1;
e0c1aef2
KH
8140 XSETINT (*x, win_x);
8141 XSETINT (*y, win_y);
12ba150f
JB
8142 *time = last_mouse_movement_time;
8143 }
8144 }
8145 }
90e65f07
JB
8146
8147 UNBLOCK_INPUT;
8148}
f451eb13 8149
06a2c219 8150
06a2c219 8151#ifdef USE_X_TOOLKIT
bffcfca9
GM
8152
8153/* Atimer callback function for TIMER. Called every 0.1s to process
8154 Xt timeouts, if needed. We must avoid calling XtAppPending as
8155 much as possible because that function does an implicit XFlush
8156 that slows us down. */
8157
8158static void
8159x_process_timeouts (timer)
8160 struct atimer *timer;
8161{
8162 if (toolkit_scroll_bar_interaction || popup_activated_flag)
8163 {
8164 BLOCK_INPUT;
8165 while (XtAppPending (Xt_app_con) & XtIMTimer)
8166 XtAppProcessEvent (Xt_app_con, XtIMTimer);
8167 UNBLOCK_INPUT;
8168 }
06a2c219
GM
8169}
8170
bffcfca9 8171#endif /* USE_X_TOOLKIT */
06a2c219
GM
8172
8173\f
8174/* Scroll bar support. */
8175
8176/* Given an X window ID, find the struct scroll_bar which manages it.
8177 This can be called in GC, so we have to make sure to strip off mark
8178 bits. */
bffcfca9 8179
06a2c219
GM
8180static struct scroll_bar *
8181x_window_to_scroll_bar (window_id)
8182 Window window_id;
8183{
8184 Lisp_Object tail;
8185
8186 for (tail = Vframe_list;
8187 XGCTYPE (tail) == Lisp_Cons;
8e713be6 8188 tail = XCDR (tail))
06a2c219
GM
8189 {
8190 Lisp_Object frame, bar, condemned;
8191
8e713be6 8192 frame = XCAR (tail);
06a2c219
GM
8193 /* All elements of Vframe_list should be frames. */
8194 if (! GC_FRAMEP (frame))
8195 abort ();
8196
8197 /* Scan this frame's scroll bar list for a scroll bar with the
8198 right window ID. */
8199 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
8200 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
8201 /* This trick allows us to search both the ordinary and
8202 condemned scroll bar lists with one loop. */
8203 ! GC_NILP (bar) || (bar = condemned,
8204 condemned = Qnil,
8205 ! GC_NILP (bar));
8206 bar = XSCROLL_BAR (bar)->next)
8207 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
8208 return XSCROLL_BAR (bar);
8209 }
8210
8211 return 0;
8212}
8213
8214
01f67d2c 8215#if defined USE_LUCID
c95fc5f1
GM
8216
8217/* Return the Lucid menu bar WINDOW is part of. Return null
8218 if WINDOW is not part of a menu bar. */
8219
8220static Widget
8221x_window_to_menu_bar (window)
8222 Window window;
8223{
8224 Lisp_Object tail;
8225
8226 for (tail = Vframe_list;
8227 XGCTYPE (tail) == Lisp_Cons;
8228 tail = XCDR (tail))
8229 {
8230 Lisp_Object frame = XCAR (tail);
8231 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
8232
8233 if (menu_bar && xlwmenu_window_p (menu_bar, window))
8234 return menu_bar;
8235 }
8236
8237 return NULL;
8238}
8239
01f67d2c 8240#endif /* USE_LUCID */
c95fc5f1 8241
06a2c219
GM
8242\f
8243/************************************************************************
8244 Toolkit scroll bars
8245 ************************************************************************/
8246
eccc05db 8247#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8248
8249static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
8250static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
8251static void x_create_toolkit_scroll_bar P_ ((struct frame *,
8252 struct scroll_bar *));
8253static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
8254 int, int, int));
8255
8256
8257/* Id of action hook installed for scroll bars. */
8258
8259static XtActionHookId action_hook_id;
8260
8261/* Lisp window being scrolled. Set when starting to interact with
8262 a toolkit scroll bar, reset to nil when ending the interaction. */
8263
8264static Lisp_Object window_being_scrolled;
8265
8266/* Last scroll bar part sent in xm_scroll_callback. */
8267
8268static int last_scroll_bar_part;
8269
ec18280f
SM
8270/* Whether this is an Xaw with arrow-scrollbars. This should imply
8271 that movements of 1/20 of the screen size are mapped to up/down. */
8272
8273static Boolean xaw3d_arrow_scroll;
8274
8275/* Whether the drag scrolling maintains the mouse at the top of the
8276 thumb. If not, resizing the thumb needs to be done more carefully
8277 to avoid jerkyness. */
8278
8279static Boolean xaw3d_pick_top;
8280
06a2c219
GM
8281
8282/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 8283 bars are used.. The hook is responsible for detecting when
06a2c219
GM
8284 the user ends an interaction with the scroll bar, and generates
8285 a `end-scroll' scroll_bar_click' event if so. */
8286
8287static void
8288xt_action_hook (widget, client_data, action_name, event, params,
8289 num_params)
8290 Widget widget;
8291 XtPointer client_data;
8292 String action_name;
8293 XEvent *event;
8294 String *params;
8295 Cardinal *num_params;
8296{
8297 int scroll_bar_p;
8298 char *end_action;
8299
8300#ifdef USE_MOTIF
8301 scroll_bar_p = XmIsScrollBar (widget);
8302 end_action = "Release";
ec18280f 8303#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8304 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
8305 end_action = "EndScroll";
ec18280f 8306#endif /* USE_MOTIF */
06a2c219 8307
06a2c219
GM
8308 if (scroll_bar_p
8309 && strcmp (action_name, end_action) == 0
8310 && WINDOWP (window_being_scrolled))
8311 {
8312 struct window *w;
8313
8314 x_send_scroll_bar_event (window_being_scrolled,
8315 scroll_bar_end_scroll, 0, 0);
8316 w = XWINDOW (window_being_scrolled);
8317 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
8318 window_being_scrolled = Qnil;
8319 last_scroll_bar_part = -1;
bffcfca9
GM
8320
8321 /* Xt timeouts no longer needed. */
8322 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
8323 }
8324}
8325
07b3d16e
GM
8326/* A vector of windows used for communication between
8327 x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
8328
8329static struct window **scroll_bar_windows;
8330static int scroll_bar_windows_size;
8331
06a2c219
GM
8332
8333/* Send a client message with message type Xatom_Scrollbar for a
8334 scroll action to the frame of WINDOW. PART is a value identifying
8335 the part of the scroll bar that was clicked on. PORTION is the
8336 amount to scroll of a whole of WHOLE. */
8337
8338static void
8339x_send_scroll_bar_event (window, part, portion, whole)
8340 Lisp_Object window;
8341 int part, portion, whole;
8342{
8343 XEvent event;
8344 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
07b3d16e
GM
8345 struct window *w = XWINDOW (window);
8346 struct frame *f = XFRAME (w->frame);
8347 int i;
06a2c219 8348
07b3d16e
GM
8349 BLOCK_INPUT;
8350
06a2c219
GM
8351 /* Construct a ClientMessage event to send to the frame. */
8352 ev->type = ClientMessage;
8353 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
8354 ev->display = FRAME_X_DISPLAY (f);
8355 ev->window = FRAME_X_WINDOW (f);
8356 ev->format = 32;
07b3d16e
GM
8357
8358 /* We can only transfer 32 bits in the XClientMessageEvent, which is
8359 not enough to store a pointer or Lisp_Object on a 64 bit system.
8360 So, store the window in scroll_bar_windows and pass the index
8361 into that array in the event. */
8362 for (i = 0; i < scroll_bar_windows_size; ++i)
8363 if (scroll_bar_windows[i] == NULL)
8364 break;
8365
8366 if (i == scroll_bar_windows_size)
8367 {
8368 int new_size = max (10, 2 * scroll_bar_windows_size);
8369 size_t nbytes = new_size * sizeof *scroll_bar_windows;
8370 size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows;
8371
8372 scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
8373 nbytes);
8374 bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
8375 scroll_bar_windows_size = new_size;
8376 }
8377
8378 scroll_bar_windows[i] = w;
8379 ev->data.l[0] = (long) i;
06a2c219
GM
8380 ev->data.l[1] = (long) part;
8381 ev->data.l[2] = (long) 0;
8382 ev->data.l[3] = (long) portion;
8383 ev->data.l[4] = (long) whole;
8384
bffcfca9
GM
8385 /* Make Xt timeouts work while the scroll bar is active. */
8386 toolkit_scroll_bar_interaction = 1;
8387
06a2c219
GM
8388 /* Setting the event mask to zero means that the message will
8389 be sent to the client that created the window, and if that
8390 window no longer exists, no event will be sent. */
06a2c219
GM
8391 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
8392 UNBLOCK_INPUT;
8393}
8394
8395
8396/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
8397 in *IEVENT. */
8398
8399static void
8400x_scroll_bar_to_input_event (event, ievent)
8401 XEvent *event;
8402 struct input_event *ievent;
8403{
8404 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
8405 Lisp_Object window;
8406 struct frame *f;
07b3d16e
GM
8407 struct window *w;
8408
8409 w = scroll_bar_windows[ev->data.l[0]];
8410 scroll_bar_windows[ev->data.l[0]] = NULL;
52e386c2 8411
07b3d16e
GM
8412 XSETWINDOW (window, w);
8413 f = XFRAME (w->frame);
06a2c219
GM
8414
8415 ievent->kind = scroll_bar_click;
8416 ievent->frame_or_window = window;
0f8aabe9 8417 ievent->arg = Qnil;
06a2c219
GM
8418 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
8419 ievent->part = ev->data.l[1];
8420 ievent->code = ev->data.l[2];
8421 ievent->x = make_number ((int) ev->data.l[3]);
8422 ievent->y = make_number ((int) ev->data.l[4]);
8423 ievent->modifiers = 0;
8424}
8425
8426
8427#ifdef USE_MOTIF
8428
8429/* Minimum and maximum values used for Motif scroll bars. */
8430
8431#define XM_SB_MIN 1
8432#define XM_SB_MAX 10000000
8433#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
8434
8435
8436/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
8437 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
8438 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
8439
8440static void
8441xm_scroll_callback (widget, client_data, call_data)
8442 Widget widget;
8443 XtPointer client_data, call_data;
8444{
8445 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8446 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
06a2c219
GM
8447 int part = -1, whole = 0, portion = 0;
8448
8449 switch (cs->reason)
8450 {
8451 case XmCR_DECREMENT:
8452 bar->dragging = Qnil;
8453 part = scroll_bar_up_arrow;
8454 break;
8455
8456 case XmCR_INCREMENT:
8457 bar->dragging = Qnil;
8458 part = scroll_bar_down_arrow;
8459 break;
8460
8461 case XmCR_PAGE_DECREMENT:
8462 bar->dragging = Qnil;
8463 part = scroll_bar_above_handle;
8464 break;
8465
8466 case XmCR_PAGE_INCREMENT:
8467 bar->dragging = Qnil;
8468 part = scroll_bar_below_handle;
8469 break;
8470
8471 case XmCR_TO_TOP:
8472 bar->dragging = Qnil;
8473 part = scroll_bar_to_top;
8474 break;
8475
8476 case XmCR_TO_BOTTOM:
8477 bar->dragging = Qnil;
8478 part = scroll_bar_to_bottom;
8479 break;
8480
8481 case XmCR_DRAG:
8482 {
8483 int slider_size;
8484 int dragging_down_p = (INTEGERP (bar->dragging)
8485 && XINT (bar->dragging) <= cs->value);
8486
8487 /* Get the slider size. */
8488 BLOCK_INPUT;
8489 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
8490 UNBLOCK_INPUT;
8491
8492 /* At the max position of the scroll bar, do a line-wise
23442ae4
GM
8493 movement. Without doing anything, we would be called with
8494 the same cs->value again and again. If we want to make
8495 sure that we can reach the end of the buffer, we have to do
8496 something.
06a2c219
GM
8497
8498 Implementation note: setting bar->dragging always to
8499 cs->value gives a smoother movement at the max position.
8500 Setting it to nil when doing line-wise movement gives
8501 a better slider behavior. */
8502
8503 if (cs->value + slider_size == XM_SB_MAX
8504 || (dragging_down_p
8505 && last_scroll_bar_part == scroll_bar_down_arrow))
8506 {
8507 part = scroll_bar_down_arrow;
8508 bar->dragging = Qnil;
8509 }
8510 else
8511 {
8512 whole = XM_SB_RANGE;
8513 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
8514 part = scroll_bar_handle;
8515 bar->dragging = make_number (cs->value);
8516 }
8517 }
8518 break;
8519
8520 case XmCR_VALUE_CHANGED:
8521 break;
8522 };
8523
8524 if (part >= 0)
8525 {
8526 window_being_scrolled = bar->window;
8527 last_scroll_bar_part = part;
8528 x_send_scroll_bar_event (bar->window, part, portion, whole);
8529 }
8530}
8531
8532
ec18280f 8533#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
8534
8535
ec18280f 8536/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
8537 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
8538 scroll bar struct. CALL_DATA is a pointer to a float saying where
8539 the thumb is. */
8540
8541static void
ec18280f 8542xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
8543 Widget widget;
8544 XtPointer client_data, call_data;
8545{
8546 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8547 float top = *(float *) call_data;
8548 float shown;
ec18280f
SM
8549 int whole, portion, height;
8550 int part;
06a2c219
GM
8551
8552 /* Get the size of the thumb, a value between 0 and 1. */
8553 BLOCK_INPUT;
ec18280f 8554 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
8555 UNBLOCK_INPUT;
8556
8557 whole = 10000000;
8558 portion = shown < 1 ? top * whole : 0;
06a2c219 8559
ec18280f
SM
8560 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
8561 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
8562 the bottom, so we force the scrolling whenever we see that we're
8563 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
8564 we try to ensure that we always stay two pixels away from the
8565 bottom). */
06a2c219
GM
8566 part = scroll_bar_down_arrow;
8567 else
8568 part = scroll_bar_handle;
8569
8570 window_being_scrolled = bar->window;
8571 bar->dragging = make_number (portion);
8572 last_scroll_bar_part = part;
8573 x_send_scroll_bar_event (bar->window, part, portion, whole);
8574}
8575
8576
ec18280f
SM
8577/* Xaw scroll bar callback. Invoked for incremental scrolling.,
8578 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
8579 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
8580 the scroll bar. CALL_DATA is an integer specifying the action that
8581 has taken place. It's magnitude is in the range 0..height of the
8582 scroll bar. Negative values mean scroll towards buffer start.
8583 Values < height of scroll bar mean line-wise movement. */
8584
8585static void
ec18280f 8586xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
8587 Widget widget;
8588 XtPointer client_data, call_data;
8589{
8590 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8591 int position = (int) call_data;
8592 Dimension height;
8593 int part;
8594
8595 /* Get the height of the scroll bar. */
8596 BLOCK_INPUT;
8597 XtVaGetValues (widget, XtNheight, &height, NULL);
8598 UNBLOCK_INPUT;
8599
ec18280f
SM
8600 if (abs (position) >= height)
8601 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
8602
8603 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
8604 it maps line-movement to call_data = max(5, height/20). */
8605 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
8606 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 8607 else
ec18280f 8608 part = scroll_bar_move_ratio;
06a2c219
GM
8609
8610 window_being_scrolled = bar->window;
8611 bar->dragging = Qnil;
8612 last_scroll_bar_part = part;
ec18280f 8613 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
8614}
8615
8616
8617#endif /* not USE_MOTIF */
8618
8619
8620/* Create the widget for scroll bar BAR on frame F. Record the widget
8621 and X window of the scroll bar in BAR. */
8622
8623static void
8624x_create_toolkit_scroll_bar (f, bar)
8625 struct frame *f;
8626 struct scroll_bar *bar;
8627{
8628 Window xwindow;
8629 Widget widget;
8630 Arg av[20];
8631 int ac = 0;
8632 char *scroll_bar_name = "verticalScrollBar";
8633 unsigned long pixel;
8634
8635 BLOCK_INPUT;
8636
8637#ifdef USE_MOTIF
06a2c219
GM
8638 /* Set resources. Create the widget. */
8639 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8640 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
8641 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
8642 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
8643 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
8644 XtSetArg (av[ac], XmNincrement, 1); ++ac;
8645 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
8646
8647 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8648 if (pixel != -1)
8649 {
8650 XtSetArg (av[ac], XmNforeground, pixel);
8651 ++ac;
8652 }
8653
8654 pixel = f->output_data.x->scroll_bar_background_pixel;
8655 if (pixel != -1)
8656 {
8657 XtSetArg (av[ac], XmNbackground, pixel);
8658 ++ac;
8659 }
8660
8661 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
8662 scroll_bar_name, av, ac);
8663
8664 /* Add one callback for everything that can happen. */
8665 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
8666 (XtPointer) bar);
8667 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
8668 (XtPointer) bar);
8669 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
8670 (XtPointer) bar);
8671 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
8672 (XtPointer) bar);
8673 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
8674 (XtPointer) bar);
8675 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
8676 (XtPointer) bar);
8677 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
8678 (XtPointer) bar);
8679
8680 /* Realize the widget. Only after that is the X window created. */
8681 XtRealizeWidget (widget);
8682
8683 /* Set the cursor to an arrow. I didn't find a resource to do that.
8684 And I'm wondering why it hasn't an arrow cursor by default. */
8685 XDefineCursor (XtDisplay (widget), XtWindow (widget),
8686 f->output_data.x->nontext_cursor);
8687
ec18280f 8688#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8689
8690 /* Set resources. Create the widget. The background of the
8691 Xaw3d scroll bar widget is a little bit light for my taste.
8692 We don't alter it here to let users change it according
8693 to their taste with `emacs*verticalScrollBar.background: xxx'. */
8694 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8695 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
8696 /* For smoother scrolling with Xaw3d -sm */
8697 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
06a2c219
GM
8698
8699 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8700 if (pixel != -1)
8701 {
8702 XtSetArg (av[ac], XtNforeground, pixel);
8703 ++ac;
8704 }
8705
8706 pixel = f->output_data.x->scroll_bar_background_pixel;
8707 if (pixel != -1)
8708 {
8709 XtSetArg (av[ac], XtNbackground, pixel);
8710 ++ac;
8711 }
7c1bef7a
MB
8712
8713 /* Top/bottom shadow colors. */
8714
8715 /* Allocate them, if necessary. */
8716 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
8717 {
8718 pixel = f->output_data.x->scroll_bar_background_pixel;
8719 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8720 &pixel, 1.2, 0x8000))
8721 pixel = -1;
8722 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
8723 }
8724 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8725 {
8726 pixel = f->output_data.x->scroll_bar_background_pixel;
8727 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8728 &pixel, 0.6, 0x4000))
8729 pixel = -1;
8730 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
8731 }
8732
8733 /* Tell the toolkit about them. */
8734 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
8735 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8736 /* We tried to allocate a color for the top/bottom shadow, and
8737 failed, so tell Xaw3d to use dithering instead. */
8738 {
8739 XtSetArg (av[ac], XtNbeNiceToColormap, True);
8740 ++ac;
8741 }
8742 else
8743 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
8744 be more consistent with other emacs 3d colors, and since Xaw3d is
8745 not good at dealing with allocation failure. */
8746 {
8747 /* This tells Xaw3d to use real colors instead of dithering for
8748 the shadows. */
8749 XtSetArg (av[ac], XtNbeNiceToColormap, False);
8750 ++ac;
8751
8752 /* Specify the colors. */
8753 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
8754 if (pixel != -1)
8755 {
8756 XtSetArg (av[ac], "topShadowPixel", pixel);
8757 ++ac;
8758 }
8759 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
8760 if (pixel != -1)
8761 {
8762 XtSetArg (av[ac], "bottomShadowPixel", pixel);
8763 ++ac;
8764 }
8765 }
8766
06a2c219
GM
8767 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
8768 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
8769
8770 {
8771 char *initial = "";
8772 char *val = initial;
8773 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
8774 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
8775 if (val == initial)
8776 { /* ARROW_SCROLL */
8777 xaw3d_arrow_scroll = True;
8778 /* Isn't that just a personal preference ? -sm */
8779 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
8780 }
8781 }
06a2c219
GM
8782
8783 /* Define callbacks. */
ec18280f
SM
8784 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
8785 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
8786 (XtPointer) bar);
8787
8788 /* Realize the widget. Only after that is the X window created. */
8789 XtRealizeWidget (widget);
8790
ec18280f 8791#endif /* !USE_MOTIF */
06a2c219
GM
8792
8793 /* Install an action hook that let's us detect when the user
8794 finishes interacting with a scroll bar. */
8795 if (action_hook_id == 0)
8796 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
8797
8798 /* Remember X window and widget in the scroll bar vector. */
8799 SET_SCROLL_BAR_X_WIDGET (bar, widget);
8800 xwindow = XtWindow (widget);
8801 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
8802
8803 UNBLOCK_INPUT;
8804}
8805
8806
8807/* Set the thumb size and position of scroll bar BAR. We are currently
8808 displaying PORTION out of a whole WHOLE, and our position POSITION. */
8809
8810static void
8811x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
8812 struct scroll_bar *bar;
8813 int portion, position, whole;
f451eb13 8814{
e83dc917
GM
8815 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8816 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
06a2c219 8817 float top, shown;
f451eb13 8818
06a2c219
GM
8819 if (whole == 0)
8820 top = 0, shown = 1;
8821 else
f451eb13 8822 {
06a2c219
GM
8823 top = (float) position / whole;
8824 shown = (float) portion / whole;
8825 }
f451eb13 8826
06a2c219 8827 BLOCK_INPUT;
f451eb13 8828
06a2c219
GM
8829#ifdef USE_MOTIF
8830 {
8831 int size, value;
06a2c219 8832
ec18280f 8833 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
8834 is the scroll bar's maximum and MIN is the scroll bar's minimum
8835 value. */
8836 size = shown * XM_SB_RANGE;
8837 size = min (size, XM_SB_RANGE);
8838 size = max (size, 1);
8839
8840 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
8841 value = top * XM_SB_RANGE;
8842 value = min (value, XM_SB_MAX - size);
8843 value = max (value, XM_SB_MIN);
8844
06a2c219
GM
8845 if (NILP (bar->dragging))
8846 XmScrollBarSetValues (widget, value, size, 0, 0, False);
8847 else if (last_scroll_bar_part == scroll_bar_down_arrow)
8848 /* This has the negative side effect that the slider value is
ec18280f 8849 not what it would be if we scrolled here using line-wise or
06a2c219
GM
8850 page-wise movement. */
8851 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
8852 else
8853 {
8854 /* If currently dragging, only update the slider size.
8855 This reduces flicker effects. */
8856 int old_value, old_size, increment, page_increment;
8857
8858 XmScrollBarGetValues (widget, &old_value, &old_size,
8859 &increment, &page_increment);
8860 XmScrollBarSetValues (widget, old_value,
8861 min (size, XM_SB_RANGE - old_value),
8862 0, 0, False);
8863 }
06a2c219 8864 }
ec18280f 8865#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 8866 {
ec18280f
SM
8867 float old_top, old_shown;
8868 Dimension height;
8869 XtVaGetValues (widget,
8870 XtNtopOfThumb, &old_top,
8871 XtNshown, &old_shown,
8872 XtNheight, &height,
8873 NULL);
8874
8875 /* Massage the top+shown values. */
8876 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8877 top = max (0, min (1, top));
8878 else
8879 top = old_top;
8880 /* Keep two pixels available for moving the thumb down. */
8881 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8882
8883 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8884 check that your system's configuration file contains a define
8885 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8886 if (top != old_top || shown != old_shown)
eb393530 8887 {
ec18280f 8888 if (NILP (bar->dragging))
eb393530 8889 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8890 else
8891 {
ec18280f
SM
8892#ifdef HAVE_XAW3D
8893 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8894 int scroll_mode = 0;
ec18280f
SM
8895
8896 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8897 if (xaw3d_arrow_scroll)
8898 {
8899 /* Xaw3d stupidly ignores resize requests while dragging
8900 so we have to make it believe it's not in dragging mode. */
8901 scroll_mode = sb->scrollbar.scroll_mode;
8902 if (scroll_mode == 2)
8903 sb->scrollbar.scroll_mode = 0;
8904 }
8905#endif
8906 /* Try to make the scrolling a tad smoother. */
8907 if (!xaw3d_pick_top)
8908 shown = min (shown, old_shown);
8909
8910 XawScrollbarSetThumb (widget, top, shown);
8911
8912#ifdef HAVE_XAW3D
8913 if (xaw3d_arrow_scroll && scroll_mode == 2)
8914 sb->scrollbar.scroll_mode = scroll_mode;
8915#endif
06a2c219 8916 }
06a2c219
GM
8917 }
8918 }
ec18280f 8919#endif /* !USE_MOTIF */
06a2c219
GM
8920
8921 UNBLOCK_INPUT;
f451eb13
JB
8922}
8923
06a2c219
GM
8924#endif /* USE_TOOLKIT_SCROLL_BARS */
8925
8926
8927\f
8928/************************************************************************
8929 Scroll bars, general
8930 ************************************************************************/
8931
8932/* Create a scroll bar and return the scroll bar vector for it. W is
8933 the Emacs window on which to create the scroll bar. TOP, LEFT,
8934 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8935 scroll bar. */
8936
ab648270 8937static struct scroll_bar *
06a2c219
GM
8938x_scroll_bar_create (w, top, left, width, height)
8939 struct window *w;
f451eb13
JB
8940 int top, left, width, height;
8941{
06a2c219 8942 struct frame *f = XFRAME (w->frame);
334208b7
RS
8943 struct scroll_bar *bar
8944 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8945
8946 BLOCK_INPUT;
8947
eccc05db 8948#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8949 x_create_toolkit_scroll_bar (f, bar);
8950#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8951 {
8952 XSetWindowAttributes a;
8953 unsigned long mask;
5c187dee 8954 Window window;
06a2c219
GM
8955
8956 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8957 if (a.background_pixel == -1)
8958 a.background_pixel = f->output_data.x->background_pixel;
8959
12ba150f 8960 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 8961 | ButtonMotionMask | PointerMotionHintMask
12ba150f 8962 | ExposureMask);
7a13e894 8963 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 8964
dbc4e1c1 8965 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8966
06a2c219
GM
8967 /* Clear the area of W that will serve as a scroll bar. This is
8968 for the case that a window has been split horizontally. In
8969 this case, no clear_frame is generated to reduce flickering. */
7b49b9d2
GM
8970 if (width > 0 && height > 0)
8971 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8972 left, top, width,
8973 window_box_height (w), False);
06a2c219
GM
8974
8975 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8976 /* Position and size of scroll bar. */
8977 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8978 top,
8979 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8980 height,
8981 /* Border width, depth, class, and visual. */
8982 0,
8983 CopyFromParent,
8984 CopyFromParent,
8985 CopyFromParent,
8986 /* Attributes. */
8987 mask, &a);
8988 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 8989 }
06a2c219 8990#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8991
06a2c219 8992 XSETWINDOW (bar->window, w);
e0c1aef2
KH
8993 XSETINT (bar->top, top);
8994 XSETINT (bar->left, left);
8995 XSETINT (bar->width, width);
8996 XSETINT (bar->height, height);
8997 XSETINT (bar->start, 0);
8998 XSETINT (bar->end, 0);
12ba150f 8999 bar->dragging = Qnil;
f451eb13
JB
9000
9001 /* Add bar to its frame's list of scroll bars. */
334208b7 9002 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 9003 bar->prev = Qnil;
334208b7 9004 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 9005 if (!NILP (bar->next))
e0c1aef2 9006 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 9007
06a2c219 9008 /* Map the window/widget. */
eccc05db 9009#ifdef USE_TOOLKIT_SCROLL_BARS
f964b4d7
GM
9010 {
9011 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
9012 XtConfigureWidget (scroll_bar,
9013 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9014 top,
9015 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
9016 max (height, 1), 0);
9017 XtMapWidget (scroll_bar);
9018 }
06a2c219 9019#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 9020 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 9021#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9022
9023 UNBLOCK_INPUT;
12ba150f 9024 return bar;
f451eb13
JB
9025}
9026
06a2c219 9027
12ba150f 9028/* Draw BAR's handle in the proper position.
06a2c219 9029
12ba150f
JB
9030 If the handle is already drawn from START to END, don't bother
9031 redrawing it, unless REBUILD is non-zero; in that case, always
9032 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 9033 events.)
12ba150f
JB
9034
9035 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
9036 fit inside its rectangle, but if the user is dragging the scroll
9037 bar handle, we want to let them drag it down all the way, so that
9038 the bar's top is as far down as it goes; otherwise, there's no way
9039 to move to the very end of the buffer. */
9040
5c187dee
GM
9041#ifndef USE_TOOLKIT_SCROLL_BARS
9042
f451eb13 9043static void
ab648270
JB
9044x_scroll_bar_set_handle (bar, start, end, rebuild)
9045 struct scroll_bar *bar;
f451eb13 9046 int start, end;
12ba150f 9047 int rebuild;
f451eb13 9048{
12ba150f 9049 int dragging = ! NILP (bar->dragging);
ab648270 9050 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9051 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9052 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
9053
9054 /* If the display is already accurate, do nothing. */
9055 if (! rebuild
9056 && start == XINT (bar->start)
9057 && end == XINT (bar->end))
9058 return;
9059
f451eb13
JB
9060 BLOCK_INPUT;
9061
9062 {
d9cdbb3d
RS
9063 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
9064 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
9065 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
9066
9067 /* Make sure the values are reasonable, and try to preserve
9068 the distance between start and end. */
12ba150f
JB
9069 {
9070 int length = end - start;
9071
9072 if (start < 0)
9073 start = 0;
9074 else if (start > top_range)
9075 start = top_range;
9076 end = start + length;
9077
9078 if (end < start)
9079 end = start;
9080 else if (end > top_range && ! dragging)
9081 end = top_range;
9082 }
f451eb13 9083
ab648270 9084 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
9085 XSETINT (bar->start, start);
9086 XSETINT (bar->end, end);
f451eb13 9087
12ba150f
JB
9088 /* Clip the end position, just for display. */
9089 if (end > top_range)
9090 end = top_range;
f451eb13 9091
ab648270 9092 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
9093 below top positions, to make sure the handle is always at least
9094 that many pixels tall. */
ab648270 9095 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 9096
12ba150f
JB
9097 /* Draw the empty space above the handle. Note that we can't clear
9098 zero-height areas; that means "clear to end of window." */
9099 if (0 < start)
c5e6e06b
GM
9100 x_clear_area (FRAME_X_DISPLAY (f), w,
9101 /* x, y, width, height, and exposures. */
9102 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9103 VERTICAL_SCROLL_BAR_TOP_BORDER,
9104 inside_width, start,
9105 False);
f451eb13 9106
06a2c219
GM
9107 /* Change to proper foreground color if one is specified. */
9108 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9109 XSetForeground (FRAME_X_DISPLAY (f), gc,
9110 f->output_data.x->scroll_bar_foreground_pixel);
9111
12ba150f 9112 /* Draw the handle itself. */
334208b7 9113 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
12ba150f 9114 /* x, y, width, height */
ab648270
JB
9115 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9116 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 9117 inside_width, end - start);
f451eb13 9118
06a2c219
GM
9119 /* Restore the foreground color of the GC if we changed it above. */
9120 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9121 XSetForeground (FRAME_X_DISPLAY (f), gc,
9122 f->output_data.x->foreground_pixel);
f451eb13 9123
12ba150f
JB
9124 /* Draw the empty space below the handle. Note that we can't
9125 clear zero-height areas; that means "clear to end of window." */
9126 if (end < inside_height)
c5e6e06b
GM
9127 x_clear_area (FRAME_X_DISPLAY (f), w,
9128 /* x, y, width, height, and exposures. */
9129 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9130 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
9131 inside_width, inside_height - end,
9132 False);
f451eb13 9133
f451eb13
JB
9134 }
9135
f451eb13
JB
9136 UNBLOCK_INPUT;
9137}
9138
5c187dee 9139#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 9140
06a2c219
GM
9141/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
9142 nil. */
58769bee 9143
12ba150f 9144static void
ab648270
JB
9145x_scroll_bar_remove (bar)
9146 struct scroll_bar *bar;
12ba150f 9147{
e83dc917 9148 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
9149 BLOCK_INPUT;
9150
eccc05db 9151#ifdef USE_TOOLKIT_SCROLL_BARS
e83dc917
GM
9152 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
9153#else
9154 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
9155#endif
06a2c219 9156
ab648270
JB
9157 /* Disassociate this scroll bar from its window. */
9158 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
9159
9160 UNBLOCK_INPUT;
9161}
9162
06a2c219 9163
12ba150f
JB
9164/* Set the handle of the vertical scroll bar for WINDOW to indicate
9165 that we are displaying PORTION characters out of a total of WHOLE
ab648270 9166 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 9167 create one. */
06a2c219 9168
12ba150f 9169static void
06a2c219
GM
9170XTset_vertical_scroll_bar (w, portion, whole, position)
9171 struct window *w;
f451eb13
JB
9172 int portion, whole, position;
9173{
06a2c219 9174 struct frame *f = XFRAME (w->frame);
ab648270 9175 struct scroll_bar *bar;
3c6ede7b 9176 int top, height, left, sb_left, width, sb_width;
06a2c219 9177 int window_x, window_y, window_width, window_height;
06a2c219 9178
3c6ede7b 9179 /* Get window dimensions. */
06a2c219 9180 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
9181 top = window_y;
9182 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9183 height = window_height;
06a2c219 9184
3c6ede7b 9185 /* Compute the left edge of the scroll bar area. */
06a2c219 9186 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
9187 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
9188 else
9189 left = XFASTINT (w->left);
9190 left *= CANON_X_UNIT (f);
9191 left += FRAME_INTERNAL_BORDER_WIDTH (f);
9192
9193 /* Compute the width of the scroll bar which might be less than
9194 the width of the area reserved for the scroll bar. */
9195 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
9196 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 9197 else
3c6ede7b 9198 sb_width = width;
12ba150f 9199
3c6ede7b
GM
9200 /* Compute the left edge of the scroll bar. */
9201#ifdef USE_TOOLKIT_SCROLL_BARS
9202 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9203 sb_left = left + width - sb_width - (width - sb_width) / 2;
9204 else
9205 sb_left = left + (width - sb_width) / 2;
9206#else
9207 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9208 sb_left = left + width - sb_width;
9209 else
9210 sb_left = left;
9211#endif
9212
ab648270 9213 /* Does the scroll bar exist yet? */
06a2c219 9214 if (NILP (w->vertical_scroll_bar))
3c6ede7b 9215 {
7b49b9d2 9216 if (width > 0 && height > 0)
b547b6e8
GM
9217 {
9218 BLOCK_INPUT;
9219 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9220 left, top, width, height, False);
9221 UNBLOCK_INPUT;
9222 }
9223
3c6ede7b
GM
9224 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
9225 }
f451eb13 9226 else
12ba150f
JB
9227 {
9228 /* It may just need to be moved and resized. */
06a2c219
GM
9229 unsigned int mask = 0;
9230
9231 bar = XSCROLL_BAR (w->vertical_scroll_bar);
9232
9233 BLOCK_INPUT;
9234
3c6ede7b 9235 if (sb_left != XINT (bar->left))
06a2c219 9236 mask |= CWX;
3c6ede7b 9237 if (top != XINT (bar->top))
06a2c219 9238 mask |= CWY;
3c6ede7b 9239 if (sb_width != XINT (bar->width))
06a2c219 9240 mask |= CWWidth;
3c6ede7b 9241 if (height != XINT (bar->height))
06a2c219
GM
9242 mask |= CWHeight;
9243
9244#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
9245
9246 /* Since toolkit scroll bars are smaller than the space reserved
9247 for them on the frame, we have to clear "under" them. */
7b49b9d2 9248 if (width > 0 && height > 0)
f964b4d7
GM
9249 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9250 left, top, width, height, False);
06a2c219
GM
9251
9252 /* Move/size the scroll bar widget. */
9253 if (mask)
e83dc917 9254 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
3c6ede7b
GM
9255 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9256 top,
9257 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
f964b4d7 9258 max (height, 1), 0);
06a2c219
GM
9259
9260#else /* not USE_TOOLKIT_SCROLL_BARS */
9261
357e7376
GM
9262 /* Clear areas not covered by the scroll bar because of
9263 VERTICAL_SCROLL_BAR_WIDTH_TRIM. */
e1f6572f
RS
9264 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
9265 {
c5e6e06b
GM
9266 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9267 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9268 height, False);
9269 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9270 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9271 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9272 height, False);
e1f6572f 9273 }
357e7376
GM
9274
9275 /* Clear areas not covered by the scroll bar because it's not as
9276 wide as the area reserved for it . This makes sure a
9277 previous mode line display is cleared after C-x 2 C-x 1, for
9278 example. */
9279 {
9280 int area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9281 int rest = area_width - sb_width;
38d2af0c
GM
9282 if (rest > 0 && height > 0)
9283 {
9284 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
9285 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9286 left + area_width - rest, top,
9287 rest, height, False);
9288 else
9289 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9290 left, top, rest, height, False);
9291 }
357e7376 9292 }
06a2c219
GM
9293
9294 /* Move/size the scroll bar window. */
9295 if (mask)
9296 {
9297 XWindowChanges wc;
9298
3c6ede7b
GM
9299 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
9300 wc.y = top;
9301 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
9302 wc.height = height;
06a2c219
GM
9303 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
9304 mask, &wc);
9305 }
9306
9307#endif /* not USE_TOOLKIT_SCROLL_BARS */
9308
9309 /* Remember new settings. */
3c6ede7b
GM
9310 XSETINT (bar->left, sb_left);
9311 XSETINT (bar->top, top);
9312 XSETINT (bar->width, sb_width);
9313 XSETINT (bar->height, height);
06a2c219
GM
9314
9315 UNBLOCK_INPUT;
12ba150f 9316 }
f451eb13 9317
eccc05db 9318#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
9319 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
9320#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 9321 /* Set the scroll bar's current state, unless we're currently being
f451eb13 9322 dragged. */
12ba150f 9323 if (NILP (bar->dragging))
f451eb13 9324 {
92857db0 9325 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 9326
12ba150f 9327 if (whole == 0)
ab648270 9328 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
9329 else
9330 {
43f868f5
JB
9331 int start = ((double) position * top_range) / whole;
9332 int end = ((double) (position + portion) * top_range) / whole;
ab648270 9333 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 9334 }
f451eb13 9335 }
06a2c219 9336#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9337
06a2c219 9338 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
9339}
9340
12ba150f 9341
f451eb13 9342/* The following three hooks are used when we're doing a thorough
ab648270 9343 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 9344 are going to be deleted, because keeping track of when windows go
12ba150f
JB
9345 away is a real pain - "Can you say set-window-configuration, boys
9346 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 9347 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 9348 from the fiery pit when we actually redisplay its window. */
f451eb13 9349
ab648270
JB
9350/* Arrange for all scroll bars on FRAME to be removed at the next call
9351 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
9352 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
9353
58769bee 9354static void
ab648270 9355XTcondemn_scroll_bars (frame)
f451eb13
JB
9356 FRAME_PTR frame;
9357{
f9e24cb9
RS
9358 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
9359 while (! NILP (FRAME_SCROLL_BARS (frame)))
9360 {
9361 Lisp_Object bar;
9362 bar = FRAME_SCROLL_BARS (frame);
9363 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
9364 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
9365 XSCROLL_BAR (bar)->prev = Qnil;
9366 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
9367 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
9368 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
9369 }
f451eb13
JB
9370}
9371
fa2dfc30 9372
06a2c219 9373/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 9374 Note that WINDOW isn't necessarily condemned at all. */
fa2dfc30 9375
f451eb13 9376static void
ab648270 9377XTredeem_scroll_bar (window)
12ba150f 9378 struct window *window;
f451eb13 9379{
ab648270 9380 struct scroll_bar *bar;
fa2dfc30 9381 struct frame *f;
12ba150f 9382
ab648270
JB
9383 /* We can't redeem this window's scroll bar if it doesn't have one. */
9384 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
9385 abort ();
9386
ab648270 9387 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
9388
9389 /* Unlink it from the condemned list. */
fa2dfc30
GM
9390 f = XFRAME (WINDOW_FRAME (window));
9391 if (NILP (bar->prev))
9392 {
9393 /* If the prev pointer is nil, it must be the first in one of
9394 the lists. */
9395 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
9396 /* It's not condemned. Everything's fine. */
9397 return;
9398 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
9399 window->vertical_scroll_bar))
9400 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
9401 else
9402 /* If its prev pointer is nil, it must be at the front of
9403 one or the other! */
9404 abort ();
9405 }
9406 else
9407 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f 9408
fa2dfc30
GM
9409 if (! NILP (bar->next))
9410 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 9411
fa2dfc30
GM
9412 bar->next = FRAME_SCROLL_BARS (f);
9413 bar->prev = Qnil;
9414 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
9415 if (! NILP (bar->next))
9416 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13
JB
9417}
9418
ab648270
JB
9419/* Remove all scroll bars on FRAME that haven't been saved since the
9420 last call to `*condemn_scroll_bars_hook'. */
06a2c219 9421
f451eb13 9422static void
ab648270 9423XTjudge_scroll_bars (f)
12ba150f 9424 FRAME_PTR f;
f451eb13 9425{
12ba150f 9426 Lisp_Object bar, next;
f451eb13 9427
ab648270 9428 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
9429
9430 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
9431 more events on the hapless scroll bars. */
9432 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
9433
9434 for (; ! NILP (bar); bar = next)
f451eb13 9435 {
ab648270 9436 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 9437
ab648270 9438 x_scroll_bar_remove (b);
12ba150f
JB
9439
9440 next = b->next;
9441 b->next = b->prev = Qnil;
f451eb13 9442 }
12ba150f 9443
ab648270 9444 /* Now there should be no references to the condemned scroll bars,
12ba150f 9445 and they should get garbage-collected. */
f451eb13
JB
9446}
9447
9448
06a2c219
GM
9449/* Handle an Expose or GraphicsExpose event on a scroll bar. This
9450 is a no-op when using toolkit scroll bars.
ab648270
JB
9451
9452 This may be called from a signal handler, so we have to ignore GC
9453 mark bits. */
06a2c219 9454
f451eb13 9455static void
ab648270
JB
9456x_scroll_bar_expose (bar, event)
9457 struct scroll_bar *bar;
f451eb13
JB
9458 XEvent *event;
9459{
06a2c219
GM
9460#ifndef USE_TOOLKIT_SCROLL_BARS
9461
ab648270 9462 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9463 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9464 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 9465 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 9466
f451eb13
JB
9467 BLOCK_INPUT;
9468
ab648270 9469 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 9470
06a2c219 9471 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 9472 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
9473
9474 /* x, y, width, height */
d9cdbb3d 9475 0, 0,
3cbd2e0b 9476 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
9477 XINT (bar->height) - 1);
9478
f451eb13 9479 UNBLOCK_INPUT;
06a2c219
GM
9480
9481#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9482}
9483
ab648270
JB
9484/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
9485 is set to something other than no_event, it is enqueued.
9486
9487 This may be called from a signal handler, so we have to ignore GC
9488 mark bits. */
06a2c219 9489
5c187dee
GM
9490#ifndef USE_TOOLKIT_SCROLL_BARS
9491
f451eb13 9492static void
ab648270
JB
9493x_scroll_bar_handle_click (bar, event, emacs_event)
9494 struct scroll_bar *bar;
f451eb13
JB
9495 XEvent *event;
9496 struct input_event *emacs_event;
9497{
0299d313 9498 if (! GC_WINDOWP (bar->window))
12ba150f
JB
9499 abort ();
9500
ab648270 9501 emacs_event->kind = scroll_bar_click;
69388238 9502 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
9503 emacs_event->modifiers
9504 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
9505 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
9506 event->xbutton.state)
9507 | (event->type == ButtonRelease
9508 ? up_modifier
9509 : down_modifier));
12ba150f 9510 emacs_event->frame_or_window = bar->window;
0f8aabe9 9511 emacs_event->arg = Qnil;
f451eb13 9512 emacs_event->timestamp = event->xbutton.time;
12ba150f 9513 {
06a2c219 9514#if 0
d9cdbb3d 9515 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 9516 int internal_height
d9cdbb3d 9517 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9518#endif
0299d313 9519 int top_range
d9cdbb3d 9520 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 9521 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
9522
9523 if (y < 0) y = 0;
9524 if (y > top_range) y = top_range;
9525
9526 if (y < XINT (bar->start))
ab648270
JB
9527 emacs_event->part = scroll_bar_above_handle;
9528 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9529 emacs_event->part = scroll_bar_handle;
12ba150f 9530 else
ab648270 9531 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
9532
9533 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
9534 they want to drag it. Lisp code needs to be able to decide
9535 whether or not we're dragging. */
929787e1 9536#if 0
12ba150f
JB
9537 /* If the user has just clicked on the handle, record where they're
9538 holding it. */
9539 if (event->type == ButtonPress
ab648270 9540 && emacs_event->part == scroll_bar_handle)
e0c1aef2 9541 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 9542#endif
12ba150f
JB
9543
9544 /* If the user has released the handle, set it to its final position. */
9545 if (event->type == ButtonRelease
9546 && ! NILP (bar->dragging))
9547 {
9548 int new_start = y - XINT (bar->dragging);
9549 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 9550
ab648270 9551 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
9552 bar->dragging = Qnil;
9553 }
f451eb13 9554
5116f055
JB
9555 /* Same deal here as the other #if 0. */
9556#if 0
58769bee 9557 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 9558 the handle. */
ab648270 9559 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
9560 emacs_event->x = bar->start;
9561 else
e0c1aef2 9562 XSETINT (emacs_event->x, y);
5116f055 9563#else
e0c1aef2 9564 XSETINT (emacs_event->x, y);
5116f055 9565#endif
f451eb13 9566
e0c1aef2 9567 XSETINT (emacs_event->y, top_range);
12ba150f
JB
9568 }
9569}
f451eb13 9570
ab648270
JB
9571/* Handle some mouse motion while someone is dragging the scroll bar.
9572
9573 This may be called from a signal handler, so we have to ignore GC
9574 mark bits. */
06a2c219 9575
f451eb13 9576static void
ab648270
JB
9577x_scroll_bar_note_movement (bar, event)
9578 struct scroll_bar *bar;
f451eb13
JB
9579 XEvent *event;
9580{
39d8bb4d
KH
9581 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
9582
f451eb13
JB
9583 last_mouse_movement_time = event->xmotion.time;
9584
39d8bb4d 9585 f->mouse_moved = 1;
e0c1aef2 9586 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
9587
9588 /* If we're dragging the bar, display it. */
ab648270 9589 if (! GC_NILP (bar->dragging))
f451eb13
JB
9590 {
9591 /* Where should the handle be now? */
12ba150f 9592 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 9593
12ba150f 9594 if (new_start != XINT (bar->start))
f451eb13 9595 {
12ba150f 9596 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 9597
ab648270 9598 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
9599 }
9600 }
f451eb13
JB
9601}
9602
5c187dee
GM
9603#endif /* !USE_TOOLKIT_SCROLL_BARS */
9604
12ba150f 9605/* Return information to the user about the current position of the mouse
ab648270 9606 on the scroll bar. */
06a2c219 9607
12ba150f 9608static void
334208b7
RS
9609x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
9610 FRAME_PTR *fp;
12ba150f 9611 Lisp_Object *bar_window;
ab648270 9612 enum scroll_bar_part *part;
12ba150f
JB
9613 Lisp_Object *x, *y;
9614 unsigned long *time;
9615{
ab648270 9616 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
9617 Window w = SCROLL_BAR_X_WINDOW (bar);
9618 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 9619 int win_x, win_y;
559cb2fb
JB
9620 Window dummy_window;
9621 int dummy_coord;
9622 unsigned int dummy_mask;
12ba150f 9623
cf7cb199
JB
9624 BLOCK_INPUT;
9625
ab648270 9626 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 9627 report that. */
334208b7 9628 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 9629
559cb2fb
JB
9630 /* Root, child, root x and root y. */
9631 &dummy_window, &dummy_window,
9632 &dummy_coord, &dummy_coord,
12ba150f 9633
559cb2fb
JB
9634 /* Position relative to scroll bar. */
9635 &win_x, &win_y,
12ba150f 9636
559cb2fb
JB
9637 /* Mouse buttons and modifier keys. */
9638 &dummy_mask))
7a13e894 9639 ;
559cb2fb
JB
9640 else
9641 {
06a2c219 9642#if 0
559cb2fb 9643 int inside_height
d9cdbb3d 9644 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9645#endif
559cb2fb 9646 int top_range
d9cdbb3d 9647 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
9648
9649 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
9650
9651 if (! NILP (bar->dragging))
9652 win_y -= XINT (bar->dragging);
9653
9654 if (win_y < 0)
9655 win_y = 0;
9656 if (win_y > top_range)
9657 win_y = top_range;
9658
334208b7 9659 *fp = f;
7a13e894 9660 *bar_window = bar->window;
559cb2fb
JB
9661
9662 if (! NILP (bar->dragging))
9663 *part = scroll_bar_handle;
9664 else if (win_y < XINT (bar->start))
9665 *part = scroll_bar_above_handle;
9666 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9667 *part = scroll_bar_handle;
9668 else
9669 *part = scroll_bar_below_handle;
12ba150f 9670
e0c1aef2
KH
9671 XSETINT (*x, win_y);
9672 XSETINT (*y, top_range);
12ba150f 9673
39d8bb4d 9674 f->mouse_moved = 0;
559cb2fb
JB
9675 last_mouse_scroll_bar = Qnil;
9676 }
12ba150f 9677
559cb2fb 9678 *time = last_mouse_movement_time;
cf7cb199 9679
cf7cb199 9680 UNBLOCK_INPUT;
12ba150f
JB
9681}
9682
f451eb13 9683
dbc4e1c1 9684/* The screen has been cleared so we may have changed foreground or
ab648270
JB
9685 background colors, and the scroll bars may need to be redrawn.
9686 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
9687 redraw them. */
9688
dfcf069d 9689void
ab648270 9690x_scroll_bar_clear (f)
dbc4e1c1
JB
9691 FRAME_PTR f;
9692{
06a2c219 9693#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
9694 Lisp_Object bar;
9695
b80c363e
RS
9696 /* We can have scroll bars even if this is 0,
9697 if we just turned off scroll bar mode.
9698 But in that case we should not clear them. */
9699 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
9700 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
9701 bar = XSCROLL_BAR (bar)->next)
c5e6e06b
GM
9702 XClearArea (FRAME_X_DISPLAY (f),
9703 SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
b80c363e 9704 0, 0, 0, 0, True);
06a2c219 9705#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
9706}
9707
06a2c219 9708/* This processes Expose events from the menu-bar specific X event
19126e11 9709 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 9710 when handling menu-bar or pop-up items. */
3afe33e7 9711
06a2c219 9712int
3afe33e7
RS
9713process_expose_from_menu (event)
9714 XEvent event;
9715{
9716 FRAME_PTR f;
19126e11 9717 struct x_display_info *dpyinfo;
06a2c219 9718 int frame_exposed_p = 0;
3afe33e7 9719
f94397b5
KH
9720 BLOCK_INPUT;
9721
19126e11
KH
9722 dpyinfo = x_display_info_for_display (event.xexpose.display);
9723 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
9724 if (f)
9725 {
9726 if (f->async_visible == 0)
9727 {
9728 f->async_visible = 1;
9729 f->async_iconified = 0;
06c488fd 9730 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
9731 SET_FRAME_GARBAGED (f);
9732 }
9733 else
9734 {
06a2c219
GM
9735 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
9736 event.xexpose.x, event.xexpose.y,
9737 event.xexpose.width, event.xexpose.height);
9738 frame_exposed_p = 1;
3afe33e7
RS
9739 }
9740 }
9741 else
9742 {
9743 struct scroll_bar *bar
9744 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9745
3afe33e7
RS
9746 if (bar)
9747 x_scroll_bar_expose (bar, &event);
9748 }
f94397b5
KH
9749
9750 UNBLOCK_INPUT;
06a2c219 9751 return frame_exposed_p;
3afe33e7 9752}
09756a85
RS
9753\f
9754/* Define a queue to save up SelectionRequest events for later handling. */
9755
9756struct selection_event_queue
9757 {
9758 XEvent event;
9759 struct selection_event_queue *next;
9760 };
9761
9762static struct selection_event_queue *queue;
9763
9764/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 9765
09756a85
RS
9766static int x_queue_selection_requests;
9767
9768/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 9769
09756a85 9770static void
334208b7
RS
9771x_queue_event (f, event)
9772 FRAME_PTR f;
09756a85
RS
9773 XEvent *event;
9774{
9775 struct selection_event_queue *queue_tmp
06a2c219 9776 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 9777
58769bee 9778 if (queue_tmp != NULL)
09756a85
RS
9779 {
9780 queue_tmp->event = *event;
9781 queue_tmp->next = queue;
9782 queue = queue_tmp;
9783 }
9784}
9785
9786/* Take all the queued events and put them back
9787 so that they get processed afresh. */
9788
9789static void
db3906fd
RS
9790x_unqueue_events (display)
9791 Display *display;
09756a85 9792{
58769bee 9793 while (queue != NULL)
09756a85
RS
9794 {
9795 struct selection_event_queue *queue_tmp = queue;
db3906fd 9796 XPutBackEvent (display, &queue_tmp->event);
09756a85 9797 queue = queue_tmp->next;
06a2c219 9798 xfree ((char *)queue_tmp);
09756a85
RS
9799 }
9800}
9801
9802/* Start queuing SelectionRequest events. */
9803
9804void
db3906fd
RS
9805x_start_queuing_selection_requests (display)
9806 Display *display;
09756a85
RS
9807{
9808 x_queue_selection_requests++;
9809}
9810
9811/* Stop queuing SelectionRequest events. */
9812
9813void
db3906fd
RS
9814x_stop_queuing_selection_requests (display)
9815 Display *display;
09756a85
RS
9816{
9817 x_queue_selection_requests--;
db3906fd 9818 x_unqueue_events (display);
09756a85 9819}
f451eb13
JB
9820\f
9821/* The main X event-reading loop - XTread_socket. */
dc6f92b8 9822
06a2c219 9823/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
9824 but we have to put it out here, since static variables within functions
9825 sometimes don't work. */
06a2c219 9826
dc6f92b8
JB
9827static Time enter_timestamp;
9828
11edeb03 9829/* This holds the state XLookupString needs to implement dead keys
58769bee 9830 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
9831 says that a portable program can't use this, but Stephen Gildea assures
9832 me that letting the compiler initialize it to zeros will work okay.
9833
9834 This must be defined outside of XTread_socket, for the same reasons
f7d40b3b 9835 given for enter_timestamp, above. */
06a2c219 9836
11edeb03
JB
9837static XComposeStatus compose_status;
9838
10e6549c
RS
9839/* Record the last 100 characters stored
9840 to help debug the loss-of-chars-during-GC problem. */
06a2c219 9841
2224b905
RS
9842static int temp_index;
9843static short temp_buffer[100];
10e6549c 9844
7a13e894
RS
9845/* Set this to nonzero to fake an "X I/O error"
9846 on a particular display. */
06a2c219 9847
7a13e894
RS
9848struct x_display_info *XTread_socket_fake_io_error;
9849
2224b905
RS
9850/* When we find no input here, we occasionally do a no-op command
9851 to verify that the X server is still running and we can still talk with it.
9852 We try all the open displays, one by one.
9853 This variable is used for cycling thru the displays. */
06a2c219 9854
2224b905
RS
9855static struct x_display_info *next_noop_dpyinfo;
9856
06a2c219
GM
9857#define SET_SAVED_MENU_EVENT(size) \
9858 do \
9859 { \
9860 if (f->output_data.x->saved_menu_event == 0) \
9861 f->output_data.x->saved_menu_event \
9862 = (XEvent *) xmalloc (sizeof (XEvent)); \
9863 bcopy (&event, f->output_data.x->saved_menu_event, size); \
9864 if (numchars >= 1) \
9865 { \
9866 bufp->kind = menu_bar_activate_event; \
9867 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 9868 bufp->arg = Qnil; \
06a2c219
GM
9869 bufp++; \
9870 count++; \
9871 numchars--; \
9872 } \
9873 } \
9874 while (0)
9875
8805890a 9876#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 9877#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 9878
dc6f92b8
JB
9879/* Read events coming from the X server.
9880 This routine is called by the SIGIO handler.
9881 We return as soon as there are no more events to be read.
9882
9883 Events representing keys are stored in buffer BUFP,
9884 which can hold up to NUMCHARS characters.
9885 We return the number of characters stored into the buffer,
9886 thus pretending to be `read'.
9887
dc6f92b8
JB
9888 EXPECTED is nonzero if the caller knows input is available. */
9889
7c5283e4 9890int
f66868ba 9891XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 9892 register int sd;
8805890a
KH
9893 /* register */ struct input_event *bufp;
9894 /* register */ int numchars;
dc6f92b8
JB
9895 int expected;
9896{
9897 int count = 0;
9898 int nbytes = 0;
dc6f92b8 9899 XEvent event;
f676886a 9900 struct frame *f;
66f55a9d 9901 int event_found = 0;
334208b7 9902 struct x_display_info *dpyinfo;
379b5ac0 9903 struct coding_system coding;
dc6f92b8 9904
9ac0d9e0 9905 if (interrupt_input_blocked)
dc6f92b8 9906 {
9ac0d9e0 9907 interrupt_input_pending = 1;
dc6f92b8
JB
9908 return -1;
9909 }
9910
9ac0d9e0 9911 interrupt_input_pending = 0;
dc6f92b8 9912 BLOCK_INPUT;
c0a04927
RS
9913
9914 /* So people can tell when we have read the available input. */
9915 input_signal_count++;
9916
dc6f92b8 9917 if (numchars <= 0)
06a2c219 9918 abort (); /* Don't think this happens. */
dc6f92b8 9919
bde5503b
GM
9920 ++handling_signal;
9921
379b5ac0
KH
9922 /* The input should be decoded if it is from XIM. Currently the
9923 locale of XIM is the same as that of the system. So, we can use
9924 Vlocale_coding_system which is initialized properly at Emacs
9925 startup time. */
9926 setup_coding_system (Vlocale_coding_system, &coding);
9927 coding.src_multibyte = 0;
9928 coding.dst_multibyte = 1;
9929 /* The input is converted to events, thus we can't handle
9930 composition. Anyway, there's no XIM that gives us composition
9931 information. */
9932 coding.composing = COMPOSITION_DISABLED;
9933
7a13e894
RS
9934 /* Find the display we are supposed to read input for.
9935 It's the one communicating on descriptor SD. */
9936 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9937 {
9938#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9939#ifdef FIOSNBIO
7a13e894
RS
9940 /* If available, Xlib uses FIOSNBIO to make the socket
9941 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9942 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9943 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9944 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9945#endif /* ! defined (FIOSNBIO) */
7a13e894 9946#endif
dc6f92b8 9947
7a13e894
RS
9948#if 0 /* This code can't be made to work, with multiple displays,
9949 and appears not to be used on any system any more.
9950 Also keyboard.c doesn't turn O_NDELAY on and off
9951 for X connections. */
dc6f92b8
JB
9952#ifndef SIGIO
9953#ifndef HAVE_SELECT
7a13e894
RS
9954 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9955 {
9956 extern int read_alarm_should_throw;
9957 read_alarm_should_throw = 1;
9958 XPeekEvent (dpyinfo->display, &event);
9959 read_alarm_should_throw = 0;
9960 }
c118dd06
JB
9961#endif /* HAVE_SELECT */
9962#endif /* SIGIO */
7a13e894 9963#endif
dc6f92b8 9964
7a13e894
RS
9965 /* For debugging, this gives a way to fake an I/O error. */
9966 if (dpyinfo == XTread_socket_fake_io_error)
9967 {
9968 XTread_socket_fake_io_error = 0;
9969 x_io_error_quitter (dpyinfo->display);
9970 }
dc6f92b8 9971
06a2c219 9972 while (XPending (dpyinfo->display))
dc6f92b8 9973 {
7a13e894 9974 XNextEvent (dpyinfo->display, &event);
06a2c219 9975
531483fb 9976#ifdef HAVE_X_I18N
d1bc4182 9977 {
f2be1146
GM
9978 /* Filter events for the current X input method.
9979 XFilterEvent returns non-zero if the input method has
9980 consumed the event. We pass the frame's X window to
9981 XFilterEvent because that's the one for which the IC
9982 was created. */
f5d11644
GM
9983 struct frame *f1 = x_any_window_to_frame (dpyinfo,
9984 event.xclient.window);
9985 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
9986 break;
9987 }
0cd6403b 9988#endif
7a13e894
RS
9989 event_found = 1;
9990
9991 switch (event.type)
9992 {
9993 case ClientMessage:
c047688c 9994 {
7a13e894
RS
9995 if (event.xclient.message_type
9996 == dpyinfo->Xatom_wm_protocols
9997 && event.xclient.format == 32)
c047688c 9998 {
7a13e894
RS
9999 if (event.xclient.data.l[0]
10000 == dpyinfo->Xatom_wm_take_focus)
c047688c 10001 {
8c1a6a84
RS
10002 /* Use x_any_window_to_frame because this
10003 could be the shell widget window
10004 if the frame has no title bar. */
10005 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
10006#ifdef HAVE_X_I18N
10007 /* Not quite sure this is needed -pd */
8c1a6a84 10008 if (f && FRAME_XIC (f))
6c183ba5
RS
10009 XSetICFocus (FRAME_XIC (f));
10010#endif
f1da8f06
GM
10011#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
10012 instructs the WM to set the input focus automatically for
10013 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
10014 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
10015 it has set the focus. So, XSetInputFocus below is not
10016 needed.
10017
10018 The call to XSetInputFocus below has also caused trouble. In
10019 cases where the XSetInputFocus done by the WM and the one
10020 below are temporally close (on a fast machine), the call
10021 below can generate additional FocusIn events which confuse
10022 Emacs. */
10023
bf7253f4
RS
10024 /* Since we set WM_TAKE_FOCUS, we must call
10025 XSetInputFocus explicitly. But not if f is null,
10026 since that might be an event for a deleted frame. */
7a13e894 10027 if (f)
bf7253f4
RS
10028 {
10029 Display *d = event.xclient.display;
10030 /* Catch and ignore errors, in case window has been
10031 iconified by a window manager such as GWM. */
10032 int count = x_catch_errors (d);
10033 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
10034 /* The ICCCM says this is
10035 the only valid choice. */
10036 RevertToParent,
bf7253f4
RS
10037 event.xclient.data.l[1]);
10038 /* This is needed to detect the error
10039 if there is an error. */
10040 XSync (d, False);
10041 x_uncatch_errors (d, count);
10042 }
7a13e894 10043 /* Not certain about handling scroll bars here */
f1da8f06 10044#endif /* 0 */
c047688c 10045 }
7a13e894
RS
10046 else if (event.xclient.data.l[0]
10047 == dpyinfo->Xatom_wm_save_yourself)
10048 {
10049 /* Save state modify the WM_COMMAND property to
06a2c219 10050 something which can reinstate us. This notifies
7a13e894
RS
10051 the session manager, who's looking for such a
10052 PropertyNotify. Can restart processing when
06a2c219 10053 a keyboard or mouse event arrives. */
7a13e894
RS
10054 if (numchars > 0)
10055 {
19126e11
KH
10056 f = x_top_window_to_frame (dpyinfo,
10057 event.xclient.window);
7a13e894
RS
10058
10059 /* This is just so we only give real data once
10060 for a single Emacs process. */
b86bd3dd 10061 if (f == SELECTED_FRAME ())
7a13e894
RS
10062 XSetCommand (FRAME_X_DISPLAY (f),
10063 event.xclient.window,
10064 initial_argv, initial_argc);
f000f5c5 10065 else if (f)
7a13e894
RS
10066 XSetCommand (FRAME_X_DISPLAY (f),
10067 event.xclient.window,
10068 0, 0);
10069 }
10070 }
10071 else if (event.xclient.data.l[0]
10072 == dpyinfo->Xatom_wm_delete_window)
1fb20991 10073 {
19126e11
KH
10074 struct frame *f
10075 = x_any_window_to_frame (dpyinfo,
10076 event.xclient.window);
1fb20991 10077
7a13e894
RS
10078 if (f)
10079 {
10080 if (numchars == 0)
10081 abort ();
1fb20991 10082
7a13e894
RS
10083 bufp->kind = delete_window_event;
10084 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10085 bufp->arg = Qnil;
7a13e894
RS
10086 bufp++;
10087
10088 count += 1;
10089 numchars -= 1;
10090 }
1fb20991 10091 }
c047688c 10092 }
7a13e894
RS
10093 else if (event.xclient.message_type
10094 == dpyinfo->Xatom_wm_configure_denied)
10095 {
10096 }
10097 else if (event.xclient.message_type
10098 == dpyinfo->Xatom_wm_window_moved)
10099 {
10100 int new_x, new_y;
19126e11
KH
10101 struct frame *f
10102 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 10103
7a13e894
RS
10104 new_x = event.xclient.data.s[0];
10105 new_y = event.xclient.data.s[1];
1fb20991 10106
7a13e894
RS
10107 if (f)
10108 {
7556890b
RS
10109 f->output_data.x->left_pos = new_x;
10110 f->output_data.x->top_pos = new_y;
7a13e894 10111 }
1fb20991 10112 }
0fdff6bb 10113#ifdef HACK_EDITRES
7a13e894
RS
10114 else if (event.xclient.message_type
10115 == dpyinfo->Xatom_editres)
10116 {
19126e11
KH
10117 struct frame *f
10118 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 10119 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 10120 &event, NULL);
7a13e894 10121 }
0fdff6bb 10122#endif /* HACK_EDITRES */
06a2c219
GM
10123 else if ((event.xclient.message_type
10124 == dpyinfo->Xatom_DONE)
10125 || (event.xclient.message_type
10126 == dpyinfo->Xatom_PAGE))
10127 {
10128 /* Ghostview job completed. Kill it. We could
10129 reply with "Next" if we received "Page", but we
10130 currently never do because we are interested in
10131 images, only, which should have 1 page. */
06a2c219
GM
10132 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
10133 struct frame *f
10134 = x_window_to_frame (dpyinfo, event.xclient.window);
10135 x_kill_gs_process (pixmap, f);
10136 expose_frame (f, 0, 0, 0, 0);
10137 }
10138#ifdef USE_TOOLKIT_SCROLL_BARS
10139 /* Scroll bar callbacks send a ClientMessage from which
10140 we construct an input_event. */
10141 else if (event.xclient.message_type
10142 == dpyinfo->Xatom_Scrollbar)
10143 {
10144 x_scroll_bar_to_input_event (&event, bufp);
10145 ++bufp, ++count, --numchars;
10146 goto out;
10147 }
10148#endif /* USE_TOOLKIT_SCROLL_BARS */
10149 else
10150 goto OTHER;
7a13e894
RS
10151 }
10152 break;
dc6f92b8 10153
7a13e894 10154 case SelectionNotify:
3afe33e7 10155#ifdef USE_X_TOOLKIT
19126e11 10156 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 10157 goto OTHER;
3afe33e7 10158#endif /* not USE_X_TOOLKIT */
dfcf069d 10159 x_handle_selection_notify (&event.xselection);
7a13e894 10160 break;
d56a553a 10161
06a2c219 10162 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 10163#ifdef USE_X_TOOLKIT
19126e11 10164 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 10165 goto OTHER;
3afe33e7 10166#endif /* USE_X_TOOLKIT */
7a13e894
RS
10167 {
10168 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 10169
7a13e894
RS
10170 if (numchars == 0)
10171 abort ();
d56a553a 10172
7a13e894
RS
10173 bufp->kind = selection_clear_event;
10174 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10175 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10176 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10177 bufp->frame_or_window = Qnil;
0f8aabe9 10178 bufp->arg = Qnil;
7a13e894 10179 bufp++;
d56a553a 10180
7a13e894
RS
10181 count += 1;
10182 numchars -= 1;
10183 }
10184 break;
dc6f92b8 10185
06a2c219 10186 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 10187#ifdef USE_X_TOOLKIT
19126e11 10188 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 10189 goto OTHER;
3afe33e7 10190#endif /* USE_X_TOOLKIT */
7a13e894 10191 if (x_queue_selection_requests)
19126e11 10192 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
10193 &event);
10194 else
10195 {
1d2b2268
GM
10196 XSelectionRequestEvent *eventp
10197 = (XSelectionRequestEvent *) &event;
dc6f92b8 10198
7a13e894
RS
10199 if (numchars == 0)
10200 abort ();
10201
10202 bufp->kind = selection_request_event;
10203 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10204 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
10205 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10206 SELECTION_EVENT_TARGET (bufp) = eventp->target;
10207 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
10208 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10209 bufp->frame_or_window = Qnil;
0f8aabe9 10210 bufp->arg = Qnil;
7a13e894
RS
10211 bufp++;
10212
10213 count += 1;
10214 numchars -= 1;
10215 }
10216 break;
10217
10218 case PropertyNotify:
1d2b2268
GM
10219#if 0 /* This is plain wrong. In the case that we are waiting for a
10220 PropertyNotify used as an ACK in incremental selection
10221 transfer, the property will be on the receiver's window. */
10222#if defined USE_X_TOOLKIT
19126e11 10223 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 10224 goto OTHER;
1d2b2268
GM
10225#endif
10226#endif
dfcf069d 10227 x_handle_property_notify (&event.xproperty);
1d2b2268 10228 goto OTHER;
dc6f92b8 10229
7a13e894 10230 case ReparentNotify:
19126e11 10231 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
10232 if (f)
10233 {
10234 int x, y;
7556890b 10235 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 10236 x_real_positions (f, &x, &y);
7556890b
RS
10237 f->output_data.x->left_pos = x;
10238 f->output_data.x->top_pos = y;
7a13e894
RS
10239 }
10240 break;
3bd330d4 10241
7a13e894 10242 case Expose:
19126e11 10243 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 10244 if (f)
dc6f92b8 10245 {
7a13e894
RS
10246 if (f->async_visible == 0)
10247 {
10248 f->async_visible = 1;
10249 f->async_iconified = 0;
06c488fd 10250 f->output_data.x->has_been_visible = 1;
7a13e894
RS
10251 SET_FRAME_GARBAGED (f);
10252 }
10253 else
06a2c219
GM
10254 expose_frame (x_window_to_frame (dpyinfo,
10255 event.xexpose.window),
10256 event.xexpose.x, event.xexpose.y,
10257 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
10258 }
10259 else
7a13e894 10260 {
12949a7f
EZ
10261#ifndef USE_TOOLKIT_SCROLL_BARS
10262 struct scroll_bar *bar;
10263#endif
01f67d2c 10264#if defined USE_LUCID
c95fc5f1
GM
10265 /* Submenus of the Lucid menu bar aren't widgets
10266 themselves, so there's no way to dispatch events
10267 to them. Recognize this case separately. */
10268 {
10269 Widget widget
10270 = x_window_to_menu_bar (event.xexpose.window);
10271 if (widget)
10272 xlwmenu_redisplay (widget);
10273 }
01f67d2c
PJ
10274#endif /* USE_LUCID */
10275
06a2c219
GM
10276#ifdef USE_TOOLKIT_SCROLL_BARS
10277 /* Dispatch event to the widget. */
10278 goto OTHER;
10279#else /* not USE_TOOLKIT_SCROLL_BARS */
12949a7f 10280 bar = x_window_to_scroll_bar (event.xexpose.window);
58769bee 10281
7a13e894
RS
10282 if (bar)
10283 x_scroll_bar_expose (bar, &event);
3afe33e7 10284#ifdef USE_X_TOOLKIT
7a13e894
RS
10285 else
10286 goto OTHER;
3afe33e7 10287#endif /* USE_X_TOOLKIT */
06a2c219 10288#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10289 }
10290 break;
dc6f92b8 10291
7a13e894 10292 case GraphicsExpose: /* This occurs when an XCopyArea's
d624284c
PJ
10293 source area was obscured or not
10294 available. */
19126e11 10295 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
10296 if (f)
10297 {
06a2c219
GM
10298 expose_frame (f,
10299 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
10300 event.xgraphicsexpose.width,
10301 event.xgraphicsexpose.height);
7a13e894 10302 }
3afe33e7 10303#ifdef USE_X_TOOLKIT
7a13e894
RS
10304 else
10305 goto OTHER;
3afe33e7 10306#endif /* USE_X_TOOLKIT */
7a13e894 10307 break;
dc6f92b8 10308
7a13e894 10309 case NoExpose: /* This occurs when an XCopyArea's
06a2c219 10310 source area was completely
d624284c 10311 available. */
7a13e894 10312 break;
dc6f92b8 10313
7a13e894 10314 case UnmapNotify:
06a2c219
GM
10315 /* Redo the mouse-highlight after the tooltip has gone. */
10316 if (event.xmap.window == tip_window)
10317 {
10318 tip_window = 0;
10319 redo_mouse_highlight ();
10320 }
10321
91ea2a7a 10322 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894 10323 if (f) /* F may no longer exist if
d624284c 10324 the frame was deleted. */
7a13e894
RS
10325 {
10326 /* While a frame is unmapped, display generation is
10327 disabled; you don't want to spend time updating a
10328 display that won't ever be seen. */
10329 f->async_visible = 0;
10330 /* We can't distinguish, from the event, whether the window
10331 has become iconified or invisible. So assume, if it
10332 was previously visible, than now it is iconified.
1aa6072f
RS
10333 But x_make_frame_invisible clears both
10334 the visible flag and the iconified flag;
10335 and that way, we know the window is not iconified now. */
7a13e894 10336 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
10337 {
10338 f->async_iconified = 1;
bddd097c 10339
1aa6072f
RS
10340 bufp->kind = iconify_event;
10341 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10342 bufp->arg = Qnil;
1aa6072f
RS
10343 bufp++;
10344 count++;
10345 numchars--;
10346 }
7a13e894 10347 }
7a13e894 10348 goto OTHER;
dc6f92b8 10349
7a13e894 10350 case MapNotify:
06a2c219
GM
10351 if (event.xmap.window == tip_window)
10352 /* The tooltip has been drawn already. Avoid
10353 the SET_FRAME_GARBAGED below. */
10354 goto OTHER;
10355
10356 /* We use x_top_window_to_frame because map events can
10357 come for sub-windows and they don't mean that the
10358 frame is visible. */
19126e11 10359 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
10360 if (f)
10361 {
10362 f->async_visible = 1;
10363 f->async_iconified = 0;
06c488fd 10364 f->output_data.x->has_been_visible = 1;
dc6f92b8 10365
7a13e894
RS
10366 /* wait_reading_process_input will notice this and update
10367 the frame's display structures. */
10368 SET_FRAME_GARBAGED (f);
bddd097c 10369
d806e720
RS
10370 if (f->iconified)
10371 {
10372 bufp->kind = deiconify_event;
10373 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10374 bufp->arg = Qnil;
d806e720
RS
10375 bufp++;
10376 count++;
10377 numchars--;
10378 }
e73ec6fa 10379 else if (! NILP (Vframe_list)
8e713be6 10380 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
10381 /* Force a redisplay sooner or later
10382 to update the frame titles
10383 in case this is the second frame. */
10384 record_asynch_buffer_change ();
7a13e894 10385 }
7a13e894 10386 goto OTHER;
dc6f92b8 10387
7a13e894 10388 case KeyPress:
19126e11 10389 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 10390
eccc05db 10391#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
10392 if (f == 0)
10393 {
2564ea1b
GM
10394 /* Scroll bars consume key events, but we want
10395 the keys to go to the scroll bar's frame. */
06a2c219
GM
10396 Widget widget = XtWindowToWidget (dpyinfo->display,
10397 event.xkey.window);
10398 if (widget && XmIsScrollBar (widget))
10399 {
10400 widget = XtParent (widget);
10401 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
10402 }
10403 }
eccc05db 10404#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
06a2c219 10405
7a13e894
RS
10406 if (f != 0)
10407 {
10408 KeySym keysym, orig_keysym;
379b5ac0
KH
10409 /* al%imercury@uunet.uu.net says that making this 81
10410 instead of 80 fixed a bug whereby meta chars made
10411 his Emacs hang.
10412
10413 It seems that some version of XmbLookupString has
10414 a bug of not returning XBufferOverflow in
10415 status_return even if the input is too long to
10416 fit in 81 bytes. So, we must prepare sufficient
10417 bytes for copy_buffer. 513 bytes (256 chars for
6c4a22e6 10418 two-byte character set) seems to be a fairly good
379b5ac0
KH
10419 approximation. -- 2000.8.10 handa@etl.go.jp */
10420 unsigned char copy_buffer[513];
10421 unsigned char *copy_bufptr = copy_buffer;
10422 int copy_bufsiz = sizeof (copy_buffer);
7a13e894 10423 int modifiers;
64bb1782 10424
7a13e894
RS
10425 event.xkey.state
10426 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
10427 extra_keyboard_modifiers);
10428 modifiers = event.xkey.state;
3a2712f9 10429
7a13e894 10430 /* This will have to go some day... */
752a043f 10431
7a13e894
RS
10432 /* make_lispy_event turns chars into control chars.
10433 Don't do it here because XLookupString is too eager. */
10434 event.xkey.state &= ~ControlMask;
5d46f928
RS
10435 event.xkey.state &= ~(dpyinfo->meta_mod_mask
10436 | dpyinfo->super_mod_mask
10437 | dpyinfo->hyper_mod_mask
10438 | dpyinfo->alt_mod_mask);
10439
1cf4a0d1
RS
10440 /* In case Meta is ComposeCharacter,
10441 clear its status. According to Markus Ehrnsperger
10442 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
10443 this enables ComposeCharacter to work whether or
10444 not it is combined with Meta. */
10445 if (modifiers & dpyinfo->meta_mod_mask)
10446 bzero (&compose_status, sizeof (compose_status));
10447
6c183ba5
RS
10448#ifdef HAVE_X_I18N
10449 if (FRAME_XIC (f))
10450 {
f5d11644
GM
10451 Status status_return;
10452
6c183ba5 10453 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
10454 &event.xkey, copy_bufptr,
10455 copy_bufsiz, &keysym,
6c183ba5 10456 &status_return);
f5d11644
GM
10457 if (status_return == XBufferOverflow)
10458 {
10459 copy_bufsiz = nbytes + 1;
10460 copy_bufptr = (char *) alloca (copy_bufsiz);
10461 nbytes = XmbLookupString (FRAME_XIC (f),
10462 &event.xkey, copy_bufptr,
10463 copy_bufsiz, &keysym,
10464 &status_return);
10465 }
10466
1decb680
PE
10467 if (status_return == XLookupNone)
10468 break;
10469 else if (status_return == XLookupChars)
fdd9d55e
GM
10470 {
10471 keysym = NoSymbol;
10472 modifiers = 0;
10473 }
1decb680
PE
10474 else if (status_return != XLookupKeySym
10475 && status_return != XLookupBoth)
10476 abort ();
6c183ba5
RS
10477 }
10478 else
379b5ac0
KH
10479 nbytes = XLookupString (&event.xkey, copy_bufptr,
10480 copy_bufsiz, &keysym,
10481 &compose_status);
6c183ba5 10482#else
379b5ac0
KH
10483 nbytes = XLookupString (&event.xkey, copy_bufptr,
10484 copy_bufsiz, &keysym,
10485 &compose_status);
6c183ba5 10486#endif
dc6f92b8 10487
7a13e894 10488 orig_keysym = keysym;
55123275 10489
7a13e894
RS
10490 if (numchars > 1)
10491 {
10492 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
10493 || keysym == XK_Delete
1097aea0 10494#ifdef XK_ISO_Left_Tab
441affdb 10495 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 10496#endif
852bff8f 10497 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
10498 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
10499 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 10500#ifdef HPUX
7a13e894
RS
10501 /* This recognizes the "extended function keys".
10502 It seems there's no cleaner way.
10503 Test IsModifierKey to avoid handling mode_switch
10504 incorrectly. */
10505 || ((unsigned) (keysym) >= XK_Select
10506 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
10507#endif
10508#ifdef XK_dead_circumflex
7a13e894 10509 || orig_keysym == XK_dead_circumflex
69388238
RS
10510#endif
10511#ifdef XK_dead_grave
7a13e894 10512 || orig_keysym == XK_dead_grave
69388238
RS
10513#endif
10514#ifdef XK_dead_tilde
7a13e894 10515 || orig_keysym == XK_dead_tilde
69388238
RS
10516#endif
10517#ifdef XK_dead_diaeresis
7a13e894 10518 || orig_keysym == XK_dead_diaeresis
69388238
RS
10519#endif
10520#ifdef XK_dead_macron
7a13e894 10521 || orig_keysym == XK_dead_macron
69388238
RS
10522#endif
10523#ifdef XK_dead_degree
7a13e894 10524 || orig_keysym == XK_dead_degree
69388238
RS
10525#endif
10526#ifdef XK_dead_acute
7a13e894 10527 || orig_keysym == XK_dead_acute
69388238
RS
10528#endif
10529#ifdef XK_dead_cedilla
7a13e894 10530 || orig_keysym == XK_dead_cedilla
69388238
RS
10531#endif
10532#ifdef XK_dead_breve
7a13e894 10533 || orig_keysym == XK_dead_breve
69388238
RS
10534#endif
10535#ifdef XK_dead_ogonek
7a13e894 10536 || orig_keysym == XK_dead_ogonek
69388238
RS
10537#endif
10538#ifdef XK_dead_caron
7a13e894 10539 || orig_keysym == XK_dead_caron
69388238
RS
10540#endif
10541#ifdef XK_dead_doubleacute
7a13e894 10542 || orig_keysym == XK_dead_doubleacute
69388238
RS
10543#endif
10544#ifdef XK_dead_abovedot
7a13e894 10545 || orig_keysym == XK_dead_abovedot
c34790e0 10546#endif
7a13e894
RS
10547 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
10548 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
10549 /* Any "vendor-specific" key is ok. */
f0e299de
GM
10550 || (orig_keysym & (1 << 28))
10551 || (keysym != NoSymbol && nbytes == 0))
7a13e894 10552 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
10553#ifndef HAVE_X11R5
10554#ifdef XK_Mode_switch
7a13e894 10555 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
10556#endif
10557#ifdef XK_Num_Lock
7a13e894 10558 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
10559#endif
10560#endif /* not HAVE_X11R5 */
7a13e894 10561 ))
dc6f92b8 10562 {
10e6549c
RS
10563 if (temp_index == sizeof temp_buffer / sizeof (short))
10564 temp_index = 0;
7a13e894
RS
10565 temp_buffer[temp_index++] = keysym;
10566 bufp->kind = non_ascii_keystroke;
10567 bufp->code = keysym;
e0c1aef2 10568 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10569 bufp->arg = Qnil;
334208b7
RS
10570 bufp->modifiers
10571 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10572 modifiers);
1113d9db 10573 bufp->timestamp = event.xkey.time;
dc6f92b8 10574 bufp++;
7a13e894
RS
10575 count++;
10576 numchars--;
dc6f92b8 10577 }
7a13e894
RS
10578 else if (numchars > nbytes)
10579 {
10580 register int i;
379b5ac0 10581 register int c;
379b5ac0 10582 int nchars, len;
7a13e894
RS
10583
10584 for (i = 0; i < nbytes; i++)
10585 {
379b5ac0
KH
10586 if (temp_index == (sizeof temp_buffer
10587 / sizeof (short)))
7a13e894 10588 temp_index = 0;
379b5ac0
KH
10589 temp_buffer[temp_index++] = copy_bufptr[i];
10590 }
10591
10592 if (/* If the event is not from XIM, */
10593 event.xkey.keycode != 0
10594 /* or the current locale doesn't request
10595 decoding of the intup data, ... */
10596 || coding.type == coding_type_raw_text
10597 || coding.type == coding_type_no_conversion)
10598 {
10599 /* ... we can use the input data as is. */
10600 nchars = nbytes;
10601 }
10602 else
10603 {
10604 /* We have to decode the input data. */
10605 int require;
10606 unsigned char *p;
10607
10608 require = decoding_buffer_size (&coding, nbytes);
10609 p = (unsigned char *) alloca (require);
10610 coding.mode |= CODING_MODE_LAST_BLOCK;
10611 decode_coding (&coding, copy_bufptr, p,
10612 nbytes, require);
10613 nbytes = coding.produced;
10614 nchars = coding.produced_char;
10615 copy_bufptr = p;
10616 }
10617
10618 /* Convert the input data to a sequence of
10619 character events. */
10620 for (i = 0; i < nbytes; i += len)
10621 {
fee2aedc
GM
10622 if (nchars == nbytes)
10623 c = copy_bufptr[i], len = 1;
10624 else
10625 c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
10626 nbytes - i, len);
10627
379b5ac0
KH
10628 bufp->kind = (SINGLE_BYTE_CHAR_P (c)
10629 ? ascii_keystroke
10630 : multibyte_char_keystroke);
10631 bufp->code = c;
7a13e894 10632 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10633 bufp->arg = Qnil;
7a13e894
RS
10634 bufp->modifiers
10635 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10636 modifiers);
10637 bufp->timestamp = event.xkey.time;
10638 bufp++;
10639 }
10640
379b5ac0
KH
10641 count += nchars;
10642 numchars -= nchars;
1decb680
PE
10643
10644 if (keysym == NoSymbol)
10645 break;
7a13e894
RS
10646 }
10647 else
10648 abort ();
dc6f92b8 10649 }
10e6549c
RS
10650 else
10651 abort ();
dc6f92b8 10652 }
59ddecde
GM
10653#ifdef HAVE_X_I18N
10654 /* Don't dispatch this event since XtDispatchEvent calls
10655 XFilterEvent, and two calls in a row may freeze the
10656 client. */
10657 break;
10658#else
717ca130 10659 goto OTHER;
59ddecde 10660#endif
f451eb13 10661
f5d11644 10662 case KeyRelease:
59ddecde
GM
10663#ifdef HAVE_X_I18N
10664 /* Don't dispatch this event since XtDispatchEvent calls
10665 XFilterEvent, and two calls in a row may freeze the
10666 client. */
10667 break;
10668#else
f5d11644 10669 goto OTHER;
59ddecde 10670#endif
f5d11644 10671
7a13e894 10672 /* Here's a possible interpretation of the whole
06a2c219
GM
10673 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
10674 you get a FocusIn event, you have to get a FocusOut
10675 event before you relinquish the focus. If you
10676 haven't received a FocusIn event, then a mere
10677 LeaveNotify is enough to free you. */
f451eb13 10678
7a13e894 10679 case EnterNotify:
06a2c219 10680 {
06a2c219
GM
10681 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
10682
2c850e26 10683#if 0
582c60f8 10684 if (event.xcrossing.focus)
06a2c219
GM
10685 {
10686 /* Avoid nasty pop/raise loops. */
10687 if (f && (!(f->auto_raise)
10688 || !(f->auto_lower)
10689 || (event.xcrossing.time - enter_timestamp) > 500))
10690 {
10691 x_new_focus_frame (dpyinfo, f);
10692 enter_timestamp = event.xcrossing.time;
10693 }
10694 }
10695 else if (f == dpyinfo->x_focus_frame)
10696 x_new_focus_frame (dpyinfo, 0);
2c850e26
RS
10697#endif
10698
06a2c219
GM
10699 /* EnterNotify counts as mouse movement,
10700 so update things that depend on mouse position. */
2533c408 10701 if (f && !f->output_data.x->hourglass_p)
06a2c219
GM
10702 note_mouse_movement (f, &event.xmotion);
10703 goto OTHER;
10704 }
dc6f92b8 10705
7a13e894 10706 case FocusIn:
19126e11 10707 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10708 if (event.xfocus.detail != NotifyPointer)
0f941935 10709 dpyinfo->x_focus_event_frame = f;
7a13e894 10710 if (f)
eb72635f
GM
10711 {
10712 x_new_focus_frame (dpyinfo, f);
10713
10714 /* Don't stop displaying the initial startup message
10715 for a switch-frame event we don't need. */
10716 if (GC_NILP (Vterminal_frame)
10717 && GC_CONSP (Vframe_list)
10718 && !GC_NILP (XCDR (Vframe_list)))
10719 {
10720 bufp->kind = FOCUS_IN_EVENT;
10721 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10722 bufp->arg = Qnil;
eb72635f
GM
10723 ++bufp, ++count, --numchars;
10724 }
10725 }
f9e24cb9 10726
6c183ba5
RS
10727#ifdef HAVE_X_I18N
10728 if (f && FRAME_XIC (f))
10729 XSetICFocus (FRAME_XIC (f));
10730#endif
10731
7a13e894 10732 goto OTHER;
10c5e63d 10733
7a13e894 10734 case LeaveNotify:
19126e11 10735 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 10736 if (f)
10c5e63d 10737 {
7a13e894 10738 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
10739 {
10740 /* If we move outside the frame, then we're
10741 certainly no longer on any text in the frame. */
10742 clear_mouse_face (dpyinfo);
10743 dpyinfo->mouse_face_mouse_frame = 0;
10744 }
10745
10746 /* Generate a nil HELP_EVENT to cancel a help-echo.
10747 Do it only if there's something to cancel.
10748 Otherwise, the startup message is cleared when
10749 the mouse leaves the frame. */
10750 if (any_help_event_p)
10751 {
be010514
GM
10752 Lisp_Object frame;
10753 int n;
10754
06a2c219 10755 XSETFRAME (frame, f);
82c5d67a 10756 help_echo = Qnil;
5ab2570d
GM
10757 n = gen_help_event (bufp, numchars,
10758 Qnil, frame, Qnil, Qnil, 0);
be010514 10759 bufp += n, count += n, numchars -= n;
06a2c219 10760 }
7a13e894 10761
2c850e26 10762#if 0
582c60f8 10763 if (event.xcrossing.focus)
0f941935 10764 x_mouse_leave (dpyinfo);
10c5e63d 10765 else
7a13e894 10766 {
0f941935
KH
10767 if (f == dpyinfo->x_focus_event_frame)
10768 dpyinfo->x_focus_event_frame = 0;
140d6643 10769 if (f == dpyinfo->x_focus_frame)
0f941935 10770 x_new_focus_frame (dpyinfo, 0);
7a13e894 10771 }
2c850e26 10772#endif
10c5e63d 10773 }
7a13e894 10774 goto OTHER;
dc6f92b8 10775
7a13e894 10776 case FocusOut:
19126e11 10777 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10778 if (event.xfocus.detail != NotifyPointer
0f941935
KH
10779 && f == dpyinfo->x_focus_event_frame)
10780 dpyinfo->x_focus_event_frame = 0;
10781 if (f && f == dpyinfo->x_focus_frame)
10782 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 10783
6c183ba5
RS
10784#ifdef HAVE_X_I18N
10785 if (f && FRAME_XIC (f))
10786 XUnsetICFocus (FRAME_XIC (f));
10787#endif
10788
7a13e894 10789 goto OTHER;
dc6f92b8 10790
7a13e894 10791 case MotionNotify:
dc6f92b8 10792 {
06a2c219 10793 previous_help_echo = help_echo;
7cea38bc 10794 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 10795 help_echo_pos = -1;
06a2c219 10796
7a13e894
RS
10797 if (dpyinfo->grabbed && last_mouse_frame
10798 && FRAME_LIVE_P (last_mouse_frame))
10799 f = last_mouse_frame;
10800 else
19126e11 10801 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 10802
7a13e894
RS
10803 if (f)
10804 note_mouse_movement (f, &event.xmotion);
10805 else
10806 {
e88b3c50 10807#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10808 struct scroll_bar *bar
10809 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 10810
7a13e894
RS
10811 if (bar)
10812 x_scroll_bar_note_movement (bar, &event);
e88b3c50 10813#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 10814
06a2c219
GM
10815 /* If we move outside the frame, then we're
10816 certainly no longer on any text in the frame. */
7a13e894
RS
10817 clear_mouse_face (dpyinfo);
10818 }
06a2c219
GM
10819
10820 /* If the contents of the global variable help_echo
10821 has changed, generate a HELP_EVENT. */
b7e80413
SM
10822 if (!NILP (help_echo)
10823 || !NILP (previous_help_echo))
06a2c219
GM
10824 {
10825 Lisp_Object frame;
be010514 10826 int n;
06a2c219
GM
10827
10828 if (f)
10829 XSETFRAME (frame, f);
10830 else
10831 frame = Qnil;
10832
10833 any_help_event_p = 1;
5ab2570d 10834 n = gen_help_event (bufp, numchars, help_echo, frame,
7cea38bc
GM
10835 help_echo_window, help_echo_object,
10836 help_echo_pos);
be010514 10837 bufp += n, count += n, numchars -= n;
06a2c219
GM
10838 }
10839
10840 goto OTHER;
dc6f92b8 10841 }
dc6f92b8 10842
7a13e894 10843 case ConfigureNotify:
9829ddba
RS
10844 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
10845 if (f)
af395ec1 10846 {
5c187dee 10847#ifndef USE_X_TOOLKIT
bf1b7b30
KH
10848 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
10849 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 10850
2d7fc7e8
RS
10851 /* In the toolkit version, change_frame_size
10852 is called by the code that handles resizing
10853 of the EmacsFrame widget. */
7a13e894 10854
7a13e894
RS
10855 /* Even if the number of character rows and columns has
10856 not changed, the font size may have changed, so we need
10857 to check the pixel dimensions as well. */
10858 if (columns != f->width
10859 || rows != f->height
7556890b
RS
10860 || event.xconfigure.width != f->output_data.x->pixel_width
10861 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 10862 {
7d1e984f 10863 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 10864 SET_FRAME_GARBAGED (f);
e687d06e 10865 cancel_mouse_face (f);
7a13e894 10866 }
2d7fc7e8 10867#endif
af395ec1 10868
7556890b
RS
10869 f->output_data.x->pixel_width = event.xconfigure.width;
10870 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
10871
10872 /* What we have now is the position of Emacs's own window.
10873 Convert that to the position of the window manager window. */
dcb07ae9
RS
10874 x_real_positions (f, &f->output_data.x->left_pos,
10875 &f->output_data.x->top_pos);
10876
f5d11644
GM
10877#ifdef HAVE_X_I18N
10878 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
10879 xic_set_statusarea (f);
10880#endif
10881
dcb07ae9
RS
10882 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
10883 {
10884 /* Since the WM decorations come below top_pos now,
10885 we must put them below top_pos in the future. */
10886 f->output_data.x->win_gravity = NorthWestGravity;
10887 x_wm_set_size_hint (f, (long) 0, 0);
10888 }
8f08dc93
KH
10889#ifdef USE_MOTIF
10890 /* Some window managers pass (0,0) as the location of
10891 the window, and the Motif event handler stores it
10892 in the emacs widget, which messes up Motif menus. */
10893 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
10894 {
10895 event.xconfigure.x = f->output_data.x->widget->core.x;
10896 event.xconfigure.y = f->output_data.x->widget->core.y;
10897 }
06a2c219 10898#endif /* USE_MOTIF */
7a13e894 10899 }
2d7fc7e8 10900 goto OTHER;
dc6f92b8 10901
7a13e894
RS
10902 case ButtonPress:
10903 case ButtonRelease:
10904 {
10905 /* If we decide we want to generate an event to be seen
10906 by the rest of Emacs, we put it here. */
10907 struct input_event emacs_event;
9ea173e8 10908 int tool_bar_p = 0;
06a2c219 10909
7a13e894 10910 emacs_event.kind = no_event;
7a13e894 10911 bzero (&compose_status, sizeof (compose_status));
9b07615b 10912
06a2c219
GM
10913 if (dpyinfo->grabbed
10914 && last_mouse_frame
9f67f20b
RS
10915 && FRAME_LIVE_P (last_mouse_frame))
10916 f = last_mouse_frame;
10917 else
2224b905 10918 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 10919
06a2c219
GM
10920 if (f)
10921 {
9ea173e8
GM
10922 /* Is this in the tool-bar? */
10923 if (WINDOWP (f->tool_bar_window)
10924 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
10925 {
10926 Lisp_Object window;
10927 int p, x, y;
10928
10929 x = event.xbutton.x;
10930 y = event.xbutton.y;
10931
10932 /* Set x and y. */
10933 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 10934 if (EQ (window, f->tool_bar_window))
06a2c219 10935 {
9ea173e8
GM
10936 x_handle_tool_bar_click (f, &event.xbutton);
10937 tool_bar_p = 1;
06a2c219
GM
10938 }
10939 }
10940
9ea173e8 10941 if (!tool_bar_p)
06a2c219
GM
10942 if (!dpyinfo->x_focus_frame
10943 || f == dpyinfo->x_focus_frame)
10944 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
10945 }
10946 else
10947 {
06a2c219 10948#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10949 struct scroll_bar *bar
10950 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 10951
7a13e894
RS
10952 if (bar)
10953 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 10954#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10955 }
10956
10957 if (event.type == ButtonPress)
10958 {
10959 dpyinfo->grabbed |= (1 << event.xbutton.button);
10960 last_mouse_frame = f;
edad46f6
KH
10961 /* Ignore any mouse motion that happened
10962 before this event; any subsequent mouse-movement
10963 Emacs events should reflect only motion after
10964 the ButtonPress. */
a00e91cd
KH
10965 if (f != 0)
10966 f->mouse_moved = 0;
06a2c219 10967
9ea173e8
GM
10968 if (!tool_bar_p)
10969 last_tool_bar_item = -1;
7a13e894 10970 }
3afe33e7
RS
10971 else
10972 {
7a13e894 10973 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10974 }
23faf38f 10975
7a13e894
RS
10976 if (numchars >= 1 && emacs_event.kind != no_event)
10977 {
10978 bcopy (&emacs_event, bufp, sizeof (struct input_event));
10979 bufp++;
10980 count++;
10981 numchars--;
10982 }
3afe33e7
RS
10983
10984#ifdef USE_X_TOOLKIT
2224b905
RS
10985 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
10986 /* For a down-event in the menu bar,
10987 don't pass it to Xt right now.
10988 Instead, save it away
10989 and we will pass it to Xt from kbd_buffer_get_event.
10990 That way, we can run some Lisp code first. */
91375f8f
RS
10991 if (f && event.type == ButtonPress
10992 /* Verify the event is really within the menu bar
10993 and not just sent to it due to grabbing. */
10994 && event.xbutton.x >= 0
10995 && event.xbutton.x < f->output_data.x->pixel_width
10996 && event.xbutton.y >= 0
10997 && event.xbutton.y < f->output_data.x->menubar_height
10998 && event.xbutton.same_screen)
2224b905 10999 {
8805890a 11000 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
11001 XSETFRAME (last_mouse_press_frame, f);
11002 }
11003 else if (event.type == ButtonPress)
11004 {
11005 last_mouse_press_frame = Qnil;
30e671c3 11006 goto OTHER;
ce89ef46 11007 }
06a2c219 11008
2237cac9
RS
11009#ifdef USE_MOTIF /* This should do not harm for Lucid,
11010 but I am trying to be cautious. */
ce89ef46
RS
11011 else if (event.type == ButtonRelease)
11012 {
2237cac9 11013 if (!NILP (last_mouse_press_frame))
f10ded1c 11014 {
2237cac9
RS
11015 f = XFRAME (last_mouse_press_frame);
11016 if (f->output_data.x)
06a2c219 11017 SET_SAVED_BUTTON_EVENT;
f10ded1c 11018 }
06a2c219 11019 else
30e671c3 11020 goto OTHER;
2224b905 11021 }
2237cac9 11022#endif /* USE_MOTIF */
2224b905
RS
11023 else
11024 goto OTHER;
3afe33e7 11025#endif /* USE_X_TOOLKIT */
7a13e894
RS
11026 }
11027 break;
dc6f92b8 11028
7a13e894 11029 case CirculateNotify:
06a2c219
GM
11030 goto OTHER;
11031
7a13e894 11032 case CirculateRequest:
06a2c219
GM
11033 goto OTHER;
11034
11035 case VisibilityNotify:
11036 goto OTHER;
dc6f92b8 11037
7a13e894
RS
11038 case MappingNotify:
11039 /* Someone has changed the keyboard mapping - update the
11040 local cache. */
11041 switch (event.xmapping.request)
11042 {
11043 case MappingModifier:
11044 x_find_modifier_meanings (dpyinfo);
11045 /* This is meant to fall through. */
11046 case MappingKeyboard:
11047 XRefreshKeyboardMapping (&event.xmapping);
11048 }
7a13e894 11049 goto OTHER;
dc6f92b8 11050
7a13e894 11051 default:
7a13e894 11052 OTHER:
717ca130 11053#ifdef USE_X_TOOLKIT
7a13e894
RS
11054 BLOCK_INPUT;
11055 XtDispatchEvent (&event);
11056 UNBLOCK_INPUT;
3afe33e7 11057#endif /* USE_X_TOOLKIT */
7a13e894
RS
11058 break;
11059 }
dc6f92b8
JB
11060 }
11061 }
11062
06a2c219
GM
11063 out:;
11064
9a5196d0
RS
11065 /* On some systems, an X bug causes Emacs to get no more events
11066 when the window is destroyed. Detect that. (1994.) */
58769bee 11067 if (! event_found)
ef2a22d0 11068 {
ef2a22d0
RS
11069 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
11070 One XNOOP in 100 loops will make Emacs terminate.
11071 B. Bretthauer, 1994 */
11072 x_noop_count++;
58769bee 11073 if (x_noop_count >= 100)
ef2a22d0
RS
11074 {
11075 x_noop_count=0;
2224b905
RS
11076
11077 if (next_noop_dpyinfo == 0)
11078 next_noop_dpyinfo = x_display_list;
11079
11080 XNoOp (next_noop_dpyinfo->display);
11081
11082 /* Each time we get here, cycle through the displays now open. */
11083 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
11084 }
11085 }
502add23 11086
06a2c219 11087 /* If the focus was just given to an auto-raising frame,
0134a210 11088 raise it now. */
7a13e894 11089 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
11090 if (pending_autoraise_frame)
11091 {
11092 x_raise_frame (pending_autoraise_frame);
11093 pending_autoraise_frame = 0;
11094 }
0134a210 11095
dc6f92b8 11096 UNBLOCK_INPUT;
bde5503b 11097 --handling_signal;
dc6f92b8
JB
11098 return count;
11099}
06a2c219
GM
11100
11101
11102
dc6f92b8 11103\f
06a2c219
GM
11104/***********************************************************************
11105 Text Cursor
11106 ***********************************************************************/
11107
60626bab
GM
11108/* Notice when the text cursor of window W has been completely
11109 overwritten by a drawing operation that outputs glyphs in AREA
11110 starting at X0 and ending at X1 in the line starting at Y0 and
11111 ending at Y1. X coordinates are area-relative. X1 < 0 means all
11112 the rest of the line after X0 has been written. Y coordinates
11113 are window-relative. */
06a2c219
GM
11114
11115static void
60626bab 11116notice_overwritten_cursor (w, area, x0, x1, y0, y1)
06a2c219 11117 struct window *w;
60626bab
GM
11118 enum glyph_row_area area;
11119 int x0, y0, x1, y1;
06a2c219 11120{
60626bab 11121 if (area == TEXT_AREA
f0a48a01 11122 && w->phys_cursor_on_p
60626bab
GM
11123 && y0 <= w->phys_cursor.y
11124 && y1 >= w->phys_cursor.y + w->phys_cursor_height
11125 && x0 <= w->phys_cursor.x
11126 && (x1 < 0 || x1 > w->phys_cursor.x))
f0a48a01 11127 w->phys_cursor_on_p = 0;
06a2c219 11128}
f451eb13
JB
11129
11130
06a2c219
GM
11131/* Set clipping for output in glyph row ROW. W is the window in which
11132 we operate. GC is the graphics context to set clipping in.
11133 WHOLE_LINE_P non-zero means include the areas used for truncation
11134 mark display and alike in the clipping rectangle.
11135
11136 ROW may be a text row or, e.g., a mode line. Text rows must be
11137 clipped to the interior of the window dedicated to text display,
11138 mode lines must be clipped to the whole window. */
dc6f92b8
JB
11139
11140static void
06a2c219
GM
11141x_clip_to_row (w, row, gc, whole_line_p)
11142 struct window *w;
11143 struct glyph_row *row;
11144 GC gc;
11145 int whole_line_p;
dc6f92b8 11146{
06a2c219
GM
11147 struct frame *f = XFRAME (WINDOW_FRAME (w));
11148 XRectangle clip_rect;
11149 int window_x, window_y, window_width, window_height;
dc6f92b8 11150
06a2c219 11151 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 11152
06a2c219
GM
11153 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
11154 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
11155 clip_rect.y = max (clip_rect.y, window_y);
11156 clip_rect.width = window_width;
11157 clip_rect.height = row->visible_height;
5c1aae96 11158
06a2c219
GM
11159 /* If clipping to the whole line, including trunc marks, extend
11160 the rectangle to the left and increase its width. */
11161 if (whole_line_p)
11162 {
3f332ef3
KS
11163 clip_rect.x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
11164 clip_rect.width += FRAME_X_FRINGE_WIDTH (f);
06a2c219 11165 }
5c1aae96 11166
06a2c219 11167 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
11168}
11169
06a2c219
GM
11170
11171/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
11172
11173static void
06a2c219
GM
11174x_draw_hollow_cursor (w, row)
11175 struct window *w;
11176 struct glyph_row *row;
dc6f92b8 11177{
06a2c219
GM
11178 struct frame *f = XFRAME (WINDOW_FRAME (w));
11179 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11180 Display *dpy = FRAME_X_DISPLAY (f);
11181 int x, y, wd, h;
11182 XGCValues xgcv;
11183 struct glyph *cursor_glyph;
11184 GC gc;
11185
11186 /* Compute frame-relative coordinates from window-relative
11187 coordinates. */
11188 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11189 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
11190 + row->ascent - w->phys_cursor_ascent);
11191 h = row->height - 1;
11192
11193 /* Get the glyph the cursor is on. If we can't tell because
11194 the current matrix is invalid or such, give up. */
11195 cursor_glyph = get_phys_cursor_glyph (w);
11196 if (cursor_glyph == NULL)
dc6f92b8
JB
11197 return;
11198
06a2c219
GM
11199 /* Compute the width of the rectangle to draw. If on a stretch
11200 glyph, and `x-stretch-block-cursor' is nil, don't draw a
11201 rectangle as wide as the glyph, but use a canonical character
11202 width instead. */
11203 wd = cursor_glyph->pixel_width - 1;
11204 if (cursor_glyph->type == STRETCH_GLYPH
11205 && !x_stretch_cursor_p)
11206 wd = min (CANON_X_UNIT (f), wd);
11207
11208 /* The foreground of cursor_gc is typically the same as the normal
11209 background color, which can cause the cursor box to be invisible. */
11210 xgcv.foreground = f->output_data.x->cursor_pixel;
11211 if (dpyinfo->scratch_cursor_gc)
11212 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
11213 else
11214 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
11215 GCForeground, &xgcv);
11216 gc = dpyinfo->scratch_cursor_gc;
11217
11218 /* Set clipping, draw the rectangle, and reset clipping again. */
11219 x_clip_to_row (w, row, gc, 0);
11220 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
11221 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
11222}
11223
06a2c219
GM
11224
11225/* Draw a bar cursor on window W in glyph row ROW.
11226
11227 Implementation note: One would like to draw a bar cursor with an
11228 angle equal to the one given by the font property XA_ITALIC_ANGLE.
11229 Unfortunately, I didn't find a font yet that has this property set.
11230 --gerd. */
dc6f92b8
JB
11231
11232static void
f02d8aa0 11233x_draw_bar_cursor (w, row, width)
06a2c219
GM
11234 struct window *w;
11235 struct glyph_row *row;
f02d8aa0 11236 int width;
dc6f92b8 11237{
92f424df
GM
11238 struct frame *f = XFRAME (w->frame);
11239 struct glyph *cursor_glyph;
06a2c219 11240
92f424df
GM
11241 /* If cursor is out of bounds, don't draw garbage. This can happen
11242 in mini-buffer windows when switching between echo area glyphs
11243 and mini-buffer. */
11244 cursor_glyph = get_phys_cursor_glyph (w);
11245 if (cursor_glyph == NULL)
11246 return;
06a2c219 11247
92f424df
GM
11248 /* If on an image, draw like a normal cursor. That's usually better
11249 visible than drawing a bar, esp. if the image is large so that
11250 the bar might not be in the window. */
11251 if (cursor_glyph->type == IMAGE_GLYPH)
11252 {
11253 struct glyph_row *row;
11254 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
11255 x_draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
11256 }
11257 else
11258 {
34e5d0af
GM
11259 Display *dpy = FRAME_X_DISPLAY (f);
11260 Window window = FRAME_X_WINDOW (f);
11261 GC gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
11262 unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures;
11263 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
11264 XGCValues xgcv;
11265
11266 /* If the glyph's background equals the color we normally draw
11267 the bar cursor in, the bar cursor in its normal color is
11268 invisible. Use the glyph's foreground color instead in this
11269 case, on the assumption that the glyph's colors are chosen so
11270 that the glyph is legible. */
11271 if (face->background == f->output_data.x->cursor_pixel)
11272 xgcv.background = xgcv.foreground = face->foreground;
11273 else
11274 xgcv.background = xgcv.foreground = f->output_data.x->cursor_pixel;
06a2c219 11275 xgcv.graphics_exposures = 0;
92f424df 11276
06a2c219
GM
11277 if (gc)
11278 XChangeGC (dpy, gc, mask, &xgcv);
11279 else
11280 {
11281 gc = XCreateGC (dpy, window, mask, &xgcv);
11282 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
11283 }
92f424df 11284
f02d8aa0
GM
11285 if (width < 0)
11286 width = f->output_data.x->cursor_width;
34e5d0af 11287 width = min (cursor_glyph->pixel_width, width);
92f424df 11288
06a2c219
GM
11289 x_clip_to_row (w, row, gc, 0);
11290 XFillRectangle (dpy, window, gc,
34e5d0af 11291 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
06a2c219 11292 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
34e5d0af 11293 width, row->height);
06a2c219
GM
11294 XSetClipMask (dpy, gc, None);
11295 }
dc6f92b8
JB
11296}
11297
06a2c219
GM
11298
11299/* Clear the cursor of window W to background color, and mark the
11300 cursor as not shown. This is used when the text where the cursor
11301 is is about to be rewritten. */
11302
dc6f92b8 11303static void
06a2c219
GM
11304x_clear_cursor (w)
11305 struct window *w;
dc6f92b8 11306{
06a2c219
GM
11307 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
11308 x_update_window_cursor (w, 0);
11309}
90e65f07 11310
dbc4e1c1 11311
06a2c219
GM
11312/* Draw the cursor glyph of window W in glyph row ROW. See the
11313 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 11314
06a2c219
GM
11315static void
11316x_draw_phys_cursor_glyph (w, row, hl)
11317 struct window *w;
11318 struct glyph_row *row;
11319 enum draw_glyphs_face hl;
11320{
11321 /* If cursor hpos is out of bounds, don't draw garbage. This can
11322 happen in mini-buffer windows when switching between echo area
11323 glyphs and mini-buffer. */
11324 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e 11325 {
f0a48a01
GM
11326 int on_p = w->phys_cursor_on_p;
11327
66ac4b0e
GM
11328 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
11329 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
f0a48a01
GM
11330 hl, 0);
11331 w->phys_cursor_on_p = on_p;
66ac4b0e
GM
11332
11333 /* When we erase the cursor, and ROW is overlapped by other
11334 rows, make sure that these overlapping parts of other rows
11335 are redrawn. */
11336 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
11337 {
11338 if (row > w->current_matrix->rows
11339 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
11340 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
11341
11342 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
11343 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
11344 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
11345 }
11346 }
06a2c219 11347}
dbc4e1c1 11348
eea6af04 11349
06a2c219 11350/* Erase the image of a cursor of window W from the screen. */
eea6af04 11351
06a2c219
GM
11352static void
11353x_erase_phys_cursor (w)
11354 struct window *w;
11355{
11356 struct frame *f = XFRAME (w->frame);
11357 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11358 int hpos = w->phys_cursor.hpos;
11359 int vpos = w->phys_cursor.vpos;
11360 int mouse_face_here_p = 0;
11361 struct glyph_matrix *active_glyphs = w->current_matrix;
11362 struct glyph_row *cursor_row;
11363 struct glyph *cursor_glyph;
11364 enum draw_glyphs_face hl;
11365
11366 /* No cursor displayed or row invalidated => nothing to do on the
11367 screen. */
11368 if (w->phys_cursor_type == NO_CURSOR)
11369 goto mark_cursor_off;
11370
11371 /* VPOS >= active_glyphs->nrows means that window has been resized.
11372 Don't bother to erase the cursor. */
11373 if (vpos >= active_glyphs->nrows)
11374 goto mark_cursor_off;
11375
11376 /* If row containing cursor is marked invalid, there is nothing we
11377 can do. */
11378 cursor_row = MATRIX_ROW (active_glyphs, vpos);
11379 if (!cursor_row->enabled_p)
11380 goto mark_cursor_off;
11381
11382 /* This can happen when the new row is shorter than the old one.
11383 In this case, either x_draw_glyphs or clear_end_of_line
11384 should have cleared the cursor. Note that we wouldn't be
11385 able to erase the cursor in this case because we don't have a
11386 cursor glyph at hand. */
11387 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
11388 goto mark_cursor_off;
11389
11390 /* If the cursor is in the mouse face area, redisplay that when
11391 we clear the cursor. */
8801a864
KR
11392 if (! NILP (dpyinfo->mouse_face_window)
11393 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
11394 && (vpos > dpyinfo->mouse_face_beg_row
11395 || (vpos == dpyinfo->mouse_face_beg_row
11396 && hpos >= dpyinfo->mouse_face_beg_col))
11397 && (vpos < dpyinfo->mouse_face_end_row
11398 || (vpos == dpyinfo->mouse_face_end_row
11399 && hpos < dpyinfo->mouse_face_end_col))
11400 /* Don't redraw the cursor's spot in mouse face if it is at the
11401 end of a line (on a newline). The cursor appears there, but
11402 mouse highlighting does not. */
11403 && cursor_row->used[TEXT_AREA] > hpos)
11404 mouse_face_here_p = 1;
11405
11406 /* Maybe clear the display under the cursor. */
11407 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
11408 {
11409 int x;
045dee35 11410 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 11411
06a2c219
GM
11412 cursor_glyph = get_phys_cursor_glyph (w);
11413 if (cursor_glyph == NULL)
11414 goto mark_cursor_off;
dbc4e1c1 11415
e0300d33 11416 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
06a2c219 11417
c5e6e06b
GM
11418 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11419 x,
11420 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
11421 cursor_row->y)),
11422 cursor_glyph->pixel_width,
11423 cursor_row->visible_height,
11424 False);
dbc4e1c1 11425 }
06a2c219
GM
11426
11427 /* Erase the cursor by redrawing the character underneath it. */
11428 if (mouse_face_here_p)
11429 hl = DRAW_MOUSE_FACE;
06a2c219
GM
11430 else
11431 hl = DRAW_NORMAL_TEXT;
11432 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 11433
06a2c219
GM
11434 mark_cursor_off:
11435 w->phys_cursor_on_p = 0;
11436 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
11437}
11438
11439
b7f83f9e
GM
11440/* Non-zero if physical cursor of window W is within mouse face. */
11441
11442static int
11443cursor_in_mouse_face_p (w)
11444 struct window *w;
11445{
11446 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
11447 int in_mouse_face = 0;
11448
11449 if (WINDOWP (dpyinfo->mouse_face_window)
11450 && XWINDOW (dpyinfo->mouse_face_window) == w)
11451 {
11452 int hpos = w->phys_cursor.hpos;
11453 int vpos = w->phys_cursor.vpos;
11454
11455 if (vpos >= dpyinfo->mouse_face_beg_row
11456 && vpos <= dpyinfo->mouse_face_end_row
11457 && (vpos > dpyinfo->mouse_face_beg_row
11458 || hpos >= dpyinfo->mouse_face_beg_col)
11459 && (vpos < dpyinfo->mouse_face_end_row
11460 || hpos < dpyinfo->mouse_face_end_col
11461 || dpyinfo->mouse_face_past_end))
11462 in_mouse_face = 1;
11463 }
11464
11465 return in_mouse_face;
11466}
11467
11468
06a2c219
GM
11469/* Display or clear cursor of window W. If ON is zero, clear the
11470 cursor. If it is non-zero, display the cursor. If ON is nonzero,
11471 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 11472
06a2c219
GM
11473void
11474x_display_and_set_cursor (w, on, hpos, vpos, x, y)
11475 struct window *w;
11476 int on, hpos, vpos, x, y;
dbc4e1c1 11477{
06a2c219
GM
11478 struct frame *f = XFRAME (w->frame);
11479 int new_cursor_type;
f02d8aa0 11480 int new_cursor_width;
06a2c219
GM
11481 struct glyph_matrix *current_glyphs;
11482 struct glyph_row *glyph_row;
11483 struct glyph *glyph;
34368a22 11484 int cursor_non_selected;
dbc4e1c1 11485
49d838ea 11486 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
11487 windows and frames; in the latter case, the frame or window may
11488 be in the midst of changing its size, and x and y may be off the
11489 window. */
11490 if (! FRAME_VISIBLE_P (f)
11491 || FRAME_GARBAGED_P (f)
11492 || vpos >= w->current_matrix->nrows
11493 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
11494 return;
11495
11496 /* If cursor is off and we want it off, return quickly. */
06a2c219 11497 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
11498 return;
11499
06a2c219
GM
11500 current_glyphs = w->current_matrix;
11501 glyph_row = MATRIX_ROW (current_glyphs, vpos);
11502 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
11503
11504 /* If cursor row is not enabled, we don't really know where to
11505 display the cursor. */
11506 if (!glyph_row->enabled_p)
11507 {
11508 w->phys_cursor_on_p = 0;
11509 return;
11510 }
11511
11512 xassert (interrupt_input_blocked);
11513
11514 /* Set new_cursor_type to the cursor we want to be displayed. In a
11515 mini-buffer window, we want the cursor only to appear if we are
11516 reading input from this window. For the selected window, we want
11517 the cursor type given by the frame parameter. If explicitly
11518 marked off, draw no cursor. In all other cases, we want a hollow
11519 box cursor. */
34368a22
RS
11520 cursor_non_selected
11521 = !NILP (Fbuffer_local_value (Qcursor_in_non_selected_windows,
11522 w->buffer));
f02d8aa0 11523 new_cursor_width = -1;
9b4a7047
GM
11524 if (cursor_in_echo_area
11525 && FRAME_HAS_MINIBUF_P (f)
11526 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 11527 {
9b4a7047
GM
11528 if (w == XWINDOW (echo_area_window))
11529 new_cursor_type = FRAME_DESIRED_CURSOR (f);
34368a22 11530 else if (cursor_non_selected)
06a2c219 11531 new_cursor_type = HOLLOW_BOX_CURSOR;
9a7bdceb
GM
11532 else
11533 new_cursor_type = NO_CURSOR;
06a2c219 11534 }
06a2c219 11535 else
9b4a7047 11536 {
7a58ab59
GM
11537 if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
11538 || w != XWINDOW (f->selected_window))
9b4a7047 11539 {
2c850e26 11540 if ((MINI_WINDOW_P (w) && minibuf_level == 0)
34368a22 11541 || !cursor_non_selected
5cefa566 11542 || NILP (XBUFFER (w->buffer)->cursor_type))
9b4a7047
GM
11543 new_cursor_type = NO_CURSOR;
11544 else
11545 new_cursor_type = HOLLOW_BOX_CURSOR;
11546 }
11547 else if (w->cursor_off_p)
11548 new_cursor_type = NO_CURSOR;
11549 else
f02d8aa0
GM
11550 {
11551 struct buffer *b = XBUFFER (w->buffer);
11552
11553 if (EQ (b->cursor_type, Qt))
11554 new_cursor_type = FRAME_DESIRED_CURSOR (f);
11555 else
11556 new_cursor_type = x_specified_cursor_type (b->cursor_type,
11557 &new_cursor_width);
11558 }
9b4a7047 11559 }
06a2c219
GM
11560
11561 /* If cursor is currently being shown and we don't want it to be or
11562 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 11563 erase it. */
06a2c219 11564 if (w->phys_cursor_on_p
dc6f92b8 11565 && (!on
06a2c219
GM
11566 || w->phys_cursor.x != x
11567 || w->phys_cursor.y != y
11568 || new_cursor_type != w->phys_cursor_type))
11569 x_erase_phys_cursor (w);
11570
11571 /* If the cursor is now invisible and we want it to be visible,
11572 display it. */
11573 if (on && !w->phys_cursor_on_p)
11574 {
11575 w->phys_cursor_ascent = glyph_row->ascent;
11576 w->phys_cursor_height = glyph_row->height;
11577
11578 /* Set phys_cursor_.* before x_draw_.* is called because some
11579 of them may need the information. */
11580 w->phys_cursor.x = x;
11581 w->phys_cursor.y = glyph_row->y;
11582 w->phys_cursor.hpos = hpos;
11583 w->phys_cursor.vpos = vpos;
11584 w->phys_cursor_type = new_cursor_type;
11585 w->phys_cursor_on_p = 1;
11586
11587 switch (new_cursor_type)
dc6f92b8 11588 {
06a2c219
GM
11589 case HOLLOW_BOX_CURSOR:
11590 x_draw_hollow_cursor (w, glyph_row);
11591 break;
11592
11593 case FILLED_BOX_CURSOR:
11594 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
11595 break;
11596
11597 case BAR_CURSOR:
f02d8aa0 11598 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
11599 break;
11600
11601 case NO_CURSOR:
11602 break;
dc6f92b8 11603
06a2c219
GM
11604 default:
11605 abort ();
11606 }
59ddecde
GM
11607
11608#ifdef HAVE_X_I18N
11609 if (w == XWINDOW (f->selected_window))
11610 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
11611 xic_set_preeditarea (w, x, y);
11612#endif
dc6f92b8
JB
11613 }
11614
06a2c219 11615#ifndef XFlush
f676886a 11616 if (updating_frame != f)
334208b7 11617 XFlush (FRAME_X_DISPLAY (f));
06a2c219 11618#endif
dc6f92b8
JB
11619}
11620
06a2c219
GM
11621
11622/* Display the cursor on window W, or clear it. X and Y are window
11623 relative pixel coordinates. HPOS and VPOS are glyph matrix
11624 positions. If W is not the selected window, display a hollow
11625 cursor. ON non-zero means display the cursor at X, Y which
11626 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 11627
dfcf069d 11628void
06a2c219
GM
11629x_display_cursor (w, on, hpos, vpos, x, y)
11630 struct window *w;
11631 int on, hpos, vpos, x, y;
dc6f92b8 11632{
f94397b5 11633 BLOCK_INPUT;
06a2c219 11634 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
11635 UNBLOCK_INPUT;
11636}
11637
06a2c219
GM
11638
11639/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
11640 Don't change the cursor's position. */
11641
dfcf069d 11642void
06a2c219 11643x_update_cursor (f, on_p)
5d46f928 11644 struct frame *f;
5d46f928 11645{
06a2c219
GM
11646 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
11647}
11648
11649
11650/* Call x_update_window_cursor with parameter ON_P on all leaf windows
11651 in the window tree rooted at W. */
11652
11653static void
11654x_update_cursor_in_window_tree (w, on_p)
11655 struct window *w;
11656 int on_p;
11657{
11658 while (w)
11659 {
11660 if (!NILP (w->hchild))
11661 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
11662 else if (!NILP (w->vchild))
11663 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
11664 else
11665 x_update_window_cursor (w, on_p);
11666
11667 w = NILP (w->next) ? 0 : XWINDOW (w->next);
11668 }
11669}
5d46f928 11670
f94397b5 11671
06a2c219
GM
11672/* Switch the display of W's cursor on or off, according to the value
11673 of ON. */
11674
11675static void
11676x_update_window_cursor (w, on)
11677 struct window *w;
11678 int on;
11679{
16b5d424
GM
11680 /* Don't update cursor in windows whose frame is in the process
11681 of being deleted. */
11682 if (w->current_matrix)
11683 {
11684 BLOCK_INPUT;
11685 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
11686 w->phys_cursor.x, w->phys_cursor.y);
11687 UNBLOCK_INPUT;
11688 }
dc6f92b8 11689}
06a2c219
GM
11690
11691
11692
dc6f92b8
JB
11693\f
11694/* Icons. */
11695
dbc4e1c1 11696/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
11697
11698int
990ba854 11699x_bitmap_icon (f, file)
f676886a 11700 struct frame *f;
990ba854 11701 Lisp_Object file;
dc6f92b8 11702{
06a2c219 11703 int bitmap_id;
dc6f92b8 11704
c118dd06 11705 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11706 return 1;
11707
990ba854 11708 /* Free up our existing icon bitmap if any. */
7556890b
RS
11709 if (f->output_data.x->icon_bitmap > 0)
11710 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11711 f->output_data.x->icon_bitmap = 0;
990ba854
RS
11712
11713 if (STRINGP (file))
7f2ae036
RS
11714 bitmap_id = x_create_bitmap_from_file (f, file);
11715 else
11716 {
990ba854 11717 /* Create the GNU bitmap if necessary. */
5bf01b68 11718 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
11719 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
11720 = x_create_bitmap_from_data (f, gnu_bits,
11721 gnu_width, gnu_height);
990ba854
RS
11722
11723 /* The first time we create the GNU bitmap,
06a2c219 11724 this increments the ref-count one extra time.
990ba854
RS
11725 As a result, the GNU bitmap is never freed.
11726 That way, we don't have to worry about allocating it again. */
334208b7 11727 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 11728
334208b7 11729 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
11730 }
11731
11732 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 11733 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
11734
11735 return 0;
11736}
11737
11738
1be2d067
KH
11739/* Make the x-window of frame F use a rectangle with text.
11740 Use ICON_NAME as the text. */
dc6f92b8
JB
11741
11742int
f676886a
JB
11743x_text_icon (f, icon_name)
11744 struct frame *f;
dc6f92b8
JB
11745 char *icon_name;
11746{
c118dd06 11747 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11748 return 1;
11749
1be2d067
KH
11750#ifdef HAVE_X11R4
11751 {
11752 XTextProperty text;
11753 text.value = (unsigned char *) icon_name;
11754 text.encoding = XA_STRING;
11755 text.format = 8;
11756 text.nitems = strlen (icon_name);
11757#ifdef USE_X_TOOLKIT
7556890b 11758 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
11759 &text);
11760#else /* not USE_X_TOOLKIT */
11761 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
11762#endif /* not USE_X_TOOLKIT */
11763 }
11764#else /* not HAVE_X11R4 */
11765 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
11766#endif /* not HAVE_X11R4 */
58769bee 11767
7556890b
RS
11768 if (f->output_data.x->icon_bitmap > 0)
11769 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11770 f->output_data.x->icon_bitmap = 0;
b1c884c3 11771 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
11772
11773 return 0;
11774}
11775\f
e99db5a1
RS
11776#define X_ERROR_MESSAGE_SIZE 200
11777
11778/* If non-nil, this should be a string.
11779 It means catch X errors and store the error message in this string. */
11780
11781static Lisp_Object x_error_message_string;
11782
11783/* An X error handler which stores the error message in
11784 x_error_message_string. This is called from x_error_handler if
11785 x_catch_errors is in effect. */
11786
06a2c219 11787static void
e99db5a1
RS
11788x_error_catcher (display, error)
11789 Display *display;
11790 XErrorEvent *error;
11791{
11792 XGetErrorText (display, error->error_code,
11793 XSTRING (x_error_message_string)->data,
11794 X_ERROR_MESSAGE_SIZE);
11795}
11796
11797/* Begin trapping X errors for display DPY. Actually we trap X errors
11798 for all displays, but DPY should be the display you are actually
11799 operating on.
11800
11801 After calling this function, X protocol errors no longer cause
11802 Emacs to exit; instead, they are recorded in the string
11803 stored in x_error_message_string.
11804
11805 Calling x_check_errors signals an Emacs error if an X error has
11806 occurred since the last call to x_catch_errors or x_check_errors.
11807
11808 Calling x_uncatch_errors resumes the normal error handling. */
11809
11810void x_check_errors ();
11811static Lisp_Object x_catch_errors_unwind ();
11812
11813int
11814x_catch_errors (dpy)
11815 Display *dpy;
11816{
11817 int count = specpdl_ptr - specpdl;
11818
11819 /* Make sure any errors from previous requests have been dealt with. */
11820 XSync (dpy, False);
11821
11822 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
11823
11824 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
11825 XSTRING (x_error_message_string)->data[0] = 0;
11826
11827 return count;
11828}
11829
11830/* Unbind the binding that we made to check for X errors. */
11831
11832static Lisp_Object
11833x_catch_errors_unwind (old_val)
11834 Lisp_Object old_val;
11835{
11836 x_error_message_string = old_val;
11837 return Qnil;
11838}
11839
11840/* If any X protocol errors have arrived since the last call to
11841 x_catch_errors or x_check_errors, signal an Emacs error using
11842 sprintf (a buffer, FORMAT, the x error message text) as the text. */
11843
11844void
11845x_check_errors (dpy, format)
11846 Display *dpy;
11847 char *format;
11848{
11849 /* Make sure to catch any errors incurred so far. */
11850 XSync (dpy, False);
11851
11852 if (XSTRING (x_error_message_string)->data[0])
11853 error (format, XSTRING (x_error_message_string)->data);
11854}
11855
9829ddba
RS
11856/* Nonzero if we had any X protocol errors
11857 since we did x_catch_errors on DPY. */
e99db5a1
RS
11858
11859int
11860x_had_errors_p (dpy)
11861 Display *dpy;
11862{
11863 /* Make sure to catch any errors incurred so far. */
11864 XSync (dpy, False);
11865
11866 return XSTRING (x_error_message_string)->data[0] != 0;
11867}
11868
9829ddba
RS
11869/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
11870
06a2c219 11871void
9829ddba
RS
11872x_clear_errors (dpy)
11873 Display *dpy;
11874{
11875 XSTRING (x_error_message_string)->data[0] = 0;
11876}
11877
e99db5a1
RS
11878/* Stop catching X protocol errors and let them make Emacs die.
11879 DPY should be the display that was passed to x_catch_errors.
11880 COUNT should be the value that was returned by
11881 the corresponding call to x_catch_errors. */
11882
11883void
11884x_uncatch_errors (dpy, count)
11885 Display *dpy;
11886 int count;
11887{
11888 unbind_to (count, Qnil);
11889}
11890
11891#if 0
11892static unsigned int x_wire_count;
11893x_trace_wire ()
11894{
11895 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
11896}
11897#endif /* ! 0 */
11898
11899\f
11900/* Handle SIGPIPE, which can happen when the connection to a server
11901 simply goes away. SIGPIPE is handled by x_connection_signal.
11902 Don't need to do anything, because the write which caused the
11903 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 11904 which will do the appropriate cleanup for us. */
e99db5a1
RS
11905
11906static SIGTYPE
11907x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 11908 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
11909{
11910#ifdef USG
11911 /* USG systems forget handlers when they are used;
11912 must reestablish each time */
11913 signal (signalnum, x_connection_signal);
11914#endif /* USG */
11915}
0da1ab50 11916
e99db5a1 11917\f
0da1ab50
GM
11918/************************************************************************
11919 Handling X errors
11920 ************************************************************************/
4746118a 11921
f0e299de
GM
11922/* Error message passed to x_connection_closed. */
11923
11924static char *error_msg;
11925
a7248e4f 11926/* Function installed as fatal_error_signal_hook in
f0e299de
GM
11927 x_connection_closed. Print the X error message, and exit normally,
11928 instead of dumping core when XtCloseDisplay fails. */
11929
11930static void
11931x_fatal_error_signal ()
11932{
11933 fprintf (stderr, "%s\n", error_msg);
11934 exit (70);
11935}
11936
0da1ab50
GM
11937/* Handle the loss of connection to display DPY. ERROR_MESSAGE is
11938 the text of an error message that lead to the connection loss. */
16bd92ea 11939
4746118a 11940static SIGTYPE
5978125e
GM
11941x_connection_closed (dpy, error_message)
11942 Display *dpy;
7a13e894 11943 char *error_message;
4746118a 11944{
5978125e 11945 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
7a13e894 11946 Lisp_Object frame, tail;
0da1ab50 11947 int count;
0da1ab50 11948
f0e299de
GM
11949 error_msg = (char *) alloca (strlen (error_message) + 1);
11950 strcpy (error_msg, error_message);
1a532e54
GM
11951 handling_signal = 0;
11952
0da1ab50
GM
11953 /* Prevent being called recursively because of an error condition
11954 below. Otherwise, we might end up with printing ``can't find per
11955 display information'' in the recursive call instead of printing
11956 the original message here. */
11957 count = x_catch_errors (dpy);
11958
8a4f36cc
GM
11959 /* We have to close the display to inform Xt that it doesn't
11960 exist anymore. If we don't, Xt will continue to wait for
11961 events from the display. As a consequence, a sequence of
11962
11963 M-x make-frame-on-display RET :1 RET
11964 ...kill the new frame, so that we get an IO error...
11965 M-x make-frame-on-display RET :1 RET
11966
11967 will indefinitely wait in Xt for events for display `:1', opened
11968 in the first class to make-frame-on-display.
6186a4a0 11969
8a4f36cc
GM
11970 Closing the display is reported to lead to a bus error on
11971 OpenWindows in certain situations. I suspect that is a bug
11972 in OpenWindows. I don't know how to cicumvent it here. */
11973
f613a4c8 11974#ifdef USE_X_TOOLKIT
ae24cb3b
GM
11975 /* If DPYINFO is null, this means we didn't open the display
11976 in the first place, so don't try to close it. */
11977 if (dpyinfo)
f0e299de
GM
11978 {
11979 extern void (*fatal_error_signal_hook) P_ ((void));
11980 fatal_error_signal_hook = x_fatal_error_signal;
11981 XtCloseDisplay (dpy);
11982 fatal_error_signal_hook = NULL;
11983 }
f613a4c8 11984#endif
adabc3a9 11985
8a4f36cc 11986 /* Indicate that this display is dead. */
9e80b57d
KR
11987 if (dpyinfo)
11988 dpyinfo->display = 0;
6186a4a0 11989
06a2c219 11990 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
11991 that are on the dead display. */
11992 FOR_EACH_FRAME (tail, frame)
11993 {
11994 Lisp_Object minibuf_frame;
11995 minibuf_frame
11996 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
11997 if (FRAME_X_P (XFRAME (frame))
11998 && FRAME_X_P (XFRAME (minibuf_frame))
11999 && ! EQ (frame, minibuf_frame)
12000 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
12001 Fdelete_frame (frame, Qt);
12002 }
12003
12004 /* Now delete all remaining frames on the dead display.
06a2c219 12005 We are now sure none of these is used as the mini-buffer
7a13e894
RS
12006 for another frame that we need to delete. */
12007 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
12008 if (FRAME_X_P (XFRAME (frame))
12009 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
12010 {
12011 /* Set this to t so that Fdelete_frame won't get confused
12012 trying to find a replacement. */
12013 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
12014 Fdelete_frame (frame, Qt);
12015 }
7a13e894 12016
482a1bd2
KH
12017 if (dpyinfo)
12018 x_delete_display (dpyinfo);
7a13e894 12019
0da1ab50
GM
12020 x_uncatch_errors (dpy, count);
12021
7a13e894
RS
12022 if (x_display_list == 0)
12023 {
f0e299de 12024 fprintf (stderr, "%s\n", error_msg);
7a13e894
RS
12025 shut_down_emacs (0, 0, Qnil);
12026 exit (70);
12027 }
12ba150f 12028
7a13e894
RS
12029 /* Ordinary stack unwind doesn't deal with these. */
12030#ifdef SIGIO
12031 sigunblock (sigmask (SIGIO));
12032#endif
12033 sigunblock (sigmask (SIGALRM));
12034 TOTALLY_UNBLOCK_INPUT;
12035
aa4d9a9e 12036 clear_waiting_for_input ();
f0e299de 12037 error ("%s", error_msg);
4746118a
JB
12038}
12039
0da1ab50 12040
7a13e894
RS
12041/* This is the usual handler for X protocol errors.
12042 It kills all frames on the display that we got the error for.
12043 If that was the only one, it prints an error message and kills Emacs. */
12044
06a2c219 12045static void
c118dd06
JB
12046x_error_quitter (display, error)
12047 Display *display;
12048 XErrorEvent *error;
12049{
7a13e894 12050 char buf[256], buf1[356];
dc6f92b8 12051
58769bee 12052 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 12053 original error handler. */
dc6f92b8 12054
c118dd06 12055 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 12056 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 12057 buf, error->request_code);
7a13e894 12058 x_connection_closed (display, buf1);
dc6f92b8
JB
12059}
12060
0da1ab50 12061
e99db5a1
RS
12062/* This is the first-level handler for X protocol errors.
12063 It calls x_error_quitter or x_error_catcher. */
7a13e894 12064
8922af5f 12065static int
e99db5a1 12066x_error_handler (display, error)
8922af5f 12067 Display *display;
e99db5a1 12068 XErrorEvent *error;
8922af5f 12069{
e99db5a1
RS
12070 if (! NILP (x_error_message_string))
12071 x_error_catcher (display, error);
12072 else
12073 x_error_quitter (display, error);
06a2c219 12074 return 0;
f9e24cb9 12075}
c118dd06 12076
e99db5a1
RS
12077/* This is the handler for X IO errors, always.
12078 It kills all frames on the display that we lost touch with.
12079 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 12080
c118dd06 12081static int
e99db5a1 12082x_io_error_quitter (display)
c118dd06 12083 Display *display;
c118dd06 12084{
e99db5a1 12085 char buf[256];
dc6f92b8 12086
e99db5a1
RS
12087 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
12088 x_connection_closed (display, buf);
06a2c219 12089 return 0;
dc6f92b8 12090}
dc6f92b8 12091\f
f451eb13
JB
12092/* Changing the font of the frame. */
12093
76bcdf39
RS
12094/* Give frame F the font named FONTNAME as its default font, and
12095 return the full name of that font. FONTNAME may be a wildcard
12096 pattern; in that case, we choose some font that fits the pattern.
12097 The return value shows which font we chose. */
12098
b5cf7a0e 12099Lisp_Object
f676886a
JB
12100x_new_font (f, fontname)
12101 struct frame *f;
dc6f92b8
JB
12102 register char *fontname;
12103{
dc43ef94 12104 struct font_info *fontp
ee569018 12105 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 12106
dc43ef94
KH
12107 if (!fontp)
12108 return Qnil;
2224a5fc 12109
dc43ef94 12110 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 12111 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94 12112 f->output_data.x->fontset = -1;
976b73d7
KS
12113
12114 x_compute_fringe_widths (f, 1);
12115
b2cad826
KH
12116 /* Compute the scroll bar width in character columns. */
12117 if (f->scroll_bar_pixel_width > 0)
12118 {
7556890b 12119 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
12120 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
12121 }
12122 else
4e61bddf
RS
12123 {
12124 int wid = FONT_WIDTH (f->output_data.x->font);
12125 f->scroll_bar_cols = (14 + wid - 1) / wid;
12126 }
b2cad826 12127
f676886a 12128 /* Now make the frame display the given font. */
c118dd06 12129 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 12130 {
7556890b
RS
12131 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
12132 f->output_data.x->font->fid);
12133 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
12134 f->output_data.x->font->fid);
12135 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
12136 f->output_data.x->font->fid);
f676886a 12137
a27f9f86 12138 frame_update_line_height (f);
3497f73e
GM
12139
12140 /* Don't change the size of a tip frame; there's no point in
12141 doing it because it's done in Fx_show_tip, and it leads to
12142 problems because the tip frame has no widget. */
12143 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
12144 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 12145 }
a27f9f86
RS
12146 else
12147 /* If we are setting a new frame's font for the first time,
12148 there are no faces yet, so this font's height is the line height. */
7556890b 12149 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 12150
dc43ef94
KH
12151 return build_string (fontp->full_name);
12152}
12153
12154/* Give frame F the fontset named FONTSETNAME as its default font, and
12155 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
12156 pattern; in that case, we choose some fontset that fits the pattern.
12157 The return value shows which fontset we chose. */
b5cf7a0e 12158
dc43ef94
KH
12159Lisp_Object
12160x_new_fontset (f, fontsetname)
12161 struct frame *f;
12162 char *fontsetname;
12163{
ee569018 12164 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 12165 Lisp_Object result;
b5cf7a0e 12166
dc43ef94
KH
12167 if (fontset < 0)
12168 return Qnil;
b5cf7a0e 12169
2da424f1
KH
12170 if (f->output_data.x->fontset == fontset)
12171 /* This fontset is already set in frame F. There's nothing more
12172 to do. */
ee569018 12173 return fontset_name (fontset);
dc43ef94 12174
ee569018 12175 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
12176
12177 if (!STRINGP (result))
12178 /* Can't load ASCII font. */
12179 return Qnil;
12180
12181 /* Since x_new_font doesn't update any fontset information, do it now. */
12182 f->output_data.x->fontset = fontset;
dc43ef94 12183
f5d11644
GM
12184#ifdef HAVE_X_I18N
12185 if (FRAME_XIC (f)
12186 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 12187 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
12188#endif
12189
dc43ef94 12190 return build_string (fontsetname);
dc6f92b8 12191}
f5d11644 12192
976b73d7
KS
12193/* Compute actual fringe widths */
12194
12195void
12196x_compute_fringe_widths (f, redraw)
12197 struct frame *f;
12198 int redraw;
12199{
12200 int o_left = f->output_data.x->left_fringe_width;
12201 int o_right = f->output_data.x->right_fringe_width;
12202 int o_cols = f->output_data.x->fringe_cols;
12203
12204 Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist);
12205 Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist);
12206 int left_fringe_width, right_fringe_width;
12207
12208 if (!NILP (left_fringe))
12209 left_fringe = Fcdr (left_fringe);
12210 if (!NILP (right_fringe))
12211 right_fringe = Fcdr (right_fringe);
12212
12213 left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 :
12214 XINT (left_fringe));
12215 right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 :
12216 XINT (right_fringe));
12217
12218 if (left_fringe_width || right_fringe_width)
12219 {
12220 int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width;
12221 int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width;
12222 int conf_wid = left_wid + right_wid;
12223 int font_wid = FONT_WIDTH (f->output_data.x->font);
12224 int cols = (left_wid + right_wid + font_wid-1) / font_wid;
12225 int real_wid = cols * font_wid;
12226 if (left_wid && right_wid)
12227 {
12228 if (left_fringe_width < 0)
12229 {
12230 /* Left fringe width is fixed, adjust right fringe if necessary */
12231 f->output_data.x->left_fringe_width = left_wid;
12232 f->output_data.x->right_fringe_width = real_wid - left_wid;
12233 }
12234 else if (right_fringe_width < 0)
12235 {
12236 /* Right fringe width is fixed, adjust left fringe if necessary */
12237 f->output_data.x->left_fringe_width = real_wid - right_wid;
12238 f->output_data.x->right_fringe_width = right_wid;
12239 }
12240 else
12241 {
12242 /* Adjust both fringes with an equal amount.
12243 Note that we are doing integer arithmetic here, so don't
12244 lose a pixel if the total width is an odd number. */
12245 int fill = real_wid - conf_wid;
12246 f->output_data.x->left_fringe_width = left_wid + fill/2;
12247 f->output_data.x->right_fringe_width = right_wid + fill - fill/2;
12248 }
12249 }
12250 else if (left_fringe_width)
12251 {
12252 f->output_data.x->left_fringe_width = real_wid;
12253 f->output_data.x->right_fringe_width = 0;
12254 }
12255 else
12256 {
12257 f->output_data.x->left_fringe_width = 0;
12258 f->output_data.x->right_fringe_width = real_wid;
12259 }
12260 f->output_data.x->fringe_cols = cols;
12261 f->output_data.x->fringes_extra = real_wid;
12262 }
12263 else
12264 {
12265 f->output_data.x->left_fringe_width = 0;
12266 f->output_data.x->right_fringe_width = 0;
12267 f->output_data.x->fringe_cols = 0;
12268 f->output_data.x->fringes_extra = 0;
12269 }
12270
12271 if (redraw && FRAME_VISIBLE_P (f))
12272 if (o_left != f->output_data.x->left_fringe_width ||
12273 o_right != f->output_data.x->right_fringe_width ||
12274 o_cols != f->output_data.x->fringe_cols)
12275 redraw_frame (f);
12276}
f5d11644
GM
12277\f
12278/***********************************************************************
12279 X Input Methods
12280 ***********************************************************************/
12281
12282#ifdef HAVE_X_I18N
12283
12284#ifdef HAVE_X11R6
12285
12286/* XIM destroy callback function, which is called whenever the
12287 connection to input method XIM dies. CLIENT_DATA contains a
12288 pointer to the x_display_info structure corresponding to XIM. */
12289
12290static void
12291xim_destroy_callback (xim, client_data, call_data)
12292 XIM xim;
12293 XPointer client_data;
12294 XPointer call_data;
12295{
12296 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
12297 Lisp_Object frame, tail;
12298
12299 BLOCK_INPUT;
12300
12301 /* No need to call XDestroyIC.. */
12302 FOR_EACH_FRAME (tail, frame)
12303 {
12304 struct frame *f = XFRAME (frame);
12305 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
12306 {
12307 FRAME_XIC (f) = NULL;
12308 if (FRAME_XIC_FONTSET (f))
12309 {
12310 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
12311 FRAME_XIC_FONTSET (f) = NULL;
12312 }
12313 }
12314 }
12315
12316 /* No need to call XCloseIM. */
12317 dpyinfo->xim = NULL;
12318 XFree (dpyinfo->xim_styles);
12319 UNBLOCK_INPUT;
12320}
12321
12322#endif /* HAVE_X11R6 */
12323
12324/* Open the connection to the XIM server on display DPYINFO.
12325 RESOURCE_NAME is the resource name Emacs uses. */
12326
12327static void
12328xim_open_dpy (dpyinfo, resource_name)
12329 struct x_display_info *dpyinfo;
12330 char *resource_name;
12331{
287f7dd6 12332#ifdef USE_XIM
f5d11644
GM
12333 XIM xim;
12334
12335 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
12336 dpyinfo->xim = xim;
12337
12338 if (xim)
12339 {
f5d11644
GM
12340#ifdef HAVE_X11R6
12341 XIMCallback destroy;
12342#endif
12343
12344 /* Get supported styles and XIM values. */
12345 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
12346
12347#ifdef HAVE_X11R6
12348 destroy.callback = xim_destroy_callback;
12349 destroy.client_data = (XPointer)dpyinfo;
cea2ad76 12350 /* This isn't prototyped in OSF 5.0. */
f5d11644
GM
12351 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
12352#endif
12353 }
287f7dd6
GM
12354
12355#else /* not USE_XIM */
12356 dpyinfo->xim = NULL;
12357#endif /* not USE_XIM */
f5d11644
GM
12358}
12359
12360
b9de836c 12361#ifdef HAVE_X11R6_XIM
f5d11644
GM
12362
12363struct xim_inst_t
12364{
12365 struct x_display_info *dpyinfo;
12366 char *resource_name;
12367};
12368
12369/* XIM instantiate callback function, which is called whenever an XIM
12370 server is available. DISPLAY is teh display of the XIM.
12371 CLIENT_DATA contains a pointer to an xim_inst_t structure created
12372 when the callback was registered. */
12373
12374static void
12375xim_instantiate_callback (display, client_data, call_data)
12376 Display *display;
12377 XPointer client_data;
12378 XPointer call_data;
12379{
12380 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
12381 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
12382
12383 /* We don't support multiple XIM connections. */
12384 if (dpyinfo->xim)
12385 return;
12386
12387 xim_open_dpy (dpyinfo, xim_inst->resource_name);
12388
12389 /* Create XIC for the existing frames on the same display, as long
12390 as they have no XIC. */
12391 if (dpyinfo->xim && dpyinfo->reference_count > 0)
12392 {
12393 Lisp_Object tail, frame;
12394
12395 BLOCK_INPUT;
12396 FOR_EACH_FRAME (tail, frame)
12397 {
12398 struct frame *f = XFRAME (frame);
12399
12400 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
12401 if (FRAME_XIC (f) == NULL)
12402 {
12403 create_frame_xic (f);
12404 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
12405 xic_set_statusarea (f);
12406 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
12407 {
12408 struct window *w = XWINDOW (f->selected_window);
12409 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
12410 }
12411 }
12412 }
12413
12414 UNBLOCK_INPUT;
12415 }
12416}
12417
b9de836c 12418#endif /* HAVE_X11R6_XIM */
f5d11644
GM
12419
12420
12421/* Open a connection to the XIM server on display DPYINFO.
12422 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
12423 connection only at the first time. On X11R6, open the connection
12424 in the XIM instantiate callback function. */
12425
12426static void
12427xim_initialize (dpyinfo, resource_name)
12428 struct x_display_info *dpyinfo;
12429 char *resource_name;
12430{
287f7dd6 12431#ifdef USE_XIM
b9de836c 12432#ifdef HAVE_X11R6_XIM
f5d11644
GM
12433 struct xim_inst_t *xim_inst;
12434 int len;
12435
12436 dpyinfo->xim = NULL;
12437 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
12438 xim_inst->dpyinfo = dpyinfo;
12439 len = strlen (resource_name);
12440 xim_inst->resource_name = (char *) xmalloc (len + 1);
12441 bcopy (resource_name, xim_inst->resource_name, len + 1);
12442 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12443 resource_name, EMACS_CLASS,
12444 xim_instantiate_callback,
2ebb2f8b
DL
12445 /* Fixme: This is XPointer in
12446 XFree86 but (XPointer *) on
12447 Tru64, at least. */
12448 (XPointer) xim_inst);
b9de836c 12449#else /* not HAVE_X11R6_XIM */
f5d11644
GM
12450 dpyinfo->xim = NULL;
12451 xim_open_dpy (dpyinfo, resource_name);
b9de836c 12452#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
12453
12454#else /* not USE_XIM */
12455 dpyinfo->xim = NULL;
12456#endif /* not USE_XIM */
f5d11644
GM
12457}
12458
12459
12460/* Close the connection to the XIM server on display DPYINFO. */
12461
12462static void
12463xim_close_dpy (dpyinfo)
12464 struct x_display_info *dpyinfo;
12465{
287f7dd6 12466#ifdef USE_XIM
b9de836c 12467#ifdef HAVE_X11R6_XIM
8a4f36cc
GM
12468 if (dpyinfo->display)
12469 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12470 NULL, EMACS_CLASS,
12471 xim_instantiate_callback, NULL);
b9de836c 12472#endif /* not HAVE_X11R6_XIM */
8a4f36cc
GM
12473 if (dpyinfo->display)
12474 XCloseIM (dpyinfo->xim);
f5d11644
GM
12475 dpyinfo->xim = NULL;
12476 XFree (dpyinfo->xim_styles);
287f7dd6 12477#endif /* USE_XIM */
f5d11644
GM
12478}
12479
b9de836c 12480#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
12481
12482
dc6f92b8 12483\f
2e365682
RS
12484/* Calculate the absolute position in frame F
12485 from its current recorded position values and gravity. */
12486
dfcf069d 12487void
43bca5d5 12488x_calc_absolute_position (f)
f676886a 12489 struct frame *f;
dc6f92b8 12490{
06a2c219 12491 Window child;
6dba1858 12492 int win_x = 0, win_y = 0;
7556890b 12493 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
12494 int this_window;
12495
9829ddba
RS
12496 /* We have nothing to do if the current position
12497 is already for the top-left corner. */
12498 if (! ((flags & XNegative) || (flags & YNegative)))
12499 return;
12500
c81412a0 12501#ifdef USE_X_TOOLKIT
7556890b 12502 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
12503#else
12504 this_window = FRAME_X_WINDOW (f);
12505#endif
6dba1858
RS
12506
12507 /* Find the position of the outside upper-left corner of
9829ddba
RS
12508 the inner window, with respect to the outer window.
12509 But do this only if we will need the results. */
7556890b 12510 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 12511 {
9829ddba
RS
12512 int count;
12513
6dba1858 12514 BLOCK_INPUT;
9829ddba
RS
12515 count = x_catch_errors (FRAME_X_DISPLAY (f));
12516 while (1)
12517 {
12518 x_clear_errors (FRAME_X_DISPLAY (f));
12519 XTranslateCoordinates (FRAME_X_DISPLAY (f),
12520
12521 /* From-window, to-window. */
12522 this_window,
12523 f->output_data.x->parent_desc,
12524
12525 /* From-position, to-position. */
12526 0, 0, &win_x, &win_y,
12527
12528 /* Child of win. */
12529 &child);
12530 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12531 {
12532 Window newroot, newparent = 0xdeadbeef;
12533 Window *newchildren;
2ebb2f8b 12534 unsigned int nchildren;
9829ddba
RS
12535
12536 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
12537 &newparent, &newchildren, &nchildren))
12538 break;
58769bee 12539
7c3c78a3 12540 XFree ((char *) newchildren);
6dba1858 12541
9829ddba
RS
12542 f->output_data.x->parent_desc = newparent;
12543 }
12544 else
12545 break;
12546 }
6dba1858 12547
9829ddba 12548 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
12549 UNBLOCK_INPUT;
12550 }
12551
12552 /* Treat negative positions as relative to the leftmost bottommost
12553 position that fits on the screen. */
20f55f9a 12554 if (flags & XNegative)
7556890b 12555 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
12556 - 2 * f->output_data.x->border_width - win_x
12557 - PIXEL_WIDTH (f)
12558 + f->output_data.x->left_pos);
dc6f92b8 12559
7708ced0
GM
12560 {
12561 int height = PIXEL_HEIGHT (f);
06a2c219 12562
7708ced0
GM
12563#if defined USE_X_TOOLKIT && defined USE_MOTIF
12564 /* Something is fishy here. When using Motif, starting Emacs with
12565 `-g -0-0', the frame appears too low by a few pixels.
12566
12567 This seems to be so because initially, while Emacs is starting,
12568 the column widget's height and the frame's pixel height are
12569 different. The column widget's height is the right one. In
12570 later invocations, when Emacs is up, the frame's pixel height
12571 is right, though.
12572
12573 It's not obvious where the initial small difference comes from.
12574 2000-12-01, gerd. */
12575
12576 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
06a2c219 12577#endif
2e365682 12578
7708ced0
GM
12579 if (flags & YNegative)
12580 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
12581 - 2 * f->output_data.x->border_width
12582 - win_y
12583 - height
12584 + f->output_data.x->top_pos);
12585 }
12586
3a35ab44
RS
12587 /* The left_pos and top_pos
12588 are now relative to the top and left screen edges,
12589 so the flags should correspond. */
7556890b 12590 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
12591}
12592
3a35ab44
RS
12593/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
12594 to really change the position, and 0 when calling from
12595 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
12596 position values). It is -1 when calling from x_set_frame_parameters,
12597 which means, do adjust for borders but don't change the gravity. */
3a35ab44 12598
dfcf069d 12599void
dc05a16b 12600x_set_offset (f, xoff, yoff, change_gravity)
f676886a 12601 struct frame *f;
dc6f92b8 12602 register int xoff, yoff;
dc05a16b 12603 int change_gravity;
dc6f92b8 12604{
4a4cbdd5
KH
12605 int modified_top, modified_left;
12606
aa3ff7c9 12607 if (change_gravity > 0)
3a35ab44 12608 {
7556890b
RS
12609 f->output_data.x->top_pos = yoff;
12610 f->output_data.x->left_pos = xoff;
12611 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 12612 if (xoff < 0)
7556890b 12613 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 12614 if (yoff < 0)
7556890b
RS
12615 f->output_data.x->size_hint_flags |= YNegative;
12616 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 12617 }
43bca5d5 12618 x_calc_absolute_position (f);
dc6f92b8
JB
12619
12620 BLOCK_INPUT;
c32cdd9a 12621 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 12622
7556890b
RS
12623 modified_left = f->output_data.x->left_pos;
12624 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
12625#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
12626 this seems to be unnecessary and incorrect. rms, 4/17/97. */
12627 /* It is a mystery why we need to add the border_width here
12628 when the frame is already visible, but experiment says we do. */
aa3ff7c9 12629 if (change_gravity != 0)
4a4cbdd5 12630 {
7556890b
RS
12631 modified_left += f->output_data.x->border_width;
12632 modified_top += f->output_data.x->border_width;
4a4cbdd5 12633 }
e73ec6fa 12634#endif
4a4cbdd5 12635
3afe33e7 12636#ifdef USE_X_TOOLKIT
7556890b 12637 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 12638 modified_left, modified_top);
3afe33e7 12639#else /* not USE_X_TOOLKIT */
334208b7 12640 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 12641 modified_left, modified_top);
3afe33e7 12642#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12643 UNBLOCK_INPUT;
12644}
12645
dc6f92b8 12646
499b1844
GM
12647/* Change the size of frame F's X window to COLS/ROWS in the case F
12648 doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
12649 top-left-corner window gravity for this size change and subsequent
12650 size changes. Otherwise we leave the window gravity unchanged. */
12651
12652static void
12653x_set_window_size_1 (f, change_gravity, cols, rows)
f676886a 12654 struct frame *f;
bc20ebbf 12655 int change_gravity;
b1c884c3 12656 int cols, rows;
dc6f92b8
JB
12657{
12658 int pixelwidth, pixelheight;
80fd1fe2 12659
b1c884c3 12660 check_frame_size (f, &rows, &cols);
7556890b 12661 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
12662 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
12663 ? 0
12664 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 12665 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 12666 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
976b73d7
KS
12667
12668 x_compute_fringe_widths (f, 0);
12669
f451eb13
JB
12670 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
12671 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 12672
7556890b 12673 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 12674 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 12675
334208b7
RS
12676 XSync (FRAME_X_DISPLAY (f), False);
12677 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12678 pixelwidth, pixelheight);
b1c884c3
JB
12679
12680 /* Now, strictly speaking, we can't be sure that this is accurate,
12681 but the window manager will get around to dealing with the size
12682 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
12683 ConfigureNotify event gets here.
12684
12685 We could just not bother storing any of this information here,
12686 and let the ConfigureNotify event set everything up, but that
fddd5ceb 12687 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 12688 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
12689 point in the future when the ConfigureNotify event arrives.
12690
12691 We pass 1 for DELAY since we can't run Lisp code inside of
12692 a BLOCK_INPUT. */
7d1e984f 12693 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
12694 PIXEL_WIDTH (f) = pixelwidth;
12695 PIXEL_HEIGHT (f) = pixelheight;
12696
aee9a898
RS
12697 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
12698 receive in the ConfigureNotify event; if we get what we asked
12699 for, then the event won't cause the screen to become garbaged, so
12700 we have to make sure to do it here. */
12701 SET_FRAME_GARBAGED (f);
12702
12703 XFlush (FRAME_X_DISPLAY (f));
499b1844
GM
12704}
12705
12706
12707/* Call this to change the size of frame F's x-window.
12708 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
12709 for this size change and subsequent size changes.
12710 Otherwise we leave the window gravity unchanged. */
aee9a898 12711
499b1844
GM
12712void
12713x_set_window_size (f, change_gravity, cols, rows)
12714 struct frame *f;
12715 int change_gravity;
12716 int cols, rows;
12717{
12718 BLOCK_INPUT;
12719
12720#ifdef USE_X_TOOLKIT
12721
f1f4d345 12722 if (f->output_data.x->widget != NULL)
499b1844
GM
12723 {
12724 /* The x and y position of the widget is clobbered by the
12725 call to XtSetValues within EmacsFrameSetCharSize.
12726 This is a real kludge, but I don't understand Xt so I can't
12727 figure out a correct fix. Can anyone else tell me? -- rms. */
12728 int xpos = f->output_data.x->widget->core.x;
12729 int ypos = f->output_data.x->widget->core.y;
12730 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
12731 f->output_data.x->widget->core.x = xpos;
12732 f->output_data.x->widget->core.y = ypos;
12733 }
12734 else
12735 x_set_window_size_1 (f, change_gravity, cols, rows);
12736
12737#else /* not USE_X_TOOLKIT */
12738
12739 x_set_window_size_1 (f, change_gravity, cols, rows);
12740
aee9a898
RS
12741#endif /* not USE_X_TOOLKIT */
12742
4d73d038 12743 /* If cursor was outside the new size, mark it as off. */
06a2c219 12744 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 12745
aee9a898
RS
12746 /* Clear out any recollection of where the mouse highlighting was,
12747 since it might be in a place that's outside the new frame size.
12748 Actually checking whether it is outside is a pain in the neck,
12749 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 12750 cancel_mouse_face (f);
dbc4e1c1 12751
dc6f92b8
JB
12752 UNBLOCK_INPUT;
12753}
dc6f92b8 12754\f
d047c4eb 12755/* Mouse warping. */
dc6f92b8 12756
9b378208 12757void
f676886a
JB
12758x_set_mouse_position (f, x, y)
12759 struct frame *f;
dc6f92b8
JB
12760 int x, y;
12761{
12762 int pix_x, pix_y;
12763
7556890b
RS
12764 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
12765 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
12766
12767 if (pix_x < 0) pix_x = 0;
12768 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
12769
12770 if (pix_y < 0) pix_y = 0;
12771 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
12772
12773 BLOCK_INPUT;
dc6f92b8 12774
334208b7
RS
12775 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12776 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
12777 UNBLOCK_INPUT;
12778}
12779
9b378208
RS
12780/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
12781
12782void
12783x_set_mouse_pixel_position (f, pix_x, pix_y)
12784 struct frame *f;
12785 int pix_x, pix_y;
12786{
12787 BLOCK_INPUT;
12788
334208b7
RS
12789 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12790 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
12791 UNBLOCK_INPUT;
12792}
d047c4eb
KH
12793\f
12794/* focus shifting, raising and lowering. */
9b378208 12795
dfcf069d 12796void
f676886a
JB
12797x_focus_on_frame (f)
12798 struct frame *f;
dc6f92b8 12799{
1fb20991 12800#if 0 /* This proves to be unpleasant. */
f676886a 12801 x_raise_frame (f);
1fb20991 12802#endif
6d4238f3
JB
12803#if 0
12804 /* I don't think that the ICCCM allows programs to do things like this
12805 without the interaction of the window manager. Whatever you end up
f676886a 12806 doing with this code, do it to x_unfocus_frame too. */
334208b7 12807 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 12808 RevertToPointerRoot, CurrentTime);
c118dd06 12809#endif /* ! 0 */
dc6f92b8
JB
12810}
12811
dfcf069d 12812void
f676886a
JB
12813x_unfocus_frame (f)
12814 struct frame *f;
dc6f92b8 12815{
6d4238f3 12816#if 0
f676886a 12817 /* Look at the remarks in x_focus_on_frame. */
0f941935 12818 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 12819 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 12820 RevertToPointerRoot, CurrentTime);
c118dd06 12821#endif /* ! 0 */
dc6f92b8
JB
12822}
12823
f676886a 12824/* Raise frame F. */
dc6f92b8 12825
dfcf069d 12826void
f676886a
JB
12827x_raise_frame (f)
12828 struct frame *f;
dc6f92b8 12829{
3a88c238 12830 if (f->async_visible)
dc6f92b8
JB
12831 {
12832 BLOCK_INPUT;
3afe33e7 12833#ifdef USE_X_TOOLKIT
7556890b 12834 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12835#else /* not USE_X_TOOLKIT */
334208b7 12836 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12837#endif /* not USE_X_TOOLKIT */
334208b7 12838 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12839 UNBLOCK_INPUT;
12840 }
12841}
12842
f676886a 12843/* Lower frame F. */
dc6f92b8 12844
dfcf069d 12845void
f676886a
JB
12846x_lower_frame (f)
12847 struct frame *f;
dc6f92b8 12848{
3a88c238 12849 if (f->async_visible)
dc6f92b8
JB
12850 {
12851 BLOCK_INPUT;
3afe33e7 12852#ifdef USE_X_TOOLKIT
7556890b 12853 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12854#else /* not USE_X_TOOLKIT */
334208b7 12855 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12856#endif /* not USE_X_TOOLKIT */
334208b7 12857 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12858 UNBLOCK_INPUT;
12859 }
12860}
12861
dbc4e1c1 12862static void
6b0442dc 12863XTframe_raise_lower (f, raise_flag)
dbc4e1c1 12864 FRAME_PTR f;
6b0442dc 12865 int raise_flag;
dbc4e1c1 12866{
6b0442dc 12867 if (raise_flag)
dbc4e1c1
JB
12868 x_raise_frame (f);
12869 else
12870 x_lower_frame (f);
12871}
d047c4eb
KH
12872\f
12873/* Change of visibility. */
dc6f92b8 12874
9382638d
KH
12875/* This tries to wait until the frame is really visible.
12876 However, if the window manager asks the user where to position
12877 the frame, this will return before the user finishes doing that.
12878 The frame will not actually be visible at that time,
12879 but it will become visible later when the window manager
12880 finishes with it. */
12881
dfcf069d 12882void
f676886a
JB
12883x_make_frame_visible (f)
12884 struct frame *f;
dc6f92b8 12885{
990ba854 12886 Lisp_Object type;
1aa6072f 12887 int original_top, original_left;
31be9251
GM
12888 int retry_count = 2;
12889
12890 retry:
dc6f92b8 12891
dc6f92b8 12892 BLOCK_INPUT;
dc6f92b8 12893
990ba854
RS
12894 type = x_icon_type (f);
12895 if (!NILP (type))
12896 x_bitmap_icon (f, type);
bdcd49ba 12897
f676886a 12898 if (! FRAME_VISIBLE_P (f))
90e65f07 12899 {
1aa6072f
RS
12900 /* We test FRAME_GARBAGED_P here to make sure we don't
12901 call x_set_offset a second time
12902 if we get to x_make_frame_visible a second time
12903 before the window gets really visible. */
12904 if (! FRAME_ICONIFIED_P (f)
12905 && ! f->output_data.x->asked_for_visible)
12906 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
12907
12908 f->output_data.x->asked_for_visible = 1;
12909
90e65f07 12910 if (! EQ (Vx_no_window_manager, Qt))
f676886a 12911 x_wm_set_window_state (f, NormalState);
3afe33e7 12912#ifdef USE_X_TOOLKIT
d7a38a2e 12913 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 12914 XtMapWidget (f->output_data.x->widget);
3afe33e7 12915#else /* not USE_X_TOOLKIT */
7f9c7f94 12916 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12917#endif /* not USE_X_TOOLKIT */
0134a210
RS
12918#if 0 /* This seems to bring back scroll bars in the wrong places
12919 if the window configuration has changed. They seem
12920 to come back ok without this. */
ab648270 12921 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 12922 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 12923#endif
90e65f07 12924 }
dc6f92b8 12925
334208b7 12926 XFlush (FRAME_X_DISPLAY (f));
90e65f07 12927
0dacf791
RS
12928 /* Synchronize to ensure Emacs knows the frame is visible
12929 before we do anything else. We do this loop with input not blocked
12930 so that incoming events are handled. */
12931 {
12932 Lisp_Object frame;
12ce2351 12933 int count;
28c01ffe
RS
12934 /* This must be before UNBLOCK_INPUT
12935 since events that arrive in response to the actions above
12936 will set it when they are handled. */
12937 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
12938
12939 original_left = f->output_data.x->left_pos;
12940 original_top = f->output_data.x->top_pos;
c0a04927
RS
12941
12942 /* This must come after we set COUNT. */
12943 UNBLOCK_INPUT;
12944
2745e6c4 12945 /* We unblock here so that arriving X events are processed. */
1aa6072f 12946
dcb07ae9
RS
12947 /* Now move the window back to where it was "supposed to be".
12948 But don't do it if the gravity is negative.
12949 When the gravity is negative, this uses a position
28c01ffe
RS
12950 that is 3 pixels too low. Perhaps that's really the border width.
12951
12952 Don't do this if the window has never been visible before,
12953 because the window manager may choose the position
12954 and we don't want to override it. */
1aa6072f 12955
4d3f5d9a 12956 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 12957 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 12958 && previously_visible)
1aa6072f 12959 {
2745e6c4
RS
12960 Drawable rootw;
12961 int x, y;
12962 unsigned int width, height, border, depth;
06a2c219 12963
1aa6072f 12964 BLOCK_INPUT;
9829ddba 12965
06a2c219
GM
12966 /* On some window managers (such as FVWM) moving an existing
12967 window, even to the same place, causes the window manager
12968 to introduce an offset. This can cause the window to move
12969 to an unexpected location. Check the geometry (a little
12970 slow here) and then verify that the window is in the right
12971 place. If the window is not in the right place, move it
12972 there, and take the potential window manager hit. */
2745e6c4
RS
12973 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12974 &rootw, &x, &y, &width, &height, &border, &depth);
12975
12976 if (original_left != x || original_top != y)
12977 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12978 original_left, original_top);
12979
1aa6072f
RS
12980 UNBLOCK_INPUT;
12981 }
9829ddba 12982
e0c1aef2 12983 XSETFRAME (frame, f);
c0a04927 12984
12ce2351
GM
12985 /* Wait until the frame is visible. Process X events until a
12986 MapNotify event has been seen, or until we think we won't get a
12987 MapNotify at all.. */
12988 for (count = input_signal_count + 10;
12989 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 12990 {
12ce2351 12991 /* Force processing of queued events. */
334208b7 12992 x_sync (f);
12ce2351
GM
12993
12994 /* Machines that do polling rather than SIGIO have been
12995 observed to go into a busy-wait here. So we'll fake an
12996 alarm signal to let the handler know that there's something
12997 to be read. We used to raise a real alarm, but it seems
12998 that the handler isn't always enabled here. This is
12999 probably a bug. */
8b2f8d4e 13000 if (input_polling_used ())
3b2fa4e6 13001 {
12ce2351
GM
13002 /* It could be confusing if a real alarm arrives while
13003 processing the fake one. Turn it off and let the
13004 handler reset it. */
3e71d8f2 13005 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
13006 int old_poll_suppress_count = poll_suppress_count;
13007 poll_suppress_count = 1;
13008 poll_for_input_1 ();
13009 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 13010 }
12ce2351
GM
13011
13012 /* See if a MapNotify event has been processed. */
13013 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 13014 }
31be9251
GM
13015
13016 /* 2000-09-28: In
13017
13018 (let ((f (selected-frame)))
13019 (iconify-frame f)
13020 (raise-frame f))
13021
13022 the frame is not raised with various window managers on
13023 FreeBSD, Linux and Solaris. It turns out that, for some
13024 unknown reason, the call to XtMapWidget is completely ignored.
13025 Mapping the widget a second time works. */
13026
13027 if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
13028 goto retry;
0dacf791 13029 }
dc6f92b8
JB
13030}
13031
06a2c219 13032/* Change from mapped state to withdrawn state. */
dc6f92b8 13033
d047c4eb
KH
13034/* Make the frame visible (mapped and not iconified). */
13035
dfcf069d 13036void
f676886a
JB
13037x_make_frame_invisible (f)
13038 struct frame *f;
dc6f92b8 13039{
546e6d5b
RS
13040 Window window;
13041
13042#ifdef USE_X_TOOLKIT
13043 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 13044 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
13045#else /* not USE_X_TOOLKIT */
13046 window = FRAME_X_WINDOW (f);
13047#endif /* not USE_X_TOOLKIT */
dc6f92b8 13048
9319ae23 13049 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
13050 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
13051 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 13052
5627c40e 13053#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 13054 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 13055 return;
5627c40e 13056#endif
dc6f92b8
JB
13057
13058 BLOCK_INPUT;
c118dd06 13059
af31d76f
RS
13060 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
13061 that the current position of the window is user-specified, rather than
13062 program-specified, so that when the window is mapped again, it will be
13063 placed at the same location, without forcing the user to position it
13064 by hand again (they have already done that once for this window.) */
c32cdd9a 13065 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 13066
c118dd06
JB
13067#ifdef HAVE_X11R4
13068
334208b7
RS
13069 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
13070 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
13071 {
13072 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13073 error ("Can't notify window manager of window withdrawal");
c118dd06 13074 }
c118dd06 13075#else /* ! defined (HAVE_X11R4) */
16bd92ea 13076
c118dd06 13077 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
13078 if (! EQ (Vx_no_window_manager, Qt))
13079 {
16bd92ea 13080 XEvent unmap;
dc6f92b8 13081
16bd92ea 13082 unmap.xunmap.type = UnmapNotify;
546e6d5b 13083 unmap.xunmap.window = window;
334208b7 13084 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 13085 unmap.xunmap.from_configure = False;
334208b7
RS
13086 if (! XSendEvent (FRAME_X_DISPLAY (f),
13087 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 13088 False,
06a2c219 13089 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
13090 &unmap))
13091 {
13092 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13093 error ("Can't notify window manager of withdrawal");
16bd92ea 13094 }
dc6f92b8
JB
13095 }
13096
16bd92ea 13097 /* Unmap the window ourselves. Cheeky! */
334208b7 13098 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 13099#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 13100
5627c40e
RS
13101 /* We can't distinguish this from iconification
13102 just by the event that we get from the server.
13103 So we can't win using the usual strategy of letting
13104 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
13105 and synchronize with the server to make sure we agree. */
13106 f->visible = 0;
13107 FRAME_ICONIFIED_P (f) = 0;
13108 f->async_visible = 0;
13109 f->async_iconified = 0;
13110
334208b7 13111 x_sync (f);
5627c40e 13112
dc6f92b8
JB
13113 UNBLOCK_INPUT;
13114}
13115
06a2c219 13116/* Change window state from mapped to iconified. */
dc6f92b8 13117
dfcf069d 13118void
f676886a
JB
13119x_iconify_frame (f)
13120 struct frame *f;
dc6f92b8 13121{
3afe33e7 13122 int result;
990ba854 13123 Lisp_Object type;
dc6f92b8 13124
9319ae23 13125 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
13126 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
13127 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 13128
3a88c238 13129 if (f->async_iconified)
dc6f92b8
JB
13130 return;
13131
3afe33e7 13132 BLOCK_INPUT;
546e6d5b 13133
9af3143a
RS
13134 FRAME_SAMPLE_VISIBILITY (f);
13135
990ba854
RS
13136 type = x_icon_type (f);
13137 if (!NILP (type))
13138 x_bitmap_icon (f, type);
bdcd49ba
RS
13139
13140#ifdef USE_X_TOOLKIT
13141
546e6d5b
RS
13142 if (! FRAME_VISIBLE_P (f))
13143 {
13144 if (! EQ (Vx_no_window_manager, Qt))
13145 x_wm_set_window_state (f, IconicState);
13146 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 13147 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
13148 /* The server won't give us any event to indicate
13149 that an invisible frame was changed to an icon,
13150 so we have to record it here. */
13151 f->iconified = 1;
1e6bc770 13152 f->visible = 1;
9cf30a30 13153 f->async_iconified = 1;
1e6bc770 13154 f->async_visible = 0;
546e6d5b
RS
13155 UNBLOCK_INPUT;
13156 return;
13157 }
13158
334208b7 13159 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 13160 XtWindow (f->output_data.x->widget),
334208b7 13161 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
13162 UNBLOCK_INPUT;
13163
13164 if (!result)
546e6d5b 13165 error ("Can't notify window manager of iconification");
3afe33e7
RS
13166
13167 f->async_iconified = 1;
1e6bc770
RS
13168 f->async_visible = 0;
13169
8c002a25
KH
13170
13171 BLOCK_INPUT;
334208b7 13172 XFlush (FRAME_X_DISPLAY (f));
8c002a25 13173 UNBLOCK_INPUT;
3afe33e7
RS
13174#else /* not USE_X_TOOLKIT */
13175
fd13dbb2
RS
13176 /* Make sure the X server knows where the window should be positioned,
13177 in case the user deiconifies with the window manager. */
13178 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 13179 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 13180
16bd92ea
JB
13181 /* Since we don't know which revision of X we're running, we'll use both
13182 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
13183
13184 /* X11R4: send a ClientMessage to the window manager using the
13185 WM_CHANGE_STATE type. */
13186 {
13187 XEvent message;
58769bee 13188
c118dd06 13189 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 13190 message.xclient.type = ClientMessage;
334208b7 13191 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
13192 message.xclient.format = 32;
13193 message.xclient.data.l[0] = IconicState;
13194
334208b7
RS
13195 if (! XSendEvent (FRAME_X_DISPLAY (f),
13196 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
13197 False,
13198 SubstructureRedirectMask | SubstructureNotifyMask,
13199 &message))
dc6f92b8
JB
13200 {
13201 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13202 error ("Can't notify window manager of iconification");
dc6f92b8 13203 }
16bd92ea 13204 }
dc6f92b8 13205
58769bee 13206 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
13207 IconicState. */
13208 x_wm_set_window_state (f, IconicState);
dc6f92b8 13209
a9c00105
RS
13210 if (!FRAME_VISIBLE_P (f))
13211 {
13212 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 13213 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
13214 }
13215
3a88c238 13216 f->async_iconified = 1;
1e6bc770 13217 f->async_visible = 0;
dc6f92b8 13218
334208b7 13219 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 13220 UNBLOCK_INPUT;
8c002a25 13221#endif /* not USE_X_TOOLKIT */
dc6f92b8 13222}
19f71add 13223
d047c4eb 13224\f
19f71add 13225/* Free X resources of frame F. */
dc6f92b8 13226
dfcf069d 13227void
19f71add 13228x_free_frame_resources (f)
f676886a 13229 struct frame *f;
dc6f92b8 13230{
7f9c7f94 13231 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
c6ea2775
EZ
13232 Lisp_Object bar;
13233 struct scroll_bar *b;
7f9c7f94 13234
dc6f92b8 13235 BLOCK_INPUT;
c0ff3fab 13236
6186a4a0
RS
13237 /* If a display connection is dead, don't try sending more
13238 commands to the X server. */
19f71add 13239 if (dpyinfo->display)
6186a4a0 13240 {
19f71add 13241 if (f->output_data.x->icon_desc)
6186a4a0 13242 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
c6ea2775
EZ
13243
13244#ifdef USE_X_TOOLKIT
13245 /* Explicitly destroy the scroll bars of the frame. Without
13246 this, we get "BadDrawable" errors from the toolkit later on,
13247 presumably from expose events generated for the disappearing
13248 toolkit scroll bars. */
13249 for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next)
13250 {
13251 b = XSCROLL_BAR (bar);
13252 x_scroll_bar_remove (b);
13253 }
13254#endif
13255
31f41daf 13256#ifdef HAVE_X_I18N
f5d11644
GM
13257 if (FRAME_XIC (f))
13258 free_frame_xic (f);
31f41daf 13259#endif
c6ea2775 13260
3afe33e7 13261#ifdef USE_X_TOOLKIT
06a2c219 13262 if (f->output_data.x->widget)
30ca89f5
GM
13263 {
13264 XtDestroyWidget (f->output_data.x->widget);
13265 f->output_data.x->widget = NULL;
13266 }
c6ea2775
EZ
13267 /* Tooltips don't have widgets, only a simple X window, even if
13268 we are using a toolkit. */
13269 else if (FRAME_X_WINDOW (f))
13270 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13271
6186a4a0 13272 free_frame_menubar (f);
c6ea2775
EZ
13273#else /* !USE_X_TOOLKIT */
13274 if (FRAME_X_WINDOW (f))
13275 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13276#endif /* !USE_X_TOOLKIT */
3afe33e7 13277
3e71d8f2
GM
13278 unload_color (f, f->output_data.x->foreground_pixel);
13279 unload_color (f, f->output_data.x->background_pixel);
13280 unload_color (f, f->output_data.x->cursor_pixel);
13281 unload_color (f, f->output_data.x->cursor_foreground_pixel);
13282 unload_color (f, f->output_data.x->border_pixel);
13283 unload_color (f, f->output_data.x->mouse_pixel);
c6ea2775 13284
3e71d8f2
GM
13285 if (f->output_data.x->scroll_bar_background_pixel != -1)
13286 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
13287 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
13288 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
7c1bef7a
MB
13289#ifdef USE_TOOLKIT_SCROLL_BARS
13290 /* Scrollbar shadow colors. */
13291 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
13292 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
13293 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
13294 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
13295#endif /* USE_TOOLKIT_SCROLL_BARS */
3e71d8f2
GM
13296 if (f->output_data.x->white_relief.allocated_p)
13297 unload_color (f, f->output_data.x->white_relief.pixel);
13298 if (f->output_data.x->black_relief.allocated_p)
13299 unload_color (f, f->output_data.x->black_relief.pixel);
4ca78676 13300
19f71add
GM
13301 if (FRAME_FACE_CACHE (f))
13302 free_frame_faces (f);
13303
4ca78676 13304 x_free_gcs (f);
6186a4a0
RS
13305 XFlush (FRAME_X_DISPLAY (f));
13306 }
dc6f92b8 13307
df89d8a4 13308 if (f->output_data.x->saved_menu_event)
06a2c219 13309 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 13310
7556890b 13311 xfree (f->output_data.x);
19f71add
GM
13312 f->output_data.x = NULL;
13313
0f941935
KH
13314 if (f == dpyinfo->x_focus_frame)
13315 dpyinfo->x_focus_frame = 0;
13316 if (f == dpyinfo->x_focus_event_frame)
13317 dpyinfo->x_focus_event_frame = 0;
13318 if (f == dpyinfo->x_highlight_frame)
13319 dpyinfo->x_highlight_frame = 0;
c0ff3fab 13320
7f9c7f94 13321 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 13322 {
7f9c7f94
RS
13323 dpyinfo->mouse_face_beg_row
13324 = dpyinfo->mouse_face_beg_col = -1;
13325 dpyinfo->mouse_face_end_row
13326 = dpyinfo->mouse_face_end_col = -1;
13327 dpyinfo->mouse_face_window = Qnil;
21323706
RS
13328 dpyinfo->mouse_face_deferred_gc = 0;
13329 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 13330 }
0134a210 13331
c0ff3fab 13332 UNBLOCK_INPUT;
dc6f92b8 13333}
19f71add
GM
13334
13335
13336/* Destroy the X window of frame F. */
13337
13338void
13339x_destroy_window (f)
13340 struct frame *f;
13341{
13342 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13343
13344 /* If a display connection is dead, don't try sending more
13345 commands to the X server. */
13346 if (dpyinfo->display != 0)
13347 x_free_frame_resources (f);
13348
13349 dpyinfo->reference_count--;
13350}
13351
dc6f92b8 13352\f
f451eb13
JB
13353/* Setting window manager hints. */
13354
af31d76f
RS
13355/* Set the normal size hints for the window manager, for frame F.
13356 FLAGS is the flags word to use--or 0 meaning preserve the flags
13357 that the window now has.
13358 If USER_POSITION is nonzero, we set the USPosition
13359 flag (this is useful when FLAGS is 0). */
6dba1858 13360
dfcf069d 13361void
af31d76f 13362x_wm_set_size_hint (f, flags, user_position)
f676886a 13363 struct frame *f;
af31d76f
RS
13364 long flags;
13365 int user_position;
dc6f92b8
JB
13366{
13367 XSizeHints size_hints;
3afe33e7
RS
13368
13369#ifdef USE_X_TOOLKIT
7e4f2521
FP
13370 Arg al[2];
13371 int ac = 0;
13372 Dimension widget_width, widget_height;
7556890b 13373 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 13374#else /* not USE_X_TOOLKIT */
c118dd06 13375 Window window = FRAME_X_WINDOW (f);
3afe33e7 13376#endif /* not USE_X_TOOLKIT */
dc6f92b8 13377
b72a58fd
RS
13378 /* Setting PMaxSize caused various problems. */
13379 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 13380
7556890b
RS
13381 size_hints.x = f->output_data.x->left_pos;
13382 size_hints.y = f->output_data.x->top_pos;
7553a6b7 13383
7e4f2521
FP
13384#ifdef USE_X_TOOLKIT
13385 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
13386 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 13387 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
13388 size_hints.height = widget_height;
13389 size_hints.width = widget_width;
13390#else /* not USE_X_TOOLKIT */
f676886a
JB
13391 size_hints.height = PIXEL_HEIGHT (f);
13392 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 13393#endif /* not USE_X_TOOLKIT */
7553a6b7 13394
7556890b
RS
13395 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
13396 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
13397 size_hints.max_width
13398 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
13399 size_hints.max_height
13400 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 13401
d067ea8b
KH
13402 /* Calculate the base and minimum sizes.
13403
13404 (When we use the X toolkit, we don't do it here.
13405 Instead we copy the values that the widgets are using, below.) */
13406#ifndef USE_X_TOOLKIT
b1c884c3 13407 {
b0342f17 13408 int base_width, base_height;
0134a210 13409 int min_rows = 0, min_cols = 0;
b0342f17 13410
f451eb13
JB
13411 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
13412 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 13413
0134a210 13414 check_frame_size (f, &min_rows, &min_cols);
b0342f17 13415
0134a210
RS
13416 /* The window manager uses the base width hints to calculate the
13417 current number of rows and columns in the frame while
13418 resizing; min_width and min_height aren't useful for this
13419 purpose, since they might not give the dimensions for a
13420 zero-row, zero-column frame.
58769bee 13421
0134a210
RS
13422 We use the base_width and base_height members if we have
13423 them; otherwise, we set the min_width and min_height members
13424 to the size for a zero x zero frame. */
b0342f17
JB
13425
13426#ifdef HAVE_X11R4
0134a210
RS
13427 size_hints.flags |= PBaseSize;
13428 size_hints.base_width = base_width;
13429 size_hints.base_height = base_height;
13430 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
13431 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 13432#else
0134a210
RS
13433 size_hints.min_width = base_width;
13434 size_hints.min_height = base_height;
b0342f17 13435#endif
b1c884c3 13436 }
dc6f92b8 13437
d067ea8b 13438 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 13439 if (flags)
dc6f92b8 13440 {
d067ea8b
KH
13441 size_hints.flags |= flags;
13442 goto no_read;
13443 }
13444#endif /* not USE_X_TOOLKIT */
13445
13446 {
13447 XSizeHints hints; /* Sometimes I hate X Windows... */
13448 long supplied_return;
13449 int value;
af31d76f
RS
13450
13451#ifdef HAVE_X11R4
d067ea8b
KH
13452 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
13453 &supplied_return);
af31d76f 13454#else
d067ea8b 13455 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 13456#endif
58769bee 13457
d067ea8b
KH
13458#ifdef USE_X_TOOLKIT
13459 size_hints.base_height = hints.base_height;
13460 size_hints.base_width = hints.base_width;
13461 size_hints.min_height = hints.min_height;
13462 size_hints.min_width = hints.min_width;
13463#endif
13464
13465 if (flags)
13466 size_hints.flags |= flags;
13467 else
13468 {
13469 if (value == 0)
13470 hints.flags = 0;
13471 if (hints.flags & PSize)
13472 size_hints.flags |= PSize;
13473 if (hints.flags & PPosition)
13474 size_hints.flags |= PPosition;
13475 if (hints.flags & USPosition)
13476 size_hints.flags |= USPosition;
13477 if (hints.flags & USSize)
13478 size_hints.flags |= USSize;
13479 }
13480 }
13481
06a2c219 13482#ifndef USE_X_TOOLKIT
d067ea8b 13483 no_read:
06a2c219 13484#endif
0134a210 13485
af31d76f 13486#ifdef PWinGravity
7556890b 13487 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 13488 size_hints.flags |= PWinGravity;
dc05a16b 13489
af31d76f 13490 if (user_position)
6dba1858 13491 {
af31d76f
RS
13492 size_hints.flags &= ~ PPosition;
13493 size_hints.flags |= USPosition;
6dba1858 13494 }
2554751d 13495#endif /* PWinGravity */
6dba1858 13496
b0342f17 13497#ifdef HAVE_X11R4
334208b7 13498 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13499#else
334208b7 13500 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13501#endif
dc6f92b8
JB
13502}
13503
13504/* Used for IconicState or NormalState */
06a2c219 13505
dfcf069d 13506void
f676886a
JB
13507x_wm_set_window_state (f, state)
13508 struct frame *f;
dc6f92b8
JB
13509 int state;
13510{
3afe33e7 13511#ifdef USE_X_TOOLKIT
546e6d5b
RS
13512 Arg al[1];
13513
13514 XtSetArg (al[0], XtNinitialState, state);
7556890b 13515 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 13516#else /* not USE_X_TOOLKIT */
c118dd06 13517 Window window = FRAME_X_WINDOW (f);
dc6f92b8 13518
7556890b
RS
13519 f->output_data.x->wm_hints.flags |= StateHint;
13520 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 13521
7556890b 13522 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 13523#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13524}
13525
dfcf069d 13526void
7f2ae036 13527x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 13528 struct frame *f;
7f2ae036 13529 int pixmap_id;
dc6f92b8 13530{
d2bd6bc4
RS
13531 Pixmap icon_pixmap;
13532
06a2c219 13533#ifndef USE_X_TOOLKIT
c118dd06 13534 Window window = FRAME_X_WINDOW (f);
75231bad 13535#endif
dc6f92b8 13536
7f2ae036 13537 if (pixmap_id > 0)
dbc4e1c1 13538 {
d2bd6bc4 13539 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 13540 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
13541 }
13542 else
68568555
RS
13543 {
13544 /* It seems there is no way to turn off use of an icon pixmap.
13545 The following line does it, only if no icon has yet been created,
13546 for some window managers. But with mwm it crashes.
13547 Some people say it should clear the IconPixmapHint bit in this case,
13548 but that doesn't work, and the X consortium said it isn't the
13549 right thing at all. Since there is no way to win,
13550 best to explicitly give up. */
13551#if 0
13552 f->output_data.x->wm_hints.icon_pixmap = None;
13553#else
13554 return;
13555#endif
13556 }
b1c884c3 13557
d2bd6bc4
RS
13558#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
13559
13560 {
13561 Arg al[1];
13562 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
13563 XtSetValues (f->output_data.x->widget, al, 1);
13564 }
13565
13566#else /* not USE_X_TOOLKIT */
13567
7556890b
RS
13568 f->output_data.x->wm_hints.flags |= IconPixmapHint;
13569 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
13570
13571#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13572}
13573
dfcf069d 13574void
f676886a
JB
13575x_wm_set_icon_position (f, icon_x, icon_y)
13576 struct frame *f;
dc6f92b8
JB
13577 int icon_x, icon_y;
13578{
75231bad 13579#ifdef USE_X_TOOLKIT
7556890b 13580 Window window = XtWindow (f->output_data.x->widget);
75231bad 13581#else
c118dd06 13582 Window window = FRAME_X_WINDOW (f);
75231bad 13583#endif
dc6f92b8 13584
7556890b
RS
13585 f->output_data.x->wm_hints.flags |= IconPositionHint;
13586 f->output_data.x->wm_hints.icon_x = icon_x;
13587 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 13588
7556890b 13589 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
13590}
13591
13592\f
06a2c219
GM
13593/***********************************************************************
13594 Fonts
13595 ***********************************************************************/
dc43ef94
KH
13596
13597/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 13598
dc43ef94
KH
13599struct font_info *
13600x_get_font_info (f, font_idx)
13601 FRAME_PTR f;
13602 int font_idx;
13603{
13604 return (FRAME_X_FONT_TABLE (f) + font_idx);
13605}
13606
13607
9c11f79e
GM
13608/* Return a list of names of available fonts matching PATTERN on frame F.
13609
13610 If SIZE is > 0, it is the size (maximum bounds width) of fonts
13611 to be listed.
13612
13613 SIZE < 0 means include scalable fonts.
13614
13615 Frame F null means we have not yet created any frame on X, and
13616 consult the first display in x_display_list. MAXNAMES sets a limit
13617 on how many fonts to match. */
dc43ef94
KH
13618
13619Lisp_Object
13620x_list_fonts (f, pattern, size, maxnames)
9c11f79e 13621 struct frame *f;
dc43ef94
KH
13622 Lisp_Object pattern;
13623 int size;
13624 int maxnames;
13625{
06a2c219
GM
13626 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
13627 Lisp_Object tem, second_best;
9c11f79e
GM
13628 struct x_display_info *dpyinfo
13629 = f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
13630 Display *dpy = dpyinfo->display;
09c6077f 13631 int try_XLoadQueryFont = 0;
53ca4657 13632 int count;
9c11f79e
GM
13633 int allow_scalable_fonts_p = 0;
13634
13635 if (size < 0)
13636 {
13637 allow_scalable_fonts_p = 1;
13638 size = 0;
13639 }
dc43ef94 13640
6b0efe73 13641 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
13642 if (NILP (patterns))
13643 patterns = Fcons (pattern, Qnil);
81ba44e5 13644
09c6077f
KH
13645 if (maxnames == 1 && !size)
13646 /* We can return any single font matching PATTERN. */
13647 try_XLoadQueryFont = 1;
9a32686f 13648
8e713be6 13649 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 13650 {
dc43ef94 13651 int num_fonts;
3e71d8f2 13652 char **names = NULL;
dc43ef94 13653
8e713be6 13654 pattern = XCAR (patterns);
536f4067
RS
13655 /* See if we cached the result for this particular query.
13656 The cache is an alist of the form:
9c11f79e
GM
13657 ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */
13658 tem = XCDR (dpyinfo->name_list_element);
13659 key = Fcons (Fcons (pattern, make_number (maxnames)),
13660 allow_scalable_fonts_p ? Qt : Qnil);
13661 list = Fassoc (key, tem);
13662 if (!NILP (list))
b5210ea7
KH
13663 {
13664 list = Fcdr_safe (list);
13665 /* We have a cashed list. Don't have to get the list again. */
13666 goto label_cached;
13667 }
13668
13669 /* At first, put PATTERN in the cache. */
09c6077f 13670
dc43ef94 13671 BLOCK_INPUT;
17d85edc
KH
13672 count = x_catch_errors (dpy);
13673
09c6077f
KH
13674 if (try_XLoadQueryFont)
13675 {
13676 XFontStruct *font;
13677 unsigned long value;
13678
13679 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
13680 if (x_had_errors_p (dpy))
13681 {
13682 /* This error is perhaps due to insufficient memory on X
13683 server. Let's just ignore it. */
13684 font = NULL;
13685 x_clear_errors (dpy);
13686 }
13687
09c6077f
KH
13688 if (font
13689 && XGetFontProperty (font, XA_FONT, &value))
13690 {
13691 char *name = (char *) XGetAtomName (dpy, (Atom) value);
13692 int len = strlen (name);
01c752b5 13693 char *tmp;
09c6077f 13694
6f6512e8
KH
13695 /* If DXPC (a Differential X Protocol Compressor)
13696 Ver.3.7 is running, XGetAtomName will return null
13697 string. We must avoid such a name. */
13698 if (len == 0)
13699 try_XLoadQueryFont = 0;
13700 else
13701 {
13702 num_fonts = 1;
13703 names = (char **) alloca (sizeof (char *));
13704 /* Some systems only allow alloca assigned to a
13705 simple var. */
13706 tmp = (char *) alloca (len + 1); names[0] = tmp;
13707 bcopy (name, names[0], len + 1);
13708 XFree (name);
13709 }
09c6077f
KH
13710 }
13711 else
13712 try_XLoadQueryFont = 0;
a083fd23
RS
13713
13714 if (font)
13715 XFreeFont (dpy, font);
09c6077f
KH
13716 }
13717
13718 if (!try_XLoadQueryFont)
17d85edc
KH
13719 {
13720 /* We try at least 10 fonts because XListFonts will return
13721 auto-scaled fonts at the head. */
13722 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
13723 &num_fonts);
13724 if (x_had_errors_p (dpy))
13725 {
13726 /* This error is perhaps due to insufficient memory on X
13727 server. Let's just ignore it. */
13728 names = NULL;
13729 x_clear_errors (dpy);
13730 }
13731 }
13732
13733 x_uncatch_errors (dpy, count);
dc43ef94
KH
13734 UNBLOCK_INPUT;
13735
13736 if (names)
13737 {
13738 int i;
dc43ef94
KH
13739
13740 /* Make a list of all the fonts we got back.
13741 Store that in the font cache for the display. */
13742 for (i = 0; i < num_fonts; i++)
13743 {
06a2c219 13744 int width = 0;
dc43ef94 13745 char *p = names[i];
06a2c219
GM
13746 int average_width = -1, dashes = 0;
13747
dc43ef94 13748 /* Count the number of dashes in NAMES[I]. If there are
9c11f79e
GM
13749 14 dashes, and the field value following 12th dash
13750 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
13751 is usually too ugly to be used for editing. Let's
13752 ignore it. */
dc43ef94
KH
13753 while (*p)
13754 if (*p++ == '-')
13755 {
13756 dashes++;
13757 if (dashes == 7) /* PIXEL_SIZE field */
13758 width = atoi (p);
13759 else if (dashes == 12) /* AVERAGE_WIDTH field */
13760 average_width = atoi (p);
13761 }
9c11f79e
GM
13762
13763 if (allow_scalable_fonts_p
13764 || dashes < 14 || average_width != 0)
dc43ef94
KH
13765 {
13766 tem = build_string (names[i]);
13767 if (NILP (Fassoc (tem, list)))
13768 {
13769 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
13770 && ((fast_c_string_match_ignore_case
13771 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
13772 >= 0))
13773 /* We can set the value of PIXEL_SIZE to the
b5210ea7 13774 width of this font. */
dc43ef94
KH
13775 list = Fcons (Fcons (tem, make_number (width)), list);
13776 else
13777 /* For the moment, width is not known. */
13778 list = Fcons (Fcons (tem, Qnil), list);
13779 }
13780 }
13781 }
e38f4136 13782
09c6077f 13783 if (!try_XLoadQueryFont)
e38f4136
GM
13784 {
13785 BLOCK_INPUT;
13786 XFreeFontNames (names);
13787 UNBLOCK_INPUT;
13788 }
dc43ef94
KH
13789 }
13790
b5210ea7 13791 /* Now store the result in the cache. */
f3fbd155
KR
13792 XSETCDR (dpyinfo->name_list_element,
13793 Fcons (Fcons (key, list), XCDR (dpyinfo->name_list_element)));
dc43ef94 13794
b5210ea7
KH
13795 label_cached:
13796 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 13797
b5210ea7
KH
13798 newlist = second_best = Qnil;
13799 /* Make a list of the fonts that have the right width. */
8e713be6 13800 for (; CONSP (list); list = XCDR (list))
b5210ea7 13801 {
536f4067
RS
13802 int found_size;
13803
8e713be6 13804 tem = XCAR (list);
dc43ef94 13805
8e713be6 13806 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
13807 continue;
13808 if (!size)
13809 {
8e713be6 13810 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
13811 continue;
13812 }
dc43ef94 13813
8e713be6 13814 if (!INTEGERP (XCDR (tem)))
dc43ef94 13815 {
b5210ea7 13816 /* Since we have not yet known the size of this font, we
9c11f79e 13817 must try slow function call XLoadQueryFont. */
dc43ef94
KH
13818 XFontStruct *thisinfo;
13819
13820 BLOCK_INPUT;
17d85edc 13821 count = x_catch_errors (dpy);
dc43ef94 13822 thisinfo = XLoadQueryFont (dpy,
8e713be6 13823 XSTRING (XCAR (tem))->data);
17d85edc
KH
13824 if (x_had_errors_p (dpy))
13825 {
13826 /* This error is perhaps due to insufficient memory on X
13827 server. Let's just ignore it. */
13828 thisinfo = NULL;
13829 x_clear_errors (dpy);
13830 }
13831 x_uncatch_errors (dpy, count);
dc43ef94
KH
13832 UNBLOCK_INPUT;
13833
13834 if (thisinfo)
13835 {
f3fbd155
KR
13836 XSETCDR (tem,
13837 (thisinfo->min_bounds.width == 0
13838 ? make_number (0)
13839 : make_number (thisinfo->max_bounds.width)));
e38f4136 13840 BLOCK_INPUT;
dc43ef94 13841 XFreeFont (dpy, thisinfo);
e38f4136 13842 UNBLOCK_INPUT;
dc43ef94
KH
13843 }
13844 else
b5210ea7 13845 /* For unknown reason, the previous call of XListFont had
06a2c219 13846 returned a font which can't be opened. Record the size
b5210ea7 13847 as 0 not to try to open it again. */
f3fbd155 13848 XSETCDR (tem, make_number (0));
dc43ef94 13849 }
536f4067 13850
8e713be6 13851 found_size = XINT (XCDR (tem));
536f4067 13852 if (found_size == size)
8e713be6 13853 newlist = Fcons (XCAR (tem), newlist);
536f4067 13854 else if (found_size > 0)
b5210ea7 13855 {
536f4067 13856 if (NILP (second_best))
b5210ea7 13857 second_best = tem;
536f4067
RS
13858 else if (found_size < size)
13859 {
8e713be6
KR
13860 if (XINT (XCDR (second_best)) > size
13861 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
13862 second_best = tem;
13863 }
13864 else
13865 {
8e713be6
KR
13866 if (XINT (XCDR (second_best)) > size
13867 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
13868 second_best = tem;
13869 }
b5210ea7
KH
13870 }
13871 }
13872 if (!NILP (newlist))
13873 break;
13874 else if (!NILP (second_best))
13875 {
8e713be6 13876 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 13877 break;
dc43ef94 13878 }
dc43ef94
KH
13879 }
13880
13881 return newlist;
13882}
13883
06a2c219
GM
13884
13885#if GLYPH_DEBUG
13886
13887/* Check that FONT is valid on frame F. It is if it can be found in F's
13888 font table. */
13889
13890static void
13891x_check_font (f, font)
13892 struct frame *f;
13893 XFontStruct *font;
13894{
13895 int i;
13896 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13897
13898 xassert (font != NULL);
13899
13900 for (i = 0; i < dpyinfo->n_fonts; i++)
13901 if (dpyinfo->font_table[i].name
13902 && font == dpyinfo->font_table[i].font)
13903 break;
13904
13905 xassert (i < dpyinfo->n_fonts);
13906}
13907
13908#endif /* GLYPH_DEBUG != 0 */
13909
13910/* Set *W to the minimum width, *H to the minimum font height of FONT.
13911 Note: There are (broken) X fonts out there with invalid XFontStruct
13912 min_bounds contents. For example, handa@etl.go.jp reports that
13913 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
13914 have font->min_bounds.width == 0. */
13915
13916static INLINE void
13917x_font_min_bounds (font, w, h)
13918 XFontStruct *font;
13919 int *w, *h;
13920{
13921 *h = FONT_HEIGHT (font);
13922 *w = font->min_bounds.width;
13923
13924 /* Try to handle the case where FONT->min_bounds has invalid
13925 contents. Since the only font known to have invalid min_bounds
13926 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
13927 if (*w <= 0)
13928 *w = font->max_bounds.width;
13929}
13930
13931
13932/* Compute the smallest character width and smallest font height over
13933 all fonts available on frame F. Set the members smallest_char_width
13934 and smallest_font_height in F's x_display_info structure to
13935 the values computed. Value is non-zero if smallest_font_height or
13936 smallest_char_width become smaller than they were before. */
13937
13938static int
13939x_compute_min_glyph_bounds (f)
13940 struct frame *f;
13941{
13942 int i;
13943 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13944 XFontStruct *font;
13945 int old_width = dpyinfo->smallest_char_width;
13946 int old_height = dpyinfo->smallest_font_height;
13947
13948 dpyinfo->smallest_font_height = 100000;
13949 dpyinfo->smallest_char_width = 100000;
13950
13951 for (i = 0; i < dpyinfo->n_fonts; ++i)
13952 if (dpyinfo->font_table[i].name)
13953 {
13954 struct font_info *fontp = dpyinfo->font_table + i;
13955 int w, h;
13956
13957 font = (XFontStruct *) fontp->font;
13958 xassert (font != (XFontStruct *) ~0);
13959 x_font_min_bounds (font, &w, &h);
13960
13961 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
13962 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
13963 }
13964
13965 xassert (dpyinfo->smallest_char_width > 0
13966 && dpyinfo->smallest_font_height > 0);
13967
13968 return (dpyinfo->n_fonts == 1
13969 || dpyinfo->smallest_char_width < old_width
13970 || dpyinfo->smallest_font_height < old_height);
13971}
13972
13973
dc43ef94
KH
13974/* Load font named FONTNAME of the size SIZE for frame F, and return a
13975 pointer to the structure font_info while allocating it dynamically.
13976 If SIZE is 0, load any size of font.
13977 If loading is failed, return NULL. */
13978
13979struct font_info *
13980x_load_font (f, fontname, size)
13981 struct frame *f;
13982 register char *fontname;
13983 int size;
13984{
13985 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13986 Lisp_Object font_names;
d645aaa4 13987 int count;
dc43ef94
KH
13988
13989 /* Get a list of all the fonts that match this name. Once we
13990 have a list of matching fonts, we compare them against the fonts
13991 we already have by comparing names. */
09c6077f 13992 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
13993
13994 if (!NILP (font_names))
13995 {
13996 Lisp_Object tail;
13997 int i;
13998
13999 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 14000 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
14001 if (dpyinfo->font_table[i].name
14002 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 14003 XSTRING (XCAR (tail))->data)
06a2c219 14004 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 14005 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
14006 return (dpyinfo->font_table + i);
14007 }
14008
14009 /* Load the font and add it to the table. */
14010 {
14011 char *full_name;
14012 XFontStruct *font;
14013 struct font_info *fontp;
14014 unsigned long value;
06a2c219 14015 int i;
dc43ef94 14016
2da424f1
KH
14017 /* If we have found fonts by x_list_font, load one of them. If
14018 not, we still try to load a font by the name given as FONTNAME
14019 because XListFonts (called in x_list_font) of some X server has
14020 a bug of not finding a font even if the font surely exists and
14021 is loadable by XLoadQueryFont. */
e1d6d5b9 14022 if (size > 0 && !NILP (font_names))
8e713be6 14023 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
14024
14025 BLOCK_INPUT;
d645aaa4 14026 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 14027 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
14028 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
14029 {
14030 /* This error is perhaps due to insufficient memory on X
14031 server. Let's just ignore it. */
14032 font = NULL;
14033 x_clear_errors (FRAME_X_DISPLAY (f));
14034 }
14035 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 14036 UNBLOCK_INPUT;
b5210ea7 14037 if (!font)
dc43ef94
KH
14038 return NULL;
14039
06a2c219
GM
14040 /* Find a free slot in the font table. */
14041 for (i = 0; i < dpyinfo->n_fonts; ++i)
14042 if (dpyinfo->font_table[i].name == NULL)
14043 break;
14044
14045 /* If no free slot found, maybe enlarge the font table. */
14046 if (i == dpyinfo->n_fonts
14047 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 14048 {
06a2c219
GM
14049 int sz;
14050 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
14051 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 14052 dpyinfo->font_table
06a2c219 14053 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
14054 }
14055
06a2c219
GM
14056 fontp = dpyinfo->font_table + i;
14057 if (i == dpyinfo->n_fonts)
14058 ++dpyinfo->n_fonts;
dc43ef94
KH
14059
14060 /* Now fill in the slots of *FONTP. */
14061 BLOCK_INPUT;
14062 fontp->font = font;
06a2c219 14063 fontp->font_idx = i;
dc43ef94
KH
14064 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
14065 bcopy (fontname, fontp->name, strlen (fontname) + 1);
14066
14067 /* Try to get the full name of FONT. Put it in FULL_NAME. */
14068 full_name = 0;
14069 if (XGetFontProperty (font, XA_FONT, &value))
14070 {
14071 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
14072 char *p = name;
14073 int dashes = 0;
14074
14075 /* Count the number of dashes in the "full name".
14076 If it is too few, this isn't really the font's full name,
14077 so don't use it.
14078 In X11R4, the fonts did not come with their canonical names
14079 stored in them. */
14080 while (*p)
14081 {
14082 if (*p == '-')
14083 dashes++;
14084 p++;
14085 }
14086
14087 if (dashes >= 13)
14088 {
14089 full_name = (char *) xmalloc (p - name + 1);
14090 bcopy (name, full_name, p - name + 1);
14091 }
14092
14093 XFree (name);
14094 }
14095
14096 if (full_name != 0)
14097 fontp->full_name = full_name;
14098 else
14099 fontp->full_name = fontp->name;
14100
14101 fontp->size = font->max_bounds.width;
d5749adb 14102 fontp->height = FONT_HEIGHT (font);
dc43ef94 14103
2da424f1
KH
14104 if (NILP (font_names))
14105 {
14106 /* We come here because of a bug of XListFonts mentioned at
14107 the head of this block. Let's store this information in
14108 the cache for x_list_fonts. */
14109 Lisp_Object lispy_name = build_string (fontname);
14110 Lisp_Object lispy_full_name = build_string (fontp->full_name);
9c11f79e
GM
14111 Lisp_Object key = Fcons (Fcons (lispy_name, make_number (256)),
14112 Qnil);
2da424f1 14113
f3fbd155
KR
14114 XSETCDR (dpyinfo->name_list_element,
14115 Fcons (Fcons (key,
14116 Fcons (Fcons (lispy_full_name,
14117 make_number (fontp->size)),
14118 Qnil)),
14119 XCDR (dpyinfo->name_list_element)));
2da424f1 14120 if (full_name)
9c11f79e
GM
14121 {
14122 key = Fcons (Fcons (lispy_full_name, make_number (256)),
14123 Qnil);
f3fbd155
KR
14124 XSETCDR (dpyinfo->name_list_element,
14125 Fcons (Fcons (key,
14126 Fcons (Fcons (lispy_full_name,
14127 make_number (fontp->size)),
14128 Qnil)),
14129 XCDR (dpyinfo->name_list_element)));
9c11f79e 14130 }
2da424f1
KH
14131 }
14132
dc43ef94
KH
14133 /* The slot `encoding' specifies how to map a character
14134 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
14135 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
14136 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 14137 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 14138 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
14139 which is never used by any charset. If mapping can't be
14140 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
14141 fontp->encoding[1]
14142 = (font->max_byte1 == 0
14143 /* 1-byte font */
14144 ? (font->min_char_or_byte2 < 0x80
14145 ? (font->max_char_or_byte2 < 0x80
14146 ? 0 /* 0x20..0x7F */
8ff102bd 14147 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
14148 : 1) /* 0xA0..0xFF */
14149 /* 2-byte font */
14150 : (font->min_byte1 < 0x80
14151 ? (font->max_byte1 < 0x80
14152 ? (font->min_char_or_byte2 < 0x80
14153 ? (font->max_char_or_byte2 < 0x80
14154 ? 0 /* 0x2020..0x7F7F */
8ff102bd 14155 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 14156 : 3) /* 0x20A0..0x7FFF */
8ff102bd 14157 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
14158 : (font->min_char_or_byte2 < 0x80
14159 ? (font->max_char_or_byte2 < 0x80
14160 ? 2 /* 0xA020..0xFF7F */
8ff102bd 14161 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
14162 : 1))); /* 0xA0A0..0xFFFF */
14163
14164 fontp->baseline_offset
14165 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
14166 ? (long) value : 0);
14167 fontp->relative_compose
14168 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
14169 ? (long) value : 0);
f78798df
KH
14170 fontp->default_ascent
14171 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
14172 ? (long) value : 0);
dc43ef94 14173
06a2c219
GM
14174 /* Set global flag fonts_changed_p to non-zero if the font loaded
14175 has a character with a smaller width than any other character
14176 before, or if the font loaded has a smalle>r height than any
14177 other font loaded before. If this happens, it will make a
14178 glyph matrix reallocation necessary. */
14179 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 14180 UNBLOCK_INPUT;
dc43ef94
KH
14181 return fontp;
14182 }
14183}
14184
06a2c219
GM
14185
14186/* Return a pointer to struct font_info of a font named FONTNAME for
14187 frame F. If no such font is loaded, return NULL. */
14188
dc43ef94
KH
14189struct font_info *
14190x_query_font (f, fontname)
14191 struct frame *f;
14192 register char *fontname;
14193{
14194 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14195 int i;
14196
14197 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
14198 if (dpyinfo->font_table[i].name
14199 && (!strcmp (dpyinfo->font_table[i].name, fontname)
14200 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
14201 return (dpyinfo->font_table + i);
14202 return NULL;
14203}
14204
06a2c219
GM
14205
14206/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
14207 `encoder' of the structure. */
14208
14209void
14210x_find_ccl_program (fontp)
14211 struct font_info *fontp;
14212{
a42f54e6 14213 Lisp_Object list, elt;
a6582676 14214
f9b5db02 14215 elt = Qnil;
8e713be6 14216 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 14217 {
8e713be6 14218 elt = XCAR (list);
a6582676 14219 if (CONSP (elt)
8e713be6 14220 && STRINGP (XCAR (elt))
9f2feff6
KH
14221 && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
14222 >= 0)
14223 || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
14224 >= 0)))
a42f54e6
KH
14225 break;
14226 }
f9b5db02 14227
a42f54e6
KH
14228 if (! NILP (list))
14229 {
d27f8ca7
KH
14230 struct ccl_program *ccl
14231 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 14232
8e713be6 14233 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
14234 xfree (ccl);
14235 else
14236 fontp->font_encoder = ccl;
a6582676
KH
14237 }
14238}
14239
06a2c219 14240
dc43ef94 14241\f
06a2c219
GM
14242/***********************************************************************
14243 Initialization
14244 ***********************************************************************/
f451eb13 14245
3afe33e7
RS
14246#ifdef USE_X_TOOLKIT
14247static XrmOptionDescRec emacs_options[] = {
14248 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
14249 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
14250
14251 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
14252 XrmoptionSepArg, NULL},
14253 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
14254
14255 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14256 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14257 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14258 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14259 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14260 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
14261 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
14262};
14263#endif /* USE_X_TOOLKIT */
14264
7a13e894
RS
14265static int x_initialized;
14266
29b38361
KH
14267#ifdef MULTI_KBOARD
14268/* Test whether two display-name strings agree up to the dot that separates
14269 the screen number from the server number. */
14270static int
14271same_x_server (name1, name2)
14272 char *name1, *name2;
14273{
14274 int seen_colon = 0;
cf591cc1
RS
14275 unsigned char *system_name = XSTRING (Vsystem_name)->data;
14276 int system_name_length = strlen (system_name);
14277 int length_until_period = 0;
14278
14279 while (system_name[length_until_period] != 0
14280 && system_name[length_until_period] != '.')
14281 length_until_period++;
14282
14283 /* Treat `unix' like an empty host name. */
14284 if (! strncmp (name1, "unix:", 5))
14285 name1 += 4;
14286 if (! strncmp (name2, "unix:", 5))
14287 name2 += 4;
14288 /* Treat this host's name like an empty host name. */
14289 if (! strncmp (name1, system_name, system_name_length)
14290 && name1[system_name_length] == ':')
14291 name1 += system_name_length;
14292 if (! strncmp (name2, system_name, system_name_length)
14293 && name2[system_name_length] == ':')
14294 name2 += system_name_length;
14295 /* Treat this host's domainless name like an empty host name. */
14296 if (! strncmp (name1, system_name, length_until_period)
14297 && name1[length_until_period] == ':')
14298 name1 += length_until_period;
14299 if (! strncmp (name2, system_name, length_until_period)
14300 && name2[length_until_period] == ':')
14301 name2 += length_until_period;
14302
29b38361
KH
14303 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
14304 {
14305 if (*name1 == ':')
14306 seen_colon++;
14307 if (seen_colon && *name1 == '.')
14308 return 1;
14309 }
14310 return (seen_colon
14311 && (*name1 == '.' || *name1 == '\0')
14312 && (*name2 == '.' || *name2 == '\0'));
14313}
14314#endif
14315
334208b7 14316struct x_display_info *
1f8255f2 14317x_term_init (display_name, xrm_option, resource_name)
334208b7 14318 Lisp_Object display_name;
1f8255f2
RS
14319 char *xrm_option;
14320 char *resource_name;
dc6f92b8 14321{
334208b7 14322 int connection;
7a13e894 14323 Display *dpy;
334208b7
RS
14324 struct x_display_info *dpyinfo;
14325 XrmDatabase xrdb;
14326
60439948
KH
14327 BLOCK_INPUT;
14328
7a13e894
RS
14329 if (!x_initialized)
14330 {
14331 x_initialize ();
14332 x_initialized = 1;
14333 }
dc6f92b8 14334
3afe33e7 14335#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
14336 /* weiner@footloose.sps.mot.com reports that this causes
14337 errors with X11R5:
14338 X protocol error: BadAtom (invalid Atom parameter)
14339 on protocol request 18skiloaf.
14340 So let's not use it until R6. */
14341#ifdef HAVE_X11XTR6
bdcd49ba
RS
14342 XtSetLanguageProc (NULL, NULL, NULL);
14343#endif
14344
7f9c7f94
RS
14345 {
14346 int argc = 0;
14347 char *argv[3];
14348
14349 argv[0] = "";
14350 argc = 1;
14351 if (xrm_option)
14352 {
14353 argv[argc++] = "-xrm";
14354 argv[argc++] = xrm_option;
14355 }
14356 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
14357 resource_name, EMACS_CLASS,
14358 emacs_options, XtNumber (emacs_options),
14359 &argc, argv);
39d8bb4d
KH
14360
14361#ifdef HAVE_X11XTR6
10537cb1 14362 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 14363 fixup_locale ();
39d8bb4d 14364#endif
7f9c7f94 14365 }
3afe33e7
RS
14366
14367#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
14368#ifdef HAVE_X11R5
14369 XSetLocaleModifiers ("");
14370#endif
7a13e894 14371 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 14372#endif /* not USE_X_TOOLKIT */
334208b7 14373
7a13e894
RS
14374 /* Detect failure. */
14375 if (dpy == 0)
60439948
KH
14376 {
14377 UNBLOCK_INPUT;
14378 return 0;
14379 }
7a13e894
RS
14380
14381 /* We have definitely succeeded. Record the new connection. */
14382
14383 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
f04e1297 14384 bzero (dpyinfo, sizeof *dpyinfo);
7a13e894 14385
29b38361
KH
14386#ifdef MULTI_KBOARD
14387 {
14388 struct x_display_info *share;
14389 Lisp_Object tail;
14390
14391 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
14392 share = share->next, tail = XCDR (tail))
14393 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
14394 XSTRING (display_name)->data))
14395 break;
14396 if (share)
14397 dpyinfo->kboard = share->kboard;
14398 else
14399 {
14400 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
14401 init_kboard (dpyinfo->kboard);
59e755be
KH
14402 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
14403 {
14404 char *vendor = ServerVendor (dpy);
9b6ed9f3 14405 UNBLOCK_INPUT;
59e755be
KH
14406 dpyinfo->kboard->Vsystem_key_alist
14407 = call1 (Qvendor_specific_keysyms,
14408 build_string (vendor ? vendor : ""));
9b6ed9f3 14409 BLOCK_INPUT;
59e755be
KH
14410 }
14411
29b38361
KH
14412 dpyinfo->kboard->next_kboard = all_kboards;
14413 all_kboards = dpyinfo->kboard;
0ad5446c
KH
14414 /* Don't let the initial kboard remain current longer than necessary.
14415 That would cause problems if a file loaded on startup tries to
06a2c219 14416 prompt in the mini-buffer. */
0ad5446c
KH
14417 if (current_kboard == initial_kboard)
14418 current_kboard = dpyinfo->kboard;
29b38361
KH
14419 }
14420 dpyinfo->kboard->reference_count++;
14421 }
b9737ad3
KH
14422#endif
14423
7a13e894
RS
14424 /* Put this display on the chain. */
14425 dpyinfo->next = x_display_list;
14426 x_display_list = dpyinfo;
14427
14428 /* Put it on x_display_name_list as well, to keep them parallel. */
14429 x_display_name_list = Fcons (Fcons (display_name, Qnil),
14430 x_display_name_list);
8e713be6 14431 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
14432
14433 dpyinfo->display = dpy;
dc6f92b8 14434
dc6f92b8 14435#if 0
7a13e894 14436 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 14437#endif /* ! 0 */
7a13e894
RS
14438
14439 dpyinfo->x_id_name
fc932ac6
RS
14440 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
14441 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
14442 + 2);
14443 sprintf (dpyinfo->x_id_name, "%s@%s",
14444 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
14445
14446 /* Figure out which modifier bits mean what. */
334208b7 14447 x_find_modifier_meanings (dpyinfo);
f451eb13 14448
ab648270 14449 /* Get the scroll bar cursor. */
7a13e894 14450 dpyinfo->vertical_scroll_bar_cursor
334208b7 14451 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 14452
334208b7
RS
14453 xrdb = x_load_resources (dpyinfo->display, xrm_option,
14454 resource_name, EMACS_CLASS);
14455#ifdef HAVE_XRMSETDATABASE
14456 XrmSetDatabase (dpyinfo->display, xrdb);
14457#else
14458 dpyinfo->display->db = xrdb;
14459#endif
547d9db8 14460 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
14461 all versions. */
14462 dpyinfo->xrdb = xrdb;
334208b7
RS
14463
14464 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
14465 DefaultScreen (dpyinfo->display));
5ff67d81 14466 select_visual (dpyinfo);
43bd1b2b 14467 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
14468 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
14469 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
14470 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
14471 dpyinfo->grabbed = 0;
14472 dpyinfo->reference_count = 0;
14473 dpyinfo->icon_bitmap_id = -1;
06a2c219 14474 dpyinfo->font_table = NULL;
7a13e894
RS
14475 dpyinfo->n_fonts = 0;
14476 dpyinfo->font_table_size = 0;
14477 dpyinfo->bitmaps = 0;
14478 dpyinfo->bitmaps_size = 0;
14479 dpyinfo->bitmaps_last = 0;
14480 dpyinfo->scratch_cursor_gc = 0;
14481 dpyinfo->mouse_face_mouse_frame = 0;
14482 dpyinfo->mouse_face_deferred_gc = 0;
14483 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
14484 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 14485 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894 14486 dpyinfo->mouse_face_window = Qnil;
0a61c667 14487 dpyinfo->mouse_face_overlay = Qnil;
7a13e894
RS
14488 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
14489 dpyinfo->mouse_face_defer = 0;
0f941935
KH
14490 dpyinfo->x_focus_frame = 0;
14491 dpyinfo->x_focus_event_frame = 0;
14492 dpyinfo->x_highlight_frame = 0;
06a2c219 14493 dpyinfo->image_cache = make_image_cache ();
334208b7 14494
43bd1b2b 14495 /* See if a private colormap is requested. */
5ff67d81
GM
14496 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
14497 {
14498 if (dpyinfo->visual->class == PseudoColor)
14499 {
14500 Lisp_Object value;
14501 value = display_x_get_resource (dpyinfo,
14502 build_string ("privateColormap"),
14503 build_string ("PrivateColormap"),
14504 Qnil, Qnil);
14505 if (STRINGP (value)
14506 && (!strcmp (XSTRING (value)->data, "true")
14507 || !strcmp (XSTRING (value)->data, "on")))
14508 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
14509 }
43bd1b2b 14510 }
5ff67d81
GM
14511 else
14512 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
14513 dpyinfo->visual, AllocNone);
43bd1b2b 14514
06a2c219
GM
14515 {
14516 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
14517 double pixels = DisplayHeight (dpyinfo->display, screen_number);
14518 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
14519 dpyinfo->resy = pixels * 25.4 / mm;
14520 pixels = DisplayWidth (dpyinfo->display, screen_number);
14521 mm = DisplayWidthMM (dpyinfo->display, screen_number);
14522 dpyinfo->resx = pixels * 25.4 / mm;
14523 }
14524
334208b7
RS
14525 dpyinfo->Xatom_wm_protocols
14526 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
14527 dpyinfo->Xatom_wm_take_focus
14528 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
14529 dpyinfo->Xatom_wm_save_yourself
14530 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
14531 dpyinfo->Xatom_wm_delete_window
14532 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
14533 dpyinfo->Xatom_wm_change_state
14534 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
14535 dpyinfo->Xatom_wm_configure_denied
14536 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
14537 dpyinfo->Xatom_wm_window_moved
14538 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
14539 dpyinfo->Xatom_editres
14540 = XInternAtom (dpyinfo->display, "Editres", False);
14541 dpyinfo->Xatom_CLIPBOARD
14542 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
14543 dpyinfo->Xatom_TIMESTAMP
14544 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
14545 dpyinfo->Xatom_TEXT
14546 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
14547 dpyinfo->Xatom_COMPOUND_TEXT
14548 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
14549 dpyinfo->Xatom_DELETE
14550 = XInternAtom (dpyinfo->display, "DELETE", False);
14551 dpyinfo->Xatom_MULTIPLE
14552 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
14553 dpyinfo->Xatom_INCR
14554 = XInternAtom (dpyinfo->display, "INCR", False);
14555 dpyinfo->Xatom_EMACS_TMP
14556 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
14557 dpyinfo->Xatom_TARGETS
14558 = XInternAtom (dpyinfo->display, "TARGETS", False);
14559 dpyinfo->Xatom_NULL
14560 = XInternAtom (dpyinfo->display, "NULL", False);
14561 dpyinfo->Xatom_ATOM_PAIR
14562 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
14563 /* For properties of font. */
14564 dpyinfo->Xatom_PIXEL_SIZE
14565 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
14566 dpyinfo->Xatom_MULE_BASELINE_OFFSET
14567 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
14568 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
14569 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
14570 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
14571 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 14572
06a2c219
GM
14573 /* Ghostscript support. */
14574 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
14575 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
14576
14577 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
14578 False);
14579
547d9db8
KH
14580 dpyinfo->cut_buffers_initialized = 0;
14581
334208b7
RS
14582 connection = ConnectionNumber (dpyinfo->display);
14583 dpyinfo->connection = connection;
14584
dc43ef94 14585 {
5d7cc324
RS
14586 char null_bits[1];
14587
14588 null_bits[0] = 0x00;
dc43ef94
KH
14589
14590 dpyinfo->null_pixel
14591 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14592 null_bits, 1, 1, (long) 0, (long) 0,
14593 1);
14594 }
14595
06a2c219
GM
14596 {
14597 extern int gray_bitmap_width, gray_bitmap_height;
10659c77 14598 extern char *gray_bitmap_bits;
06a2c219
GM
14599 dpyinfo->gray
14600 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14601 gray_bitmap_bits,
14602 gray_bitmap_width, gray_bitmap_height,
14603 (unsigned long) 1, (unsigned long) 0, 1);
14604 }
14605
f5d11644
GM
14606#ifdef HAVE_X_I18N
14607 xim_initialize (dpyinfo, resource_name);
14608#endif
14609
87485d6f
MW
14610#ifdef subprocesses
14611 /* This is only needed for distinguishing keyboard and process input. */
334208b7 14612 if (connection != 0)
7a13e894 14613 add_keyboard_wait_descriptor (connection);
87485d6f 14614#endif
6d4238f3 14615
041b69ac 14616#ifndef F_SETOWN_BUG
dc6f92b8 14617#ifdef F_SETOWN
dc6f92b8 14618#ifdef F_SETOWN_SOCK_NEG
61c3ce62 14619 /* stdin is a socket here */
334208b7 14620 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 14621#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 14622 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
14623#endif /* ! defined (F_SETOWN_SOCK_NEG) */
14624#endif /* ! defined (F_SETOWN) */
041b69ac 14625#endif /* F_SETOWN_BUG */
dc6f92b8
JB
14626
14627#ifdef SIGIO
eee20f6a
KH
14628 if (interrupt_input)
14629 init_sigio (connection);
c118dd06 14630#endif /* ! defined (SIGIO) */
dc6f92b8 14631
51b592fb 14632#ifdef USE_LUCID
f8c39f51 14633#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
14634 /* Make sure that we have a valid font for dialog boxes
14635 so that Xt does not crash. */
14636 {
14637 Display *dpy = dpyinfo->display;
14638 XrmValue d, fr, to;
14639 Font font;
e99db5a1 14640 int count;
51b592fb
RS
14641
14642 d.addr = (XPointer)&dpy;
14643 d.size = sizeof (Display *);
14644 fr.addr = XtDefaultFont;
14645 fr.size = sizeof (XtDefaultFont);
14646 to.size = sizeof (Font *);
14647 to.addr = (XPointer)&font;
e99db5a1 14648 count = x_catch_errors (dpy);
51b592fb
RS
14649 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
14650 abort ();
14651 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
14652 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 14653 x_uncatch_errors (dpy, count);
51b592fb
RS
14654 }
14655#endif
f8c39f51 14656#endif
51b592fb 14657
34e23e5a
GM
14658 /* See if we should run in synchronous mode. This is useful
14659 for debugging X code. */
14660 {
14661 Lisp_Object value;
14662 value = display_x_get_resource (dpyinfo,
14663 build_string ("synchronous"),
14664 build_string ("Synchronous"),
14665 Qnil, Qnil);
14666 if (STRINGP (value)
14667 && (!strcmp (XSTRING (value)->data, "true")
14668 || !strcmp (XSTRING (value)->data, "on")))
14669 XSynchronize (dpyinfo->display, True);
14670 }
14671
60439948
KH
14672 UNBLOCK_INPUT;
14673
7a13e894
RS
14674 return dpyinfo;
14675}
14676\f
14677/* Get rid of display DPYINFO, assuming all frames are already gone,
14678 and without sending any more commands to the X server. */
dc6f92b8 14679
7a13e894
RS
14680void
14681x_delete_display (dpyinfo)
14682 struct x_display_info *dpyinfo;
14683{
14684 delete_keyboard_wait_descriptor (dpyinfo->connection);
14685
14686 /* Discard this display from x_display_name_list and x_display_list.
14687 We can't use Fdelq because that can quit. */
14688 if (! NILP (x_display_name_list)
8e713be6
KR
14689 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
14690 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
14691 else
14692 {
14693 Lisp_Object tail;
14694
14695 tail = x_display_name_list;
8e713be6 14696 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 14697 {
bffcfca9 14698 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 14699 {
f3fbd155 14700 XSETCDR (tail, XCDR (XCDR (tail)));
7a13e894
RS
14701 break;
14702 }
8e713be6 14703 tail = XCDR (tail);
7a13e894
RS
14704 }
14705 }
14706
9bda743f
GM
14707 if (next_noop_dpyinfo == dpyinfo)
14708 next_noop_dpyinfo = dpyinfo->next;
14709
7a13e894
RS
14710 if (x_display_list == dpyinfo)
14711 x_display_list = dpyinfo->next;
7f9c7f94
RS
14712 else
14713 {
14714 struct x_display_info *tail;
7a13e894 14715
7f9c7f94
RS
14716 for (tail = x_display_list; tail; tail = tail->next)
14717 if (tail->next == dpyinfo)
14718 tail->next = tail->next->next;
14719 }
7a13e894 14720
0d777288
RS
14721#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
14722#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
14723 XrmDestroyDatabase (dpyinfo->xrdb);
14724#endif
0d777288 14725#endif
29b38361
KH
14726#ifdef MULTI_KBOARD
14727 if (--dpyinfo->kboard->reference_count == 0)
39f79001 14728 delete_kboard (dpyinfo->kboard);
b9737ad3 14729#endif
f5d11644
GM
14730#ifdef HAVE_X_I18N
14731 if (dpyinfo->xim)
14732 xim_close_dpy (dpyinfo);
14733#endif
14734
b9737ad3
KH
14735 xfree (dpyinfo->font_table);
14736 xfree (dpyinfo->x_id_name);
f04e1297 14737 xfree (dpyinfo->color_cells);
b9737ad3 14738 xfree (dpyinfo);
7a13e894 14739}
f04e1297 14740
7a13e894
RS
14741\f
14742/* Set up use of X before we make the first connection. */
14743
06a2c219
GM
14744static struct redisplay_interface x_redisplay_interface =
14745{
14746 x_produce_glyphs,
14747 x_write_glyphs,
14748 x_insert_glyphs,
14749 x_clear_end_of_line,
14750 x_scroll_run,
14751 x_after_update_window_line,
14752 x_update_window_begin,
14753 x_update_window_end,
14754 XTcursor_to,
14755 x_flush,
71b8321e 14756 x_clear_mouse_face,
66ac4b0e
GM
14757 x_get_glyph_overhangs,
14758 x_fix_overlapping_area
06a2c219
GM
14759};
14760
dfcf069d 14761void
7a13e894
RS
14762x_initialize ()
14763{
06a2c219
GM
14764 rif = &x_redisplay_interface;
14765
14766 clear_frame_hook = x_clear_frame;
14767 ins_del_lines_hook = x_ins_del_lines;
06a2c219 14768 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
14769 ring_bell_hook = XTring_bell;
14770 reset_terminal_modes_hook = XTreset_terminal_modes;
14771 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
14772 update_begin_hook = x_update_begin;
14773 update_end_hook = x_update_end;
dc6f92b8
JB
14774 set_terminal_window_hook = XTset_terminal_window;
14775 read_socket_hook = XTread_socket;
b8009dd1 14776 frame_up_to_date_hook = XTframe_up_to_date;
90e65f07 14777 mouse_position_hook = XTmouse_position;
f451eb13 14778 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 14779 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
14780 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
14781 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
14782 redeem_scroll_bar_hook = XTredeem_scroll_bar;
14783 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 14784 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 14785
f676886a 14786 scroll_region_ok = 1; /* we'll scroll partial frames */
9017309f 14787 char_ins_del_ok = 1;
dc6f92b8
JB
14788 line_ins_del_ok = 1; /* we'll just blt 'em */
14789 fast_clear_end_of_line = 1; /* X does this well */
58769bee 14790 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
14791 off the bottom */
14792 baud_rate = 19200;
14793
7a13e894 14794 x_noop_count = 0;
9ea173e8 14795 last_tool_bar_item = -1;
06a2c219
GM
14796 any_help_event_p = 0;
14797
b30b24cb
RS
14798 /* Try to use interrupt input; if we can't, then start polling. */
14799 Fset_input_mode (Qt, Qnil, Qt, Qnil);
14800
7f9c7f94
RS
14801#ifdef USE_X_TOOLKIT
14802 XtToolkitInitialize ();
651f03b6 14803
7f9c7f94 14804 Xt_app_con = XtCreateApplicationContext ();
651f03b6
GM
14805
14806 /* Register a converter from strings to pixels, which uses
14807 Emacs' color allocation infrastructure. */
14808 XtAppSetTypeConverter (Xt_app_con,
14809 XtRString, XtRPixel, cvt_string_to_pixel,
14810 cvt_string_to_pixel_args,
14811 XtNumber (cvt_string_to_pixel_args),
14812 XtCacheByDisplay, cvt_pixel_dtor);
14813
665881ad 14814 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
14815
14816 /* Install an asynchronous timer that processes Xt timeout events
14817 every 0.1s. This is necessary because some widget sets use
14818 timeouts internally, for example the LessTif menu bar, or the
14819 Xaw3d scroll bar. When Xt timouts aren't processed, these
14820 widgets don't behave normally. */
14821 {
14822 EMACS_TIME interval;
14823 EMACS_SET_SECS_USECS (interval, 0, 100000);
14824 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
14825 }
db74249b 14826#endif
bffcfca9 14827
eccc05db 14828#ifdef USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
14829 xaw3d_arrow_scroll = False;
14830 xaw3d_pick_top = True;
7f9c7f94
RS
14831#endif
14832
58769bee 14833 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 14834 original error handler. */
e99db5a1 14835 XSetErrorHandler (x_error_handler);
334208b7 14836 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 14837
06a2c219 14838 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
14839#ifdef SIGWINCH
14840 signal (SIGWINCH, SIG_DFL);
c118dd06 14841#endif /* ! defined (SIGWINCH) */
dc6f92b8 14842
92e2441b 14843 signal (SIGPIPE, x_connection_signal);
dc6f92b8 14844}
55123275 14845
06a2c219 14846
55123275
JB
14847void
14848syms_of_xterm ()
14849{
e99db5a1
RS
14850 staticpro (&x_error_message_string);
14851 x_error_message_string = Qnil;
14852
7a13e894
RS
14853 staticpro (&x_display_name_list);
14854 x_display_name_list = Qnil;
334208b7 14855
ab648270 14856 staticpro (&last_mouse_scroll_bar);
e53cb100 14857 last_mouse_scroll_bar = Qnil;
59e755be
KH
14858
14859 staticpro (&Qvendor_specific_keysyms);
14860 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
14861
14862 staticpro (&last_mouse_press_frame);
14863 last_mouse_press_frame = Qnil;
06a2c219 14864
06a2c219 14865 help_echo = Qnil;
be010514
GM
14866 staticpro (&help_echo);
14867 help_echo_object = Qnil;
14868 staticpro (&help_echo_object);
7cea38bc
GM
14869 help_echo_window = Qnil;
14870 staticpro (&help_echo_window);
06a2c219 14871 previous_help_echo = Qnil;
be010514
GM
14872 staticpro (&previous_help_echo);
14873 help_echo_pos = -1;
06a2c219 14874
7ee72033
MB
14875 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
14876 doc: /* *Non-nil means draw block cursor as wide as the glyph under it.
228299fa
GM
14877For example, if a block cursor is over a tab, it will be drawn as
14878wide as that tab on the display. */);
06a2c219
GM
14879 x_stretch_cursor_p = 0;
14880
a72d5ce5 14881 DEFVAR_BOOL ("x-use-underline-position-properties",
7ee72033
MB
14882 &x_use_underline_position_properties,
14883 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
f0529b5b 14884nil means ignore them. If you encounter fonts with bogus
228299fa
GM
14885UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
14886to 4.1, set this to nil. */);
a72d5ce5
GM
14887 x_use_underline_position_properties = 1;
14888
7ee72033
MB
14889 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
14890 doc: /* What X toolkit scroll bars Emacs uses.
228299fa
GM
14891A value of nil means Emacs doesn't use X toolkit scroll bars.
14892Otherwise, value is a symbol describing the X toolkit. */);
eccc05db 14893#ifdef USE_TOOLKIT_SCROLL_BARS
5bf04520
GM
14894#ifdef USE_MOTIF
14895 Vx_toolkit_scroll_bars = intern ("motif");
14896#elif defined HAVE_XAW3D
14897 Vx_toolkit_scroll_bars = intern ("xaw3d");
14898#else
14899 Vx_toolkit_scroll_bars = intern ("xaw");
14900#endif
06a2c219 14901#else
5bf04520 14902 Vx_toolkit_scroll_bars = Qnil;
06a2c219
GM
14903#endif
14904
06a2c219
GM
14905 staticpro (&last_mouse_motion_frame);
14906 last_mouse_motion_frame = Qnil;
55123275 14907}
6cf0ae86 14908
1d6c120a 14909#endif /* HAVE_X_WINDOWS */