Fix typo in comment.
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
abfb6b46 2 Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001, 2002
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 100#ifdef USE_LUCID
55a8b3ed 101extern int xlwmenu_window_p P_ ((Widget w, Window window));
d624284c
PJ
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.) */
7d0393cf 241
06a2c219 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
503e457e
PJ
256/* Non-zero means autoselect window with the mouse cursor. */
257
ee8ceff8 258int mouse_autoselect_window;
5bc62483 259
ee8ceff8 260/* Last window where we saw the mouse. Used by mouse-autoselect-window. */
5bc62483 261static Lisp_Object last_window;
503e457e 262
06a2c219
GM
263/* Non-zero means draw block and hollow cursor as wide as the glyph
264 under it. For example, if a block cursor is over a tab, it will be
265 drawn as wide as that tab on the display. */
266
267int x_stretch_cursor_p;
268
a72d5ce5
GM
269/* Non-zero means make use of UNDERLINE_POSITION font properties. */
270
271int x_use_underline_position_properties;
272
06a2c219
GM
273/* This is a chain of structures for all the X displays currently in
274 use. */
275
334208b7 276struct x_display_info *x_display_list;
dc6f92b8 277
06a2c219
GM
278/* This is a list of cons cells, each of the form (NAME
279 . FONT-LIST-CACHE), one for each element of x_display_list and in
280 the same order. NAME is the name of the frame. FONT-LIST-CACHE
281 records previous values returned by x-list-fonts. */
282
7a13e894 283Lisp_Object x_display_name_list;
f451eb13 284
987d2ad1 285/* Frame being updated by update_frame. This is declared in term.c.
06a2c219
GM
286 This is set by update_begin and looked at by all the XT functions.
287 It is zero while not inside an update. In that case, the XT
288 functions assume that `selected_frame' is the frame to apply to. */
289
d0386f2a 290extern struct frame *updating_frame;
dc6f92b8 291
06a2c219
GM
292/* This is a frame waiting to be auto-raised, within XTread_socket. */
293
0134a210
RS
294struct frame *pending_autoraise_frame;
295
7f9c7f94
RS
296#ifdef USE_X_TOOLKIT
297/* The application context for Xt use. */
298XtAppContext Xt_app_con;
06a2c219
GM
299static String Xt_default_resources[] = {0};
300#endif /* USE_X_TOOLKIT */
665881ad 301
7d0393cf 302/* Nominal cursor position -- where to draw output.
06a2c219
GM
303 HPOS and VPOS are window relative glyph matrix coordinates.
304 X and Y are window relative pixel coordinates. */
dc6f92b8 305
06a2c219 306struct cursor_pos output_cursor;
dc6f92b8 307
bffcfca9
GM
308/* Non-zero means user is interacting with a toolkit scroll bar. */
309
310static int toolkit_scroll_bar_interaction;
dc6f92b8 311
69388238
RS
312/* Mouse movement.
313
06a2c219 314 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
315 so that we would have to call XQueryPointer after each MotionNotify
316 event to ask for another such event. However, this made mouse tracking
317 slow, and there was a bug that made it eventually stop.
318
319 Simply asking for MotionNotify all the time seems to work better.
320
69388238
RS
321 In order to avoid asking for motion events and then throwing most
322 of them away or busy-polling the server for mouse positions, we ask
323 the server for pointer motion hints. This means that we get only
324 one event per group of mouse movements. "Groups" are delimited by
325 other kinds of events (focus changes and button clicks, for
326 example), or by XQueryPointer calls; when one of these happens, we
327 get another MotionNotify event the next time the mouse moves. This
328 is at least as efficient as getting motion events when mouse
329 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 330 is off. */
69388238
RS
331
332/* Where the mouse was last time we reported a mouse event. */
69388238 333
06a2c219
GM
334FRAME_PTR last_mouse_frame;
335static XRectangle last_mouse_glyph;
2237cac9
RS
336static Lisp_Object last_mouse_press_frame;
337
69388238
RS
338/* The scroll bar in which the last X motion event occurred.
339
06a2c219
GM
340 If the last X motion event occurred in a scroll bar, we set this so
341 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
342 an ordinary motion.
343
06a2c219
GM
344 If the last X motion event didn't occur in a scroll bar, we set
345 this to Qnil, to tell XTmouse_position to return an ordinary motion
346 event. */
347
69388238
RS
348static Lisp_Object last_mouse_scroll_bar;
349
69388238
RS
350/* This is a hack. We would really prefer that XTmouse_position would
351 return the time associated with the position it returns, but there
06a2c219 352 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
353 along with the position query. So, we just keep track of the time
354 of the last movement we received, and return that in hopes that
355 it's somewhat accurate. */
06a2c219 356
69388238
RS
357static Time last_mouse_movement_time;
358
06a2c219
GM
359/* Incremented by XTread_socket whenever it really tries to read
360 events. */
361
c0a04927
RS
362#ifdef __STDC__
363static int volatile input_signal_count;
364#else
365static int input_signal_count;
366#endif
367
7a13e894 368/* Used locally within XTread_socket. */
06a2c219 369
7a13e894 370static int x_noop_count;
dc6f92b8 371
7a13e894 372/* Initial values of argv and argc. */
06a2c219 373
7a13e894
RS
374extern char **initial_argv;
375extern int initial_argc;
dc6f92b8 376
7a13e894 377extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 378
06a2c219 379/* Tells if a window manager is present or not. */
7a13e894
RS
380
381extern Lisp_Object Vx_no_window_manager;
dc6f92b8 382
c2df547c 383extern Lisp_Object Qface, Qmouse_face;
b8009dd1 384
dc6f92b8
JB
385extern int errno;
386
dfeccd2d 387/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 388
31ade731 389extern EMACS_INT extra_keyboard_modifiers;
64bb1782 390
98659da6
KG
391/* The keysyms to use for the various modifiers. */
392
393Lisp_Object Vx_alt_keysym, Vx_hyper_keysym, Vx_meta_keysym, Vx_super_keysym;
394static Lisp_Object Qalt, Qhyper, Qmeta, Qsuper, Qmodifier_value;
395
59e755be 396static Lisp_Object Qvendor_specific_keysyms;
c997eae5 397static Lisp_Object Qlatin_1, Qutf_8;
59e755be 398
952291d9
GM
399extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
400extern Lisp_Object x_icon_type P_ ((struct frame *));
c32cdd9a 401
7a13e894 402
06a2c219
GM
403/* Enumeration for overriding/changing the face to use for drawing
404 glyphs in x_draw_glyphs. */
405
406enum draw_glyphs_face
407{
408 DRAW_NORMAL_TEXT,
409 DRAW_INVERSE_VIDEO,
410 DRAW_CURSOR,
411 DRAW_MOUSE_FACE,
412 DRAW_IMAGE_RAISED,
413 DRAW_IMAGE_SUNKEN
414};
415
b7f83f9e 416static int cursor_in_mouse_face_p P_ ((struct window *));
fa262c07 417static int clear_mouse_face P_ ((struct x_display_info *));
651f03b6 418static int x_alloc_nearest_color_1 P_ ((Display *, Colormap, XColor *));
499b1844 419static void x_set_window_size_1 P_ ((struct frame *, int, int, int));
651f03b6 420static const XColor *x_color_cells P_ ((Display *, int *));
71b8321e 421static void x_update_window_end P_ ((struct window *, int, int));
06a2c219
GM
422static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
423void x_delete_display P_ ((struct x_display_info *));
424static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
425 unsigned));
426static int fast_find_position P_ ((struct window *, int, int *, int *,
7e376260 427 int *, int *, Lisp_Object));
f9db2310
GM
428static int fast_find_string_pos P_ ((struct window *, int, Lisp_Object,
429 int *, int *, int *, int *, int));
06a2c219
GM
430static void set_output_cursor P_ ((struct cursor_pos *));
431static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
f9db2310 432 int *, int *, int *, int));
b436feb6
GM
433static void note_mode_line_or_margin_highlight P_ ((struct window *, int,
434 int, int));
06a2c219 435static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
436static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
437static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
438static void show_mouse_face P_ ((struct x_display_info *,
439 enum draw_glyphs_face));
440static int x_io_error_quitter P_ ((Display *));
441int x_catch_errors P_ ((Display *));
442void x_uncatch_errors P_ ((Display *, int));
443void x_lower_frame P_ ((struct frame *));
444void x_scroll_bar_clear P_ ((struct frame *));
445int x_had_errors_p P_ ((Display *));
446void x_wm_set_size_hint P_ ((struct frame *, long, int));
447void x_raise_frame P_ ((struct frame *));
448void x_set_window_size P_ ((struct frame *, int, int, int));
449void x_wm_set_window_state P_ ((struct frame *, int));
450void x_wm_set_icon_pixmap P_ ((struct frame *, int));
451void x_initialize P_ ((void));
452static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
453static int x_compute_min_glyph_bounds P_ ((struct frame *));
454static void x_draw_phys_cursor_glyph P_ ((struct window *,
455 struct glyph_row *,
456 enum draw_glyphs_face));
457static void x_update_end P_ ((struct frame *));
458static void XTframe_up_to_date P_ ((struct frame *));
06a2c219
GM
459static void XTset_terminal_modes P_ ((void));
460static void XTreset_terminal_modes P_ ((void));
461static void XTcursor_to P_ ((int, int, int, int));
462static void x_write_glyphs P_ ((struct glyph *, int));
463static void x_clear_end_of_line P_ ((int));
464static void x_clear_frame P_ ((void));
465static void x_clear_cursor P_ ((struct window *));
466static void frame_highlight P_ ((struct frame *));
467static void frame_unhighlight P_ ((struct frame *));
468static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
cab34f50
JD
469static int x_focus_changed P_ ((int,
470 int,
471 struct x_display_info *,
472 struct frame *,
473 struct input_event *,
474 int));
475static int x_detect_focus_change P_ ((struct x_display_info *,
476 XEvent *,
477 struct input_event *,
478 int));
06a2c219
GM
479static void XTframe_rehighlight P_ ((struct frame *));
480static void x_frame_rehighlight P_ ((struct x_display_info *));
481static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
65c26775
EZ
482static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int,
483 enum text_cursor_kinds));
06a2c219
GM
484static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
485 XRectangle *));
486static void expose_frame P_ ((struct frame *, int, int, int, int));
82f053ab 487static int expose_window_tree P_ ((struct window *, XRectangle *));
4f53f3b8
RS
488static void expose_overlaps P_ ((struct window *, struct glyph_row *,
489 struct glyph_row *));
a39202f6 490static int expose_window P_ ((struct window *, XRectangle *));
06a2c219
GM
491static void expose_area P_ ((struct window *, struct glyph_row *,
492 XRectangle *, enum glyph_row_area));
82f053ab 493static int expose_line P_ ((struct window *, struct glyph_row *,
06a2c219
GM
494 XRectangle *));
495static void x_update_cursor_in_window_tree P_ ((struct window *, int));
496static void x_update_window_cursor P_ ((struct window *, int));
497static void x_erase_phys_cursor P_ ((struct window *));
498void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
7d0393cf 499static void x_draw_fringe_bitmap P_ ((struct window *, struct glyph_row *,
976b73d7 500 enum fringe_bitmap_type, int left_p));
06a2c219
GM
501
502static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
503 GC, int));
504static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
3f332ef3 505static void x_draw_row_fringe_bitmaps P_ ((struct window *, struct glyph_row *));
60626bab
GM
506static void notice_overwritten_cursor P_ ((struct window *, enum glyph_row_area,
507 int, int, int, int));
06a2c219 508static void x_flush P_ ((struct frame *f));
952291d9
GM
509static void x_update_begin P_ ((struct frame *));
510static void x_update_window_begin P_ ((struct window *));
511static void x_draw_vertical_border P_ ((struct window *));
512static void x_after_update_window_line P_ ((struct glyph_row *));
513static INLINE void take_vertical_position_into_account P_ ((struct it *));
514static void x_produce_stretch_glyph P_ ((struct it *));
b52b65bd
GM
515static struct scroll_bar *x_window_to_scroll_bar P_ ((Window));
516static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
517 enum scroll_bar_part *,
518 Lisp_Object *, Lisp_Object *,
519 unsigned long *));
d0fa3e56
EZ
520static void x_check_fullscreen P_ ((struct frame *));
521static void x_check_fullscreen_move P_ ((struct frame *));
06a2c219
GM
522
523/* Flush display of frame F, or of all frames if F is null. */
524
525static void
526x_flush (f)
527 struct frame *f;
528{
529 BLOCK_INPUT;
530 if (f == NULL)
531 {
532 Lisp_Object rest, frame;
533 FOR_EACH_FRAME (rest, frame)
534 x_flush (XFRAME (frame));
535 }
536 else if (FRAME_X_P (f))
537 XFlush (FRAME_X_DISPLAY (f));
538 UNBLOCK_INPUT;
539}
540
dc6f92b8 541
06a2c219
GM
542/* Remove calls to XFlush by defining XFlush to an empty replacement.
543 Calls to XFlush should be unnecessary because the X output buffer
544 is flushed automatically as needed by calls to XPending,
545 XNextEvent, or XWindowEvent according to the XFlush man page.
546 XTread_socket calls XPending. Removing XFlush improves
547 performance. */
548
7d0393cf 549#define XFlush(DISPLAY) (void) 0
b8009dd1 550
334208b7 551\f
06a2c219
GM
552/***********************************************************************
553 Debugging
554 ***********************************************************************/
555
9382638d 556#if 0
06a2c219
GM
557
558/* This is a function useful for recording debugging information about
559 the sequence of occurrences in this file. */
9382638d 560
7d0393cf 561struct record
9382638d
KH
562{
563 char *locus;
564 int type;
565};
566
567struct record event_record[100];
568
569int event_record_index;
570
571record_event (locus, type)
572 char *locus;
573 int type;
574{
575 if (event_record_index == sizeof (event_record) / sizeof (struct record))
576 event_record_index = 0;
577
578 event_record[event_record_index].locus = locus;
579 event_record[event_record_index].type = type;
580 event_record_index++;
581}
582
583#endif /* 0 */
06a2c219
GM
584
585
9382638d 586\f
334208b7
RS
587/* Return the struct x_display_info corresponding to DPY. */
588
589struct x_display_info *
590x_display_info_for_display (dpy)
591 Display *dpy;
592{
593 struct x_display_info *dpyinfo;
594
595 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
596 if (dpyinfo->display == dpy)
597 return dpyinfo;
16bd92ea 598
334208b7
RS
599 return 0;
600}
f451eb13 601
06a2c219
GM
602
603\f
604/***********************************************************************
605 Starting and ending an update
606 ***********************************************************************/
7d0393cf 607
06a2c219
GM
608/* Start an update of frame F. This function is installed as a hook
609 for update_begin, i.e. it is called when update_begin is called.
610 This function is called prior to calls to x_update_window_begin for
611 each window being updated. Currently, there is nothing to do here
612 because all interesting stuff is done on a window basis. */
dc6f92b8 613
dfcf069d 614static void
06a2c219 615x_update_begin (f)
f676886a 616 struct frame *f;
58769bee 617{
06a2c219
GM
618 /* Nothing to do. */
619}
dc6f92b8 620
dc6f92b8 621
06a2c219
GM
622/* Start update of window W. Set the global variable updated_window
623 to the window being updated and set output_cursor to the cursor
624 position of W. */
dc6f92b8 625
06a2c219
GM
626static void
627x_update_window_begin (w)
628 struct window *w;
629{
630 struct frame *f = XFRAME (WINDOW_FRAME (w));
631 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
7d0393cf 632
06a2c219
GM
633 updated_window = w;
634 set_output_cursor (&w->cursor);
b8009dd1 635
06a2c219 636 BLOCK_INPUT;
d1bc4182 637
06a2c219 638 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 639 {
514e4681 640 /* Don't do highlighting for mouse motion during the update. */
06a2c219 641 display_info->mouse_face_defer = 1;
37c2c98b 642
06a2c219
GM
643 /* If F needs to be redrawn, simply forget about any prior mouse
644 highlighting. */
9f67f20b 645 if (FRAME_GARBAGED_P (f))
06a2c219
GM
646 display_info->mouse_face_window = Qnil;
647
64f26cf5
GM
648#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
649 their mouse_face_p flag set, which means that they are always
650 unequal to rows in a desired matrix which never have that
651 flag set. So, rows containing mouse-face glyphs are never
652 scrolled, and we don't have to switch the mouse highlight off
653 here to prevent it from being scrolled. */
7d0393cf 654
06a2c219
GM
655 /* Can we tell that this update does not affect the window
656 where the mouse highlight is? If so, no need to turn off.
657 Likewise, don't do anything if the frame is garbaged;
658 in that case, the frame's current matrix that we would use
659 is all wrong, and we will redisplay that line anyway. */
660 if (!NILP (display_info->mouse_face_window)
661 && w == XWINDOW (display_info->mouse_face_window))
514e4681 662 {
06a2c219 663 int i;
514e4681 664
06a2c219
GM
665 for (i = 0; i < w->desired_matrix->nrows; ++i)
666 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
667 break;
668
06a2c219
GM
669 if (i < w->desired_matrix->nrows)
670 clear_mouse_face (display_info);
514e4681 671 }
64f26cf5 672#endif /* 0 */
b8009dd1 673 }
6ccf47d1 674
dc6f92b8
JB
675 UNBLOCK_INPUT;
676}
677
06a2c219
GM
678
679/* Draw a vertical window border to the right of window W if W doesn't
680 have vertical scroll bars. */
681
dfcf069d 682static void
06a2c219
GM
683x_draw_vertical_border (w)
684 struct window *w;
58769bee 685{
06a2c219 686 struct frame *f = XFRAME (WINDOW_FRAME (w));
7d0393cf 687
06a2c219
GM
688 /* Redraw borders between horizontally adjacent windows. Don't
689 do it for frames with vertical scroll bars because either the
690 right scroll bar of a window, or the left scroll bar of its
691 neighbor will suffice as a border. */
692 if (!WINDOW_RIGHTMOST_P (w)
693 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
694 {
695 int x0, x1, y0, y1;
dc6f92b8 696
06a2c219 697 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
3f332ef3 698 x1 += FRAME_X_RIGHT_FRINGE_WIDTH (f);
06a2c219 699 y1 -= 1;
7d0393cf
JB
700
701 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219
GM
702 f->output_data.x->normal_gc, x1, y0, x1, y1);
703 }
704}
7d0393cf
JB
705
706
71b8321e
GM
707/* End update of window W (which is equal to updated_window).
708
709 Draw vertical borders between horizontally adjacent windows, and
710 display W's cursor if CURSOR_ON_P is non-zero.
711
712 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
713 glyphs in mouse-face were overwritten. In that case we have to
714 make sure that the mouse-highlight is properly redrawn.
715
716 W may be a menu bar pseudo-window in case we don't have X toolkit
717 support. Such windows don't have a cursor, so don't display it
718 here. */
06a2c219
GM
719
720static void
71b8321e 721x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 722 struct window *w;
71b8321e 723 int cursor_on_p, mouse_face_overwritten_p;
06a2c219 724{
140330de 725 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7d0393cf 726
06a2c219
GM
727 if (!w->pseudo_window_p)
728 {
729 BLOCK_INPUT;
71b8321e 730
06a2c219
GM
731 if (cursor_on_p)
732 x_display_and_set_cursor (w, 1, output_cursor.hpos,
733 output_cursor.vpos,
734 output_cursor.x, output_cursor.y);
7d0393cf 735
06a2c219
GM
736 x_draw_vertical_border (w);
737 UNBLOCK_INPUT;
738 }
7d0393cf 739
140330de
GM
740 /* If a row with mouse-face was overwritten, arrange for
741 XTframe_up_to_date to redisplay the mouse highlight. */
742 if (mouse_face_overwritten_p)
743 {
744 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
745 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
746 dpyinfo->mouse_face_window = Qnil;
747 }
7d0393cf 748
06a2c219
GM
749 updated_window = NULL;
750}
dc6f92b8 751
dc6f92b8 752
06a2c219
GM
753/* End update of frame F. This function is installed as a hook in
754 update_end. */
755
756static void
757x_update_end (f)
758 struct frame *f;
759{
760 /* Mouse highlight may be displayed again. */
aa8bff2e 761 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 762
06a2c219 763 BLOCK_INPUT;
334208b7 764 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
765 UNBLOCK_INPUT;
766}
b8009dd1 767
06a2c219
GM
768
769/* This function is called from various places in xdisp.c whenever a
770 complete update has been performed. The global variable
771 updated_window is not available here. */
b8009dd1 772
dfcf069d 773static void
b8009dd1 774XTframe_up_to_date (f)
06a2c219 775 struct frame *f;
b8009dd1 776{
06a2c219 777 if (FRAME_X_P (f))
514e4681 778 {
06a2c219 779 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 780
06a2c219
GM
781 if (dpyinfo->mouse_face_deferred_gc
782 || f == dpyinfo->mouse_face_mouse_frame)
783 {
784 BLOCK_INPUT;
785 if (dpyinfo->mouse_face_mouse_frame)
786 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
787 dpyinfo->mouse_face_mouse_x,
788 dpyinfo->mouse_face_mouse_y);
789 dpyinfo->mouse_face_deferred_gc = 0;
790 UNBLOCK_INPUT;
791 }
514e4681 792 }
b8009dd1 793}
06a2c219
GM
794
795
796/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
3f332ef3 797 arrow bitmaps, or clear the fringes if no bitmaps are required
06a2c219
GM
798 before DESIRED_ROW is made current. The window being updated is
799 found in updated_window. This function It is called from
800 update_window_line only if it is known that there are differences
801 between bitmaps to be drawn between current row and DESIRED_ROW. */
802
803static void
804x_after_update_window_line (desired_row)
805 struct glyph_row *desired_row;
806{
807 struct window *w = updated_window;
ef253080 808 struct frame *f;
259cf6bc 809 int width, height;
7d0393cf 810
06a2c219 811 xassert (w);
7d0393cf 812
06a2c219
GM
813 if (!desired_row->mode_line_p && !w->pseudo_window_p)
814 {
815 BLOCK_INPUT;
3f332ef3 816 x_draw_row_fringe_bitmaps (w, desired_row);
ef253080
GM
817 UNBLOCK_INPUT;
818 }
7d0393cf 819
ef253080
GM
820 /* When a window has disappeared, make sure that no rest of
821 full-width rows stays visible in the internal border. Could
822 check here if updated_window is the leftmost/rightmost window,
823 but I guess it's not worth doing since vertically split windows
824 are almost never used, internal border is rarely set, and the
825 overhead is very small. */
826 if (windows_or_buffers_changed
827 && desired_row->full_width_p
828 && (f = XFRAME (w->frame),
829 width = FRAME_INTERNAL_BORDER_WIDTH (f),
259cf6bc
GM
830 width != 0)
831 && (height = desired_row->visible_height,
832 height > 0))
ef253080 833 {
ef253080 834 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
06a2c219 835
ef253080
GM
836 /* Internal border is drawn below the tool bar. */
837 if (WINDOWP (f->tool_bar_window)
838 && w == XWINDOW (f->tool_bar_window))
839 y -= width;
7d0393cf 840
ef253080
GM
841 BLOCK_INPUT;
842 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
843 0, y, width, height, False);
844 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
845 f->output_data.x->pixel_width - width,
846 y, width, height, False);
06a2c219
GM
847 UNBLOCK_INPUT;
848 }
849}
850
851
3f332ef3 852/* Draw the bitmap WHICH in one of the left or right fringes of
06a2c219
GM
853 window W. ROW is the glyph row for which to display the bitmap; it
854 determines the vertical position at which the bitmap has to be
855 drawn. */
856
857static void
976b73d7 858x_draw_fringe_bitmap (w, row, which, left_p)
06a2c219
GM
859 struct window *w;
860 struct glyph_row *row;
3f332ef3 861 enum fringe_bitmap_type which;
976b73d7 862 int left_p;
06a2c219
GM
863{
864 struct frame *f = XFRAME (WINDOW_FRAME (w));
865 Display *display = FRAME_X_DISPLAY (f);
866 Window window = FRAME_X_WINDOW (f);
867 int x, y, wd, h, dy;
976b73d7 868 int b1, b2;
b436feb6 869 unsigned char *bits = NULL;
06a2c219
GM
870 Pixmap pixmap;
871 GC gc = f->output_data.x->normal_gc;
872 struct face *face;
873 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
874
875 /* Must clip because of partially visible lines. */
876 x_clip_to_row (w, row, gc, 1);
877
976b73d7
KS
878 /* Convert row to frame coordinates. */
879 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
880
06a2c219
GM
881 switch (which)
882 {
976b73d7
KS
883 case NO_FRINGE_BITMAP:
884 wd = 0;
885 h = 0;
886 break;
887
06a2c219
GM
888 case LEFT_TRUNCATION_BITMAP:
889 wd = left_width;
890 h = left_height;
891 bits = left_bits;
06a2c219 892 break;
7d0393cf 893
06a2c219 894 case OVERLAY_ARROW_BITMAP:
976b73d7
KS
895 wd = ov_width;
896 h = ov_height;
06a2c219 897 bits = ov_bits;
06a2c219 898 break;
7d0393cf 899
06a2c219
GM
900 case RIGHT_TRUNCATION_BITMAP:
901 wd = right_width;
902 h = right_height;
903 bits = right_bits;
06a2c219
GM
904 break;
905
906 case CONTINUED_LINE_BITMAP:
976b73d7
KS
907 wd = continued_width;
908 h = continued_height;
06a2c219 909 bits = continued_bits;
06a2c219 910 break;
7d0393cf 911
06a2c219
GM
912 case CONTINUATION_LINE_BITMAP:
913 wd = continuation_width;
914 h = continuation_height;
915 bits = continuation_bits;
06a2c219
GM
916 break;
917
918 case ZV_LINE_BITMAP:
919 wd = zv_width;
976b73d7
KS
920 h = zv_height - (y % zv_period);
921 bits = zv_bits + (y % zv_period);
06a2c219
GM
922 break;
923
924 default:
925 abort ();
926 }
927
976b73d7
KS
928 /* Clip bitmap if too high. */
929 if (h > row->height)
930 h = row->height;
931
932 /* Set dy to the offset in the row to start drawing the bitmap. */
06a2c219
GM
933 dy = (row->height - h) / 2;
934
976b73d7
KS
935 face = FACE_FROM_ID (f, FRINGE_FACE_ID);
936 PREPARE_FACE_FOR_DISPLAY (f, face);
937
938 /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill
939 the fringe. */
dbdc9702 940 b1 = b2 = -1;
976b73d7
KS
941 if (left_p)
942 {
943 if (wd > FRAME_X_LEFT_FRINGE_WIDTH (f))
944 wd = FRAME_X_LEFT_FRINGE_WIDTH (f);
945 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
946 - wd
947 - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2);
948 if (wd < FRAME_X_LEFT_FRINGE_WIDTH (f) || row->height > h)
949 {
950 /* If W has a vertical border to its left, don't draw over it. */
951 int border = ((XFASTINT (w->left) > 0
952 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
953 ? 1 : 0);
954 b1 = (window_box_left (w, -1)
955 - FRAME_X_LEFT_FRINGE_WIDTH (f)
956 + border);
957 b2 = (FRAME_X_LEFT_FRINGE_WIDTH (f) - border);
958 }
959 }
960 else
961 {
962 if (wd > FRAME_X_RIGHT_FRINGE_WIDTH (f))
963 wd = FRAME_X_RIGHT_FRINGE_WIDTH (f);
964 x = (window_box_right (w, -1)
965 + (FRAME_X_RIGHT_FRINGE_WIDTH (f) - wd) / 2);
966 /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill
967 the fringe. */
968 if (wd < FRAME_X_RIGHT_FRINGE_WIDTH (f) || row->height > h)
969 {
970 b1 = window_box_right (w, -1);
971 b2 = FRAME_X_RIGHT_FRINGE_WIDTH (f);
972 }
973 }
974
975 if (b1 >= 0)
976 {
977 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
7d0393cf 978
976b73d7
KS
979 /* In case the same realized face is used for fringes and
980 for something displayed in the text (e.g. face `region' on
981 mono-displays, the fill style may have been changed to
982 FillSolid in x_draw_glyph_string_background. */
983 if (face->stipple)
984 XSetFillStyle (display, face->gc, FillOpaqueStippled);
985 else
986 XSetForeground (display, face->gc, face->background);
7d0393cf 987
976b73d7
KS
988 XFillRectangle (display, window, face->gc,
989 b1,
990 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
991 row->y)),
992 b2,
993 row->visible_height);
994 if (!face->stipple)
995 XSetForeground (display, face->gc, face->foreground);
996 }
997
dbdc9702
GM
998 if (which != NO_FRINGE_BITMAP)
999 {
1000 /* Draw the bitmap. I believe these small pixmaps can be cached
1001 by the server. */
1002 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
1003 face->foreground,
1004 face->background, depth);
1005 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
1006 XFreePixmap (display, pixmap);
1007 }
7d0393cf 1008
06a2c219
GM
1009 XSetClipMask (display, gc, None);
1010}
1011
1012
3f332ef3 1013/* Draw fringe bitmaps for glyph row ROW on window W. Call this
06a2c219
GM
1014 function with input blocked. */
1015
1016static void
3f332ef3 1017x_draw_row_fringe_bitmaps (w, row)
06a2c219
GM
1018 struct window *w;
1019 struct glyph_row *row;
1020{
1021 struct frame *f = XFRAME (w->frame);
3f332ef3 1022 enum fringe_bitmap_type bitmap;
06a2c219
GM
1023
1024 xassert (interrupt_input_blocked);
1025
1026 /* If row is completely invisible, because of vscrolling, we
1027 don't have to draw anything. */
1028 if (row->visible_height <= 0)
1029 return;
1030
976b73d7
KS
1031 if (FRAME_X_LEFT_FRINGE_WIDTH (f) != 0)
1032 {
1033 /* Decide which bitmap to draw in the left fringe. */
1034 if (row->overlay_arrow_p)
1035 bitmap = OVERLAY_ARROW_BITMAP;
1036 else if (row->truncated_on_left_p)
1037 bitmap = LEFT_TRUNCATION_BITMAP;
1038 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
1039 bitmap = CONTINUATION_LINE_BITMAP;
1040 else if (row->indicate_empty_line_p)
1041 bitmap = ZV_LINE_BITMAP;
dcd08bfb 1042 else
976b73d7 1043 bitmap = NO_FRINGE_BITMAP;
06a2c219 1044
976b73d7
KS
1045 x_draw_fringe_bitmap (w, row, bitmap, 1);
1046 }
06a2c219 1047
976b73d7 1048 if (FRAME_X_RIGHT_FRINGE_WIDTH (f) != 0)
06a2c219 1049 {
976b73d7
KS
1050 /* Decide which bitmap to draw in the right fringe. */
1051 if (row->truncated_on_right_p)
1052 bitmap = RIGHT_TRUNCATION_BITMAP;
1053 else if (row->continued_p)
1054 bitmap = CONTINUED_LINE_BITMAP;
1055 else if (row->indicate_empty_line_p && FRAME_X_LEFT_FRINGE_WIDTH (f) == 0)
1056 bitmap = ZV_LINE_BITMAP;
dcd08bfb 1057 else
976b73d7 1058 bitmap = NO_FRINGE_BITMAP;
06a2c219 1059
976b73d7
KS
1060 x_draw_fringe_bitmap (w, row, bitmap, 0);
1061 }
06a2c219
GM
1062}
1063
dc6f92b8 1064\f
06a2c219
GM
1065
1066/* This is called when starting Emacs and when restarting after
1067 suspend. When starting Emacs, no X window is mapped. And nothing
1068 must be done to Emacs's own window if it is suspended (though that
1069 rarely happens). */
dc6f92b8 1070
dfcf069d 1071static void
dc6f92b8
JB
1072XTset_terminal_modes ()
1073{
1074}
1075
06a2c219
GM
1076/* This is called when exiting or suspending Emacs. Exiting will make
1077 the X-windows go away, and suspending requires no action. */
dc6f92b8 1078
dfcf069d 1079static void
dc6f92b8
JB
1080XTreset_terminal_modes ()
1081{
dc6f92b8 1082}
06a2c219
GM
1083
1084
dc6f92b8 1085\f
06a2c219
GM
1086/***********************************************************************
1087 Output Cursor
1088 ***********************************************************************/
1089
1090/* Set the global variable output_cursor to CURSOR. All cursor
1091 positions are relative to updated_window. */
dc6f92b8 1092
dfcf069d 1093static void
06a2c219
GM
1094set_output_cursor (cursor)
1095 struct cursor_pos *cursor;
dc6f92b8 1096{
06a2c219
GM
1097 output_cursor.hpos = cursor->hpos;
1098 output_cursor.vpos = cursor->vpos;
1099 output_cursor.x = cursor->x;
1100 output_cursor.y = cursor->y;
1101}
1102
1103
1104/* Set a nominal cursor position.
dc6f92b8 1105
06a2c219
GM
1106 HPOS and VPOS are column/row positions in a window glyph matrix. X
1107 and Y are window text area relative pixel positions.
7d0393cf 1108
06a2c219
GM
1109 If this is done during an update, updated_window will contain the
1110 window that is being updated and the position is the future output
1111 cursor position for that window. If updated_window is null, use
1112 selected_window and display the cursor at the given position. */
1113
1114static void
1115XTcursor_to (vpos, hpos, y, x)
1116 int vpos, hpos, y, x;
1117{
1118 struct window *w;
1119
1120 /* If updated_window is not set, work on selected_window. */
1121 if (updated_window)
1122 w = updated_window;
1123 else
1124 w = XWINDOW (selected_window);
dbcb258a 1125
06a2c219
GM
1126 /* Set the output cursor. */
1127 output_cursor.hpos = hpos;
1128 output_cursor.vpos = vpos;
1129 output_cursor.x = x;
1130 output_cursor.y = y;
dc6f92b8 1131
06a2c219
GM
1132 /* If not called as part of an update, really display the cursor.
1133 This will also set the cursor position of W. */
1134 if (updated_window == NULL)
dc6f92b8
JB
1135 {
1136 BLOCK_INPUT;
06a2c219 1137 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1138 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1139 UNBLOCK_INPUT;
1140 }
1141}
dc43ef94 1142
06a2c219
GM
1143
1144\f
1145/***********************************************************************
1146 Display Iterator
1147 ***********************************************************************/
1148
1149/* Function prototypes of this page. */
1150
1151static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1152 struct glyph *,
ee569018
KH
1153 XChar2b *,
1154 int *));
06a2c219 1155static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
abfb6b46
GM
1156 int, XChar2b *, int,
1157 int));
06a2c219
GM
1158static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1159static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1160static void x_append_glyph P_ ((struct it *));
b4192550 1161static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1162static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1163 int, int, double));
1164static void x_produce_glyphs P_ ((struct it *));
06a2c219 1165static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1166
1167
e2ef8ee6
GM
1168/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1169 is not contained in the font. */
dc43ef94 1170
06a2c219 1171static INLINE XCharStruct *
ee569018 1172x_per_char_metric (font, char2b)
06a2c219
GM
1173 XFontStruct *font;
1174 XChar2b *char2b;
1175{
1176 /* The result metric information. */
1177 XCharStruct *pcm = NULL;
dc6f92b8 1178
06a2c219 1179 xassert (font && char2b);
dc6f92b8 1180
06a2c219 1181 if (font->per_char != NULL)
dc6f92b8 1182 {
06a2c219 1183 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1184 {
06a2c219
GM
1185 /* min_char_or_byte2 specifies the linear character index
1186 corresponding to the first element of the per_char array,
1187 max_char_or_byte2 is the index of the last character. A
1188 character with non-zero CHAR2B->byte1 is not in the font.
1189 A character with byte2 less than min_char_or_byte2 or
1190 greater max_char_or_byte2 is not in the font. */
1191 if (char2b->byte1 == 0
1192 && char2b->byte2 >= font->min_char_or_byte2
1193 && char2b->byte2 <= font->max_char_or_byte2)
1194 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1195 }
06a2c219 1196 else
dc6f92b8 1197 {
06a2c219
GM
1198 /* If either min_byte1 or max_byte1 are nonzero, both
1199 min_char_or_byte2 and max_char_or_byte2 are less than
1200 256, and the 2-byte character index values corresponding
1201 to the per_char array element N (counting from 0) are:
1202
1203 byte1 = N/D + min_byte1
1204 byte2 = N\D + min_char_or_byte2
1205
1206 where:
1207
1208 D = max_char_or_byte2 - min_char_or_byte2 + 1
1209 / = integer division
1210 \ = integer modulus */
1211 if (char2b->byte1 >= font->min_byte1
1212 && char2b->byte1 <= font->max_byte1
1213 && char2b->byte2 >= font->min_char_or_byte2
1214 && char2b->byte2 <= font->max_char_or_byte2)
1215 {
1216 pcm = (font->per_char
1217 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1218 * (char2b->byte1 - font->min_byte1))
1219 + (char2b->byte2 - font->min_char_or_byte2));
1220 }
dc6f92b8 1221 }
06a2c219
GM
1222 }
1223 else
1224 {
1225 /* If the per_char pointer is null, all glyphs between the first
1226 and last character indexes inclusive have the same
1227 information, as given by both min_bounds and max_bounds. */
1228 if (char2b->byte2 >= font->min_char_or_byte2
1229 && char2b->byte2 <= font->max_char_or_byte2)
1230 pcm = &font->max_bounds;
1231 }
dc6f92b8 1232
ee569018 1233 return ((pcm == NULL
3e71d8f2 1234 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1235 ? NULL : pcm);
06a2c219 1236}
b73b6aaf 1237
57b03282 1238
06a2c219
GM
1239/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1240 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1241
06a2c219
GM
1242static INLINE void
1243x_encode_char (c, char2b, font_info)
1244 int c;
1245 XChar2b *char2b;
1246 struct font_info *font_info;
1247{
1248 int charset = CHAR_CHARSET (c);
1249 XFontStruct *font = font_info->font;
1250
1251 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1252 This may be either a program in a special encoder language or a
1253 fixed encoding. */
1254 if (font_info->font_encoder)
1255 {
1256 /* It's a program. */
1257 struct ccl_program *ccl = font_info->font_encoder;
1258
1259 if (CHARSET_DIMENSION (charset) == 1)
1260 {
1261 ccl->reg[0] = charset;
1262 ccl->reg[1] = char2b->byte2;
6e666629 1263 ccl->reg[2] = -1;
06a2c219
GM
1264 }
1265 else
1266 {
1267 ccl->reg[0] = charset;
1268 ccl->reg[1] = char2b->byte1;
1269 ccl->reg[2] = char2b->byte2;
1270 }
7d0393cf 1271
06a2c219 1272 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
7d0393cf 1273
06a2c219
GM
1274 /* We assume that MSBs are appropriately set/reset by CCL
1275 program. */
1276 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1277 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1278 else
1279 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1280 }
1281 else if (font_info->encoding[charset])
1282 {
1283 /* Fixed encoding scheme. See fontset.h for the meaning of the
1284 encoding numbers. */
1285 int enc = font_info->encoding[charset];
7d0393cf 1286
06a2c219
GM
1287 if ((enc == 1 || enc == 2)
1288 && CHARSET_DIMENSION (charset) == 2)
1289 char2b->byte1 |= 0x80;
7d0393cf 1290
06a2c219
GM
1291 if (enc == 1 || enc == 3)
1292 char2b->byte2 |= 0x80;
1293 }
1294}
1295
1296
1297/* Get face and two-byte form of character C in face FACE_ID on frame
1298 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
abfb6b46
GM
1299 means we want to display multibyte text. DISPLAY_P non-zero means
1300 make sure that X resources for the face returned are allocated.
1301 Value is a pointer to a realized face that is ready for display if
1302 DISPLAY_P is non-zero. */
06a2c219
GM
1303
1304static INLINE struct face *
abfb6b46 1305x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p)
06a2c219
GM
1306 struct frame *f;
1307 int c, face_id;
1308 XChar2b *char2b;
abfb6b46 1309 int multibyte_p, display_p;
06a2c219
GM
1310{
1311 struct face *face = FACE_FROM_ID (f, face_id);
1312
1313 if (!multibyte_p)
1314 {
1315 /* Unibyte case. We don't have to encode, but we have to make
1316 sure to use a face suitable for unibyte. */
1317 char2b->byte1 = 0;
1318 char2b->byte2 = c;
ee569018
KH
1319 face_id = FACE_FOR_CHAR (f, face, c);
1320 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1321 }
1322 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1323 {
1324 /* Case of ASCII in a face known to fit ASCII. */
1325 char2b->byte1 = 0;
1326 char2b->byte2 = c;
1327 }
1328 else
1329 {
1330 int c1, c2, charset;
7d0393cf 1331
06a2c219
GM
1332 /* Split characters into bytes. If c2 is -1 afterwards, C is
1333 really a one-byte character so that byte1 is zero. */
1334 SPLIT_CHAR (c, charset, c1, c2);
1335 if (c2 > 0)
1336 char2b->byte1 = c1, char2b->byte2 = c2;
1337 else
1338 char2b->byte1 = 0, char2b->byte2 = c1;
1339
06a2c219 1340 /* Maybe encode the character in *CHAR2B. */
ee569018 1341 if (face->font != NULL)
06a2c219
GM
1342 {
1343 struct font_info *font_info
1344 = FONT_INFO_FROM_ID (f, face->font_info_id);
1345 if (font_info)
ee569018 1346 x_encode_char (c, char2b, font_info);
06a2c219
GM
1347 }
1348 }
1349
1350 /* Make sure X resources of the face are allocated. */
abfb6b46
GM
1351 if (display_p)
1352 {
1353 xassert (face != NULL);
1354 PREPARE_FACE_FOR_DISPLAY (f, face);
1355 }
7d0393cf 1356
06a2c219
GM
1357 return face;
1358}
1359
1360
1361/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1362 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1363 a pointer to a realized face that is ready for display. */
1364
1365static INLINE struct face *
ee569018 1366x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1367 struct frame *f;
1368 struct glyph *glyph;
1369 XChar2b *char2b;
ee569018 1370 int *two_byte_p;
06a2c219
GM
1371{
1372 struct face *face;
1373
1374 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1375 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1376
ee569018
KH
1377 if (two_byte_p)
1378 *two_byte_p = 0;
1379
06a2c219
GM
1380 if (!glyph->multibyte_p)
1381 {
1382 /* Unibyte case. We don't have to encode, but we have to make
1383 sure to use a face suitable for unibyte. */
1384 char2b->byte1 = 0;
43d120d8 1385 char2b->byte2 = glyph->u.ch;
06a2c219 1386 }
43d120d8
KH
1387 else if (glyph->u.ch < 128
1388 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1389 {
1390 /* Case of ASCII in a face known to fit ASCII. */
1391 char2b->byte1 = 0;
43d120d8 1392 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1393 }
1394 else
1395 {
1396 int c1, c2, charset;
7d0393cf 1397
06a2c219
GM
1398 /* Split characters into bytes. If c2 is -1 afterwards, C is
1399 really a one-byte character so that byte1 is zero. */
43d120d8 1400 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1401 if (c2 > 0)
1402 char2b->byte1 = c1, char2b->byte2 = c2;
1403 else
1404 char2b->byte1 = 0, char2b->byte2 = c1;
1405
1406 /* Maybe encode the character in *CHAR2B. */
1407 if (charset != CHARSET_ASCII)
1408 {
1409 struct font_info *font_info
1410 = FONT_INFO_FROM_ID (f, face->font_info_id);
1411 if (font_info)
1412 {
43d120d8 1413 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1414 if (two_byte_p)
1415 *two_byte_p
1416 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1417 }
1418 }
1419 }
1420
1421 /* Make sure X resources of the face are allocated. */
1422 xassert (face != NULL);
1423 PREPARE_FACE_FOR_DISPLAY (f, face);
1424 return face;
1425}
1426
1427
7d0393cf 1428/* Store one glyph for IT->char_to_display in IT->glyph_row.
06a2c219
GM
1429 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1430
1431static INLINE void
1432x_append_glyph (it)
1433 struct it *it;
1434{
1435 struct glyph *glyph;
1436 enum glyph_row_area area = it->area;
7d0393cf 1437
06a2c219
GM
1438 xassert (it->glyph_row);
1439 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
7d0393cf 1440
06a2c219
GM
1441 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1442 if (glyph < it->glyph_row->glyphs[area + 1])
1443 {
06a2c219
GM
1444 glyph->charpos = CHARPOS (it->position);
1445 glyph->object = it->object;
88d75730 1446 glyph->pixel_width = it->pixel_width;
06a2c219 1447 glyph->voffset = it->voffset;
88d75730 1448 glyph->type = CHAR_GLYPH;
06a2c219 1449 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1450 glyph->left_box_line_p = it->start_of_box_run_p;
1451 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1452 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1453 || it->phys_descent > it->descent);
88d75730 1454 glyph->padding_p = 0;
ee569018 1455 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1456 glyph->face_id = it->face_id;
1457 glyph->u.ch = it->char_to_display;
06a2c219
GM
1458 ++it->glyph_row->used[area];
1459 }
1460}
1461
7d0393cf 1462/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
b4192550
KH
1463 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1464
1465static INLINE void
1466x_append_composite_glyph (it)
1467 struct it *it;
1468{
1469 struct glyph *glyph;
1470 enum glyph_row_area area = it->area;
7d0393cf 1471
b4192550 1472 xassert (it->glyph_row);
7d0393cf 1473
b4192550
KH
1474 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1475 if (glyph < it->glyph_row->glyphs[area + 1])
1476 {
b4192550
KH
1477 glyph->charpos = CHARPOS (it->position);
1478 glyph->object = it->object;
88d75730 1479 glyph->pixel_width = it->pixel_width;
b4192550 1480 glyph->voffset = it->voffset;
88d75730 1481 glyph->type = COMPOSITE_GLYPH;
b4192550 1482 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1483 glyph->left_box_line_p = it->start_of_box_run_p;
1484 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1485 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1486 || it->phys_descent > it->descent);
88d75730
GM
1487 glyph->padding_p = 0;
1488 glyph->glyph_not_available_p = 0;
1489 glyph->face_id = it->face_id;
1490 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1491 ++it->glyph_row->used[area];
1492 }
1493}
1494
06a2c219
GM
1495
1496/* Change IT->ascent and IT->height according to the setting of
1497 IT->voffset. */
1498
1499static INLINE void
1500take_vertical_position_into_account (it)
1501 struct it *it;
1502{
1503 if (it->voffset)
1504 {
1505 if (it->voffset < 0)
1506 /* Increase the ascent so that we can display the text higher
1507 in the line. */
1508 it->ascent += abs (it->voffset);
1509 else
1510 /* Increase the descent so that we can display the text lower
1511 in the line. */
1512 it->descent += it->voffset;
1513 }
1514}
1515
1516
1517/* Produce glyphs/get display metrics for the image IT is loaded with.
1518 See the description of struct display_iterator in dispextern.h for
1519 an overview of struct display_iterator. */
1520
1521static void
1522x_produce_image_glyph (it)
1523 struct it *it;
1524{
1525 struct image *img;
1526 struct face *face;
1527
1528 xassert (it->what == IT_IMAGE);
1529
1530 face = FACE_FROM_ID (it->f, it->face_id);
1531 img = IMAGE_FROM_ID (it->f, it->image_id);
1532 xassert (img);
1533
1534 /* Make sure X resources of the face and image are loaded. */
1535 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1536 prepare_image_for_display (it->f, img);
1537
95af8492 1538 it->ascent = it->phys_ascent = image_ascent (img, face);
22d650b8
GM
1539 it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
1540 it->pixel_width = img->width + 2 * img->hmargin;
06a2c219
GM
1541
1542 it->nglyphs = 1;
7d0393cf 1543
06a2c219
GM
1544 if (face->box != FACE_NO_BOX)
1545 {
ea2ba0d4
KH
1546 if (face->box_line_width > 0)
1547 {
1548 it->ascent += face->box_line_width;
1549 it->descent += face->box_line_width;
1550 }
7d0393cf 1551
06a2c219 1552 if (it->start_of_box_run_p)
ea2ba0d4 1553 it->pixel_width += abs (face->box_line_width);
06a2c219 1554 if (it->end_of_box_run_p)
ea2ba0d4 1555 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1556 }
1557
1558 take_vertical_position_into_account (it);
7d0393cf 1559
06a2c219
GM
1560 if (it->glyph_row)
1561 {
1562 struct glyph *glyph;
1563 enum glyph_row_area area = it->area;
7d0393cf 1564
06a2c219
GM
1565 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1566 if (glyph < it->glyph_row->glyphs[area + 1])
1567 {
06a2c219
GM
1568 glyph->charpos = CHARPOS (it->position);
1569 glyph->object = it->object;
88d75730 1570 glyph->pixel_width = it->pixel_width;
06a2c219 1571 glyph->voffset = it->voffset;
88d75730 1572 glyph->type = IMAGE_GLYPH;
06a2c219 1573 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1574 glyph->left_box_line_p = it->start_of_box_run_p;
1575 glyph->right_box_line_p = it->end_of_box_run_p;
1576 glyph->overlaps_vertically_p = 0;
1577 glyph->padding_p = 0;
1578 glyph->glyph_not_available_p = 0;
1579 glyph->face_id = it->face_id;
1580 glyph->u.img_id = img->id;
06a2c219
GM
1581 ++it->glyph_row->used[area];
1582 }
1583 }
1584}
1585
1586
1587/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
7d0393cf
JB
1588 of the glyph, WIDTH and HEIGHT are the width and height of the
1589 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
06a2c219 1590 ascent of the glyph (0 <= ASCENT <= 1). */
7d0393cf 1591
06a2c219
GM
1592static void
1593x_append_stretch_glyph (it, object, width, height, ascent)
1594 struct it *it;
1595 Lisp_Object object;
1596 int width, height;
1597 double ascent;
1598{
1599 struct glyph *glyph;
1600 enum glyph_row_area area = it->area;
1601
1602 xassert (ascent >= 0 && ascent <= 1);
7d0393cf 1603
06a2c219
GM
1604 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1605 if (glyph < it->glyph_row->glyphs[area + 1])
1606 {
06a2c219
GM
1607 glyph->charpos = CHARPOS (it->position);
1608 glyph->object = object;
88d75730 1609 glyph->pixel_width = width;
06a2c219 1610 glyph->voffset = it->voffset;
88d75730 1611 glyph->type = STRETCH_GLYPH;
06a2c219 1612 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1613 glyph->left_box_line_p = it->start_of_box_run_p;
1614 glyph->right_box_line_p = it->end_of_box_run_p;
1615 glyph->overlaps_vertically_p = 0;
1616 glyph->padding_p = 0;
1617 glyph->glyph_not_available_p = 0;
1618 glyph->face_id = it->face_id;
1619 glyph->u.stretch.ascent = height * ascent;
1620 glyph->u.stretch.height = height;
06a2c219
GM
1621 ++it->glyph_row->used[area];
1622 }
1623}
1624
1625
1626/* Produce a stretch glyph for iterator IT. IT->object is the value
1627 of the glyph property displayed. The value must be a list
1628 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1629 being recognized:
1630
1631 1. `:width WIDTH' specifies that the space should be WIDTH *
7d0393cf 1632 canonical char width wide. WIDTH may be an integer or floating
06a2c219
GM
1633 point number.
1634
1635 2. `:relative-width FACTOR' specifies that the width of the stretch
1636 should be computed from the width of the first character having the
1637 `glyph' property, and should be FACTOR times that width.
1638
1639 3. `:align-to HPOS' specifies that the space should be wide enough
1640 to reach HPOS, a value in canonical character units.
1641
7d0393cf 1642 Exactly one of the above pairs must be present.
06a2c219
GM
1643
1644 4. `:height HEIGHT' specifies that the height of the stretch produced
1645 should be HEIGHT, measured in canonical character units.
1646
269b7745 1647 5. `:relative-height FACTOR' specifies that the height of the
06a2c219
GM
1648 stretch should be FACTOR times the height of the characters having
1649 the glyph property.
1650
1651 Either none or exactly one of 4 or 5 must be present.
1652
1653 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1654 of the stretch should be used for the ascent of the stretch.
1655 ASCENT must be in the range 0 <= ASCENT <= 100. */
1656
1657#define NUMVAL(X) \
1658 ((INTEGERP (X) || FLOATP (X)) \
1659 ? XFLOATINT (X) \
1660 : - 1)
1661
1662
1663static void
1664x_produce_stretch_glyph (it)
1665 struct it *it;
1666{
1667 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1668#if GLYPH_DEBUG
1669 extern Lisp_Object Qspace;
1670#endif
1671 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1672 extern Lisp_Object QCrelative_width, QCrelative_height;
1673 extern Lisp_Object QCalign_to;
1674 Lisp_Object prop, plist;
1675 double width = 0, height = 0, ascent = 0;
1676 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1677 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1678
1679 PREPARE_FACE_FOR_DISPLAY (it->f, face);
7d0393cf 1680
06a2c219
GM
1681 /* List should start with `space'. */
1682 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1683 plist = XCDR (it->object);
1684
1685 /* Compute the width of the stretch. */
1686 if (prop = Fplist_get (plist, QCwidth),
1687 NUMVAL (prop) > 0)
1688 /* Absolute width `:width WIDTH' specified and valid. */
1689 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1690 else if (prop = Fplist_get (plist, QCrelative_width),
1691 NUMVAL (prop) > 0)
1692 {
1693 /* Relative width `:relative-width FACTOR' specified and valid.
1694 Compute the width of the characters having the `glyph'
1695 property. */
1696 struct it it2;
1697 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
7d0393cf 1698
06a2c219
GM
1699 it2 = *it;
1700 if (it->multibyte_p)
1701 {
1702 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1703 - IT_BYTEPOS (*it));
1704 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1705 }
1706 else
1707 it2.c = *p, it2.len = 1;
1708
1709 it2.glyph_row = NULL;
1710 it2.what = IT_CHARACTER;
1711 x_produce_glyphs (&it2);
1712 width = NUMVAL (prop) * it2.pixel_width;
1713 }
1714 else if (prop = Fplist_get (plist, QCalign_to),
1715 NUMVAL (prop) > 0)
1716 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1717 else
1718 /* Nothing specified -> width defaults to canonical char width. */
1719 width = CANON_X_UNIT (it->f);
7d0393cf 1720
06a2c219
GM
1721 /* Compute height. */
1722 if (prop = Fplist_get (plist, QCheight),
1723 NUMVAL (prop) > 0)
1724 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1725 else if (prop = Fplist_get (plist, QCrelative_height),
1726 NUMVAL (prop) > 0)
1727 height = FONT_HEIGHT (font) * NUMVAL (prop);
1728 else
1729 height = FONT_HEIGHT (font);
1730
7d0393cf 1731 /* Compute percentage of height used for ascent. If
06a2c219
GM
1732 `:ascent ASCENT' is present and valid, use that. Otherwise,
1733 derive the ascent from the font in use. */
1734 if (prop = Fplist_get (plist, QCascent),
1735 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1736 ascent = NUMVAL (prop) / 100.0;
1737 else
1738 ascent = (double) font->ascent / FONT_HEIGHT (font);
1739
1740 if (width <= 0)
1741 width = 1;
1742 if (height <= 0)
1743 height = 1;
1744
1745 if (it->glyph_row)
1746 {
1747 Lisp_Object object = it->stack[it->sp - 1].string;
1748 if (!STRINGP (object))
1749 object = it->w->buffer;
1750 x_append_stretch_glyph (it, object, width, height, ascent);
1751 }
1752
1753 it->pixel_width = width;
66ac4b0e
GM
1754 it->ascent = it->phys_ascent = height * ascent;
1755 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1756 it->nglyphs = 1;
1757
1758 if (face->box != FACE_NO_BOX)
1759 {
ea2ba0d4
KH
1760 if (face->box_line_width > 0)
1761 {
1762 it->ascent += face->box_line_width;
1763 it->descent += face->box_line_width;
1764 }
7d0393cf 1765
06a2c219 1766 if (it->start_of_box_run_p)
ea2ba0d4 1767 it->pixel_width += abs (face->box_line_width);
06a2c219 1768 if (it->end_of_box_run_p)
ea2ba0d4 1769 it->pixel_width += abs (face->box_line_width);
06a2c219 1770 }
7d0393cf 1771
06a2c219
GM
1772 take_vertical_position_into_account (it);
1773}
1774
b4192550
KH
1775/* Return proper value to be used as baseline offset of font that has
1776 ASCENT and DESCENT to draw characters by the font at the vertical
1777 center of the line of frame F.
1778
1779 Here, out task is to find the value of BOFF in the following figure;
1780
1781 -------------------------+-----------+-
1782 -+-+---------+-+ | |
1783 | | | | | |
1784 | | | | F_ASCENT F_HEIGHT
1785 | | | ASCENT | |
1786 HEIGHT | | | | |
1787 | | |-|-+------+-----------|------- baseline
1788 | | | | BOFF | |
1789 | |---------|-+-+ | |
1790 | | | DESCENT | |
1791 -+-+---------+-+ F_DESCENT |
1792 -------------------------+-----------+-
1793
1794 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1795 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1796 DESCENT = FONT->descent
1797 HEIGHT = FONT_HEIGHT (FONT)
1798 F_DESCENT = (F->output_data.x->font->descent
1799 - F->output_data.x->baseline_offset)
1800 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1801*/
1802
458f45fa
KH
1803#define VCENTER_BASELINE_OFFSET(FONT, F) \
1804 ((FONT)->descent \
1805 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT)) \
1806 + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \
1807 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1808
1809/* Produce glyphs/get display metrics for the display element IT is
1810 loaded with. See the description of struct display_iterator in
1811 dispextern.h for an overview of struct display_iterator. */
1812
1813static void
1814x_produce_glyphs (it)
1815 struct it *it;
1816{
ee569018
KH
1817 it->glyph_not_available_p = 0;
1818
06a2c219
GM
1819 if (it->what == IT_CHARACTER)
1820 {
1821 XChar2b char2b;
1822 XFontStruct *font;
ee569018 1823 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1824 XCharStruct *pcm;
06a2c219 1825 int font_not_found_p;
b4192550
KH
1826 struct font_info *font_info;
1827 int boff; /* baseline offset */
a4249304
KH
1828 /* We may change it->multibyte_p upon unibyte<->multibyte
1829 conversion. So, save the current value now and restore it
1830 later.
1831
1832 Note: It seems that we don't have to record multibyte_p in
1833 struct glyph because the character code itself tells if or
1834 not the character is multibyte. Thus, in the future, we must
1835 consider eliminating the field `multibyte_p' in the struct
c347a1c3 1836 glyph. */
a4249304 1837 int saved_multibyte_p = it->multibyte_p;
06a2c219 1838
ee569018
KH
1839 /* Maybe translate single-byte characters to multibyte, or the
1840 other way. */
06a2c219 1841 it->char_to_display = it->c;
ee569018 1842 if (!ASCII_BYTE_P (it->c))
06a2c219 1843 {
ee569018
KH
1844 if (unibyte_display_via_language_environment
1845 && SINGLE_BYTE_CHAR_P (it->c)
1846 && (it->c >= 0240
1847 || !NILP (Vnonascii_translation_table)))
1848 {
1849 it->char_to_display = unibyte_char_to_multibyte (it->c);
a4249304 1850 it->multibyte_p = 1;
ee569018
KH
1851 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1852 face = FACE_FROM_ID (it->f, it->face_id);
1853 }
1854 else if (!SINGLE_BYTE_CHAR_P (it->c)
1855 && !it->multibyte_p)
1856 {
c347a1c3 1857 it->multibyte_p = 1;
ee569018
KH
1858 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1859 face = FACE_FROM_ID (it->f, it->face_id);
1860 }
06a2c219 1861 }
7d0393cf 1862
ee569018
KH
1863 /* Get font to use. Encode IT->char_to_display. */
1864 x_get_char_face_and_encoding (it->f, it->char_to_display,
1865 it->face_id, &char2b,
abfb6b46 1866 it->multibyte_p, 0);
06a2c219
GM
1867 font = face->font;
1868
1869 /* When no suitable font found, use the default font. */
1870 font_not_found_p = font == NULL;
1871 if (font_not_found_p)
b4192550
KH
1872 {
1873 font = FRAME_FONT (it->f);
1874 boff = it->f->output_data.x->baseline_offset;
1875 font_info = NULL;
1876 }
1877 else
1878 {
1879 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1880 boff = font_info->baseline_offset;
1881 if (font_info->vertical_centering)
1882 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1883 }
06a2c219
GM
1884
1885 if (it->char_to_display >= ' '
1886 && (!it->multibyte_p || it->char_to_display < 128))
1887 {
1888 /* Either unibyte or ASCII. */
1889 int stretched_p;
1890
1891 it->nglyphs = 1;
06a2c219
GM
1892
1893 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1894 it->ascent = font->ascent + boff;
1895 it->descent = font->descent - boff;
474848ac
GM
1896
1897 if (pcm)
1898 {
1899 it->phys_ascent = pcm->ascent + boff;
1900 it->phys_descent = pcm->descent - boff;
1901 it->pixel_width = pcm->width;
1902 }
1903 else
1904 {
1905 it->glyph_not_available_p = 1;
1906 it->phys_ascent = font->ascent + boff;
1907 it->phys_descent = font->descent - boff;
1908 it->pixel_width = FONT_WIDTH (font);
1909 }
06a2c219
GM
1910
1911 /* If this is a space inside a region of text with
1912 `space-width' property, change its width. */
1913 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1914 if (stretched_p)
1915 it->pixel_width *= XFLOATINT (it->space_width);
1916
1917 /* If face has a box, add the box thickness to the character
1918 height. If character has a box line to the left and/or
1919 right, add the box line width to the character's width. */
1920 if (face->box != FACE_NO_BOX)
1921 {
1922 int thick = face->box_line_width;
7d0393cf 1923
ea2ba0d4
KH
1924 if (thick > 0)
1925 {
1926 it->ascent += thick;
1927 it->descent += thick;
1928 }
1929 else
1930 thick = -thick;
1931
06a2c219
GM
1932 if (it->start_of_box_run_p)
1933 it->pixel_width += thick;
1934 if (it->end_of_box_run_p)
1935 it->pixel_width += thick;
1936 }
1937
1938 /* If face has an overline, add the height of the overline
1939 (1 pixel) and a 1 pixel margin to the character height. */
1940 if (face->overline_p)
1941 it->ascent += 2;
1942
1943 take_vertical_position_into_account (it);
7d0393cf 1944
06a2c219
GM
1945 /* If we have to actually produce glyphs, do it. */
1946 if (it->glyph_row)
1947 {
1948 if (stretched_p)
1949 {
1950 /* Translate a space with a `space-width' property
1951 into a stretch glyph. */
1952 double ascent = (double) font->ascent / FONT_HEIGHT (font);
7d0393cf 1953 x_append_stretch_glyph (it, it->object, it->pixel_width,
06a2c219
GM
1954 it->ascent + it->descent, ascent);
1955 }
1956 else
1957 x_append_glyph (it);
1958
1959 /* If characters with lbearing or rbearing are displayed
1960 in this line, record that fact in a flag of the
1961 glyph row. This is used to optimize X output code. */
1c7e22fd 1962 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1963 it->glyph_row->contains_overlapping_glyphs_p = 1;
1964 }
1965 }
1966 else if (it->char_to_display == '\n')
1967 {
1968 /* A newline has no width but we need the height of the line. */
1969 it->pixel_width = 0;
1970 it->nglyphs = 0;
b4192550
KH
1971 it->ascent = it->phys_ascent = font->ascent + boff;
1972 it->descent = it->phys_descent = font->descent - boff;
7d0393cf 1973
ea2ba0d4
KH
1974 if (face->box != FACE_NO_BOX
1975 && face->box_line_width > 0)
06a2c219 1976 {
ea2ba0d4
KH
1977 it->ascent += face->box_line_width;
1978 it->descent += face->box_line_width;
06a2c219
GM
1979 }
1980 }
1981 else if (it->char_to_display == '\t')
1982 {
1983 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1984 int x = it->current_x + it->continuation_lines_width;
06a2c219 1985 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
2a32b5ea
GM
1986
1987 /* If the distance from the current position to the next tab
1988 stop is less than a canonical character width, use the
1989 tab stop after that. */
1990 if (next_tab_x - x < CANON_X_UNIT (it->f))
1991 next_tab_x += tab_width;
7d0393cf 1992
06a2c219
GM
1993 it->pixel_width = next_tab_x - x;
1994 it->nglyphs = 1;
b4192550
KH
1995 it->ascent = it->phys_ascent = font->ascent + boff;
1996 it->descent = it->phys_descent = font->descent - boff;
7d0393cf 1997
06a2c219
GM
1998 if (it->glyph_row)
1999 {
2000 double ascent = (double) it->ascent / (it->ascent + it->descent);
7d0393cf 2001 x_append_stretch_glyph (it, it->object, it->pixel_width,
06a2c219
GM
2002 it->ascent + it->descent, ascent);
2003 }
2004 }
7d0393cf 2005 else
06a2c219
GM
2006 {
2007 /* A multi-byte character. Assume that the display width of the
2008 character is the width of the character multiplied by the
b4192550 2009 width of the font. */
06a2c219 2010
b4192550
KH
2011 /* If we found a font, this font should give us the right
2012 metrics. If we didn't find a font, use the frame's
2013 default font and calculate the width of the character
2014 from the charset width; this is what old redisplay code
2015 did. */
2016 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
2017 if (font_not_found_p || !pcm)
2018 {
2019 int charset = CHAR_CHARSET (it->char_to_display);
2020
2021 it->glyph_not_available_p = 1;
2022 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
2023 * CHARSET_WIDTH (charset));
2024 it->phys_ascent = font->ascent + boff;
2025 it->phys_descent = font->descent - boff;
2026 }
2027 else
2028 {
2029 it->pixel_width = pcm->width;
2030 it->phys_ascent = pcm->ascent + boff;
2031 it->phys_descent = pcm->descent - boff;
2032 if (it->glyph_row
2033 && (pcm->lbearing < 0
2034 || pcm->rbearing > pcm->width))
2035 it->glyph_row->contains_overlapping_glyphs_p = 1;
2036 }
b4192550
KH
2037 it->nglyphs = 1;
2038 it->ascent = font->ascent + boff;
2039 it->descent = font->descent - boff;
06a2c219
GM
2040 if (face->box != FACE_NO_BOX)
2041 {
2042 int thick = face->box_line_width;
ea2ba0d4
KH
2043
2044 if (thick > 0)
2045 {
2046 it->ascent += thick;
2047 it->descent += thick;
2048 }
2049 else
2050 thick = - thick;
7d0393cf 2051
06a2c219
GM
2052 if (it->start_of_box_run_p)
2053 it->pixel_width += thick;
2054 if (it->end_of_box_run_p)
2055 it->pixel_width += thick;
2056 }
7d0393cf 2057
06a2c219
GM
2058 /* If face has an overline, add the height of the overline
2059 (1 pixel) and a 1 pixel margin to the character height. */
2060 if (face->overline_p)
2061 it->ascent += 2;
2062
2063 take_vertical_position_into_account (it);
7d0393cf 2064
06a2c219
GM
2065 if (it->glyph_row)
2066 x_append_glyph (it);
2067 }
a4249304 2068 it->multibyte_p = saved_multibyte_p;
06a2c219 2069 }
b4192550
KH
2070 else if (it->what == IT_COMPOSITION)
2071 {
2072 /* Note: A composition is represented as one glyph in the
2073 glyph matrix. There are no padding glyphs. */
2074 XChar2b char2b;
2075 XFontStruct *font;
ee569018 2076 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2077 XCharStruct *pcm;
2078 int font_not_found_p;
2079 struct font_info *font_info;
2080 int boff; /* baseline offset */
2081 struct composition *cmp = composition_table[it->cmp_id];
2082
2083 /* Maybe translate single-byte characters to multibyte. */
2084 it->char_to_display = it->c;
2085 if (unibyte_display_via_language_environment
2086 && SINGLE_BYTE_CHAR_P (it->c)
2087 && (it->c >= 0240
2088 || (it->c >= 0200
2089 && !NILP (Vnonascii_translation_table))))
2090 {
2091 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550 2092 }
7d0393cf 2093
b4192550 2094 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2095 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2096 face = FACE_FROM_ID (it->f, it->face_id);
2097 x_get_char_face_and_encoding (it->f, it->char_to_display,
abfb6b46 2098 it->face_id, &char2b, it->multibyte_p, 0);
b4192550
KH
2099 font = face->font;
2100
2101 /* When no suitable font found, use the default font. */
2102 font_not_found_p = font == NULL;
2103 if (font_not_found_p)
2104 {
2105 font = FRAME_FONT (it->f);
2106 boff = it->f->output_data.x->baseline_offset;
2107 font_info = NULL;
2108 }
2109 else
2110 {
2111 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2112 boff = font_info->baseline_offset;
2113 if (font_info->vertical_centering)
2114 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2115 }
2116
2117 /* There are no padding glyphs, so there is only one glyph to
2118 produce for the composition. Important is that pixel_width,
2119 ascent and descent are the values of what is drawn by
2120 draw_glyphs (i.e. the values of the overall glyphs composed). */
2121 it->nglyphs = 1;
2122
2123 /* If we have not yet calculated pixel size data of glyphs of
2124 the composition for the current face font, calculate them
2125 now. Theoretically, we have to check all fonts for the
2126 glyphs, but that requires much time and memory space. So,
2127 here we check only the font of the first glyph. This leads
2128 to incorrect display very rarely, and C-l (recenter) can
2129 correct the display anyway. */
2130 if (cmp->font != (void *) font)
2131 {
2132 /* Ascent and descent of the font of the first character of
2133 this composition (adjusted by baseline offset). Ascent
2134 and descent of overall glyphs should not be less than
2135 them respectively. */
2136 int font_ascent = font->ascent + boff;
2137 int font_descent = font->descent - boff;
2138 /* Bounding box of the overall glyphs. */
2139 int leftmost, rightmost, lowest, highest;
329bed06 2140 int i, width, ascent, descent;
b4192550
KH
2141
2142 cmp->font = (void *) font;
2143
2144 /* Initialize the bounding box. */
1bdeec2e
KH
2145 if (font_info
2146 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2147 {
2148 width = pcm->width;
2149 ascent = pcm->ascent;
2150 descent = pcm->descent;
2151 }
2152 else
2153 {
2154 width = FONT_WIDTH (font);
2155 ascent = font->ascent;
2156 descent = font->descent;
2157 }
7d0393cf 2158
329bed06
GM
2159 rightmost = width;
2160 lowest = - descent + boff;
2161 highest = ascent + boff;
b4192550 2162 leftmost = 0;
7d0393cf 2163
b4192550
KH
2164 if (font_info
2165 && font_info->default_ascent
2166 && CHAR_TABLE_P (Vuse_default_ascent)
2167 && !NILP (Faref (Vuse_default_ascent,
2168 make_number (it->char_to_display))))
2169 highest = font_info->default_ascent + boff;
2170
2171 /* Draw the first glyph at the normal position. It may be
2172 shifted to right later if some other glyphs are drawn at
2173 the left. */
2174 cmp->offsets[0] = 0;
2175 cmp->offsets[1] = boff;
2176
2177 /* Set cmp->offsets for the remaining glyphs. */
2178 for (i = 1; i < cmp->glyph_len; i++)
2179 {
2180 int left, right, btm, top;
2181 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018 2182 int face_id = FACE_FOR_CHAR (it->f, face, ch);
7d0393cf 2183
ee569018
KH
2184 face = FACE_FROM_ID (it->f, face_id);
2185 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
abfb6b46 2186 it->multibyte_p, 0);
b4192550
KH
2187 font = face->font;
2188 if (font == NULL)
2189 {
2190 font = FRAME_FONT (it->f);
2191 boff = it->f->output_data.x->baseline_offset;
2192 font_info = NULL;
2193 }
2194 else
2195 {
2196 font_info
2197 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2198 boff = font_info->baseline_offset;
2199 if (font_info->vertical_centering)
2200 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2201 }
2202
1bdeec2e
KH
2203 if (font_info
2204 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2205 {
2206 width = pcm->width;
2207 ascent = pcm->ascent;
2208 descent = pcm->descent;
2209 }
2210 else
2211 {
2212 width = FONT_WIDTH (font);
1bdeec2e
KH
2213 ascent = 1;
2214 descent = 0;
329bed06 2215 }
b4192550
KH
2216
2217 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2218 {
2219 /* Relative composition with or without
2220 alternate chars. */
329bed06
GM
2221 left = (leftmost + rightmost - width) / 2;
2222 btm = - descent + boff;
b4192550
KH
2223 if (font_info && font_info->relative_compose
2224 && (! CHAR_TABLE_P (Vignore_relative_composition)
2225 || NILP (Faref (Vignore_relative_composition,
2226 make_number (ch)))))
2227 {
2228
329bed06 2229 if (- descent >= font_info->relative_compose)
b4192550
KH
2230 /* One extra pixel between two glyphs. */
2231 btm = highest + 1;
329bed06 2232 else if (ascent <= 0)
b4192550 2233 /* One extra pixel between two glyphs. */
329bed06 2234 btm = lowest - 1 - ascent - descent;
b4192550
KH
2235 }
2236 }
2237 else
2238 {
2239 /* A composition rule is specified by an integer
2240 value that encodes global and new reference
2241 points (GREF and NREF). GREF and NREF are
2242 specified by numbers as below:
2243
2244 0---1---2 -- ascent
2245 | |
2246 | |
2247 | |
2248 9--10--11 -- center
2249 | |
2250 ---3---4---5--- baseline
2251 | |
2252 6---7---8 -- descent
2253 */
2254 int rule = COMPOSITION_RULE (cmp, i);
2255 int gref, nref, grefx, grefy, nrefx, nrefy;
2256
2257 COMPOSITION_DECODE_RULE (rule, gref, nref);
2258 grefx = gref % 3, nrefx = nref % 3;
2259 grefy = gref / 3, nrefy = nref / 3;
2260
2261 left = (leftmost
2262 + grefx * (rightmost - leftmost) / 2
329bed06 2263 - nrefx * width / 2);
b4192550
KH
2264 btm = ((grefy == 0 ? highest
2265 : grefy == 1 ? 0
2266 : grefy == 2 ? lowest
2267 : (highest + lowest) / 2)
329bed06
GM
2268 - (nrefy == 0 ? ascent + descent
2269 : nrefy == 1 ? descent - boff
b4192550 2270 : nrefy == 2 ? 0
329bed06 2271 : (ascent + descent) / 2));
b4192550
KH
2272 }
2273
2274 cmp->offsets[i * 2] = left;
329bed06 2275 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2276
2277 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2278 right = left + width;
2279 top = btm + descent + ascent;
b4192550
KH
2280 if (left < leftmost)
2281 leftmost = left;
2282 if (right > rightmost)
2283 rightmost = right;
2284 if (top > highest)
2285 highest = top;
2286 if (btm < lowest)
2287 lowest = btm;
2288 }
2289
2290 /* If there are glyphs whose x-offsets are negative,
2291 shift all glyphs to the right and make all x-offsets
2292 non-negative. */
2293 if (leftmost < 0)
2294 {
2295 for (i = 0; i < cmp->glyph_len; i++)
2296 cmp->offsets[i * 2] -= leftmost;
2297 rightmost -= leftmost;
2298 }
2299
2300 cmp->pixel_width = rightmost;
2301 cmp->ascent = highest;
2302 cmp->descent = - lowest;
2303 if (cmp->ascent < font_ascent)
2304 cmp->ascent = font_ascent;
2305 if (cmp->descent < font_descent)
2306 cmp->descent = font_descent;
2307 }
2308
2309 it->pixel_width = cmp->pixel_width;
2310 it->ascent = it->phys_ascent = cmp->ascent;
2311 it->descent = it->phys_descent = cmp->descent;
2312
2313 if (face->box != FACE_NO_BOX)
2314 {
2315 int thick = face->box_line_width;
ea2ba0d4
KH
2316
2317 if (thick > 0)
2318 {
2319 it->ascent += thick;
2320 it->descent += thick;
2321 }
2322 else
2323 thick = - thick;
7d0393cf 2324
b4192550
KH
2325 if (it->start_of_box_run_p)
2326 it->pixel_width += thick;
2327 if (it->end_of_box_run_p)
2328 it->pixel_width += thick;
2329 }
7d0393cf 2330
b4192550
KH
2331 /* If face has an overline, add the height of the overline
2332 (1 pixel) and a 1 pixel margin to the character height. */
2333 if (face->overline_p)
2334 it->ascent += 2;
2335
2336 take_vertical_position_into_account (it);
7d0393cf 2337
b4192550
KH
2338 if (it->glyph_row)
2339 x_append_composite_glyph (it);
2340 }
06a2c219
GM
2341 else if (it->what == IT_IMAGE)
2342 x_produce_image_glyph (it);
2343 else if (it->what == IT_STRETCH)
2344 x_produce_stretch_glyph (it);
2345
3017fdd1
GM
2346 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2347 because this isn't true for images with `:ascent 100'. */
2348 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2349 if (it->area == TEXT_AREA)
2350 it->current_x += it->pixel_width;
7d0393cf 2351
d365f5bb 2352 it->descent += it->extra_line_spacing;
7d0393cf 2353
06a2c219
GM
2354 it->max_ascent = max (it->max_ascent, it->ascent);
2355 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2356 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2357 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2358}
2359
2360
2361/* Estimate the pixel height of the mode or top line on frame F.
2362 FACE_ID specifies what line's height to estimate. */
2363
2364int
2365x_estimate_mode_line_height (f, face_id)
2366 struct frame *f;
2367 enum face_id face_id;
2368{
43281ee3 2369 int height = FONT_HEIGHT (FRAME_FONT (f));
06a2c219
GM
2370
2371 /* This function is called so early when Emacs starts that the face
2372 cache and mode line face are not yet initialized. */
2373 if (FRAME_FACE_CACHE (f))
2374 {
2375 struct face *face = FACE_FROM_ID (f, face_id);
2376 if (face)
43281ee3
GM
2377 {
2378 if (face->font)
2379 height = FONT_HEIGHT (face->font);
ea2ba0d4
KH
2380 if (face->box_line_width > 0)
2381 height += 2 * face->box_line_width;
43281ee3 2382 }
06a2c219 2383 }
7d0393cf 2384
06a2c219
GM
2385 return height;
2386}
2387
2388\f
2389/***********************************************************************
2390 Glyph display
2391 ***********************************************************************/
2392
2393/* A sequence of glyphs to be drawn in the same face.
2394
2395 This data structure is not really completely X specific, so it
2396 could possibly, at least partially, be useful for other systems. It
2397 is currently not part of the external redisplay interface because
2398 it's not clear what other systems will need. */
2399
2400struct glyph_string
2401{
2402 /* X-origin of the string. */
2403 int x;
2404
2405 /* Y-origin and y-position of the base line of this string. */
2406 int y, ybase;
2407
2408 /* The width of the string, not including a face extension. */
2409 int width;
2410
2411 /* The width of the string, including a face extension. */
2412 int background_width;
2413
2414 /* The height of this string. This is the height of the line this
2415 string is drawn in, and can be different from the height of the
2416 font the string is drawn in. */
2417 int height;
2418
2419 /* Number of pixels this string overwrites in front of its x-origin.
2420 This number is zero if the string has an lbearing >= 0; it is
2421 -lbearing, if the string has an lbearing < 0. */
2422 int left_overhang;
2423
2424 /* Number of pixels this string overwrites past its right-most
2425 nominal x-position, i.e. x + width. Zero if the string's
2426 rbearing is <= its nominal width, rbearing - width otherwise. */
2427 int right_overhang;
2428
2429 /* The frame on which the glyph string is drawn. */
2430 struct frame *f;
2431
2432 /* The window on which the glyph string is drawn. */
2433 struct window *w;
2434
2435 /* X display and window for convenience. */
2436 Display *display;
2437 Window window;
2438
2439 /* The glyph row for which this string was built. It determines the
2440 y-origin and height of the string. */
2441 struct glyph_row *row;
2442
2443 /* The area within row. */
2444 enum glyph_row_area area;
2445
2446 /* Characters to be drawn, and number of characters. */
2447 XChar2b *char2b;
2448 int nchars;
2449
06a2c219
GM
2450 /* A face-override for drawing cursors, mouse face and similar. */
2451 enum draw_glyphs_face hl;
2452
2453 /* Face in which this string is to be drawn. */
2454 struct face *face;
2455
2456 /* Font in which this string is to be drawn. */
2457 XFontStruct *font;
2458
2459 /* Font info for this string. */
2460 struct font_info *font_info;
2461
b4192550
KH
2462 /* Non-null means this string describes (part of) a composition.
2463 All characters from char2b are drawn composed. */
2464 struct composition *cmp;
06a2c219
GM
2465
2466 /* Index of this glyph string's first character in the glyph
b4192550
KH
2467 definition of CMP. If this is zero, this glyph string describes
2468 the first character of a composition. */
06a2c219
GM
2469 int gidx;
2470
2471 /* 1 means this glyph strings face has to be drawn to the right end
2472 of the window's drawing area. */
2473 unsigned extends_to_end_of_line_p : 1;
2474
2475 /* 1 means the background of this string has been drawn. */
2476 unsigned background_filled_p : 1;
2477
2478 /* 1 means glyph string must be drawn with 16-bit functions. */
2479 unsigned two_byte_p : 1;
2480
2481 /* 1 means that the original font determined for drawing this glyph
2482 string could not be loaded. The member `font' has been set to
2483 the frame's default font in this case. */
2484 unsigned font_not_found_p : 1;
2485
2486 /* 1 means that the face in which this glyph string is drawn has a
2487 stipple pattern. */
2488 unsigned stippled_p : 1;
2489
66ac4b0e
GM
2490 /* 1 means only the foreground of this glyph string must be drawn,
2491 and we should use the physical height of the line this glyph
2492 string appears in as clip rect. */
2493 unsigned for_overlaps_p : 1;
2494
06a2c219
GM
2495 /* The GC to use for drawing this glyph string. */
2496 GC gc;
2497
2498 /* A pointer to the first glyph in the string. This glyph
2499 corresponds to char2b[0]. Needed to draw rectangles if
2500 font_not_found_p is 1. */
2501 struct glyph *first_glyph;
2502
2503 /* Image, if any. */
2504 struct image *img;
2505
2506 struct glyph_string *next, *prev;
2507};
2508
2509
61869b99 2510#if GLYPH_DEBUG
06a2c219
GM
2511
2512static void
2513x_dump_glyph_string (s)
2514 struct glyph_string *s;
2515{
2516 fprintf (stderr, "glyph string\n");
2517 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2518 s->x, s->y, s->width, s->height);
2519 fprintf (stderr, " ybase = %d\n", s->ybase);
2520 fprintf (stderr, " hl = %d\n", s->hl);
2521 fprintf (stderr, " left overhang = %d, right = %d\n",
2522 s->left_overhang, s->right_overhang);
2523 fprintf (stderr, " nchars = %d\n", s->nchars);
2524 fprintf (stderr, " extends to end of line = %d\n",
2525 s->extends_to_end_of_line_p);
2526 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2527 fprintf (stderr, " bg width = %d\n", s->background_width);
2528}
2529
2530#endif /* GLYPH_DEBUG */
2531
2532
2533
2534static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2535 struct glyph_string **,
2536 struct glyph_string *,
2537 struct glyph_string *));
2538static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2539 struct glyph_string **,
2540 struct glyph_string *,
2541 struct glyph_string *));
2542static void x_append_glyph_string P_ ((struct glyph_string **,
2543 struct glyph_string **,
2544 struct glyph_string *));
2545static int x_left_overwritten P_ ((struct glyph_string *));
2546static int x_left_overwriting P_ ((struct glyph_string *));
2547static int x_right_overwritten P_ ((struct glyph_string *));
2548static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2549static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2550 int));
06a2c219
GM
2551static void x_init_glyph_string P_ ((struct glyph_string *,
2552 XChar2b *, struct window *,
2553 struct glyph_row *,
7d0393cf 2554 enum glyph_row_area, int,
06a2c219
GM
2555 enum draw_glyphs_face));
2556static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2557 enum glyph_row_area, int, int,
f0a48a01 2558 enum draw_glyphs_face, int));
06a2c219
GM
2559static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2560static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2561static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2562 int));
2563static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2564static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2565static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2566static void x_draw_glyph_string P_ ((struct glyph_string *));
2567static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2568static void x_set_cursor_gc P_ ((struct glyph_string *));
2569static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2570static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2571static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2572 int *, int *));
2573static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2574static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2575 unsigned long *, double, int));
06a2c219 2576static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2577 double, int, unsigned long));
06a2c219
GM
2578static void x_setup_relief_colors P_ ((struct glyph_string *));
2579static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2580static void x_draw_image_relief P_ ((struct glyph_string *));
2581static void x_draw_image_foreground P_ ((struct glyph_string *));
2582static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2583static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2584static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2585 int, int, int));
2586static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2587 int, int, int, int, XRectangle *));
2588static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2589 int, int, int, XRectangle *));
66ac4b0e
GM
2590static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2591 enum glyph_row_area));
209f68d9
GM
2592static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2593 struct glyph_row *,
2594 enum glyph_row_area, int, int));
06a2c219 2595
163dcff3
GM
2596#if GLYPH_DEBUG
2597static void x_check_font P_ ((struct frame *, XFontStruct *));
2598#endif
2599
06a2c219 2600
06a2c219
GM
2601/* Append the list of glyph strings with head H and tail T to the list
2602 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2603
2604static INLINE void
2605x_append_glyph_string_lists (head, tail, h, t)
2606 struct glyph_string **head, **tail;
2607 struct glyph_string *h, *t;
2608{
2609 if (h)
2610 {
2611 if (*head)
2612 (*tail)->next = h;
2613 else
2614 *head = h;
2615 h->prev = *tail;
2616 *tail = t;
2617 }
2618}
2619
2620
2621/* Prepend the list of glyph strings with head H and tail T to the
2622 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2623 result. */
2624
2625static INLINE void
2626x_prepend_glyph_string_lists (head, tail, h, t)
2627 struct glyph_string **head, **tail;
2628 struct glyph_string *h, *t;
2629{
2630 if (h)
2631 {
2632 if (*head)
2633 (*head)->prev = t;
2634 else
2635 *tail = t;
2636 t->next = *head;
2637 *head = h;
2638 }
2639}
2640
2641
2642/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2643 Set *HEAD and *TAIL to the resulting list. */
2644
2645static INLINE void
2646x_append_glyph_string (head, tail, s)
2647 struct glyph_string **head, **tail;
2648 struct glyph_string *s;
2649{
2650 s->next = s->prev = NULL;
2651 x_append_glyph_string_lists (head, tail, s, s);
2652}
2653
2654
2655/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2656 face. */
2657
2658static void
2659x_set_cursor_gc (s)
2660 struct glyph_string *s;
2661{
2662 if (s->font == FRAME_FONT (s->f)
2663 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2664 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2665 && !s->cmp)
06a2c219
GM
2666 s->gc = s->f->output_data.x->cursor_gc;
2667 else
2668 {
2669 /* Cursor on non-default face: must merge. */
2670 XGCValues xgcv;
2671 unsigned long mask;
2672
2673 xgcv.background = s->f->output_data.x->cursor_pixel;
2674 xgcv.foreground = s->face->background;
2675
2676 /* If the glyph would be invisible, try a different foreground. */
2677 if (xgcv.foreground == xgcv.background)
2678 xgcv.foreground = s->face->foreground;
2679 if (xgcv.foreground == xgcv.background)
2680 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2681 if (xgcv.foreground == xgcv.background)
2682 xgcv.foreground = s->face->foreground;
2683
2684 /* Make sure the cursor is distinct from text in this face. */
2685 if (xgcv.background == s->face->background
2686 && xgcv.foreground == s->face->foreground)
2687 {
2688 xgcv.background = s->face->foreground;
2689 xgcv.foreground = s->face->background;
2690 }
2691
2692 IF_DEBUG (x_check_font (s->f, s->font));
2693 xgcv.font = s->font->fid;
2694 xgcv.graphics_exposures = False;
2695 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2696
2697 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2698 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2699 mask, &xgcv);
2700 else
2701 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2702 = XCreateGC (s->display, s->window, mask, &xgcv);
2703
2704 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2705 }
2706}
2707
2708
2709/* Set up S->gc of glyph string S for drawing text in mouse face. */
7d0393cf 2710
06a2c219
GM
2711static void
2712x_set_mouse_face_gc (s)
2713 struct glyph_string *s;
7d0393cf 2714{
06a2c219 2715 int face_id;
ee569018 2716 struct face *face;
06a2c219 2717
e4ded23c 2718 /* What face has to be used last for the mouse face? */
06a2c219 2719 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2720 face = FACE_FROM_ID (s->f, face_id);
e4ded23c
GM
2721 if (face == NULL)
2722 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
7d0393cf 2723
033e3e18
GM
2724 if (s->first_glyph->type == CHAR_GLYPH)
2725 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2726 else
2727 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2728 s->face = FACE_FROM_ID (s->f, face_id);
2729 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2730
2731 /* If font in this face is same as S->font, use it. */
2732 if (s->font == s->face->font)
2733 s->gc = s->face->gc;
2734 else
2735 {
2736 /* Otherwise construct scratch_cursor_gc with values from FACE
2737 but font FONT. */
2738 XGCValues xgcv;
2739 unsigned long mask;
7d0393cf 2740
06a2c219
GM
2741 xgcv.background = s->face->background;
2742 xgcv.foreground = s->face->foreground;
2743 IF_DEBUG (x_check_font (s->f, s->font));
2744 xgcv.font = s->font->fid;
2745 xgcv.graphics_exposures = False;
2746 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
7d0393cf 2747
06a2c219
GM
2748 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2749 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2750 mask, &xgcv);
2751 else
2752 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2753 = XCreateGC (s->display, s->window, mask, &xgcv);
7d0393cf 2754
06a2c219
GM
2755 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2756 }
2757
2758 xassert (s->gc != 0);
2759}
2760
2761
2762/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2763 Faces to use in the mode line have already been computed when the
2764 matrix was built, so there isn't much to do, here. */
2765
2766static INLINE void
2767x_set_mode_line_face_gc (s)
2768 struct glyph_string *s;
7d0393cf 2769{
06a2c219 2770 s->gc = s->face->gc;
06a2c219
GM
2771}
2772
2773
2774/* Set S->gc of glyph string S for drawing that glyph string. Set
2775 S->stippled_p to a non-zero value if the face of S has a stipple
2776 pattern. */
2777
2778static INLINE void
2779x_set_glyph_string_gc (s)
2780 struct glyph_string *s;
2781{
209f68d9 2782 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
7d0393cf 2783
06a2c219
GM
2784 if (s->hl == DRAW_NORMAL_TEXT)
2785 {
2786 s->gc = s->face->gc;
2787 s->stippled_p = s->face->stipple != 0;
2788 }
2789 else if (s->hl == DRAW_INVERSE_VIDEO)
2790 {
2791 x_set_mode_line_face_gc (s);
2792 s->stippled_p = s->face->stipple != 0;
2793 }
2794 else if (s->hl == DRAW_CURSOR)
2795 {
2796 x_set_cursor_gc (s);
2797 s->stippled_p = 0;
2798 }
2799 else if (s->hl == DRAW_MOUSE_FACE)
2800 {
2801 x_set_mouse_face_gc (s);
2802 s->stippled_p = s->face->stipple != 0;
2803 }
2804 else if (s->hl == DRAW_IMAGE_RAISED
2805 || s->hl == DRAW_IMAGE_SUNKEN)
2806 {
2807 s->gc = s->face->gc;
2808 s->stippled_p = s->face->stipple != 0;
2809 }
2810 else
2811 {
2812 s->gc = s->face->gc;
2813 s->stippled_p = s->face->stipple != 0;
2814 }
2815
2816 /* GC must have been set. */
2817 xassert (s->gc != 0);
2818}
2819
2820
2821/* Return in *R the clipping rectangle for glyph string S. */
2822
2823static void
2824x_get_glyph_string_clip_rect (s, r)
2825 struct glyph_string *s;
2826 XRectangle *r;
2827{
2828 if (s->row->full_width_p)
2829 {
2830 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71 2831 int canon_x = CANON_X_UNIT (s->f);
7d0393cf 2832
1da3fd71
GM
2833 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2834 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2835
2836 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2837 {
1da3fd71 2838 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2839 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2840 r->x -= width;
2841 }
7d0393cf 2842
b9432a85 2843 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
7d0393cf 2844
06a2c219
GM
2845 /* Unless displaying a mode or menu bar line, which are always
2846 fully visible, clip to the visible part of the row. */
2847 if (s->w->pseudo_window_p)
2848 r->height = s->row->visible_height;
2849 else
2850 r->height = s->height;
2851 }
2852 else
2853 {
2854 /* This is a text line that may be partially visible. */
2855 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2856 r->width = window_box_width (s->w, s->area);
2857 r->height = s->row->visible_height;
2858 }
2859
66ac4b0e
GM
2860 /* If S draws overlapping rows, it's sufficient to use the top and
2861 bottom of the window for clipping because this glyph string
2862 intentionally draws over other lines. */
2863 if (s->for_overlaps_p)
2864 {
045dee35 2865 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2866 r->height = window_text_bottom_y (s->w) - r->y;
2867 }
98b8a90f
GM
2868 else
2869 {
2870 /* Don't use S->y for clipping because it doesn't take partially
2871 visible lines into account. For example, it can be negative for
2872 partially visible lines at the top of a window. */
2873 if (!s->row->full_width_p
2874 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
2875 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
2876 else
2877 r->y = max (0, s->row->y);
2878
2879 /* If drawing a tool-bar window, draw it over the internal border
2880 at the top of the window. */
2881 if (s->w == XWINDOW (s->f->tool_bar_window))
2882 r->y -= s->f->output_data.x->internal_border_width;
2883 }
2884
66ac4b0e 2885 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2886}
2887
2888
2889/* Set clipping for output of glyph string S. S may be part of a mode
2890 line or menu if we don't have X toolkit support. */
2891
2892static INLINE void
2893x_set_glyph_string_clipping (s)
2894 struct glyph_string *s;
2895{
2896 XRectangle r;
2897 x_get_glyph_string_clip_rect (s, &r);
2898 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2899}
2900
2901
2902/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2903 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2904
2905static INLINE void
2906x_compute_glyph_string_overhangs (s)
2907 struct glyph_string *s;
2908{
b4192550 2909 if (s->cmp == NULL
06a2c219
GM
2910 && s->first_glyph->type == CHAR_GLYPH)
2911 {
2912 XCharStruct cs;
2913 int direction, font_ascent, font_descent;
2914 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2915 &font_ascent, &font_descent, &cs);
2916 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2917 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2918 }
2919}
2920
2921
2922/* Compute overhangs and x-positions for glyph string S and its
2923 predecessors, or successors. X is the starting x-position for S.
2924 BACKWARD_P non-zero means process predecessors. */
7d0393cf 2925
06a2c219
GM
2926static void
2927x_compute_overhangs_and_x (s, x, backward_p)
2928 struct glyph_string *s;
2929 int x;
2930 int backward_p;
2931{
2932 if (backward_p)
2933 {
2934 while (s)
2935 {
2936 x_compute_glyph_string_overhangs (s);
2937 x -= s->width;
2938 s->x = x;
2939 s = s->prev;
2940 }
2941 }
2942 else
2943 {
2944 while (s)
2945 {
2946 x_compute_glyph_string_overhangs (s);
2947 s->x = x;
2948 x += s->width;
2949 s = s->next;
2950 }
2951 }
2952}
2953
2954
2955/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2956 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2957 assumed to be zero. */
06a2c219
GM
2958
2959static void
2960x_get_glyph_overhangs (glyph, f, left, right)
2961 struct glyph *glyph;
2962 struct frame *f;
2963 int *left, *right;
2964{
06a2c219 2965 *left = *right = 0;
7d0393cf 2966
b4192550 2967 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2968 {
2969 XFontStruct *font;
2970 struct face *face;
2971 struct font_info *font_info;
2972 XChar2b char2b;
ee569018
KH
2973 XCharStruct *pcm;
2974
2975 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2976 font = face->font;
2977 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2978 if (font
2979 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2980 {
06a2c219
GM
2981 if (pcm->rbearing > pcm->width)
2982 *right = pcm->rbearing - pcm->width;
2983 if (pcm->lbearing < 0)
2984 *left = -pcm->lbearing;
2985 }
2986 }
2987}
2988
2989
2990/* Return the index of the first glyph preceding glyph string S that
2991 is overwritten by S because of S's left overhang. Value is -1
2992 if no glyphs are overwritten. */
2993
2994static int
2995x_left_overwritten (s)
2996 struct glyph_string *s;
2997{
2998 int k;
7d0393cf 2999
06a2c219
GM
3000 if (s->left_overhang)
3001 {
3002 int x = 0, i;
3003 struct glyph *glyphs = s->row->glyphs[s->area];
3004 int first = s->first_glyph - glyphs;
3005
3006 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
3007 x -= glyphs[i].pixel_width;
3008
3009 k = i + 1;
3010 }
3011 else
3012 k = -1;
3013
3014 return k;
3015}
3016
3017
3018/* Return the index of the first glyph preceding glyph string S that
3019 is overwriting S because of its right overhang. Value is -1 if no
3020 glyph in front of S overwrites S. */
3021
3022static int
3023x_left_overwriting (s)
3024 struct glyph_string *s;
3025{
3026 int i, k, x;
3027 struct glyph *glyphs = s->row->glyphs[s->area];
3028 int first = s->first_glyph - glyphs;
3029
3030 k = -1;
3031 x = 0;
3032 for (i = first - 1; i >= 0; --i)
3033 {
3034 int left, right;
3035 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3036 if (x + right > 0)
3037 k = i;
3038 x -= glyphs[i].pixel_width;
3039 }
3040
3041 return k;
3042}
3043
3044
3045/* Return the index of the last glyph following glyph string S that is
3046 not overwritten by S because of S's right overhang. Value is -1 if
3047 no such glyph is found. */
3048
3049static int
3050x_right_overwritten (s)
3051 struct glyph_string *s;
3052{
3053 int k = -1;
3054
3055 if (s->right_overhang)
3056 {
3057 int x = 0, i;
3058 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3059 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219 3060 int end = s->row->used[s->area];
7d0393cf 3061
06a2c219
GM
3062 for (i = first; i < end && s->right_overhang > x; ++i)
3063 x += glyphs[i].pixel_width;
3064
3065 k = i;
3066 }
3067
3068 return k;
3069}
3070
3071
3072/* Return the index of the last glyph following glyph string S that
3073 overwrites S because of its left overhang. Value is negative
3074 if no such glyph is found. */
3075
3076static int
3077x_right_overwriting (s)
3078 struct glyph_string *s;
3079{
3080 int i, k, x;
3081 int end = s->row->used[s->area];
3082 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3083 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3084
3085 k = -1;
3086 x = 0;
3087 for (i = first; i < end; ++i)
3088 {
3089 int left, right;
3090 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3091 if (x - left < 0)
3092 k = i;
3093 x += glyphs[i].pixel_width;
3094 }
3095
3096 return k;
3097}
3098
3099
3100/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3101
3102static INLINE void
3103x_clear_glyph_string_rect (s, x, y, w, h)
3104 struct glyph_string *s;
3105 int x, y, w, h;
3106{
3107 XGCValues xgcv;
3108 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3109 XSetForeground (s->display, s->gc, xgcv.background);
3110 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3111 XSetForeground (s->display, s->gc, xgcv.foreground);
3112}
3113
3114
3115/* Draw the background of glyph_string S. If S->background_filled_p
3116 is non-zero don't draw it. FORCE_P non-zero means draw the
3117 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3118 when a string preceding S draws into the background of S, or S
3119 contains the first component of a composition. */
06a2c219
GM
3120
3121static void
3122x_draw_glyph_string_background (s, force_p)
3123 struct glyph_string *s;
3124 int force_p;
3125{
3126 /* Nothing to do if background has already been drawn or if it
3127 shouldn't be drawn in the first place. */
3128 if (!s->background_filled_p)
3129 {
ea2ba0d4
KH
3130 int box_line_width = max (s->face->box_line_width, 0);
3131
b4192550 3132 if (s->stippled_p)
06a2c219
GM
3133 {
3134 /* Fill background with a stipple pattern. */
3135 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3136 XFillRectangle (s->display, s->window, s->gc, s->x,
ea2ba0d4 3137 s->y + box_line_width,
06a2c219 3138 s->background_width,
ea2ba0d4 3139 s->height - 2 * box_line_width);
06a2c219
GM
3140 XSetFillStyle (s->display, s->gc, FillSolid);
3141 s->background_filled_p = 1;
3142 }
ea2ba0d4 3143 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
06a2c219
GM
3144 || s->font_not_found_p
3145 || s->extends_to_end_of_line_p
06a2c219
GM
3146 || force_p)
3147 {
ea2ba0d4 3148 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
06a2c219 3149 s->background_width,
ea2ba0d4 3150 s->height - 2 * box_line_width);
06a2c219
GM
3151 s->background_filled_p = 1;
3152 }
3153 }
3154}
3155
3156
3157/* Draw the foreground of glyph string S. */
3158
3159static void
3160x_draw_glyph_string_foreground (s)
3161 struct glyph_string *s;
3162{
3163 int i, x;
3164
3165 /* If first glyph of S has a left box line, start drawing the text
3166 of S to the right of that box line. */
3167 if (s->face->box != FACE_NO_BOX
3168 && s->first_glyph->left_box_line_p)
ea2ba0d4 3169 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
3170 else
3171 x = s->x;
3172
b4192550
KH
3173 /* Draw characters of S as rectangles if S's font could not be
3174 loaded. */
3175 if (s->font_not_found_p)
06a2c219 3176 {
b4192550 3177 for (i = 0; i < s->nchars; ++i)
06a2c219 3178 {
b4192550
KH
3179 struct glyph *g = s->first_glyph + i;
3180 XDrawRectangle (s->display, s->window,
3181 s->gc, x, s->y, g->pixel_width - 1,
3182 s->height - 1);
3183 x += g->pixel_width;
06a2c219
GM
3184 }
3185 }
3186 else
3187 {
b4192550
KH
3188 char *char1b = (char *) s->char2b;
3189 int boff = s->font_info->baseline_offset;
06a2c219 3190
b4192550
KH
3191 if (s->font_info->vertical_centering)
3192 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3193
3194 /* If we can use 8-bit functions, condense S->char2b. */
3195 if (!s->two_byte_p)
3196 for (i = 0; i < s->nchars; ++i)
3197 char1b[i] = s->char2b[i].byte2;
3198
3199 /* Draw text with XDrawString if background has already been
3200 filled. Otherwise, use XDrawImageString. (Note that
3201 XDrawImageString is usually faster than XDrawString.) Always
3202 use XDrawImageString when drawing the cursor so that there is
3203 no chance that characters under a box cursor are invisible. */
3204 if (s->for_overlaps_p
3205 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3206 {
3207 /* Draw characters with 16-bit or 8-bit functions. */
3208 if (s->two_byte_p)
3209 XDrawString16 (s->display, s->window, s->gc, x,
3210 s->ybase - boff, s->char2b, s->nchars);
3211 else
3212 XDrawString (s->display, s->window, s->gc, x,
3213 s->ybase - boff, char1b, s->nchars);
3214 }
06a2c219
GM
3215 else
3216 {
b4192550
KH
3217 if (s->two_byte_p)
3218 XDrawImageString16 (s->display, s->window, s->gc, x,
3219 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3220 else
b4192550
KH
3221 XDrawImageString (s->display, s->window, s->gc, x,
3222 s->ybase - boff, char1b, s->nchars);
3223 }
3224 }
3225}
06a2c219 3226
b4192550 3227/* Draw the foreground of composite glyph string S. */
06a2c219 3228
b4192550
KH
3229static void
3230x_draw_composite_glyph_string_foreground (s)
3231 struct glyph_string *s;
3232{
3233 int i, x;
06a2c219 3234
b4192550
KH
3235 /* If first glyph of S has a left box line, start drawing the text
3236 of S to the right of that box line. */
3237 if (s->face->box != FACE_NO_BOX
3238 && s->first_glyph->left_box_line_p)
ea2ba0d4 3239 x = s->x + abs (s->face->box_line_width);
b4192550
KH
3240 else
3241 x = s->x;
06a2c219 3242
b4192550
KH
3243 /* S is a glyph string for a composition. S->gidx is the index of
3244 the first character drawn for glyphs of this composition.
3245 S->gidx == 0 means we are drawing the very first character of
3246 this composition. */
06a2c219 3247
b4192550
KH
3248 /* Draw a rectangle for the composition if the font for the very
3249 first character of the composition could not be loaded. */
3250 if (s->font_not_found_p)
3251 {
3252 if (s->gidx == 0)
3253 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3254 s->width - 1, s->height - 1);
3255 }
3256 else
3257 {
3258 for (i = 0; i < s->nchars; i++, ++s->gidx)
3259 XDrawString16 (s->display, s->window, s->gc,
3260 x + s->cmp->offsets[s->gidx * 2],
3261 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3262 s->char2b + i, 1);
06a2c219
GM
3263 }
3264}
3265
3266
80c32bcc
GM
3267#ifdef USE_X_TOOLKIT
3268
3e71d8f2 3269static struct frame *x_frame_of_widget P_ ((Widget));
651f03b6
GM
3270static Boolean cvt_string_to_pixel P_ ((Display *, XrmValue *, Cardinal *,
3271 XrmValue *, XrmValue *, XtPointer *));
3272static void cvt_pixel_dtor P_ ((XtAppContext, XrmValue *, XtPointer,
3273 XrmValue *, Cardinal *));
80c32bcc 3274
3e71d8f2
GM
3275
3276/* Return the frame on which widget WIDGET is used.. Abort if frame
3277 cannot be determined. */
3278
e851c833 3279static struct frame *
3e71d8f2 3280x_frame_of_widget (widget)
80c32bcc 3281 Widget widget;
80c32bcc 3282{
80c32bcc 3283 struct x_display_info *dpyinfo;
5c187dee 3284 Lisp_Object tail;
3e71d8f2 3285 struct frame *f;
7d0393cf 3286
80c32bcc 3287 dpyinfo = x_display_info_for_display (XtDisplay (widget));
7d0393cf 3288
80c32bcc
GM
3289 /* Find the top-level shell of the widget. Note that this function
3290 can be called when the widget is not yet realized, so XtWindow
3291 (widget) == 0. That's the reason we can't simply use
3292 x_any_window_to_frame. */
3293 while (!XtIsTopLevelShell (widget))
3294 widget = XtParent (widget);
3295
3296 /* Look for a frame with that top-level widget. Allocate the color
3297 on that frame to get the right gamma correction value. */
3298 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3299 if (GC_FRAMEP (XCAR (tail))
3300 && (f = XFRAME (XCAR (tail)),
3301 (f->output_data.nothing != 1
3302 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3303 && f->output_data.x->widget == widget)
3e71d8f2 3304 return f;
80c32bcc
GM
3305
3306 abort ();
3307}
3308
3e71d8f2
GM
3309
3310/* Allocate the color COLOR->pixel on the screen and display of
3311 widget WIDGET in colormap CMAP. If an exact match cannot be
3312 allocated, try the nearest color available. Value is non-zero
3313 if successful. This is called from lwlib. */
3314
3315int
3316x_alloc_nearest_color_for_widget (widget, cmap, color)
3317 Widget widget;
3318 Colormap cmap;
3319 XColor *color;
3320{
3321 struct frame *f = x_frame_of_widget (widget);
3322 return x_alloc_nearest_color (f, cmap, color);
3323}
3324
3325
46d516e5
MB
3326/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3327 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3328 If this produces the same color as PIXEL, try a color where all RGB
3329 values have DELTA added. Return the allocated color in *PIXEL.
3330 DISPLAY is the X display, CMAP is the colormap to operate on.
3331 Value is non-zero if successful. */
3332
3333int
3334x_alloc_lighter_color_for_widget (widget, display, cmap, pixel, factor, delta)
3335 Widget widget;
3336 Display *display;
3337 Colormap cmap;
3338 unsigned long *pixel;
3339 double factor;
3340 int delta;
3341{
3342 struct frame *f = x_frame_of_widget (widget);
3343 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
3344}
3345
3346
651f03b6
GM
3347/* Structure specifying which arguments should be passed by Xt to
3348 cvt_string_to_pixel. We want the widget's screen and colormap. */
3349
3350static XtConvertArgRec cvt_string_to_pixel_args[] =
3351 {
3352 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.screen),
3353 sizeof (Screen *)},
3354 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.colormap),
3355 sizeof (Colormap)}
3356 };
3357
3358
3359/* The address of this variable is returned by
3360 cvt_string_to_pixel. */
3361
3362static Pixel cvt_string_to_pixel_value;
3363
3364
3365/* Convert a color name to a pixel color.
3366
3367 DPY is the display we are working on.
3368
3369 ARGS is an array of *NARGS XrmValue structures holding additional
3370 information about the widget for which the conversion takes place.
3371 The contents of this array are determined by the specification
3372 in cvt_string_to_pixel_args.
3373
3374 FROM is a pointer to an XrmValue which points to the color name to
3375 convert. TO is an XrmValue in which to return the pixel color.
3376
3377 CLOSURE_RET is a pointer to user-data, in which we record if
3378 we allocated the color or not.
3379
3380 Value is True if successful, False otherwise. */
3381
3382static Boolean
3383cvt_string_to_pixel (dpy, args, nargs, from, to, closure_ret)
3384 Display *dpy;
3385 XrmValue *args;
3386 Cardinal *nargs;
3387 XrmValue *from, *to;
3388 XtPointer *closure_ret;
3389{
3390 Screen *screen;
3391 Colormap cmap;
3392 Pixel pixel;
3393 String color_name;
3394 XColor color;
3395
3396 if (*nargs != 2)
3397 {
3398 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3399 "wrongParameters", "cvt_string_to_pixel",
3400 "XtToolkitError",
3401 "Screen and colormap args required", NULL, NULL);
3402 return False;
3403 }
3404
3405 screen = *(Screen **) args[0].addr;
3406 cmap = *(Colormap *) args[1].addr;
3407 color_name = (String) from->addr;
3408
3409 if (strcmp (color_name, XtDefaultBackground) == 0)
3410 {
3411 *closure_ret = (XtPointer) False;
3412 pixel = WhitePixelOfScreen (screen);
3413 }
3414 else if (strcmp (color_name, XtDefaultForeground) == 0)
3415 {
3416 *closure_ret = (XtPointer) False;
3417 pixel = BlackPixelOfScreen (screen);
3418 }
3419 else if (XParseColor (dpy, cmap, color_name, &color)
3420 && x_alloc_nearest_color_1 (dpy, cmap, &color))
3421 {
3422 pixel = color.pixel;
3423 *closure_ret = (XtPointer) True;
3424 }
3425 else
3426 {
3427 String params[1];
3428 Cardinal nparams = 1;
7d0393cf 3429
651f03b6
GM
3430 params[0] = color_name;
3431 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3432 "badValue", "cvt_string_to_pixel",
3433 "XtToolkitError", "Invalid color `%s'",
3434 params, &nparams);
3435 return False;
3436 }
3437
3438 if (to->addr != NULL)
3439 {
3440 if (to->size < sizeof (Pixel))
3441 {
3442 to->size = sizeof (Pixel);
3443 return False;
3444 }
7d0393cf 3445
651f03b6
GM
3446 *(Pixel *) to->addr = pixel;
3447 }
3448 else
3449 {
3450 cvt_string_to_pixel_value = pixel;
3451 to->addr = (XtPointer) &cvt_string_to_pixel_value;
3452 }
7d0393cf 3453
651f03b6
GM
3454 to->size = sizeof (Pixel);
3455 return True;
3456}
3457
3458
3459/* Free a pixel color which was previously allocated via
3460 cvt_string_to_pixel. This is registered as the destructor
3461 for this type of resource via XtSetTypeConverter.
3462
3463 APP is the application context in which we work.
3464
3465 TO is a pointer to an XrmValue holding the color to free.
3466 CLOSURE is the value we stored in CLOSURE_RET for this color
3467 in cvt_string_to_pixel.
3468
3469 ARGS and NARGS are like for cvt_string_to_pixel. */
3470
3471static void
3472cvt_pixel_dtor (app, to, closure, args, nargs)
3473 XtAppContext app;
3474 XrmValuePtr to;
3475 XtPointer closure;
3476 XrmValuePtr args;
3477 Cardinal *nargs;
3478{
3479 if (*nargs != 2)
3480 {
3481 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
3482 "XtToolkitError",
3483 "Screen and colormap arguments required",
3484 NULL, NULL);
3485 }
3486 else if (closure != NULL)
3487 {
3488 /* We did allocate the pixel, so free it. */
3489 Screen *screen = *(Screen **) args[0].addr;
3490 Colormap cmap = *(Colormap *) args[1].addr;
3491 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
97762eb7 3492 (Pixel *) to->addr, 1);
651f03b6
GM
3493 }
3494}
3495
3496
80c32bcc
GM
3497#endif /* USE_X_TOOLKIT */
3498
3499
f04e1297 3500/* Value is an array of XColor structures for the contents of the
651f03b6 3501 color map of display DPY. Set *NCELLS to the size of the array.
f04e1297
GM
3502 Note that this probably shouldn't be called for large color maps,
3503 say a 24-bit TrueColor map. */
3504
3505static const XColor *
651f03b6
GM
3506x_color_cells (dpy, ncells)
3507 Display *dpy;
f04e1297
GM
3508 int *ncells;
3509{
651f03b6 3510 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
f04e1297
GM
3511
3512 if (dpyinfo->color_cells == NULL)
3513 {
651f03b6 3514 Screen *screen = dpyinfo->screen;
f04e1297 3515 int i;
7d0393cf 3516
f04e1297 3517 dpyinfo->ncolor_cells
651f03b6 3518 = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
f04e1297
GM
3519 dpyinfo->color_cells
3520 = (XColor *) xmalloc (dpyinfo->ncolor_cells
3521 * sizeof *dpyinfo->color_cells);
7d0393cf 3522
f04e1297
GM
3523 for (i = 0; i < dpyinfo->ncolor_cells; ++i)
3524 dpyinfo->color_cells[i].pixel = i;
7d0393cf 3525
651f03b6 3526 XQueryColors (dpy, dpyinfo->cmap,
f04e1297
GM
3527 dpyinfo->color_cells, dpyinfo->ncolor_cells);
3528 }
3529
3530 *ncells = dpyinfo->ncolor_cells;
3531 return dpyinfo->color_cells;
3532}
3533
3534
3535/* On frame F, translate pixel colors to RGB values for the NCOLORS
3536 colors in COLORS. Use cached information, if available. */
3537
3538void
3539x_query_colors (f, colors, ncolors)
3540 struct frame *f;
3541 XColor *colors;
3542 int ncolors;
3543{
3544 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3545
3546 if (dpyinfo->color_cells)
3547 {
3548 int i;
3549 for (i = 0; i < ncolors; ++i)
3550 {
3551 unsigned long pixel = colors[i].pixel;
3552 xassert (pixel < dpyinfo->ncolor_cells);
3553 xassert (dpyinfo->color_cells[pixel].pixel == pixel);
3554 colors[i] = dpyinfo->color_cells[pixel];
3555 }
3556 }
3557 else
3558 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
3559}
3560
3561
3562/* On frame F, translate pixel color to RGB values for the color in
3563 COLOR. Use cached information, if available. */
3564
3565void
3566x_query_color (f, color)
3567 struct frame *f;
3568 XColor *color;
3569{
3570 x_query_colors (f, color, 1);
3571}
7d0393cf 3572
f04e1297 3573
651f03b6
GM
3574/* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
3575 exact match can't be allocated, try the nearest color available.
3576 Value is non-zero if successful. Set *COLOR to the color
3577 allocated. */
06a2c219 3578
651f03b6
GM
3579static int
3580x_alloc_nearest_color_1 (dpy, cmap, color)
3581 Display *dpy;
06a2c219
GM
3582 Colormap cmap;
3583 XColor *color;
3584{
80c32bcc
GM
3585 int rc;
3586
651f03b6 3587 rc = XAllocColor (dpy, cmap, color);
06a2c219
GM
3588 if (rc == 0)
3589 {
3590 /* If we got to this point, the colormap is full, so we're going
3591 to try to get the next closest color. The algorithm used is
3592 a least-squares matching, which is what X uses for closest
3593 color matching with StaticColor visuals. */
3594 int nearest, i;
3595 unsigned long nearest_delta = ~0;
f04e1297 3596 int ncells;
651f03b6 3597 const XColor *cells = x_color_cells (dpy, &ncells);
06a2c219
GM
3598
3599 for (nearest = i = 0; i < ncells; ++i)
3600 {
3601 long dred = (color->red >> 8) - (cells[i].red >> 8);
3602 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3603 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3604 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3605
3606 if (delta < nearest_delta)
3607 {
3608 nearest = i;
3609 nearest_delta = delta;
3610 }
3611 }
7d0393cf 3612
06a2c219
GM
3613 color->red = cells[nearest].red;
3614 color->green = cells[nearest].green;
3615 color->blue = cells[nearest].blue;
651f03b6 3616 rc = XAllocColor (dpy, cmap, color);
06a2c219 3617 }
35efe0a1
GM
3618 else
3619 {
3620 /* If allocation succeeded, and the allocated pixel color is not
3621 equal to a cached pixel color recorded earlier, there was a
3622 change in the colormap, so clear the color cache. */
651f03b6 3623 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
35efe0a1 3624 XColor *cached_color;
7d0393cf 3625
35efe0a1
GM
3626 if (dpyinfo->color_cells
3627 && (cached_color = &dpyinfo->color_cells[color->pixel],
cae71efe
GM
3628 (cached_color->red != color->red
3629 || cached_color->blue != color->blue
3630 || cached_color->green != color->green)))
35efe0a1
GM
3631 {
3632 xfree (dpyinfo->color_cells);
3633 dpyinfo->color_cells = NULL;
3634 dpyinfo->ncolor_cells = 0;
3635 }
3636 }
06a2c219 3637
d9c545da
GM
3638#ifdef DEBUG_X_COLORS
3639 if (rc)
3640 register_color (color->pixel);
3641#endif /* DEBUG_X_COLORS */
7d0393cf 3642
06a2c219
GM
3643 return rc;
3644}
3645
3646
651f03b6
GM
3647/* Allocate the color COLOR->pixel on frame F, colormap CMAP. If an
3648 exact match can't be allocated, try the nearest color available.
3649 Value is non-zero if successful. Set *COLOR to the color
3650 allocated. */
3651
3652int
3653x_alloc_nearest_color (f, cmap, color)
3654 struct frame *f;
3655 Colormap cmap;
3656 XColor *color;
3657{
3658 gamma_correct (f, color);
3659 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
3660}
3661
3662
d9c545da
GM
3663/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3664 It's necessary to do this instead of just using PIXEL directly to
3665 get color reference counts right. */
3666
3667unsigned long
3668x_copy_color (f, pixel)
3669 struct frame *f;
3670 unsigned long pixel;
3671{
3672 XColor color;
3673
3674 color.pixel = pixel;
3675 BLOCK_INPUT;
f04e1297 3676 x_query_color (f, &color);
d9c545da
GM
3677 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3678 UNBLOCK_INPUT;
3679#ifdef DEBUG_X_COLORS
3680 register_color (pixel);
3681#endif
3682 return color.pixel;
3683}
3684
3685
3e71d8f2
GM
3686/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3687 It's necessary to do this instead of just using PIXEL directly to
3688 get color reference counts right. */
3689
3690unsigned long
3691x_copy_dpy_color (dpy, cmap, pixel)
3692 Display *dpy;
3693 Colormap cmap;
3694 unsigned long pixel;
3695{
3696 XColor color;
3697
3698 color.pixel = pixel;
3699 BLOCK_INPUT;
3700 XQueryColor (dpy, cmap, &color);
3701 XAllocColor (dpy, cmap, &color);
3702 UNBLOCK_INPUT;
3703#ifdef DEBUG_X_COLORS
3704 register_color (pixel);
3705#endif
3706 return color.pixel;
3707}
3708
3709
6d8b0acd 3710/* Brightness beyond which a color won't have its highlight brightness
d7361edf 3711 boosted.
6d8b0acd 3712
d7361edf
MB
3713 Nominally, highlight colors for `3d' faces are calculated by
3714 brightening an object's color by a constant scale factor, but this
3715 doesn't yield good results for dark colors, so for colors who's
3716 brightness is less than this value (on a scale of 0-65535) have an
3717 use an additional additive factor.
6d8b0acd
MB
3718
3719 The value here is set so that the default menu-bar/mode-line color
3720 (grey75) will not have its highlights changed at all. */
3721#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
3722
3723
06a2c219
GM
3724/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3725 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3726 If this produces the same color as PIXEL, try a color where all RGB
3727 values have DELTA added. Return the allocated color in *PIXEL.
3728 DISPLAY is the X display, CMAP is the colormap to operate on.
3729 Value is non-zero if successful. */
3730
3731static int
3732x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3733 struct frame *f;
3734 Display *display;
3735 Colormap cmap;
3736 unsigned long *pixel;
68c45bf0 3737 double factor;
06a2c219
GM
3738 int delta;
3739{
3740 XColor color, new;
6d8b0acd 3741 long bright;
06a2c219
GM
3742 int success_p;
3743
3744 /* Get RGB color values. */
3745 color.pixel = *pixel;
f04e1297 3746 x_query_color (f, &color);
06a2c219
GM
3747
3748 /* Change RGB values by specified FACTOR. Avoid overflow! */
3749 xassert (factor >= 0);
3750 new.red = min (0xffff, factor * color.red);
3751 new.green = min (0xffff, factor * color.green);
3752 new.blue = min (0xffff, factor * color.blue);
3753
d7361edf
MB
3754 /* Calculate brightness of COLOR. */
3755 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
6d8b0acd
MB
3756
3757 /* We only boost colors that are darker than
3758 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3759 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3760 /* Make an additive adjustment to NEW, because it's dark enough so
3761 that scaling by FACTOR alone isn't enough. */
3762 {
3763 /* How far below the limit this color is (0 - 1, 1 being darker). */
3764 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3765 /* The additive adjustment. */
d7361edf 3766 int min_delta = delta * dimness * factor / 2;
6d8b0acd
MB
3767
3768 if (factor < 1)
3769 {
6d8b0acd
MB
3770 new.red = max (0, new.red - min_delta);
3771 new.green = max (0, new.green - min_delta);
3772 new.blue = max (0, new.blue - min_delta);
3773 }
3774 else
3775 {
3776 new.red = min (0xffff, min_delta + new.red);
3777 new.green = min (0xffff, min_delta + new.green);
3778 new.blue = min (0xffff, min_delta + new.blue);
3779 }
3780 }
3781
06a2c219 3782 /* Try to allocate the color. */
80c32bcc 3783 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3784 if (success_p)
3785 {
3786 if (new.pixel == *pixel)
3787 {
3788 /* If we end up with the same color as before, try adding
3789 delta to the RGB values. */
0d605c67 3790 x_free_colors (f, &new.pixel, 1);
7d0393cf 3791
06a2c219
GM
3792 new.red = min (0xffff, delta + color.red);
3793 new.green = min (0xffff, delta + color.green);
3794 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3795 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3796 }
3797 else
3798 success_p = 1;
3799 *pixel = new.pixel;
3800 }
7d0393cf 3801
06a2c219
GM
3802 return success_p;
3803}
3804
3805
3806/* Set up the foreground color for drawing relief lines of glyph
3807 string S. RELIEF is a pointer to a struct relief containing the GC
3808 with which lines will be drawn. Use a color that is FACTOR or
3809 DELTA lighter or darker than the relief's background which is found
3810 in S->f->output_data.x->relief_background. If such a color cannot
3811 be allocated, use DEFAULT_PIXEL, instead. */
7d0393cf 3812
06a2c219
GM
3813static void
3814x_setup_relief_color (f, relief, factor, delta, default_pixel)
3815 struct frame *f;
3816 struct relief *relief;
68c45bf0 3817 double factor;
06a2c219
GM
3818 int delta;
3819 unsigned long default_pixel;
3820{
3821 XGCValues xgcv;
3822 struct x_output *di = f->output_data.x;
3823 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3824 unsigned long pixel;
3825 unsigned long background = di->relief_background;
43bd1b2b 3826 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3827 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3828 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3829
3830 xgcv.graphics_exposures = False;
3831 xgcv.line_width = 1;
3832
3833 /* Free previously allocated color. The color cell will be reused
3834 when it has been freed as many times as it was allocated, so this
3835 doesn't affect faces using the same colors. */
3836 if (relief->gc
3837 && relief->allocated_p)
3838 {
0d605c67 3839 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3840 relief->allocated_p = 0;
3841 }
3842
3843 /* Allocate new color. */
3844 xgcv.foreground = default_pixel;
3845 pixel = background;
dcd08bfb
GM
3846 if (dpyinfo->n_planes != 1
3847 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3848 {
3849 relief->allocated_p = 1;
3850 xgcv.foreground = relief->pixel = pixel;
3851 }
7d0393cf 3852
06a2c219
GM
3853 if (relief->gc == 0)
3854 {
dcd08bfb 3855 xgcv.stipple = dpyinfo->gray;
06a2c219 3856 mask |= GCStipple;
dcd08bfb 3857 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3858 }
3859 else
dcd08bfb 3860 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3861}
3862
3863
3864/* Set up colors for the relief lines around glyph string S. */
3865
3866static void
3867x_setup_relief_colors (s)
3868 struct glyph_string *s;
3869{
3870 struct x_output *di = s->f->output_data.x;
3871 unsigned long color;
3872
3873 if (s->face->use_box_color_for_shadows_p)
3874 color = s->face->box_color;
e2a57b34 3875 else if (s->first_glyph->type == IMAGE_GLYPH
0cb8bb48 3876 && s->img->pixmap
e2a57b34
MB
3877 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3878 color = IMAGE_BACKGROUND (s->img, s->f, 0);
06a2c219
GM
3879 else
3880 {
3881 XGCValues xgcv;
7d0393cf 3882
06a2c219
GM
3883 /* Get the background color of the face. */
3884 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3885 color = xgcv.background;
3886 }
3887
3888 if (di->white_relief.gc == 0
3889 || color != di->relief_background)
3890 {
3891 di->relief_background = color;
3892 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3893 WHITE_PIX_DEFAULT (s->f));
3894 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3895 BLACK_PIX_DEFAULT (s->f));
3896 }
3897}
3898
3899
3900/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3901 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3902 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3903 relief. LEFT_P non-zero means draw a relief on the left side of
3904 the rectangle. RIGHT_P non-zero means draw a relief on the right
3905 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3906 when drawing. */
3907
3908static void
3909x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3910 raised_p, left_p, right_p, clip_rect)
3911 struct frame *f;
3912 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3913 XRectangle *clip_rect;
3914{
de507556
GM
3915 Display *dpy = FRAME_X_DISPLAY (f);
3916 Window window = FRAME_X_WINDOW (f);
06a2c219
GM
3917 int i;
3918 GC gc;
7d0393cf 3919
06a2c219
GM
3920 if (raised_p)
3921 gc = f->output_data.x->white_relief.gc;
3922 else
3923 gc = f->output_data.x->black_relief.gc;
de507556 3924 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3925
3926 /* Top. */
3927 for (i = 0; i < width; ++i)
de507556 3928 XDrawLine (dpy, window, gc,
06a2c219
GM
3929 left_x + i * left_p, top_y + i,
3930 right_x + 1 - i * right_p, top_y + i);
3931
3932 /* Left. */
3933 if (left_p)
3934 for (i = 0; i < width; ++i)
de507556 3935 XDrawLine (dpy, window, gc,
44655e77 3936 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
06a2c219 3937
de507556 3938 XSetClipMask (dpy, gc, None);
06a2c219
GM
3939 if (raised_p)
3940 gc = f->output_data.x->black_relief.gc;
3941 else
3942 gc = f->output_data.x->white_relief.gc;
de507556 3943 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
7d0393cf 3944
06a2c219
GM
3945 /* Bottom. */
3946 for (i = 0; i < width; ++i)
de507556
GM
3947 XDrawLine (dpy, window, gc,
3948 left_x + i * left_p, bottom_y - i,
327f42ee 3949 right_x + 1 - i * right_p, bottom_y - i);
7d0393cf 3950
06a2c219
GM
3951 /* Right. */
3952 if (right_p)
3953 for (i = 0; i < width; ++i)
de507556 3954 XDrawLine (dpy, window, gc,
06a2c219
GM
3955 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3956
de507556 3957 XSetClipMask (dpy, gc, None);
06a2c219
GM
3958}
3959
3960
3961/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3962 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3963 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3964 left side of the rectangle. RIGHT_P non-zero means draw a line
3965 on the right side of the rectangle. CLIP_RECT is the clipping
3966 rectangle to use when drawing. */
3967
3968static void
3969x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3970 left_p, right_p, clip_rect)
3971 struct glyph_string *s;
3972 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3973 XRectangle *clip_rect;
3974{
3975 XGCValues xgcv;
7d0393cf 3976
06a2c219
GM
3977 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3978 XSetForeground (s->display, s->gc, s->face->box_color);
3979 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
7d0393cf 3980
06a2c219
GM
3981 /* Top. */
3982 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3983 left_x, top_y, right_x - left_x + 1, width);
06a2c219
GM
3984
3985 /* Left. */
3986 if (left_p)
3987 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3988 left_x, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3989
3990 /* Bottom. */
3991 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3992 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
7d0393cf 3993
06a2c219
GM
3994 /* Right. */
3995 if (right_p)
3996 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3997 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3998
3999 XSetForeground (s->display, s->gc, xgcv.foreground);
4000 XSetClipMask (s->display, s->gc, None);
4001}
4002
4003
4004/* Draw a box around glyph string S. */
4005
4006static void
4007x_draw_glyph_string_box (s)
4008 struct glyph_string *s;
4009{
4010 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
4011 int left_p, right_p;
4012 struct glyph *last_glyph;
4013 XRectangle clip_rect;
4014
4015 last_x = window_box_right (s->w, s->area);
4016 if (s->row->full_width_p
4017 && !s->w->pseudo_window_p)
4018 {
3f332ef3 4019 last_x += FRAME_X_RIGHT_FRINGE_WIDTH (s->f);
06a2c219
GM
4020 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
4021 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
4022 }
7d0393cf 4023
06a2c219 4024 /* The glyph that may have a right box line. */
b4192550 4025 last_glyph = (s->cmp || s->img
06a2c219
GM
4026 ? s->first_glyph
4027 : s->first_glyph + s->nchars - 1);
4028
ea2ba0d4 4029 width = abs (s->face->box_line_width);
06a2c219
GM
4030 raised_p = s->face->box == FACE_RAISED_BOX;
4031 left_x = s->x;
57ac7c81
GM
4032 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
4033 ? last_x - 1
4034 : min (last_x, s->x + s->background_width) - 1);
06a2c219
GM
4035 top_y = s->y;
4036 bottom_y = top_y + s->height - 1;
4037
4038 left_p = (s->first_glyph->left_box_line_p
4039 || (s->hl == DRAW_MOUSE_FACE
4040 && (s->prev == NULL
4041 || s->prev->hl != s->hl)));
4042 right_p = (last_glyph->right_box_line_p
4043 || (s->hl == DRAW_MOUSE_FACE
4044 && (s->next == NULL
4045 || s->next->hl != s->hl)));
327f42ee 4046
06a2c219
GM
4047 x_get_glyph_string_clip_rect (s, &clip_rect);
4048
4049 if (s->face->box == FACE_SIMPLE_BOX)
4050 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4051 left_p, right_p, &clip_rect);
4052 else
4053 {
4054 x_setup_relief_colors (s);
4055 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
4056 width, raised_p, left_p, right_p, &clip_rect);
4057 }
4058}
4059
4060
4061/* Draw foreground of image glyph string S. */
4062
4063static void
4064x_draw_image_foreground (s)
4065 struct glyph_string *s;
4066{
4067 int x;
95af8492 4068 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4069
4070 /* If first glyph of S has a left box line, start drawing it to the
4071 right of that line. */
4072 if (s->face->box != FACE_NO_BOX
4073 && s->first_glyph->left_box_line_p)
ea2ba0d4 4074 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4075 else
4076 x = s->x;
4077
4078 /* If there is a margin around the image, adjust x- and y-position
4079 by that margin. */
22d650b8
GM
4080 x += s->img->hmargin;
4081 y += s->img->vmargin;
06a2c219
GM
4082
4083 if (s->img->pixmap)
4084 {
4085 if (s->img->mask)
4086 {
4087 /* We can't set both a clip mask and use XSetClipRectangles
4088 because the latter also sets a clip mask. We also can't
4089 trust on the shape extension to be available
4090 (XShapeCombineRegion). So, compute the rectangle to draw
4091 manually. */
4092 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4093 | GCFunction);
4094 XGCValues xgcv;
4095 XRectangle clip_rect, image_rect, r;
4096
4097 xgcv.clip_mask = s->img->mask;
4098 xgcv.clip_x_origin = x;
4099 xgcv.clip_y_origin = y;
4100 xgcv.function = GXcopy;
4101 XChangeGC (s->display, s->gc, mask, &xgcv);
7d0393cf 4102
06a2c219
GM
4103 x_get_glyph_string_clip_rect (s, &clip_rect);
4104 image_rect.x = x;
4105 image_rect.y = y;
4106 image_rect.width = s->img->width;
4107 image_rect.height = s->img->height;
4108 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4109 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4110 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
4111 }
4112 else
4113 {
49ad1d99
GM
4114 XRectangle clip_rect, image_rect, r;
4115
4116 x_get_glyph_string_clip_rect (s, &clip_rect);
4117 image_rect.x = x;
4118 image_rect.y = y;
4119 image_rect.width = s->img->width;
4120 image_rect.height = s->img->height;
4121 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4122 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4123 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
7d0393cf 4124
06a2c219
GM
4125 /* When the image has a mask, we can expect that at
4126 least part of a mouse highlight or a block cursor will
4127 be visible. If the image doesn't have a mask, make
4128 a block cursor visible by drawing a rectangle around
4129 the image. I believe it's looking better if we do
4130 nothing here for mouse-face. */
4131 if (s->hl == DRAW_CURSOR)
534c20b2
KS
4132 {
4133 int r = s->img->relief;
4134 if (r < 0) r = -r;
4135 XDrawRectangle (s->display, s->window, s->gc, x - r, y - r,
4136 s->img->width + r*2 - 1, s->img->height + r*2 - 1);
4137 }
06a2c219
GM
4138 }
4139 }
4140 else
4141 /* Draw a rectangle if image could not be loaded. */
4142 XDrawRectangle (s->display, s->window, s->gc, x, y,
4143 s->img->width - 1, s->img->height - 1);
4144}
4145
4146
4147/* Draw a relief around the image glyph string S. */
4148
4149static void
4150x_draw_image_relief (s)
4151 struct glyph_string *s;
4152{
4153 int x0, y0, x1, y1, thick, raised_p;
4154 XRectangle r;
4155 int x;
95af8492 4156 int y = s->ybase - image_ascent (s->img, s->face);
7d0393cf 4157
06a2c219
GM
4158 /* If first glyph of S has a left box line, start drawing it to the
4159 right of that line. */
4160 if (s->face->box != FACE_NO_BOX
4161 && s->first_glyph->left_box_line_p)
ea2ba0d4 4162 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4163 else
4164 x = s->x;
7d0393cf 4165
06a2c219
GM
4166 /* If there is a margin around the image, adjust x- and y-position
4167 by that margin. */
22d650b8
GM
4168 x += s->img->hmargin;
4169 y += s->img->vmargin;
7d0393cf 4170
06a2c219
GM
4171 if (s->hl == DRAW_IMAGE_SUNKEN
4172 || s->hl == DRAW_IMAGE_RAISED)
4173 {
62854fe2 4174 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
06a2c219
GM
4175 raised_p = s->hl == DRAW_IMAGE_RAISED;
4176 }
4177 else
4178 {
4179 thick = abs (s->img->relief);
4180 raised_p = s->img->relief > 0;
4181 }
7d0393cf 4182
06a2c219
GM
4183 x0 = x - thick;
4184 y0 = y - thick;
4185 x1 = x + s->img->width + thick - 1;
4186 y1 = y + s->img->height + thick - 1;
7d0393cf 4187
06a2c219
GM
4188 x_setup_relief_colors (s);
4189 x_get_glyph_string_clip_rect (s, &r);
4190 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
4191}
4192
4193
4194/* Draw the foreground of image glyph string S to PIXMAP. */
4195
4196static void
4197x_draw_image_foreground_1 (s, pixmap)
4198 struct glyph_string *s;
4199 Pixmap pixmap;
4200{
4201 int x;
95af8492 4202 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
4203
4204 /* If first glyph of S has a left box line, start drawing it to the
4205 right of that line. */
4206 if (s->face->box != FACE_NO_BOX
4207 && s->first_glyph->left_box_line_p)
ea2ba0d4 4208 x = abs (s->face->box_line_width);
06a2c219
GM
4209 else
4210 x = 0;
4211
4212 /* If there is a margin around the image, adjust x- and y-position
4213 by that margin. */
22d650b8
GM
4214 x += s->img->hmargin;
4215 y += s->img->vmargin;
dc43ef94 4216
06a2c219
GM
4217 if (s->img->pixmap)
4218 {
4219 if (s->img->mask)
4220 {
4221 /* We can't set both a clip mask and use XSetClipRectangles
4222 because the latter also sets a clip mask. We also can't
4223 trust on the shape extension to be available
4224 (XShapeCombineRegion). So, compute the rectangle to draw
4225 manually. */
4226 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4227 | GCFunction);
4228 XGCValues xgcv;
4229
4230 xgcv.clip_mask = s->img->mask;
4231 xgcv.clip_x_origin = x;
4232 xgcv.clip_y_origin = y;
4233 xgcv.function = GXcopy;
4234 XChangeGC (s->display, s->gc, mask, &xgcv);
4235
4236 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4237 0, 0, s->img->width, s->img->height, x, y);
4238 XSetClipMask (s->display, s->gc, None);
4239 }
4240 else
4241 {
4242 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4243 0, 0, s->img->width, s->img->height, x, y);
7d0393cf 4244
06a2c219
GM
4245 /* When the image has a mask, we can expect that at
4246 least part of a mouse highlight or a block cursor will
4247 be visible. If the image doesn't have a mask, make
4248 a block cursor visible by drawing a rectangle around
4249 the image. I believe it's looking better if we do
4250 nothing here for mouse-face. */
4251 if (s->hl == DRAW_CURSOR)
534c20b2
KS
4252 {
4253 int r = s->img->relief;
4254 if (r < 0) r = -r;
4255 XDrawRectangle (s->display, s->window, s->gc, x - r, y - r,
4256 s->img->width + r*2 - 1, s->img->height + r*2 - 1);
4257 }
06a2c219
GM
4258 }
4259 }
4260 else
4261 /* Draw a rectangle if image could not be loaded. */
4262 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4263 s->img->width - 1, s->img->height - 1);
4264}
dc43ef94 4265
990ba854 4266
06a2c219
GM
4267/* Draw part of the background of glyph string S. X, Y, W, and H
4268 give the rectangle to draw. */
a9a5b0a5 4269
06a2c219
GM
4270static void
4271x_draw_glyph_string_bg_rect (s, x, y, w, h)
4272 struct glyph_string *s;
4273 int x, y, w, h;
4274{
4275 if (s->stippled_p)
4276 {
4277 /* Fill background with a stipple pattern. */
4278 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4279 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4280 XSetFillStyle (s->display, s->gc, FillSolid);
4281 }
4282 else
4283 x_clear_glyph_string_rect (s, x, y, w, h);
4284}
07e34cb0 4285
b5210ea7 4286
7d0393cf 4287/* Draw image glyph string S.
dc43ef94 4288
06a2c219
GM
4289 s->y
4290 s->x +-------------------------
4291 | s->face->box
4292 |
4293 | +-------------------------
4294 | | s->img->margin
4295 | |
4296 | | +-------------------
4297 | | | the image
dc43ef94 4298
06a2c219 4299 */
dc43ef94 4300
06a2c219
GM
4301static void
4302x_draw_image_glyph_string (s)
4303 struct glyph_string *s;
4304{
4305 int x, y;
ea2ba0d4
KH
4306 int box_line_hwidth = abs (s->face->box_line_width);
4307 int box_line_vwidth = max (s->face->box_line_width, 0);
06a2c219
GM
4308 int height;
4309 Pixmap pixmap = None;
4310
ea2ba0d4 4311 height = s->height - 2 * box_line_vwidth;
06a2c219
GM
4312
4313 /* Fill background with face under the image. Do it only if row is
4314 taller than image or if image has a clip mask to reduce
4315 flickering. */
4316 s->stippled_p = s->face->stipple != 0;
4317 if (height > s->img->height
22d650b8
GM
4318 || s->img->hmargin
4319 || s->img->vmargin
06a2c219
GM
4320 || s->img->mask
4321 || s->img->pixmap == 0
4322 || s->width != s->background_width)
4323 {
ea2ba0d4
KH
4324 if (box_line_hwidth && s->first_glyph->left_box_line_p)
4325 x = s->x + box_line_hwidth;
06a2c219
GM
4326 else
4327 x = s->x;
7d0393cf 4328
ea2ba0d4 4329 y = s->y + box_line_vwidth;
7d0393cf 4330
06a2c219
GM
4331 if (s->img->mask)
4332 {
f9b5db02
GM
4333 /* Create a pixmap as large as the glyph string. Fill it
4334 with the background color. Copy the image to it, using
4335 its mask. Copy the temporary pixmap to the display. */
06a2c219
GM
4336 Screen *screen = FRAME_X_SCREEN (s->f);
4337 int depth = DefaultDepthOfScreen (screen);
4338
4339 /* Create a pixmap as large as the glyph string. */
4340 pixmap = XCreatePixmap (s->display, s->window,
4341 s->background_width,
4342 s->height, depth);
7d0393cf 4343
06a2c219
GM
4344 /* Don't clip in the following because we're working on the
4345 pixmap. */
4346 XSetClipMask (s->display, s->gc, None);
4347
4348 /* Fill the pixmap with the background color/stipple. */
4349 if (s->stippled_p)
4350 {
4351 /* Fill background with a stipple pattern. */
4352 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4353 XFillRectangle (s->display, pixmap, s->gc,
4354 0, 0, s->background_width, s->height);
4355 XSetFillStyle (s->display, s->gc, FillSolid);
4356 }
4357 else
4358 {
4359 XGCValues xgcv;
4360 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4361 &xgcv);
4362 XSetForeground (s->display, s->gc, xgcv.background);
4363 XFillRectangle (s->display, pixmap, s->gc,
4364 0, 0, s->background_width, s->height);
4365 XSetForeground (s->display, s->gc, xgcv.foreground);
4366 }
4367 }
4368 else
06a2c219 4369 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
7d0393cf 4370
06a2c219
GM
4371 s->background_filled_p = 1;
4372 }
dc43ef94 4373
06a2c219
GM
4374 /* Draw the foreground. */
4375 if (pixmap != None)
4376 {
4377 x_draw_image_foreground_1 (s, pixmap);
4378 x_set_glyph_string_clipping (s);
4379 XCopyArea (s->display, pixmap, s->window, s->gc,
4380 0, 0, s->background_width, s->height, s->x, s->y);
4381 XFreePixmap (s->display, pixmap);
4382 }
4383 else
4384 x_draw_image_foreground (s);
b5210ea7 4385
06a2c219
GM
4386 /* If we must draw a relief around the image, do it. */
4387 if (s->img->relief
4388 || s->hl == DRAW_IMAGE_RAISED
4389 || s->hl == DRAW_IMAGE_SUNKEN)
4390 x_draw_image_relief (s);
4391}
8c1a6a84 4392
990ba854 4393
06a2c219 4394/* Draw stretch glyph string S. */
dc43ef94 4395
06a2c219
GM
4396static void
4397x_draw_stretch_glyph_string (s)
4398 struct glyph_string *s;
4399{
4400 xassert (s->first_glyph->type == STRETCH_GLYPH);
4401 s->stippled_p = s->face->stipple != 0;
990ba854 4402
06a2c219
GM
4403 if (s->hl == DRAW_CURSOR
4404 && !x_stretch_cursor_p)
4405 {
4406 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4407 as wide as the stretch glyph. */
4408 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4409
06a2c219
GM
4410 /* Draw cursor. */
4411 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4412
06a2c219
GM
4413 /* Clear rest using the GC of the original non-cursor face. */
4414 if (width < s->background_width)
4415 {
06a2c219
GM
4416 int x = s->x + width, y = s->y;
4417 int w = s->background_width - width, h = s->height;
4418 XRectangle r;
b7f83f9e 4419 GC gc;
dc43ef94 4420
b7f83f9e
GM
4421 if (s->row->mouse_face_p
4422 && cursor_in_mouse_face_p (s->w))
4423 {
4424 x_set_mouse_face_gc (s);
4425 gc = s->gc;
4426 }
4427 else
4428 gc = s->face->gc;
7d0393cf 4429
06a2c219
GM
4430 x_get_glyph_string_clip_rect (s, &r);
4431 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
7d0393cf 4432
06a2c219
GM
4433 if (s->face->stipple)
4434 {
4435 /* Fill background with a stipple pattern. */
4436 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4437 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4438 XSetFillStyle (s->display, gc, FillSolid);
4439 }
4440 else
4441 {
4442 XGCValues xgcv;
4443 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4444 XSetForeground (s->display, gc, xgcv.background);
4445 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4446 XSetForeground (s->display, gc, xgcv.foreground);
4447 }
4448 }
4449 }
61e9f9f3 4450 else if (!s->background_filled_p)
06a2c219
GM
4451 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4452 s->height);
7d0393cf 4453
06a2c219
GM
4454 s->background_filled_p = 1;
4455}
4456
4457
4458/* Draw glyph string S. */
4459
4460static void
4461x_draw_glyph_string (s)
4462 struct glyph_string *s;
4463{
4458cf11
KH
4464 int relief_drawn_p = 0;
4465
06a2c219
GM
4466 /* If S draws into the background of its successor, draw the
4467 background of the successor first so that S can draw into it.
4468 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4469 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4470 {
4471 xassert (s->next->img == NULL);
4472 x_set_glyph_string_gc (s->next);
4473 x_set_glyph_string_clipping (s->next);
4474 x_draw_glyph_string_background (s->next, 1);
4475 }
97210f4e 4476
06a2c219
GM
4477 /* Set up S->gc, set clipping and draw S. */
4478 x_set_glyph_string_gc (s);
06a2c219 4479
4458cf11
KH
4480 /* Draw relief (if any) in advance for char/composition so that the
4481 glyph string can be drawn over it. */
4482 if (!s->for_overlaps_p
4483 && s->face->box != FACE_NO_BOX
4484 && (s->first_glyph->type == CHAR_GLYPH
4485 || s->first_glyph->type == COMPOSITE_GLYPH))
4486
4487 {
e6269cbb 4488 x_set_glyph_string_clipping (s);
4458cf11
KH
4489 x_draw_glyph_string_background (s, 1);
4490 x_draw_glyph_string_box (s);
e6269cbb 4491 x_set_glyph_string_clipping (s);
4458cf11
KH
4492 relief_drawn_p = 1;
4493 }
e6269cbb
GM
4494 else
4495 x_set_glyph_string_clipping (s);
4458cf11 4496
06a2c219
GM
4497 switch (s->first_glyph->type)
4498 {
4499 case IMAGE_GLYPH:
4500 x_draw_image_glyph_string (s);
4501 break;
4502
4503 case STRETCH_GLYPH:
4504 x_draw_stretch_glyph_string (s);
4505 break;
4506
4507 case CHAR_GLYPH:
66ac4b0e
GM
4508 if (s->for_overlaps_p)
4509 s->background_filled_p = 1;
4510 else
4511 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4512 x_draw_glyph_string_foreground (s);
4513 break;
4514
b4192550
KH
4515 case COMPOSITE_GLYPH:
4516 if (s->for_overlaps_p || s->gidx > 0)
4517 s->background_filled_p = 1;
4518 else
4519 x_draw_glyph_string_background (s, 1);
4520 x_draw_composite_glyph_string_foreground (s);
4521 break;
4522
06a2c219
GM
4523 default:
4524 abort ();
4525 }
4526
66ac4b0e 4527 if (!s->for_overlaps_p)
06a2c219 4528 {
66ac4b0e
GM
4529 /* Draw underline. */
4530 if (s->face->underline_p)
4531 {
e24e84cc
GM
4532 unsigned long tem, h;
4533 int y;
06a2c219 4534
e24e84cc 4535 /* Get the underline thickness. Default is 1 pixel. */
66ac4b0e
GM
4536 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4537 h = 1;
e24e84cc
GM
4538
4539 /* Get the underline position. This is the recommended
4540 vertical offset in pixels from the baseline to the top of
4541 the underline. This is a signed value according to the
4542 specs, and its default is
4543
4544 ROUND ((maximum descent) / 2), with
4545 ROUND(x) = floor (x + 0.5) */
7d0393cf 4546
a72d5ce5
GM
4547 if (x_use_underline_position_properties
4548 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
e24e84cc
GM
4549 y = s->ybase + (long) tem;
4550 else if (s->face->font)
4551 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4552 else
a02f1be0 4553 y = s->y + s->height - h;
7d0393cf 4554
66ac4b0e 4555 if (s->face->underline_defaulted_p)
e24e84cc
GM
4556 XFillRectangle (s->display, s->window, s->gc,
4557 s->x, y, s->width, h);
66ac4b0e
GM
4558 else
4559 {
4560 XGCValues xgcv;
4561 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4562 XSetForeground (s->display, s->gc, s->face->underline_color);
e24e84cc
GM
4563 XFillRectangle (s->display, s->window, s->gc,
4564 s->x, y, s->width, h);
66ac4b0e
GM
4565 XSetForeground (s->display, s->gc, xgcv.foreground);
4566 }
dc6f92b8 4567 }
07e34cb0 4568
66ac4b0e
GM
4569 /* Draw overline. */
4570 if (s->face->overline_p)
06a2c219 4571 {
66ac4b0e
GM
4572 unsigned long dy = 0, h = 1;
4573
4574 if (s->face->overline_color_defaulted_p)
4575 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4576 s->width, h);
4577 else
4578 {
4579 XGCValues xgcv;
4580 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4581 XSetForeground (s->display, s->gc, s->face->overline_color);
4582 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4583 s->width, h);
4584 XSetForeground (s->display, s->gc, xgcv.foreground);
4585 }
06a2c219 4586 }
7d0393cf 4587
66ac4b0e
GM
4588 /* Draw strike-through. */
4589 if (s->face->strike_through_p)
06a2c219 4590 {
66ac4b0e
GM
4591 unsigned long h = 1;
4592 unsigned long dy = (s->height - h) / 2;
4593
4594 if (s->face->strike_through_color_defaulted_p)
4595 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4596 s->width, h);
4597 else
4598 {
4599 XGCValues xgcv;
4600 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4601 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4602 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4603 s->width, h);
4604 XSetForeground (s->display, s->gc, xgcv.foreground);
4605 }
06a2c219 4606 }
7d0393cf 4607
4458cf11
KH
4608 /* Draw relief if not yet drawn. */
4609 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
66ac4b0e
GM
4610 x_draw_glyph_string_box (s);
4611 }
7d0393cf 4612
06a2c219
GM
4613 /* Reset clipping. */
4614 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4615}
07e34cb0 4616
06a2c219 4617
b4192550
KH
4618static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4619 struct face **, int));
06a2c219 4620
06a2c219 4621
209f68d9 4622/* Fill glyph string S with composition components specified by S->cmp.
7d0393cf 4623
b4192550
KH
4624 FACES is an array of faces for all components of this composition.
4625 S->gidx is the index of the first component for S.
4626 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4627 use its physical height for clipping.
06a2c219 4628
b4192550 4629 Value is the index of a component not in S. */
07e34cb0 4630
b4192550
KH
4631static int
4632x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4633 struct glyph_string *s;
b4192550 4634 struct face **faces;
66ac4b0e 4635 int overlaps_p;
07e34cb0 4636{
b4192550 4637 int i;
06a2c219 4638
b4192550 4639 xassert (s);
06a2c219 4640
b4192550 4641 s->for_overlaps_p = overlaps_p;
7d0393cf 4642
b4192550
KH
4643 s->face = faces[s->gidx];
4644 s->font = s->face->font;
4645 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4646
b4192550
KH
4647 /* For all glyphs of this composition, starting at the offset
4648 S->gidx, until we reach the end of the definition or encounter a
4649 glyph that requires the different face, add it to S. */
4650 ++s->nchars;
4651 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4652 ++s->nchars;
06a2c219 4653
b4192550
KH
4654 /* All glyph strings for the same composition has the same width,
4655 i.e. the width set for the first component of the composition. */
06a2c219 4656
06a2c219
GM
4657 s->width = s->first_glyph->pixel_width;
4658
4659 /* If the specified font could not be loaded, use the frame's
4660 default font, but record the fact that we couldn't load it in
4661 the glyph string so that we can draw rectangles for the
4662 characters of the glyph string. */
4663 if (s->font == NULL)
4664 {
4665 s->font_not_found_p = 1;
4666 s->font = FRAME_FONT (s->f);
4667 }
4668
4669 /* Adjust base line for subscript/superscript text. */
4670 s->ybase += s->first_glyph->voffset;
7d0393cf 4671
06a2c219
GM
4672 xassert (s->face && s->face->gc);
4673
4674 /* This glyph string must always be drawn with 16-bit functions. */
4675 s->two_byte_p = 1;
b4192550
KH
4676
4677 return s->gidx + s->nchars;
06a2c219
GM
4678}
4679
4680
209f68d9 4681/* Fill glyph string S from a sequence of character glyphs.
7d0393cf 4682
06a2c219 4683 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4684 first glyph to consider, END is the index of the last + 1.
4685 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4686 use its physical height for clipping.
66ac4b0e
GM
4687
4688 Value is the index of the first glyph not in S. */
06a2c219
GM
4689
4690static int
66ac4b0e 4691x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4692 struct glyph_string *s;
4693 int face_id;
66ac4b0e 4694 int start, end, overlaps_p;
06a2c219
GM
4695{
4696 struct glyph *glyph, *last;
4697 int voffset;
ee569018 4698 int glyph_not_available_p;
7d0393cf 4699
06a2c219
GM
4700 xassert (s->f == XFRAME (s->w->frame));
4701 xassert (s->nchars == 0);
4702 xassert (start >= 0 && end > start);
4703
66ac4b0e 4704 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4705 glyph = s->row->glyphs[s->area] + start;
4706 last = s->row->glyphs[s->area] + end;
4707 voffset = glyph->voffset;
7d0393cf 4708
ee569018
KH
4709 glyph_not_available_p = glyph->glyph_not_available_p;
4710
06a2c219
GM
4711 while (glyph < last
4712 && glyph->type == CHAR_GLYPH
4713 && glyph->voffset == voffset
ee569018
KH
4714 /* Same face id implies same font, nowadays. */
4715 && glyph->face_id == face_id
4716 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4717 {
ee569018
KH
4718 int two_byte_p;
4719
06a2c219 4720 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4721 s->char2b + s->nchars,
4722 &two_byte_p);
4723 s->two_byte_p = two_byte_p;
06a2c219
GM
4724 ++s->nchars;
4725 xassert (s->nchars <= end - start);
4726 s->width += glyph->pixel_width;
4727 ++glyph;
4728 }
4729
4730 s->font = s->face->font;
4731 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
7d0393cf 4732
06a2c219
GM
4733 /* If the specified font could not be loaded, use the frame's font,
4734 but record the fact that we couldn't load it in
4735 S->font_not_found_p so that we can draw rectangles for the
4736 characters of the glyph string. */
ee569018 4737 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4738 {
4739 s->font_not_found_p = 1;
4740 s->font = FRAME_FONT (s->f);
4741 }
4742
4743 /* Adjust base line for subscript/superscript text. */
4744 s->ybase += voffset;
66ac4b0e 4745
06a2c219
GM
4746 xassert (s->face && s->face->gc);
4747 return glyph - s->row->glyphs[s->area];
07e34cb0 4748}
dc6f92b8 4749
06a2c219
GM
4750
4751/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4752
dfcf069d 4753static void
06a2c219
GM
4754x_fill_image_glyph_string (s)
4755 struct glyph_string *s;
4756{
4757 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4758 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4759 xassert (s->img);
43d120d8 4760 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4761 s->font = s->face->font;
4762 s->width = s->first_glyph->pixel_width;
7d0393cf 4763
06a2c219
GM
4764 /* Adjust base line for subscript/superscript text. */
4765 s->ybase += s->first_glyph->voffset;
4766}
4767
4768
209f68d9 4769/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4770
209f68d9
GM
4771 ROW is the glyph row in which the glyphs are found, AREA is the
4772 area within the row. START is the index of the first glyph to
4773 consider, END is the index of the last + 1.
4774
4775 Value is the index of the first glyph not in S. */
4776
4777static int
4778x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4779 struct glyph_string *s;
209f68d9
GM
4780 struct glyph_row *row;
4781 enum glyph_row_area area;
4782 int start, end;
06a2c219 4783{
209f68d9
GM
4784 struct glyph *glyph, *last;
4785 int voffset, face_id;
7d0393cf 4786
06a2c219 4787 xassert (s->first_glyph->type == STRETCH_GLYPH);
7d0393cf 4788
209f68d9
GM
4789 glyph = s->row->glyphs[s->area] + start;
4790 last = s->row->glyphs[s->area] + end;
4791 face_id = glyph->face_id;
4792 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4793 s->font = s->face->font;
209f68d9
GM
4794 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4795 s->width = glyph->pixel_width;
4796 voffset = glyph->voffset;
4797
4798 for (++glyph;
4799 (glyph < last
4800 && glyph->type == STRETCH_GLYPH
4801 && glyph->voffset == voffset
4802 && glyph->face_id == face_id);
4803 ++glyph)
4804 s->width += glyph->pixel_width;
7d0393cf 4805
06a2c219 4806 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4807 s->ybase += voffset;
4808
c296fc01
GM
4809 /* The case that face->gc == 0 is handled when drawing the glyph
4810 string by calling PREPARE_FACE_FOR_DISPLAY. */
4811 xassert (s->face);
209f68d9 4812 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4813}
4814
4815
4816/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4817 of XChar2b structures for S; it can't be allocated in
4818 x_init_glyph_string because it must be allocated via `alloca'. W
4819 is the window on which S is drawn. ROW and AREA are the glyph row
4820 and area within the row from which S is constructed. START is the
4821 index of the first glyph structure covered by S. HL is a
4822 face-override for drawing S. */
7d0393cf 4823
06a2c219
GM
4824static void
4825x_init_glyph_string (s, char2b, w, row, area, start, hl)
4826 struct glyph_string *s;
4827 XChar2b *char2b;
4828 struct window *w;
4829 struct glyph_row *row;
4830 enum glyph_row_area area;
4831 int start;
4832 enum draw_glyphs_face hl;
4833{
4834 bzero (s, sizeof *s);
4835 s->w = w;
4836 s->f = XFRAME (w->frame);
4837 s->display = FRAME_X_DISPLAY (s->f);
4838 s->window = FRAME_X_WINDOW (s->f);
4839 s->char2b = char2b;
4840 s->hl = hl;
4841 s->row = row;
4842 s->area = area;
4843 s->first_glyph = row->glyphs[area] + start;
4844 s->height = row->height;
4845 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4846
9ea173e8
GM
4847 /* Display the internal border below the tool-bar window. */
4848 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219 4849 s->y -= s->f->output_data.x->internal_border_width;
7d0393cf 4850
06a2c219
GM
4851 s->ybase = s->y + row->ascent;
4852}
4853
4854
4855/* Set background width of glyph string S. START is the index of the
4856 first glyph following S. LAST_X is the right-most x-position + 1
4857 in the drawing area. */
4858
4859static INLINE void
4860x_set_glyph_string_background_width (s, start, last_x)
4861 struct glyph_string *s;
4862 int start;
4863 int last_x;
4864{
4865 /* If the face of this glyph string has to be drawn to the end of
4866 the drawing area, set S->extends_to_end_of_line_p. */
4867 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
7d0393cf 4868
06a2c219 4869 if (start == s->row->used[s->area]
eb79f5cc 4870 && s->area == TEXT_AREA
7b0870b2
GM
4871 && ((s->hl == DRAW_NORMAL_TEXT
4872 && (s->row->fill_line_p
4873 || s->face->background != default_face->background
4874 || s->face->stipple != default_face->stipple
4875 || s->row->mouse_face_p))
327f42ee
GM
4876 || s->hl == DRAW_MOUSE_FACE
4877 || ((s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN)
4878 && s->row->fill_line_p)))
7b0870b2 4879 s->extends_to_end_of_line_p = 1;
7d0393cf 4880
06a2c219
GM
4881 /* If S extends its face to the end of the line, set its
4882 background_width to the distance to the right edge of the drawing
4883 area. */
4884 if (s->extends_to_end_of_line_p)
1da3fd71 4885 s->background_width = last_x - s->x + 1;
06a2c219
GM
4886 else
4887 s->background_width = s->width;
4888}
4889
4890
4891/* Add a glyph string for a stretch glyph to the list of strings
4892 between HEAD and TAIL. START is the index of the stretch glyph in
4893 row area AREA of glyph row ROW. END is the index of the last glyph
4894 in that glyph row area. X is the current output position assigned
4895 to the new glyph string constructed. HL overrides that face of the
4896 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4897 is the right-most x-position of the drawing area. */
4898
8abee2e1
DL
4899/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4900 and below -- keep them on one line. */
4901#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4902 do \
4903 { \
4904 s = (struct glyph_string *) alloca (sizeof *s); \
4905 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4906 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4907 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4908 s->x = (X); \
4909 } \
4910 while (0)
4911
4912
4913/* Add a glyph string for an image glyph to the list of strings
4914 between HEAD and TAIL. START is the index of the image glyph in
4915 row area AREA of glyph row ROW. END is the index of the last glyph
4916 in that glyph row area. X is the current output position assigned
4917 to the new glyph string constructed. HL overrides that face of the
4918 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4919 is the right-most x-position of the drawing area. */
4920
8abee2e1 4921#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4922 do \
4923 { \
4924 s = (struct glyph_string *) alloca (sizeof *s); \
4925 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4926 x_fill_image_glyph_string (s); \
4927 x_append_glyph_string (&HEAD, &TAIL, s); \
4928 ++START; \
4929 s->x = (X); \
4930 } \
4931 while (0)
4932
4933
4934/* Add a glyph string for a sequence of character glyphs to the list
4935 of strings between HEAD and TAIL. START is the index of the first
4936 glyph in row area AREA of glyph row ROW that is part of the new
4937 glyph string. END is the index of the last glyph in that glyph row
4938 area. X is the current output position assigned to the new glyph
4939 string constructed. HL overrides that face of the glyph; e.g. it
4940 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4941 right-most x-position of the drawing area. */
4942
8abee2e1 4943#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4944 do \
4945 { \
3e71d8f2 4946 int c, face_id; \
06a2c219
GM
4947 XChar2b *char2b; \
4948 \
43d120d8 4949 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4950 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4951 \
b4192550
KH
4952 s = (struct glyph_string *) alloca (sizeof *s); \
4953 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4954 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4955 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4956 s->x = (X); \
4957 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4958 OVERLAPS_P); \
06a2c219
GM
4959 } \
4960 while (0)
7d0393cf 4961
06a2c219 4962
b4192550
KH
4963/* Add a glyph string for a composite sequence to the list of strings
4964 between HEAD and TAIL. START is the index of the first glyph in
4965 row area AREA of glyph row ROW that is part of the new glyph
4966 string. END is the index of the last glyph in that glyph row area.
4967 X is the current output position assigned to the new glyph string
4968 constructed. HL overrides that face of the glyph; e.g. it is
4969 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4970 x-position of the drawing area. */
4971
6c27ec25 4972#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4973 do { \
43d120d8
KH
4974 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4975 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4976 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4977 struct composition *cmp = composition_table[cmp_id]; \
4978 int glyph_len = cmp->glyph_len; \
4979 XChar2b *char2b; \
4980 struct face **faces; \
4981 struct glyph_string *first_s = NULL; \
4982 int n; \
4983 \
ee569018 4984 base_face = base_face->ascii_face; \
b4192550
KH
4985 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4986 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4987 /* At first, fill in `char2b' and `faces'. */ \
4988 for (n = 0; n < glyph_len; n++) \
4989 { \
43d120d8 4990 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4991 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4992 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4993 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
abfb6b46 4994 this_face_id, char2b + n, 1, 1); \
b4192550
KH
4995 } \
4996 \
4997 /* Make glyph_strings for each glyph sequence that is drawable by \
4998 the same face, and append them to HEAD/TAIL. */ \
4999 for (n = 0; n < cmp->glyph_len;) \
5000 { \
5001 s = (struct glyph_string *) alloca (sizeof *s); \
5002 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
5003 x_append_glyph_string (&(HEAD), &(TAIL), s); \
5004 s->cmp = cmp; \
5005 s->gidx = n; \
b4192550
KH
5006 s->x = (X); \
5007 \
5008 if (n == 0) \
5009 first_s = s; \
5010 \
5011 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
5012 } \
5013 \
5014 ++START; \
5015 s = first_s; \
5016 } while (0)
7d0393cf 5017
b4192550 5018
06a2c219
GM
5019/* Build a list of glyph strings between HEAD and TAIL for the glyphs
5020 of AREA of glyph row ROW on window W between indices START and END.
5021 HL overrides the face for drawing glyph strings, e.g. it is
5022 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
5023 x-positions of the drawing area.
5024
5025 This is an ugly monster macro construct because we must use alloca
5026 to allocate glyph strings (because x_draw_glyphs can be called
5027 asynchronously). */
5028
8abee2e1 5029#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
5030 do \
5031 { \
5032 HEAD = TAIL = NULL; \
5033 while (START < END) \
5034 { \
5035 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
5036 switch (first_glyph->type) \
5037 { \
5038 case CHAR_GLYPH: \
5039 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
5040 TAIL, HL, X, LAST_X, \
5041 OVERLAPS_P); \
06a2c219
GM
5042 break; \
5043 \
b4192550
KH
5044 case COMPOSITE_GLYPH: \
5045 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
5046 HEAD, TAIL, HL, X, LAST_X,\
5047 OVERLAPS_P); \
5048 break; \
5049 \
06a2c219
GM
5050 case STRETCH_GLYPH: \
5051 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
5052 HEAD, TAIL, HL, X, LAST_X); \
5053 break; \
5054 \
5055 case IMAGE_GLYPH: \
5056 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
5057 TAIL, HL, X, LAST_X); \
5058 break; \
5059 \
5060 default: \
5061 abort (); \
5062 } \
5063 \
5064 x_set_glyph_string_background_width (s, START, LAST_X); \
5065 (X) += s->width; \
5066 } \
5067 } \
5068 while (0)
5069
5070
5071/* Draw glyphs between START and END in AREA of ROW on window W,
5072 starting at x-position X. X is relative to AREA in W. HL is a
5073 face-override with the following meaning:
5074
5075 DRAW_NORMAL_TEXT draw normally
5076 DRAW_CURSOR draw in cursor face
5077 DRAW_MOUSE_FACE draw in mouse face.
5078 DRAW_INVERSE_VIDEO draw in mode line face
5079 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
5080 DRAW_IMAGE_RAISED draw an image with a raised relief around it
5081
66ac4b0e
GM
5082 If OVERLAPS_P is non-zero, draw only the foreground of characters
5083 and clip to the physical height of ROW.
5084
06a2c219 5085 Value is the x-position reached, relative to AREA of W. */
7d0393cf 5086
06a2c219 5087static int
f0a48a01 5088x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
06a2c219
GM
5089 struct window *w;
5090 int x;
5091 struct glyph_row *row;
5092 enum glyph_row_area area;
5093 int start, end;
5094 enum draw_glyphs_face hl;
66ac4b0e 5095 int overlaps_p;
dc6f92b8 5096{
06a2c219
GM
5097 struct glyph_string *head, *tail;
5098 struct glyph_string *s;
5099 int last_x, area_width;
5100 int x_reached;
5101 int i, j;
5102
5103 /* Let's rather be paranoid than getting a SEGV. */
06a2c219 5104 end = min (end, row->used[area]);
a8710abf
GM
5105 start = max (0, start);
5106 start = min (end, start);
06a2c219
GM
5107
5108 /* Translate X to frame coordinates. Set last_x to the right
5109 end of the drawing area. */
5110 if (row->full_width_p)
5111 {
5112 /* X is relative to the left edge of W, without scroll bars
3f332ef3 5113 or fringes. */
06a2c219 5114 struct frame *f = XFRAME (w->frame);
06a2c219 5115 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 5116
06a2c219
GM
5117 x += window_left_x;
5118 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
5119 last_x = window_left_x + area_width;
5120
5121 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5122 {
110859fc 5123 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
5124 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
5125 last_x += width;
5126 else
5127 x -= width;
5128 }
dc6f92b8 5129
b9432a85 5130 x += FRAME_INTERNAL_BORDER_WIDTH (f);
98fedd97 5131 last_x += FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
5132 }
5133 else
dc6f92b8 5134 {
06a2c219
GM
5135 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
5136 area_width = window_box_width (w, area);
5137 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
5138 }
5139
06a2c219
GM
5140 /* Build a doubly-linked list of glyph_string structures between
5141 head and tail from what we have to draw. Note that the macro
5142 BUILD_GLYPH_STRINGS will modify its start parameter. That's
5143 the reason we use a separate variable `i'. */
5144 i = start;
66ac4b0e
GM
5145 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
5146 overlaps_p);
06a2c219
GM
5147 if (tail)
5148 x_reached = tail->x + tail->background_width;
5149 else
5150 x_reached = x;
90e65f07 5151
06a2c219
GM
5152 /* If there are any glyphs with lbearing < 0 or rbearing > width in
5153 the row, redraw some glyphs in front or following the glyph
5154 strings built above. */
a8710abf 5155 if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
5156 {
5157 int dummy_x = 0;
5158 struct glyph_string *h, *t;
5159
5160 /* Compute overhangs for all glyph strings. */
5161 for (s = head; s; s = s->next)
5162 x_compute_glyph_string_overhangs (s);
5163
5164 /* Prepend glyph strings for glyphs in front of the first glyph
5165 string that are overwritten because of the first glyph
5166 string's left overhang. The background of all strings
7d0393cf 5167 prepended must be drawn because the first glyph string
06a2c219
GM
5168 draws over it. */
5169 i = x_left_overwritten (head);
5170 if (i >= 0)
5171 {
5172 j = i;
5173 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
5174 DRAW_NORMAL_TEXT, dummy_x, last_x,
5175 overlaps_p);
06a2c219 5176 start = i;
06a2c219
GM
5177 x_compute_overhangs_and_x (t, head->x, 1);
5178 x_prepend_glyph_string_lists (&head, &tail, h, t);
5179 }
58769bee 5180
06a2c219
GM
5181 /* Prepend glyph strings for glyphs in front of the first glyph
5182 string that overwrite that glyph string because of their
5183 right overhang. For these strings, only the foreground must
5184 be drawn, because it draws over the glyph string at `head'.
5185 The background must not be drawn because this would overwrite
5186 right overhangs of preceding glyphs for which no glyph
5187 strings exist. */
5188 i = x_left_overwriting (head);
5189 if (i >= 0)
5190 {
5191 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
5192 DRAW_NORMAL_TEXT, dummy_x, last_x,
5193 overlaps_p);
06a2c219
GM
5194 for (s = h; s; s = s->next)
5195 s->background_filled_p = 1;
06a2c219
GM
5196 x_compute_overhangs_and_x (t, head->x, 1);
5197 x_prepend_glyph_string_lists (&head, &tail, h, t);
5198 }
dbcb258a 5199
06a2c219
GM
5200 /* Append glyphs strings for glyphs following the last glyph
5201 string tail that are overwritten by tail. The background of
5202 these strings has to be drawn because tail's foreground draws
5203 over it. */
5204 i = x_right_overwritten (tail);
5205 if (i >= 0)
5206 {
5207 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5208 DRAW_NORMAL_TEXT, x, last_x,
5209 overlaps_p);
06a2c219
GM
5210 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5211 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219 5212 }
dc6f92b8 5213
06a2c219
GM
5214 /* Append glyph strings for glyphs following the last glyph
5215 string tail that overwrite tail. The foreground of such
5216 glyphs has to be drawn because it writes into the background
5217 of tail. The background must not be drawn because it could
5218 paint over the foreground of following glyphs. */
5219 i = x_right_overwriting (tail);
5220 if (i >= 0)
5221 {
5222 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5223 DRAW_NORMAL_TEXT, x, last_x,
5224 overlaps_p);
06a2c219
GM
5225 for (s = h; s; s = s->next)
5226 s->background_filled_p = 1;
5227 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5228 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219
GM
5229 }
5230 }
58769bee 5231
06a2c219
GM
5232 /* Draw all strings. */
5233 for (s = head; s; s = s->next)
5234 x_draw_glyph_string (s);
dc6f92b8 5235
bb313871
GM
5236 if (area == TEXT_AREA
5237 && !row->full_width_p
5238 /* When drawing overlapping rows, only the glyph strings'
5239 foreground is drawn, which doesn't erase a cursor
5240 completely. */
5241 && !overlaps_p)
f0a48a01
GM
5242 {
5243 int x0 = head ? head->x : x;
5244 int x1 = tail ? tail->x + tail->background_width : x;
7d0393cf 5245
f0a48a01
GM
5246 x0 = FRAME_TO_WINDOW_PIXEL_X (w, x0);
5247 x1 = FRAME_TO_WINDOW_PIXEL_X (w, x1);
7d0393cf 5248
bb313871 5249 if (XFASTINT (w->left_margin_width) != 0)
f0a48a01
GM
5250 {
5251 int left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
5252 x0 -= left_area_width;
5253 x1 -= left_area_width;
5254 }
5255
60626bab
GM
5256 notice_overwritten_cursor (w, area, x0, x1,
5257 row->y, MATRIX_ROW_BOTTOM_Y (row));
f0a48a01
GM
5258 }
5259
06a2c219
GM
5260 /* Value is the x-position up to which drawn, relative to AREA of W.
5261 This doesn't include parts drawn because of overhangs. */
5262 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
5263 if (!row->full_width_p)
5264 {
f0a48a01 5265 if (area > LEFT_MARGIN_AREA && XFASTINT (w->left_margin_width) != 0)
06a2c219
GM
5266 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
5267 if (area > TEXT_AREA)
5268 x_reached -= window_box_width (w, TEXT_AREA);
5269 }
7d0393cf 5270
06a2c219
GM
5271 return x_reached;
5272}
dc6f92b8 5273
dc6f92b8 5274
66ac4b0e
GM
5275/* Fix the display of area AREA of overlapping row ROW in window W. */
5276
5277static void
5278x_fix_overlapping_area (w, row, area)
5279 struct window *w;
5280 struct glyph_row *row;
5281 enum glyph_row_area area;
5282{
5283 int i, x;
7d0393cf 5284
66ac4b0e 5285 BLOCK_INPUT;
7d0393cf 5286
66ac4b0e
GM
5287 if (area == LEFT_MARGIN_AREA)
5288 x = 0;
5289 else if (area == TEXT_AREA)
5290 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5291 else
5292 x = (window_box_width (w, LEFT_MARGIN_AREA)
5293 + window_box_width (w, TEXT_AREA));
5294
5295 for (i = 0; i < row->used[area];)
5296 {
5297 if (row->glyphs[area][i].overlaps_vertically_p)
5298 {
5299 int start = i, start_x = x;
5300
5301 do
5302 {
5303 x += row->glyphs[area][i].pixel_width;
5304 ++i;
5305 }
5306 while (i < row->used[area]
5307 && row->glyphs[area][i].overlaps_vertically_p);
5308
5309 x_draw_glyphs (w, start_x, row, area, start, i,
f0a48a01 5310 DRAW_NORMAL_TEXT, 1);
66ac4b0e
GM
5311 }
5312 else
5313 {
5314 x += row->glyphs[area][i].pixel_width;
5315 ++i;
5316 }
5317 }
7d0393cf 5318
66ac4b0e
GM
5319 UNBLOCK_INPUT;
5320}
5321
5322
06a2c219
GM
5323/* Output LEN glyphs starting at START at the nominal cursor position.
5324 Advance the nominal cursor over the text. The global variable
5325 updated_window contains the window being updated, updated_row is
5326 the glyph row being updated, and updated_area is the area of that
5327 row being updated. */
dc6f92b8 5328
06a2c219
GM
5329static void
5330x_write_glyphs (start, len)
5331 struct glyph *start;
5332 int len;
5333{
f0a48a01 5334 int x, hpos;
d9cdbb3d 5335
06a2c219 5336 xassert (updated_window && updated_row);
dc6f92b8 5337 BLOCK_INPUT;
7d0393cf 5338
06a2c219 5339 /* Write glyphs. */
dc6f92b8 5340
06a2c219
GM
5341 hpos = start - updated_row->glyphs[updated_area];
5342 x = x_draw_glyphs (updated_window, output_cursor.x,
5343 updated_row, updated_area,
5344 hpos, hpos + len,
f0a48a01 5345 DRAW_NORMAL_TEXT, 0);
dc6f92b8 5346
6065f9e2
KS
5347 /* Invalidate old phys cursor if the glyph at its hpos is redrawn. */
5348 if (updated_area == TEXT_AREA
5349 && updated_window->phys_cursor_on_p
5350 && updated_window->phys_cursor.vpos == output_cursor.vpos
5351 && updated_window->phys_cursor.hpos >= hpos
5352 && updated_window->phys_cursor.hpos < hpos + len)
5353 updated_window->phys_cursor_on_p = 0;
5354
dc6f92b8 5355 UNBLOCK_INPUT;
7d0393cf 5356
06a2c219
GM
5357 /* Advance the output cursor. */
5358 output_cursor.hpos += len;
5359 output_cursor.x = x;
dc6f92b8
JB
5360}
5361
0cdd0c9f 5362
06a2c219 5363/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 5364
06a2c219
GM
5365static void
5366x_insert_glyphs (start, len)
5367 struct glyph *start;
5368 register int len;
5369{
5370 struct frame *f;
5371 struct window *w;
5372 int line_height, shift_by_width, shifted_region_width;
5373 struct glyph_row *row;
5374 struct glyph *glyph;
2beb36f9 5375 int frame_x, frame_y, hpos;
58769bee 5376
06a2c219 5377 xassert (updated_window && updated_row);
0cdd0c9f 5378 BLOCK_INPUT;
06a2c219
GM
5379 w = updated_window;
5380 f = XFRAME (WINDOW_FRAME (w));
5381
5382 /* Get the height of the line we are in. */
5383 row = updated_row;
5384 line_height = row->height;
5385
5386 /* Get the width of the glyphs to insert. */
5387 shift_by_width = 0;
5388 for (glyph = start; glyph < start + len; ++glyph)
5389 shift_by_width += glyph->pixel_width;
5390
5391 /* Get the width of the region to shift right. */
5392 shifted_region_width = (window_box_width (w, updated_area)
5393 - output_cursor.x
5394 - shift_by_width);
5395
5396 /* Shift right. */
bf0ab8a2 5397 frame_x = window_box_left (w, updated_area) + output_cursor.x;
06a2c219
GM
5398 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
5399 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5400 f->output_data.x->normal_gc,
5401 frame_x, frame_y,
5402 shifted_region_width, line_height,
5403 frame_x + shift_by_width, frame_y);
5404
5405 /* Write the glyphs. */
5406 hpos = start - row->glyphs[updated_area];
5407 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
f0a48a01 5408 DRAW_NORMAL_TEXT, 0);
7d0393cf 5409
06a2c219
GM
5410 /* Advance the output cursor. */
5411 output_cursor.hpos += len;
5412 output_cursor.x += shift_by_width;
0cdd0c9f
RS
5413 UNBLOCK_INPUT;
5414}
0cdd0c9f 5415
0cdd0c9f 5416
06a2c219
GM
5417/* Delete N glyphs at the nominal cursor position. Not implemented
5418 for X frames. */
c83febd7
RS
5419
5420static void
06a2c219
GM
5421x_delete_glyphs (n)
5422 register int n;
c83febd7 5423{
06a2c219 5424 abort ();
c83febd7
RS
5425}
5426
0cdd0c9f 5427
c5e6e06b
GM
5428/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
5429 If they are <= 0, this is probably an error. */
5430
5431void
5432x_clear_area (dpy, window, x, y, width, height, exposures)
5433 Display *dpy;
5434 Window window;
5435 int x, y;
5436 int width, height;
5437 int exposures;
5438{
5439 xassert (width > 0 && height > 0);
5440 XClearArea (dpy, window, x, y, width, height, exposures);
5441}
5442
5443
06a2c219
GM
5444/* Erase the current text line from the nominal cursor position
5445 (inclusive) to pixel column TO_X (exclusive). The idea is that
5446 everything from TO_X onward is already erased.
5447
5448 TO_X is a pixel position relative to updated_area of
5449 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 5450
06a2c219
GM
5451static void
5452x_clear_end_of_line (to_x)
5453 int to_x;
5454{
5455 struct frame *f;
5456 struct window *w = updated_window;
5457 int max_x, min_y, max_y;
5458 int from_x, from_y, to_y;
7d0393cf 5459
06a2c219
GM
5460 xassert (updated_window && updated_row);
5461 f = XFRAME (w->frame);
7d0393cf 5462
06a2c219
GM
5463 if (updated_row->full_width_p)
5464 {
5465 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
5466 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5467 && !w->pseudo_window_p)
5468 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 5469 }
06a2c219
GM
5470 else
5471 max_x = window_box_width (w, updated_area);
5472 max_y = window_text_bottom_y (w);
dc6f92b8 5473
06a2c219
GM
5474 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5475 of window. For TO_X > 0, truncate to end of drawing area. */
5476 if (to_x == 0)
5477 return;
5478 else if (to_x < 0)
5479 to_x = max_x;
5480 else
5481 to_x = min (to_x, max_x);
dbc4e1c1 5482
06a2c219 5483 to_y = min (max_y, output_cursor.y + updated_row->height);
7d0393cf 5484
06a2c219
GM
5485 /* Notice if the cursor will be cleared by this operation. */
5486 if (!updated_row->full_width_p)
60626bab
GM
5487 notice_overwritten_cursor (w, updated_area,
5488 output_cursor.x, -1,
5489 updated_row->y,
5490 MATRIX_ROW_BOTTOM_Y (updated_row));
dbc4e1c1 5491
06a2c219 5492 from_x = output_cursor.x;
7d0393cf 5493
06a2c219
GM
5494 /* Translate to frame coordinates. */
5495 if (updated_row->full_width_p)
5496 {
5497 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5498 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5499 }
0cdd0c9f
RS
5500 else
5501 {
06a2c219
GM
5502 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5503 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5504 }
7d0393cf 5505
045dee35 5506 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5507 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5508 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
7d0393cf 5509
06a2c219
GM
5510 /* Prevent inadvertently clearing to end of the X window. */
5511 if (to_x > from_x && to_y > from_y)
5512 {
5513 BLOCK_INPUT;
c5e6e06b
GM
5514 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5515 from_x, from_y, to_x - from_x, to_y - from_y,
5516 False);
06a2c219 5517 UNBLOCK_INPUT;
0cdd0c9f 5518 }
0cdd0c9f 5519}
dbc4e1c1 5520
0cdd0c9f 5521
06a2c219 5522/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5523 frame. Otherwise clear the selected frame. */
06a2c219
GM
5524
5525static void
5526x_clear_frame ()
0cdd0c9f 5527{
06a2c219 5528 struct frame *f;
0cdd0c9f 5529
06a2c219
GM
5530 if (updating_frame)
5531 f = updating_frame;
0cdd0c9f 5532 else
b86bd3dd 5533 f = SELECTED_FRAME ();
58769bee 5534
06a2c219
GM
5535 /* Clearing the frame will erase any cursor, so mark them all as no
5536 longer visible. */
5537 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5538 output_cursor.hpos = output_cursor.vpos = 0;
5539 output_cursor.x = -1;
5540
5541 /* We don't set the output cursor here because there will always
5542 follow an explicit cursor_to. */
5543 BLOCK_INPUT;
5544 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5545
5546 /* We have to clear the scroll bars, too. If we have changed
5547 colors or something like that, then they should be notified. */
5548 x_scroll_bar_clear (f);
0cdd0c9f 5549
06a2c219
GM
5550 XFlush (FRAME_X_DISPLAY (f));
5551 UNBLOCK_INPUT;
dc6f92b8 5552}
06a2c219
GM
5553
5554
dc6f92b8 5555\f
dbc4e1c1
JB
5556/* Invert the middle quarter of the frame for .15 sec. */
5557
06a2c219
GM
5558/* We use the select system call to do the waiting, so we have to make
5559 sure it's available. If it isn't, we just won't do visual bells. */
5560
dbc4e1c1
JB
5561#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5562
06a2c219
GM
5563
5564/* Subtract the `struct timeval' values X and Y, storing the result in
5565 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5566
5567static int
5568timeval_subtract (result, x, y)
5569 struct timeval *result, x, y;
5570{
06a2c219
GM
5571 /* Perform the carry for the later subtraction by updating y. This
5572 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5573 if (x.tv_usec < y.tv_usec)
5574 {
5575 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5576 y.tv_usec -= 1000000 * nsec;
5577 y.tv_sec += nsec;
5578 }
7d0393cf 5579
dbc4e1c1
JB
5580 if (x.tv_usec - y.tv_usec > 1000000)
5581 {
5582 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5583 y.tv_usec += 1000000 * nsec;
5584 y.tv_sec -= nsec;
5585 }
5586
06a2c219
GM
5587 /* Compute the time remaining to wait. tv_usec is certainly
5588 positive. */
dbc4e1c1
JB
5589 result->tv_sec = x.tv_sec - y.tv_sec;
5590 result->tv_usec = x.tv_usec - y.tv_usec;
5591
06a2c219
GM
5592 /* Return indication of whether the result should be considered
5593 negative. */
dbc4e1c1
JB
5594 return x.tv_sec < y.tv_sec;
5595}
dc6f92b8 5596
dfcf069d 5597void
f676886a
JB
5598XTflash (f)
5599 struct frame *f;
dc6f92b8 5600{
dbc4e1c1 5601 BLOCK_INPUT;
dc6f92b8 5602
dbc4e1c1
JB
5603 {
5604 GC gc;
dc6f92b8 5605
06a2c219
GM
5606 /* Create a GC that will use the GXxor function to flip foreground
5607 pixels into background pixels. */
dbc4e1c1
JB
5608 {
5609 XGCValues values;
dc6f92b8 5610
dbc4e1c1 5611 values.function = GXxor;
7556890b
RS
5612 values.foreground = (f->output_data.x->foreground_pixel
5613 ^ f->output_data.x->background_pixel);
58769bee 5614
334208b7 5615 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5616 GCFunction | GCForeground, &values);
5617 }
dc6f92b8 5618
dbc4e1c1 5619 {
e84e14c3
RS
5620 /* Get the height not including a menu bar widget. */
5621 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5622 /* Height of each line to flash. */
5623 int flash_height = FRAME_LINE_HEIGHT (f);
5624 /* These will be the left and right margins of the rectangles. */
5625 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5626 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5627
5628 int width;
5629
5630 /* Don't flash the area between a scroll bar and the frame
5631 edge it is next to. */
5632 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5633 {
5634 case vertical_scroll_bar_left:
5635 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5636 break;
5637
5638 case vertical_scroll_bar_right:
5639 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5640 break;
06a2c219
GM
5641
5642 default:
5643 break;
e84e14c3
RS
5644 }
5645
5646 width = flash_right - flash_left;
5647
5648 /* If window is tall, flash top and bottom line. */
5649 if (height > 3 * FRAME_LINE_HEIGHT (f))
5650 {
5651 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5652 flash_left,
5653 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5654 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5655 width, flash_height);
5656 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5657 flash_left,
5658 (height - flash_height
5659 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5660 width, flash_height);
5661 }
5662 else
7d0393cf 5663 /* If it is short, flash it all. */
e84e14c3
RS
5664 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5665 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5666 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5667
06a2c219 5668 x_flush (f);
dc6f92b8 5669
dbc4e1c1 5670 {
06a2c219 5671 struct timeval wakeup;
dc6f92b8 5672
66c30ea1 5673 EMACS_GET_TIME (wakeup);
dc6f92b8 5674
dbc4e1c1
JB
5675 /* Compute time to wait until, propagating carry from usecs. */
5676 wakeup.tv_usec += 150000;
5677 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5678 wakeup.tv_usec %= 1000000;
5679
101922c3
GM
5680 /* Keep waiting until past the time wakeup or any input gets
5681 available. */
5682 while (! detect_input_pending ())
dbc4e1c1 5683 {
101922c3 5684 struct timeval current;
dbc4e1c1
JB
5685 struct timeval timeout;
5686
101922c3 5687 EMACS_GET_TIME (current);
dbc4e1c1 5688
101922c3
GM
5689 /* Break if result would be negative. */
5690 if (timeval_subtract (&current, wakeup, current))
dbc4e1c1
JB
5691 break;
5692
101922c3
GM
5693 /* How long `select' should wait. */
5694 timeout.tv_sec = 0;
5695 timeout.tv_usec = 10000;
5696
dbc4e1c1 5697 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5698 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5699 }
5700 }
58769bee 5701
e84e14c3
RS
5702 /* If window is tall, flash top and bottom line. */
5703 if (height > 3 * FRAME_LINE_HEIGHT (f))
5704 {
5705 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5706 flash_left,
5707 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5708 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5709 width, flash_height);
5710 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5711 flash_left,
5712 (height - flash_height
5713 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5714 width, flash_height);
5715 }
5716 else
7d0393cf 5717 /* If it is short, flash it all. */
e84e14c3
RS
5718 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5719 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5720 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5721
334208b7 5722 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5723 x_flush (f);
dc6f92b8 5724 }
dbc4e1c1
JB
5725 }
5726
5727 UNBLOCK_INPUT;
dc6f92b8
JB
5728}
5729
06a2c219 5730#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5731
5732
dc6f92b8
JB
5733/* Make audible bell. */
5734
dfcf069d 5735void
dc6f92b8
JB
5736XTring_bell ()
5737{
b86bd3dd 5738 struct frame *f = SELECTED_FRAME ();
7d0393cf 5739
b86bd3dd
GM
5740 if (FRAME_X_DISPLAY (f))
5741 {
dbc4e1c1 5742#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5743 if (visible_bell)
5744 XTflash (f);
5745 else
dbc4e1c1 5746#endif
b86bd3dd
GM
5747 {
5748 BLOCK_INPUT;
5749 XBell (FRAME_X_DISPLAY (f), 0);
5750 XFlush (FRAME_X_DISPLAY (f));
5751 UNBLOCK_INPUT;
5752 }
dc6f92b8
JB
5753 }
5754}
06a2c219 5755
dc6f92b8 5756\f
06a2c219
GM
5757/* Specify how many text lines, from the top of the window,
5758 should be affected by insert-lines and delete-lines operations.
5759 This, and those operations, are used only within an update
5760 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5761
dfcf069d 5762static void
06a2c219
GM
5763XTset_terminal_window (n)
5764 register int n;
dc6f92b8 5765{
06a2c219 5766 /* This function intentionally left blank. */
dc6f92b8
JB
5767}
5768
06a2c219
GM
5769
5770\f
5771/***********************************************************************
5772 Line Dance
5773 ***********************************************************************/
5774
5775/* Perform an insert-lines or delete-lines operation, inserting N
5776 lines or deleting -N lines at vertical position VPOS. */
5777
dfcf069d 5778static void
06a2c219
GM
5779x_ins_del_lines (vpos, n)
5780 int vpos, n;
dc6f92b8
JB
5781{
5782 abort ();
5783}
06a2c219
GM
5784
5785
5786/* Scroll part of the display as described by RUN. */
dc6f92b8 5787
dfcf069d 5788static void
06a2c219
GM
5789x_scroll_run (w, run)
5790 struct window *w;
5791 struct run *run;
dc6f92b8 5792{
06a2c219
GM
5793 struct frame *f = XFRAME (w->frame);
5794 int x, y, width, height, from_y, to_y, bottom_y;
5795
5796 /* Get frame-relative bounding box of the text display area of W,
3f332ef3
KS
5797 without mode lines. Include in this box the left and right
5798 fringe of W. */
06a2c219 5799 window_box (w, -1, &x, &y, &width, &height);
3f332ef3
KS
5800 width += FRAME_X_FRINGE_WIDTH (f);
5801 x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
06a2c219
GM
5802
5803 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5804 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5805 bottom_y = y + height;
dc6f92b8 5806
06a2c219
GM
5807 if (to_y < from_y)
5808 {
5809 /* Scrolling up. Make sure we don't copy part of the mode
5810 line at the bottom. */
5811 if (from_y + run->height > bottom_y)
5812 height = bottom_y - from_y;
5813 else
5814 height = run->height;
5815 }
dc6f92b8 5816 else
06a2c219
GM
5817 {
5818 /* Scolling down. Make sure we don't copy over the mode line.
5819 at the bottom. */
5820 if (to_y + run->height > bottom_y)
5821 height = bottom_y - to_y;
5822 else
5823 height = run->height;
5824 }
7a13e894 5825
06a2c219 5826 BLOCK_INPUT;
7d0393cf 5827
06a2c219
GM
5828 /* Cursor off. Will be switched on again in x_update_window_end. */
5829 updated_window = w;
5830 x_clear_cursor (w);
5831
5832 XCopyArea (FRAME_X_DISPLAY (f),
5833 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5834 f->output_data.x->normal_gc,
5835 x, from_y,
5836 width, height,
5837 x, to_y);
7d0393cf 5838
06a2c219
GM
5839 UNBLOCK_INPUT;
5840}
dc6f92b8 5841
dc6f92b8 5842
06a2c219
GM
5843\f
5844/***********************************************************************
5845 Exposure Events
5846 ***********************************************************************/
7d0393cf 5847
06a2c219
GM
5848/* Redisplay an exposed area of frame F. X and Y are the upper-left
5849 corner of the exposed rectangle. W and H are width and height of
5850 the exposed area. All are pixel values. W or H zero means redraw
5851 the entire frame. */
dc6f92b8 5852
06a2c219
GM
5853static void
5854expose_frame (f, x, y, w, h)
5855 struct frame *f;
5856 int x, y, w, h;
dc6f92b8 5857{
06a2c219 5858 XRectangle r;
82f053ab 5859 int mouse_face_overwritten_p = 0;
dc6f92b8 5860
06a2c219 5861 TRACE ((stderr, "expose_frame "));
dc6f92b8 5862
06a2c219
GM
5863 /* No need to redraw if frame will be redrawn soon. */
5864 if (FRAME_GARBAGED_P (f))
dc6f92b8 5865 {
06a2c219
GM
5866 TRACE ((stderr, " garbaged\n"));
5867 return;
5868 }
5869
5870 /* If basic faces haven't been realized yet, there is no point in
5871 trying to redraw anything. This can happen when we get an expose
5872 event while Emacs is starting, e.g. by moving another window. */
5873 if (FRAME_FACE_CACHE (f) == NULL
5874 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5875 {
5876 TRACE ((stderr, " no faces\n"));
5877 return;
58769bee 5878 }
06a2c219
GM
5879
5880 if (w == 0 || h == 0)
58769bee 5881 {
06a2c219
GM
5882 r.x = r.y = 0;
5883 r.width = CANON_X_UNIT (f) * f->width;
5884 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5885 }
5886 else
5887 {
06a2c219
GM
5888 r.x = x;
5889 r.y = y;
5890 r.width = w;
5891 r.height = h;
5892 }
5893
5894 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
82f053ab 5895 mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
06a2c219 5896
9ea173e8 5897 if (WINDOWP (f->tool_bar_window))
82f053ab
GM
5898 mouse_face_overwritten_p
5899 |= expose_window (XWINDOW (f->tool_bar_window), &r);
06a2c219
GM
5900
5901#ifndef USE_X_TOOLKIT
5902 if (WINDOWP (f->menu_bar_window))
82f053ab
GM
5903 mouse_face_overwritten_p
5904 |= expose_window (XWINDOW (f->menu_bar_window), &r);
06a2c219 5905#endif /* not USE_X_TOOLKIT */
82f053ab
GM
5906
5907 /* Some window managers support a focus-follows-mouse style with
5908 delayed raising of frames. Imagine a partially obscured frame,
5909 and moving the mouse into partially obscured mouse-face on that
5910 frame. The visible part of the mouse-face will be highlighted,
5911 then the WM raises the obscured frame. With at least one WM, KDE
5912 2.1, Emacs is not getting any event for the raising of the frame
5913 (even tried with SubstructureRedirectMask), only Expose events.
5914 These expose events will draw text normally, i.e. not
5915 highlighted. Which means we must redo the highlight here.
5916 Subsume it under ``we love X''. --gerd 2001-08-15 */
5917 if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
5918 {
5919 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5920 if (f == dpyinfo->mouse_face_mouse_frame)
5921 {
5922 int x = dpyinfo->mouse_face_mouse_x;
5923 int y = dpyinfo->mouse_face_mouse_y;
5924 clear_mouse_face (dpyinfo);
5925 note_mouse_highlight (f, x, y);
5926 }
5927 }
dc6f92b8
JB
5928}
5929
06a2c219
GM
5930
5931/* Redraw (parts) of all windows in the window tree rooted at W that
82f053ab
GM
5932 intersect R. R contains frame pixel coordinates. Value is
5933 non-zero if the exposure overwrites mouse-face. */
06a2c219 5934
82f053ab 5935static int
06a2c219
GM
5936expose_window_tree (w, r)
5937 struct window *w;
5938 XRectangle *r;
dc6f92b8 5939{
82f053ab
GM
5940 struct frame *f = XFRAME (w->frame);
5941 int mouse_face_overwritten_p = 0;
7d0393cf 5942
82f053ab 5943 while (w && !FRAME_GARBAGED_P (f))
06a2c219
GM
5944 {
5945 if (!NILP (w->hchild))
82f053ab
GM
5946 mouse_face_overwritten_p
5947 |= expose_window_tree (XWINDOW (w->hchild), r);
06a2c219 5948 else if (!NILP (w->vchild))
82f053ab
GM
5949 mouse_face_overwritten_p
5950 |= expose_window_tree (XWINDOW (w->vchild), r);
5951 else
5952 mouse_face_overwritten_p |= expose_window (w, r);
7d0393cf 5953
a02f1be0 5954 w = NILP (w->next) ? NULL : XWINDOW (w->next);
06a2c219 5955 }
82f053ab
GM
5956
5957 return mouse_face_overwritten_p;
06a2c219 5958}
58769bee 5959
dc6f92b8 5960
06a2c219
GM
5961/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5962 which intersects rectangle R. R is in window-relative coordinates. */
5963
5964static void
5965expose_area (w, row, r, area)
5966 struct window *w;
5967 struct glyph_row *row;
5968 XRectangle *r;
5969 enum glyph_row_area area;
5970{
06a2c219
GM
5971 struct glyph *first = row->glyphs[area];
5972 struct glyph *end = row->glyphs[area] + row->used[area];
5973 struct glyph *last;
4bc6dcc7 5974 int first_x, start_x, x;
06a2c219 5975
6fb13182
GM
5976 if (area == TEXT_AREA && row->fill_line_p)
5977 /* If row extends face to end of line write the whole line. */
153f5ed7 5978 x_draw_glyphs (w, 0, row, area, 0, row->used[area],
f0a48a01 5979 DRAW_NORMAL_TEXT, 0);
6fb13182
GM
5980 else
5981 {
4bc6dcc7
GM
5982 /* Set START_X to the window-relative start position for drawing glyphs of
5983 AREA. The first glyph of the text area can be partially visible.
5984 The first glyphs of other areas cannot. */
5985 if (area == LEFT_MARGIN_AREA)
5986 start_x = 0;
5987 else if (area == TEXT_AREA)
5988 start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5989 else
5990 start_x = (window_box_width (w, LEFT_MARGIN_AREA)
5991 + window_box_width (w, TEXT_AREA));
5992 x = start_x;
5993
6fb13182
GM
5994 /* Find the first glyph that must be redrawn. */
5995 while (first < end
5996 && x + first->pixel_width < r->x)
5997 {
5998 x += first->pixel_width;
5999 ++first;
6000 }
7d0393cf 6001
6fb13182
GM
6002 /* Find the last one. */
6003 last = first;
6004 first_x = x;
6005 while (last < end
6006 && x < r->x + r->width)
6007 {
6008 x += last->pixel_width;
6009 ++last;
6010 }
7d0393cf 6011
6fb13182
GM
6012 /* Repaint. */
6013 if (last > first)
4bc6dcc7 6014 x_draw_glyphs (w, first_x - start_x, row, area,
6fb13182
GM
6015 first - row->glyphs[area],
6016 last - row->glyphs[area],
f0a48a01 6017 DRAW_NORMAL_TEXT, 0);
6fb13182 6018 }
06a2c219 6019}
7d0393cf 6020
58769bee 6021
06a2c219 6022/* Redraw the parts of the glyph row ROW on window W intersecting
82f053ab
GM
6023 rectangle R. R is in window-relative coordinates. Value is
6024 non-zero if mouse-face was overwritten. */
dc6f92b8 6025
82f053ab 6026static int
06a2c219
GM
6027expose_line (w, row, r)
6028 struct window *w;
6029 struct glyph_row *row;
6030 XRectangle *r;
6031{
6032 xassert (row->enabled_p);
7d0393cf 6033
06a2c219
GM
6034 if (row->mode_line_p || w->pseudo_window_p)
6035 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
f0a48a01 6036 DRAW_NORMAL_TEXT, 0);
06a2c219
GM
6037 else
6038 {
6039 if (row->used[LEFT_MARGIN_AREA])
6040 expose_area (w, row, r, LEFT_MARGIN_AREA);
6041 if (row->used[TEXT_AREA])
6042 expose_area (w, row, r, TEXT_AREA);
6043 if (row->used[RIGHT_MARGIN_AREA])
6044 expose_area (w, row, r, RIGHT_MARGIN_AREA);
3f332ef3 6045 x_draw_row_fringe_bitmaps (w, row);
06a2c219 6046 }
82f053ab
GM
6047
6048 return row->mouse_face_p;
06a2c219 6049}
dc6f92b8 6050
58769bee 6051
06a2c219
GM
6052/* Return non-zero if W's cursor intersects rectangle R. */
6053
6054static int
6055x_phys_cursor_in_rect_p (w, r)
6056 struct window *w;
6057 XRectangle *r;
6058{
6059 XRectangle cr, result;
6060 struct glyph *cursor_glyph;
6061
6062 cursor_glyph = get_phys_cursor_glyph (w);
6063 if (cursor_glyph)
6064 {
6065 cr.x = w->phys_cursor.x;
6066 cr.y = w->phys_cursor.y;
6067 cr.width = cursor_glyph->pixel_width;
6068 cr.height = w->phys_cursor_height;
6069 return x_intersect_rectangles (&cr, r, &result);
6070 }
6071 else
6072 return 0;
dc6f92b8 6073}
dc6f92b8 6074
06a2c219 6075
4f53f3b8
RS
6076/* Redraw those parts of glyphs rows during expose event handling that
6077 overlap other rows. Redrawing of an exposed line writes over parts
6078 of lines overlapping that exposed line; this function fixes that.
6079
6080 W is the window being exposed. FIRST_OVERLAPPING_ROW is the first
6081 row in W's current matrix that is exposed and overlaps other rows.
6082 LAST_OVERLAPPING_ROW is the last such row. */
6083
6084static void
6085expose_overlaps (w, first_overlapping_row, last_overlapping_row)
6086 struct window *w;
6087 struct glyph_row *first_overlapping_row;
6088 struct glyph_row *last_overlapping_row;
6089{
6090 struct glyph_row *row;
7d0393cf 6091
4f53f3b8
RS
6092 for (row = first_overlapping_row; row <= last_overlapping_row; ++row)
6093 if (row->overlapping_p)
6094 {
6095 xassert (row->enabled_p && !row->mode_line_p);
7d0393cf 6096
4f53f3b8
RS
6097 if (row->used[LEFT_MARGIN_AREA])
6098 x_fix_overlapping_area (w, row, LEFT_MARGIN_AREA);
7d0393cf 6099
4f53f3b8
RS
6100 if (row->used[TEXT_AREA])
6101 x_fix_overlapping_area (w, row, TEXT_AREA);
7d0393cf 6102
4f53f3b8
RS
6103 if (row->used[RIGHT_MARGIN_AREA])
6104 x_fix_overlapping_area (w, row, RIGHT_MARGIN_AREA);
6105 }
6106}
6107
6108
a02f1be0
GM
6109/* Redraw the part of window W intersection rectangle FR. Pixel
6110 coordinates in FR are frame-relative. Call this function with
82f053ab
GM
6111 input blocked. Value is non-zero if the exposure overwrites
6112 mouse-face. */
dc6f92b8 6113
a39202f6 6114static int
a02f1be0 6115expose_window (w, fr)
06a2c219 6116 struct window *w;
a02f1be0 6117 XRectangle *fr;
dc6f92b8 6118{
a02f1be0 6119 struct frame *f = XFRAME (w->frame);
a02f1be0 6120 XRectangle wr, r;
82f053ab 6121 int mouse_face_overwritten_p = 0;
dc6f92b8 6122
80c32bcc
GM
6123 /* If window is not yet fully initialized, do nothing. This can
6124 happen when toolkit scroll bars are used and a window is split.
6125 Reconfiguring the scroll bar will generate an expose for a newly
6126 created window. */
a39202f6 6127 if (w->current_matrix == NULL)
82f053ab 6128 return 0;
a39202f6
GM
6129
6130 /* When we're currently updating the window, display and current
6131 matrix usually don't agree. Arrange for a thorough display
6132 later. */
6133 if (w == updated_window)
6134 {
6135 SET_FRAME_GARBAGED (f);
6136 return 0;
6137 }
80c32bcc 6138
a39202f6 6139 /* Frame-relative pixel rectangle of W. */
a02f1be0
GM
6140 wr.x = XFASTINT (w->left) * CANON_X_UNIT (f);
6141 wr.y = XFASTINT (w->top) * CANON_Y_UNIT (f);
6142 wr.width = XFASTINT (w->width) * CANON_X_UNIT (f);
6143 wr.height = XFASTINT (w->height) * CANON_Y_UNIT (f);
6144
a39202f6
GM
6145 if (x_intersect_rectangles (fr, &wr, &r))
6146 {
6147 int yb = window_text_bottom_y (w);
6148 struct glyph_row *row;
6149 int cursor_cleared_p;
4f53f3b8 6150 struct glyph_row *first_overlapping_row, *last_overlapping_row;
7d0393cf 6151
a39202f6
GM
6152 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
6153 r.x, r.y, r.width, r.height));
dc6f92b8 6154
a39202f6
GM
6155 /* Convert to window coordinates. */
6156 r.x = FRAME_TO_WINDOW_PIXEL_X (w, r.x);
6157 r.y = FRAME_TO_WINDOW_PIXEL_Y (w, r.y);
dc6f92b8 6158
a39202f6
GM
6159 /* Turn off the cursor. */
6160 if (!w->pseudo_window_p
6161 && x_phys_cursor_in_rect_p (w, &r))
6162 {
6163 x_clear_cursor (w);
6164 cursor_cleared_p = 1;
6165 }
6166 else
6167 cursor_cleared_p = 0;
06a2c219 6168
4f53f3b8
RS
6169 /* Update lines intersecting rectangle R. */
6170 first_overlapping_row = last_overlapping_row = NULL;
a39202f6
GM
6171 for (row = w->current_matrix->rows;
6172 row->enabled_p;
6173 ++row)
6174 {
6175 int y0 = row->y;
6176 int y1 = MATRIX_ROW_BOTTOM_Y (row);
7d0393cf 6177
a39202f6
GM
6178 if ((y0 >= r.y && y0 < r.y + r.height)
6179 || (y1 > r.y && y1 < r.y + r.height)
6180 || (r.y >= y0 && r.y < y1)
6181 || (r.y + r.height > y0 && r.y + r.height < y1))
82f053ab 6182 {
4f53f3b8
RS
6183 if (row->overlapping_p)
6184 {
6185 if (first_overlapping_row == NULL)
6186 first_overlapping_row = row;
6187 last_overlapping_row = row;
6188 }
7d0393cf 6189
82f053ab
GM
6190 if (expose_line (w, row, &r))
6191 mouse_face_overwritten_p = 1;
6192 }
7d0393cf 6193
a39202f6
GM
6194 if (y1 >= yb)
6195 break;
6196 }
dc6f92b8 6197
a39202f6
GM
6198 /* Display the mode line if there is one. */
6199 if (WINDOW_WANTS_MODELINE_P (w)
6200 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
6201 row->enabled_p)
6202 && row->y < r.y + r.height)
82f053ab
GM
6203 {
6204 if (expose_line (w, row, &r))
6205 mouse_face_overwritten_p = 1;
6206 }
a39202f6
GM
6207
6208 if (!w->pseudo_window_p)
6209 {
4f53f3b8
RS
6210 /* Fix the display of overlapping rows. */
6211 if (first_overlapping_row)
6212 expose_overlaps (w, first_overlapping_row, last_overlapping_row);
7d0393cf 6213
a39202f6
GM
6214 /* Draw border between windows. */
6215 x_draw_vertical_border (w);
7d0393cf 6216
a39202f6
GM
6217 /* Turn the cursor on again. */
6218 if (cursor_cleared_p)
6219 x_update_window_cursor (w, 1);
6220 }
06a2c219 6221 }
82f053ab
GM
6222
6223 return mouse_face_overwritten_p;
06a2c219 6224}
dc6f92b8 6225
dc6f92b8 6226
06a2c219
GM
6227/* Determine the intersection of two rectangles R1 and R2. Return
6228 the intersection in *RESULT. Value is non-zero if RESULT is not
6229 empty. */
6230
6231static int
6232x_intersect_rectangles (r1, r2, result)
6233 XRectangle *r1, *r2, *result;
6234{
6235 XRectangle *left, *right;
6236 XRectangle *upper, *lower;
6237 int intersection_p = 0;
7d0393cf 6238
06a2c219
GM
6239 /* Rearrange so that R1 is the left-most rectangle. */
6240 if (r1->x < r2->x)
6241 left = r1, right = r2;
6242 else
6243 left = r2, right = r1;
6244
6245 /* X0 of the intersection is right.x0, if this is inside R1,
6246 otherwise there is no intersection. */
6247 if (right->x <= left->x + left->width)
6248 {
6249 result->x = right->x;
7d0393cf 6250
06a2c219
GM
6251 /* The right end of the intersection is the minimum of the
6252 the right ends of left and right. */
6253 result->width = (min (left->x + left->width, right->x + right->width)
6254 - result->x);
6255
6256 /* Same game for Y. */
6257 if (r1->y < r2->y)
6258 upper = r1, lower = r2;
6259 else
6260 upper = r2, lower = r1;
6261
6262 /* The upper end of the intersection is lower.y0, if this is inside
6263 of upper. Otherwise, there is no intersection. */
6264 if (lower->y <= upper->y + upper->height)
dc43ef94 6265 {
06a2c219 6266 result->y = lower->y;
7d0393cf 6267
06a2c219
GM
6268 /* The lower end of the intersection is the minimum of the lower
6269 ends of upper and lower. */
7d0393cf 6270 result->height = (min (lower->y + lower->height,
06a2c219
GM
6271 upper->y + upper->height)
6272 - result->y);
6273 intersection_p = 1;
dc43ef94 6274 }
dc6f92b8
JB
6275 }
6276
06a2c219 6277 return intersection_p;
dc6f92b8 6278}
06a2c219
GM
6279
6280
6281
6282
dc6f92b8 6283\f
dc6f92b8 6284static void
334208b7
RS
6285frame_highlight (f)
6286 struct frame *f;
dc6f92b8 6287{
b3e1e05c
JB
6288 /* We used to only do this if Vx_no_window_manager was non-nil, but
6289 the ICCCM (section 4.1.6) says that the window's border pixmap
6290 and border pixel are window attributes which are "private to the
6291 client", so we can always change it to whatever we want. */
6292 BLOCK_INPUT;
334208b7 6293 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6294 f->output_data.x->border_pixel);
b3e1e05c 6295 UNBLOCK_INPUT;
5d46f928 6296 x_update_cursor (f, 1);
dc6f92b8
JB
6297}
6298
6299static void
334208b7
RS
6300frame_unhighlight (f)
6301 struct frame *f;
dc6f92b8 6302{
b3e1e05c
JB
6303 /* We used to only do this if Vx_no_window_manager was non-nil, but
6304 the ICCCM (section 4.1.6) says that the window's border pixmap
6305 and border pixel are window attributes which are "private to the
6306 client", so we can always change it to whatever we want. */
6307 BLOCK_INPUT;
334208b7 6308 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6309 f->output_data.x->border_tile);
b3e1e05c 6310 UNBLOCK_INPUT;
5d46f928 6311 x_update_cursor (f, 1);
dc6f92b8 6312}
dc6f92b8 6313
f676886a
JB
6314/* The focus has changed. Update the frames as necessary to reflect
6315 the new situation. Note that we can't change the selected frame
c5acd733 6316 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 6317 Each event gets marked with the frame in which it occurred, so the
c5acd733 6318 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 6319
6d4238f3 6320static void
0f941935
KH
6321x_new_focus_frame (dpyinfo, frame)
6322 struct x_display_info *dpyinfo;
f676886a 6323 struct frame *frame;
dc6f92b8 6324{
0f941935 6325 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 6326
0f941935 6327 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 6328 {
58769bee 6329 /* Set this before calling other routines, so that they see
f676886a 6330 the correct value of x_focus_frame. */
0f941935 6331 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
6332
6333 if (old_focus && old_focus->auto_lower)
f676886a 6334 x_lower_frame (old_focus);
dc6f92b8
JB
6335
6336#if 0
f676886a 6337 selected_frame = frame;
e0c1aef2
KH
6338 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6339 selected_frame);
f676886a
JB
6340 Fselect_window (selected_frame->selected_window);
6341 choose_minibuf_frame ();
c118dd06 6342#endif /* ! 0 */
dc6f92b8 6343
0f941935
KH
6344 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6345 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
6346 else
6347 pending_autoraise_frame = 0;
6d4238f3 6348 }
dc6f92b8 6349
0f941935 6350 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
6351}
6352
cab34f50
JD
6353/* Handle FocusIn and FocusOut state changes for FRAME.
6354 If FRAME has focus and there exists more than one frame, puts
7d0393cf 6355 a FOCUS_IN_EVENT into BUFP.
cab34f50
JD
6356 Returns number of events inserted into BUFP. */
6357
6358static int
6359x_focus_changed (type, state, dpyinfo, frame, bufp, numchars)
6360 int type;
6361 int state;
6362 struct x_display_info *dpyinfo;
6363 struct frame *frame;
6364 struct input_event *bufp;
6365 int numchars;
6366{
6367 int nr_events = 0;
6368
6369 if (type == FocusIn)
6370 {
6371 if (dpyinfo->x_focus_event_frame != frame)
6372 {
6373 x_new_focus_frame (dpyinfo, frame);
6374 dpyinfo->x_focus_event_frame = frame;
7d0393cf 6375
cab34f50
JD
6376 /* Don't stop displaying the initial startup message
6377 for a switch-frame event we don't need. */
6378 if (numchars > 0
6379 && GC_NILP (Vterminal_frame)
6380 && GC_CONSP (Vframe_list)
6381 && !GC_NILP (XCDR (Vframe_list)))
6382 {
6383 bufp->kind = FOCUS_IN_EVENT;
6384 XSETFRAME (bufp->frame_or_window, frame);
6385 bufp->arg = Qnil;
6386 ++bufp;
6387 numchars--;
6388 ++nr_events;
6389 }
6390 }
6391
6392 frame->output_data.x->focus_state |= state;
6393
6394#ifdef HAVE_X_I18N
6395 if (FRAME_XIC (frame))
6396 XSetICFocus (FRAME_XIC (frame));
6397#endif
6398 }
6399 else if (type == FocusOut)
6400 {
6401 frame->output_data.x->focus_state &= ~state;
7d0393cf 6402
cab34f50
JD
6403 if (dpyinfo->x_focus_event_frame == frame)
6404 {
6405 dpyinfo->x_focus_event_frame = 0;
6406 x_new_focus_frame (dpyinfo, 0);
6407 }
6408
6409#ifdef HAVE_X_I18N
6410 if (FRAME_XIC (frame))
6411 XUnsetICFocus (FRAME_XIC (frame));
6412#endif
6413 }
6414
6415 return nr_events;
6416}
6417
6418/* The focus may have changed. Figure out if it is a real focus change,
6419 by checking both FocusIn/Out and Enter/LeaveNotify events.
6420
6421 Returns number of events inserted into BUFP. */
6422
6423static int
6424x_detect_focus_change (dpyinfo, event, bufp, numchars)
6425 struct x_display_info *dpyinfo;
6426 XEvent *event;
6427 struct input_event *bufp;
6428 int numchars;
6429{
6430 struct frame *frame;
6431 int nr_events = 0;
7d0393cf 6432
cab34f50
JD
6433 frame = x_top_window_to_frame (dpyinfo, event->xany.window);
6434 if (! frame) return nr_events;
7d0393cf 6435
cab34f50
JD
6436 switch (event->type)
6437 {
6438 case EnterNotify:
6439 case LeaveNotify:
6440 if (event->xcrossing.detail != NotifyInferior
6441 && event->xcrossing.focus
6442 && ! (frame->output_data.x->focus_state & FOCUS_EXPLICIT))
6443 nr_events = x_focus_changed ((event->type == EnterNotify
6444 ? FocusIn : FocusOut),
6445 FOCUS_IMPLICIT,
6446 dpyinfo,
6447 frame,
6448 bufp,
6449 numchars);
6450 break;
6451
6452 case FocusIn:
6453 case FocusOut:
6454 nr_events = x_focus_changed (event->type,
6455 (event->xfocus.detail == NotifyPointer
6456 ? FOCUS_IMPLICIT : FOCUS_EXPLICIT),
6457 dpyinfo,
6458 frame,
6459 bufp,
6460 numchars);
6461 break;
6462 }
6463
6464 return nr_events;
6465}
6466
6467
37c2c98b
RS
6468/* Handle an event saying the mouse has moved out of an Emacs frame. */
6469
6470void
0f941935
KH
6471x_mouse_leave (dpyinfo)
6472 struct x_display_info *dpyinfo;
37c2c98b 6473{
0f941935 6474 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 6475}
6d4238f3 6476
f451eb13
JB
6477/* The focus has changed, or we have redirected a frame's focus to
6478 another frame (this happens when a frame uses a surrogate
06a2c219 6479 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
6480
6481 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 6482 frame is being highlighted or un-highlighted; we only use it to find
0f941935 6483 the appropriate X display info. */
06a2c219 6484
6d4238f3 6485static void
0f941935
KH
6486XTframe_rehighlight (frame)
6487 struct frame *frame;
6d4238f3 6488{
0f941935
KH
6489 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6490}
6d4238f3 6491
0f941935
KH
6492static void
6493x_frame_rehighlight (dpyinfo)
6494 struct x_display_info *dpyinfo;
6495{
6496 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6497
6498 if (dpyinfo->x_focus_frame)
6d4238f3 6499 {
0f941935
KH
6500 dpyinfo->x_highlight_frame
6501 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6502 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6503 : dpyinfo->x_focus_frame);
6504 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 6505 {
0f941935
KH
6506 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6507 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 6508 }
dc6f92b8 6509 }
6d4238f3 6510 else
0f941935 6511 dpyinfo->x_highlight_frame = 0;
dc6f92b8 6512
0f941935 6513 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
6514 {
6515 if (old_highlight)
f676886a 6516 frame_unhighlight (old_highlight);
0f941935
KH
6517 if (dpyinfo->x_highlight_frame)
6518 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 6519 }
dc6f92b8 6520}
06a2c219
GM
6521
6522
dc6f92b8 6523\f
06a2c219 6524/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 6525
28430d3c
JB
6526/* Initialize mode_switch_bit and modifier_meaning. */
6527static void
334208b7
RS
6528x_find_modifier_meanings (dpyinfo)
6529 struct x_display_info *dpyinfo;
28430d3c 6530{
f689eb05 6531 int min_code, max_code;
28430d3c
JB
6532 KeySym *syms;
6533 int syms_per_code;
6534 XModifierKeymap *mods;
6535
334208b7
RS
6536 dpyinfo->meta_mod_mask = 0;
6537 dpyinfo->shift_lock_mask = 0;
6538 dpyinfo->alt_mod_mask = 0;
6539 dpyinfo->super_mod_mask = 0;
6540 dpyinfo->hyper_mod_mask = 0;
58769bee 6541
9658a521 6542#ifdef HAVE_X11R4
334208b7 6543 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 6544#else
4a60f8c5
RS
6545 min_code = dpyinfo->display->min_keycode;
6546 max_code = dpyinfo->display->max_keycode;
9658a521
JB
6547#endif
6548
334208b7 6549 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
6550 min_code, max_code - min_code + 1,
6551 &syms_per_code);
334208b7 6552 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 6553
58769bee 6554 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 6555 Alt keysyms are on. */
28430d3c 6556 {
06a2c219 6557 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
6558
6559 for (row = 3; row < 8; row++)
6560 for (col = 0; col < mods->max_keypermod; col++)
6561 {
0299d313
RS
6562 KeyCode code
6563 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 6564
af92970c
KH
6565 /* Zeroes are used for filler. Skip them. */
6566 if (code == 0)
6567 continue;
6568
28430d3c
JB
6569 /* Are any of this keycode's keysyms a meta key? */
6570 {
6571 int code_col;
6572
6573 for (code_col = 0; code_col < syms_per_code; code_col++)
6574 {
f689eb05 6575 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 6576
f689eb05 6577 switch (sym)
28430d3c 6578 {
f689eb05
JB
6579 case XK_Meta_L:
6580 case XK_Meta_R:
334208b7 6581 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 6582 break;
f689eb05
JB
6583
6584 case XK_Alt_L:
6585 case XK_Alt_R:
334208b7 6586 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
6587 break;
6588
6589 case XK_Hyper_L:
6590 case XK_Hyper_R:
334208b7 6591 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
6592 break;
6593
6594 case XK_Super_L:
6595 case XK_Super_R:
334208b7 6596 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 6597 break;
11edeb03
JB
6598
6599 case XK_Shift_Lock:
6600 /* Ignore this if it's not on the lock modifier. */
6601 if ((1 << row) == LockMask)
334208b7 6602 dpyinfo->shift_lock_mask = LockMask;
11edeb03 6603 break;
28430d3c
JB
6604 }
6605 }
6606 }
6607 }
6608 }
6609
f689eb05 6610 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 6611 if (! dpyinfo->meta_mod_mask)
a3c44b14 6612 {
334208b7
RS
6613 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6614 dpyinfo->alt_mod_mask = 0;
a3c44b14 6615 }
f689eb05 6616
148c4b70
RS
6617 /* If some keys are both alt and meta,
6618 make them just meta, not alt. */
334208b7 6619 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 6620 {
334208b7 6621 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 6622 }
58769bee 6623
28430d3c 6624 XFree ((char *) syms);
f689eb05 6625 XFreeModifiermap (mods);
28430d3c
JB
6626}
6627
dfeccd2d
JB
6628/* Convert between the modifier bits X uses and the modifier bits
6629 Emacs uses. */
06a2c219 6630
7c5283e4 6631static unsigned int
334208b7
RS
6632x_x_to_emacs_modifiers (dpyinfo, state)
6633 struct x_display_info *dpyinfo;
dc6f92b8
JB
6634 unsigned int state;
6635{
98659da6
KG
6636 EMACS_UINT mod_meta = meta_modifier;
6637 EMACS_UINT mod_alt = alt_modifier;
6638 EMACS_UINT mod_hyper = hyper_modifier;
6639 EMACS_UINT mod_super = super_modifier;
6640 Lisp_Object tem;
7d0393cf 6641
98659da6
KG
6642 tem = Fget (Vx_alt_keysym, Qmodifier_value);
6643 if (! EQ (tem, Qnil)) mod_alt = XUINT (tem);
6644 tem = Fget (Vx_meta_keysym, Qmodifier_value);
6645 if (! EQ (tem, Qnil)) mod_meta = XUINT (tem);
6646 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
6647 if (! EQ (tem, Qnil)) mod_hyper = XUINT (tem);
6648 tem = Fget (Vx_super_keysym, Qmodifier_value);
6649 if (! EQ (tem, Qnil)) mod_super = XUINT (tem);
7d0393cf 6650
98659da6 6651
334208b7 6652 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
98659da6
KG
6653 | ((state & ControlMask) ? ctrl_modifier : 0)
6654 | ((state & dpyinfo->meta_mod_mask) ? mod_meta : 0)
6655 | ((state & dpyinfo->alt_mod_mask) ? mod_alt : 0)
6656 | ((state & dpyinfo->super_mod_mask) ? mod_super : 0)
6657 | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0));
dc6f92b8
JB
6658}
6659
dfeccd2d 6660static unsigned int
334208b7
RS
6661x_emacs_to_x_modifiers (dpyinfo, state)
6662 struct x_display_info *dpyinfo;
dfeccd2d
JB
6663 unsigned int state;
6664{
98659da6
KG
6665 EMACS_UINT mod_meta = meta_modifier;
6666 EMACS_UINT mod_alt = alt_modifier;
6667 EMACS_UINT mod_hyper = hyper_modifier;
6668 EMACS_UINT mod_super = super_modifier;
7d0393cf 6669
98659da6 6670 Lisp_Object tem;
7d0393cf 6671
98659da6
KG
6672 tem = Fget (Vx_alt_keysym, Qmodifier_value);
6673 if (! EQ (tem, Qnil)) mod_alt = XUINT (tem);
6674 tem = Fget (Vx_meta_keysym, Qmodifier_value);
6675 if (! EQ (tem, Qnil)) mod_meta = XUINT (tem);
6676 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
6677 if (! EQ (tem, Qnil)) mod_hyper = XUINT (tem);
6678 tem = Fget (Vx_super_keysym, Qmodifier_value);
6679 if (! EQ (tem, Qnil)) mod_super = XUINT (tem);
7d0393cf
JB
6680
6681
98659da6
KG
6682 return ( ((state & mod_alt) ? dpyinfo->alt_mod_mask : 0)
6683 | ((state & mod_super) ? dpyinfo->super_mod_mask : 0)
6684 | ((state & mod_hyper) ? dpyinfo->hyper_mod_mask : 0)
6685 | ((state & shift_modifier) ? ShiftMask : 0)
6686 | ((state & ctrl_modifier) ? ControlMask : 0)
6687 | ((state & mod_meta) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6688}
d047c4eb
KH
6689
6690/* Convert a keysym to its name. */
6691
6692char *
6693x_get_keysym_name (keysym)
6694 KeySym keysym;
6695{
6696 char *value;
6697
6698 BLOCK_INPUT;
6699 value = XKeysymToString (keysym);
6700 UNBLOCK_INPUT;
6701
6702 return value;
6703}
06a2c219
GM
6704
6705
e4571a43
JB
6706\f
6707/* Mouse clicks and mouse movement. Rah. */
e4571a43 6708
06a2c219
GM
6709/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6710 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6711 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6712 not force the value into range. */
69388238 6713
c8dba240 6714void
69388238 6715pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6716 FRAME_PTR f;
69388238 6717 register int pix_x, pix_y;
e4571a43
JB
6718 register int *x, *y;
6719 XRectangle *bounds;
69388238 6720 int noclip;
e4571a43 6721{
06a2c219 6722 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6723 even for negative values. */
6724 if (pix_x < 0)
7556890b 6725 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6726 if (pix_y < 0)
7556890b 6727 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6728
e4571a43
JB
6729 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6730 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6731
6732 if (bounds)
6733 {
7556890b
RS
6734 bounds->width = FONT_WIDTH (f->output_data.x->font);
6735 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6736 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6737 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6738 }
6739
69388238
RS
6740 if (!noclip)
6741 {
6742 if (pix_x < 0)
6743 pix_x = 0;
3cbd2e0b
RS
6744 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6745 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6746
6747 if (pix_y < 0)
6748 pix_y = 0;
6749 else if (pix_y > f->height)
6750 pix_y = f->height;
6751 }
e4571a43
JB
6752
6753 *x = pix_x;
6754 *y = pix_y;
6755}
6756
06a2c219
GM
6757
6758/* Given HPOS/VPOS in the current matrix of W, return corresponding
6759 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6760 can't tell the positions because W's display is not up to date,
6761 return 0. */
6762
6763int
6764glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6765 struct window *w;
6766 int hpos, vpos;
6767 int *frame_x, *frame_y;
2b5c9e71 6768{
06a2c219
GM
6769 int success_p;
6770
6771 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6772 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6773
6774 if (display_completed)
6775 {
6776 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6777 struct glyph *glyph = row->glyphs[TEXT_AREA];
6778 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6779
6780 *frame_y = row->y;
6781 *frame_x = row->x;
6782 while (glyph < end)
6783 {
6784 *frame_x += glyph->pixel_width;
6785 ++glyph;
6786 }
6787
6788 success_p = 1;
6789 }
6790 else
6791 {
6792 *frame_y = *frame_x = 0;
6793 success_p = 0;
6794 }
6795
6796 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6797 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6798 return success_p;
2b5c9e71
RS
6799}
6800
06a2c219 6801
dc6f92b8
JB
6802/* Prepare a mouse-event in *RESULT for placement in the input queue.
6803
6804 If the event is a button press, then note that we have grabbed
f451eb13 6805 the mouse. */
dc6f92b8
JB
6806
6807static Lisp_Object
f451eb13 6808construct_mouse_click (result, event, f)
dc6f92b8
JB
6809 struct input_event *result;
6810 XButtonEvent *event;
f676886a 6811 struct frame *f;
dc6f92b8 6812{
3b8f9651 6813 /* Make the event type NO_EVENT; we'll change that when we decide
dc6f92b8 6814 otherwise. */
3b8f9651 6815 result->kind = MOUSE_CLICK_EVENT;
69388238 6816 result->code = event->button - Button1;
1113d9db 6817 result->timestamp = event->time;
334208b7
RS
6818 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6819 event->state)
f689eb05 6820 | (event->type == ButtonRelease
58769bee 6821 ? up_modifier
f689eb05 6822 : down_modifier));
dc6f92b8 6823
06a2c219
GM
6824 XSETINT (result->x, event->x);
6825 XSETINT (result->y, event->y);
6826 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6827 result->arg = Qnil;
06a2c219 6828 return Qnil;
dc6f92b8 6829}
b849c413 6830
69388238 6831\f
90e65f07
JB
6832/* Function to report a mouse movement to the mainstream Emacs code.
6833 The input handler calls this.
6834
6835 We have received a mouse movement event, which is given in *event.
6836 If the mouse is over a different glyph than it was last time, tell
6837 the mainstream emacs code by setting mouse_moved. If not, ask for
6838 another motion event, so we can check again the next time it moves. */
b8009dd1 6839
06a2c219
GM
6840static XMotionEvent last_mouse_motion_event;
6841static Lisp_Object last_mouse_motion_frame;
6842
90e65f07 6843static void
12ba150f 6844note_mouse_movement (frame, event)
f676886a 6845 FRAME_PTR frame;
90e65f07 6846 XMotionEvent *event;
90e65f07 6847{
e5d77022 6848 last_mouse_movement_time = event->time;
06a2c219
GM
6849 last_mouse_motion_event = *event;
6850 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6851
27f338af
RS
6852 if (event->window != FRAME_X_WINDOW (frame))
6853 {
39d8bb4d 6854 frame->mouse_moved = 1;
27f338af 6855 last_mouse_scroll_bar = Qnil;
27f338af 6856 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6857 }
6858
90e65f07 6859 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6860 else if (event->x < last_mouse_glyph.x
6861 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6862 || event->y < last_mouse_glyph.y
6863 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6864 {
39d8bb4d 6865 frame->mouse_moved = 1;
ab648270 6866 last_mouse_scroll_bar = Qnil;
b8009dd1 6867 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6868 }
6869}
6870
06a2c219
GM
6871\f
6872/************************************************************************
6873 Mouse Face
6874 ************************************************************************/
6875
6876/* Find the glyph under window-relative coordinates X/Y in window W.
6877 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6878 strings. Return in *HPOS and *VPOS the row and column number of
6879 the glyph found. Return in *AREA the glyph area containing X.
6880 Value is a pointer to the glyph found or null if X/Y is not on
6881 text, or we can't tell because W's current matrix is not up to
6882 date. */
6883
6884static struct glyph *
f9db2310 6885x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
06a2c219
GM
6886 struct window *w;
6887 int x, y;
6888 int *hpos, *vpos, *area;
f9db2310 6889 int buffer_only_p;
06a2c219
GM
6890{
6891 struct glyph *glyph, *end;
3e71d8f2 6892 struct glyph_row *row = NULL;
06a2c219
GM
6893 int x0, i, left_area_width;
6894
6895 /* Find row containing Y. Give up if some row is not enabled. */
6896 for (i = 0; i < w->current_matrix->nrows; ++i)
6897 {
6898 row = MATRIX_ROW (w->current_matrix, i);
6899 if (!row->enabled_p)
6900 return NULL;
6901 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6902 break;
6903 }
6904
6905 *vpos = i;
6906 *hpos = 0;
6907
6908 /* Give up if Y is not in the window. */
6909 if (i == w->current_matrix->nrows)
6910 return NULL;
6911
6912 /* Get the glyph area containing X. */
6913 if (w->pseudo_window_p)
6914 {
6915 *area = TEXT_AREA;
6916 x0 = 0;
6917 }
6918 else
6919 {
6920 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6921 if (x < left_area_width)
6922 {
6923 *area = LEFT_MARGIN_AREA;
6924 x0 = 0;
6925 }
6926 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6927 {
6928 *area = TEXT_AREA;
6929 x0 = row->x + left_area_width;
6930 }
6931 else
6932 {
6933 *area = RIGHT_MARGIN_AREA;
6934 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6935 }
6936 }
6937
6938 /* Find glyph containing X. */
6939 glyph = row->glyphs[*area];
6940 end = glyph + row->used[*area];
6941 while (glyph < end)
6942 {
6943 if (x < x0 + glyph->pixel_width)
6944 {
6945 if (w->pseudo_window_p)
6946 break;
f9db2310 6947 else if (!buffer_only_p || BUFFERP (glyph->object))
06a2c219
GM
6948 break;
6949 }
7d0393cf 6950
06a2c219
GM
6951 x0 += glyph->pixel_width;
6952 ++glyph;
6953 }
6954
6955 if (glyph == end)
6956 return NULL;
6957
6958 *hpos = glyph - row->glyphs[*area];
6959 return glyph;
6960}
6961
6962
6963/* Convert frame-relative x/y to coordinates relative to window W.
6964 Takes pseudo-windows into account. */
6965
6966static void
6967frame_to_window_pixel_xy (w, x, y)
6968 struct window *w;
6969 int *x, *y;
6970{
6971 if (w->pseudo_window_p)
6972 {
6973 /* A pseudo-window is always full-width, and starts at the
6974 left edge of the frame, plus a frame border. */
6975 struct frame *f = XFRAME (w->frame);
6976 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6977 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6978 }
6979 else
6980 {
6981 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6982 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6983 }
6984}
6985
6986
b436feb6
GM
6987/* Take proper action when mouse has moved to the mode or header line
6988 or marginal area of window W, x-position X and y-position Y. Area
6989 is 1, 3, 6 or 7 for the mode line, header line, left and right
6990 marginal area respectively. X is relative to the start of the text
6991 display area of W, so the width of bitmap areas and scroll bars
6992 must be subtracted to get a position relative to the start of the
6993 mode line. */
7d0393cf 6994
06a2c219 6995static void
b436feb6 6996note_mode_line_or_margin_highlight (w, x, y, portion)
06a2c219 6997 struct window *w;
b436feb6 6998 int x, y, portion;
06a2c219
GM
6999{
7000 struct frame *f = XFRAME (w->frame);
7001 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7002 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
2a793c0c 7003 int charpos;
b436feb6 7004 Lisp_Object string, help, map, pos;
06a2c219 7005
b436feb6
GM
7006 if (portion == 1 || portion == 3)
7007 string = mode_line_string (w, x, y, portion == 1, &charpos);
7008 else
7009 string = marginal_area_string (w, x, y, portion, &charpos);
e371a781 7010
b436feb6 7011 if (STRINGP (string))
06a2c219 7012 {
b436feb6 7013 pos = make_number (charpos);
7d0393cf 7014
b436feb6
GM
7015 /* If we're on a string with `help-echo' text property, arrange
7016 for the help to be displayed. This is done by setting the
7017 global variable help_echo to the help string. */
7018 help = Fget_text_property (pos, Qhelp_echo, string);
7019 if (!NILP (help))
06a2c219 7020 {
b436feb6
GM
7021 help_echo = help;
7022 XSETWINDOW (help_echo_window, w);
7023 help_echo_object = string;
7024 help_echo_pos = charpos;
06a2c219
GM
7025 }
7026
b436feb6
GM
7027 /* Change the mouse pointer according to what is under X/Y. */
7028 map = Fget_text_property (pos, Qlocal_map, string);
7029 if (!KEYMAPP (map))
7030 map = Fget_text_property (pos, Qkeymap, string);
7031 if (KEYMAPP (map))
7032 cursor = f->output_data.x->nontext_cursor;
06a2c219 7033 }
7d0393cf 7034
06a2c219
GM
7035 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
7036}
7037
7038
7039/* Take proper action when the mouse has moved to position X, Y on
7040 frame F as regards highlighting characters that have mouse-face
7041 properties. Also de-highlighting chars where the mouse was before.
27f338af 7042 X and Y can be negative or out of range. */
b8009dd1
RS
7043
7044static void
7045note_mouse_highlight (f, x, y)
06a2c219 7046 struct frame *f;
c32cdd9a 7047 int x, y;
b8009dd1 7048{
06a2c219
GM
7049 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7050 int portion;
b8009dd1
RS
7051 Lisp_Object window;
7052 struct window *w;
0d487c52
GM
7053 Cursor cursor = None;
7054 struct buffer *b;
b8009dd1 7055
06a2c219
GM
7056 /* When a menu is active, don't highlight because this looks odd. */
7057#ifdef USE_X_TOOLKIT
7058 if (popup_activated ())
7059 return;
7060#endif
7061
66301061 7062 if (NILP (Vmouse_highlight)
04fff9c0 7063 || !f->glyphs_initialized_p)
bf1c0ba1
RS
7064 return;
7065
06a2c219
GM
7066 dpyinfo->mouse_face_mouse_x = x;
7067 dpyinfo->mouse_face_mouse_y = y;
7068 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 7069
06a2c219 7070 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
7071 return;
7072
514e4681
RS
7073 if (gc_in_progress)
7074 {
06a2c219 7075 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
7076 return;
7077 }
7078
b8009dd1 7079 /* Which window is that in? */
06a2c219 7080 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
7081
7082 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
7083 if (! EQ (window, dpyinfo->mouse_face_window))
7084 clear_mouse_face (dpyinfo);
7085
7086 /* Not on a window -> return. */
7087 if (!WINDOWP (window))
7088 return;
7089
7090 /* Convert to window-relative pixel coordinates. */
7091 w = XWINDOW (window);
7092 frame_to_window_pixel_xy (w, &x, &y);
7093
9ea173e8 7094 /* Handle tool-bar window differently since it doesn't display a
06a2c219 7095 buffer. */
9ea173e8 7096 if (EQ (window, f->tool_bar_window))
06a2c219 7097 {
9ea173e8 7098 note_tool_bar_highlight (f, x, y);
06a2c219
GM
7099 return;
7100 }
7101
b436feb6
GM
7102 /* Mouse is on the mode, header line or margin? */
7103 if (portion == 1 || portion == 3 || portion == 6 || portion == 7)
06a2c219 7104 {
b436feb6 7105 note_mode_line_or_margin_highlight (w, x, y, portion);
06a2c219
GM
7106 return;
7107 }
7d0393cf 7108
0d487c52
GM
7109 if (portion == 2)
7110 cursor = f->output_data.x->horizontal_drag_cursor;
06a2c219 7111 else
0d487c52 7112 cursor = f->output_data.x->text_cursor;
b8009dd1 7113
0cdd0c9f
RS
7114 /* Are we in a window whose display is up to date?
7115 And verify the buffer's text has not changed. */
0d487c52 7116 b = XBUFFER (w->buffer);
06a2c219
GM
7117 if (/* Within text portion of the window. */
7118 portion == 0
0cdd0c9f 7119 && EQ (w->window_end_valid, w->buffer)
0d487c52
GM
7120 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
7121 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
b8009dd1 7122 {
06a2c219
GM
7123 int hpos, vpos, pos, i, area;
7124 struct glyph *glyph;
f9db2310 7125 Lisp_Object object;
0d487c52
GM
7126 Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
7127 Lisp_Object *overlay_vec = NULL;
7128 int len, noverlays;
7129 struct buffer *obuf;
7130 int obegv, ozv, same_region;
b8009dd1 7131
06a2c219 7132 /* Find the glyph under X/Y. */
f9db2310 7133 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
06a2c219
GM
7134
7135 /* Clear mouse face if X/Y not over text. */
7136 if (glyph == NULL
7137 || area != TEXT_AREA
7138 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 7139 {
fa262c07
GM
7140 if (clear_mouse_face (dpyinfo))
7141 cursor = None;
7142 goto set_cursor;
06a2c219
GM
7143 }
7144
7145 pos = glyph->charpos;
f9db2310
GM
7146 object = glyph->object;
7147 if (!STRINGP (object) && !BUFFERP (object))
fa262c07 7148 goto set_cursor;
06a2c219 7149
0d487c52
GM
7150 /* If we get an out-of-range value, return now; avoid an error. */
7151 if (BUFFERP (object) && pos > BUF_Z (b))
fa262c07 7152 goto set_cursor;
06a2c219 7153
0d487c52
GM
7154 /* Make the window's buffer temporarily current for
7155 overlays_at and compute_char_face. */
7156 obuf = current_buffer;
7157 current_buffer = b;
7158 obegv = BEGV;
7159 ozv = ZV;
7160 BEGV = BEG;
7161 ZV = Z;
06a2c219 7162
0d487c52
GM
7163 /* Is this char mouse-active or does it have help-echo? */
7164 position = make_number (pos);
f9db2310 7165
0d487c52
GM
7166 if (BUFFERP (object))
7167 {
7168 /* Put all the overlays we want in a vector in overlay_vec.
7169 Store the length in len. If there are more than 10, make
7170 enough space for all, and try again. */
7171 len = 10;
7172 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
7173 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
7174 if (noverlays > len)
7175 {
7176 len = noverlays;
7177 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
7178 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
7179 }
f8349001 7180
0d487c52
GM
7181 /* Sort overlays into increasing priority order. */
7182 noverlays = sort_overlays (overlay_vec, noverlays, w);
7183 }
7184 else
7185 noverlays = 0;
7186
7187 same_region = (EQ (window, dpyinfo->mouse_face_window)
7188 && vpos >= dpyinfo->mouse_face_beg_row
7189 && vpos <= dpyinfo->mouse_face_end_row
7190 && (vpos > dpyinfo->mouse_face_beg_row
7191 || hpos >= dpyinfo->mouse_face_beg_col)
7192 && (vpos < dpyinfo->mouse_face_end_row
7193 || hpos < dpyinfo->mouse_face_end_col
7194 || dpyinfo->mouse_face_past_end));
7195
7196 if (same_region)
7197 cursor = None;
7198
7199 /* Check mouse-face highlighting. */
7200 if (! same_region
7201 /* If there exists an overlay with mouse-face overlapping
7202 the one we are currently highlighting, we have to
7203 check if we enter the overlapping overlay, and then
7204 highlight only that. */
7205 || (OVERLAYP (dpyinfo->mouse_face_overlay)
7206 && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
7207 {
0d487c52
GM
7208 /* Find the highest priority overlay that has a mouse-face
7209 property. */
7210 overlay = Qnil;
7211 for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
7212 {
7213 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
7214 if (!NILP (mouse_face))
7215 overlay = overlay_vec[i];
7216 }
7d0393cf 7217
8bd189fb
GM
7218 /* If we're actually highlighting the same overlay as
7219 before, there's no need to do that again. */
7220 if (!NILP (overlay)
7221 && EQ (overlay, dpyinfo->mouse_face_overlay))
7222 goto check_help_echo;
7d0393cf 7223
8bd189fb
GM
7224 dpyinfo->mouse_face_overlay = overlay;
7225
7226 /* Clear the display of the old active region, if any. */
7227 if (clear_mouse_face (dpyinfo))
7228 cursor = None;
7229
0d487c52
GM
7230 /* If no overlay applies, get a text property. */
7231 if (NILP (overlay))
7232 mouse_face = Fget_text_property (position, Qmouse_face, object);
06a2c219 7233
0d487c52
GM
7234 /* Handle the overlay case. */
7235 if (!NILP (overlay))
7236 {
7237 /* Find the range of text around this char that
7238 should be active. */
7239 Lisp_Object before, after;
7240 int ignore;
7241
7242 before = Foverlay_start (overlay);
7243 after = Foverlay_end (overlay);
7244 /* Record this as the current active region. */
7245 fast_find_position (w, XFASTINT (before),
7246 &dpyinfo->mouse_face_beg_col,
7247 &dpyinfo->mouse_face_beg_row,
7248 &dpyinfo->mouse_face_beg_x,
7e376260 7249 &dpyinfo->mouse_face_beg_y, Qnil);
7d0393cf 7250
0d487c52
GM
7251 dpyinfo->mouse_face_past_end
7252 = !fast_find_position (w, XFASTINT (after),
7253 &dpyinfo->mouse_face_end_col,
7254 &dpyinfo->mouse_face_end_row,
7255 &dpyinfo->mouse_face_end_x,
7e376260 7256 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7257 dpyinfo->mouse_face_window = window;
7258 dpyinfo->mouse_face_face_id
7259 = face_at_buffer_position (w, pos, 0, 0,
7260 &ignore, pos + 1, 1);
7261
7262 /* Display it as active. */
7263 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7264 cursor = None;
0d487c52
GM
7265 }
7266 /* Handle the text property case. */
7267 else if (!NILP (mouse_face) && BUFFERP (object))
7268 {
7269 /* Find the range of text around this char that
7270 should be active. */
7271 Lisp_Object before, after, beginning, end;
7272 int ignore;
7273
7274 beginning = Fmarker_position (w->start);
7275 end = make_number (BUF_Z (XBUFFER (object))
7276 - XFASTINT (w->window_end_pos));
7277 before
7278 = Fprevious_single_property_change (make_number (pos + 1),
7279 Qmouse_face,
7280 object, beginning);
7281 after
7282 = Fnext_single_property_change (position, Qmouse_face,
7283 object, end);
7d0393cf 7284
0d487c52
GM
7285 /* Record this as the current active region. */
7286 fast_find_position (w, XFASTINT (before),
7287 &dpyinfo->mouse_face_beg_col,
7288 &dpyinfo->mouse_face_beg_row,
7289 &dpyinfo->mouse_face_beg_x,
7e376260 7290 &dpyinfo->mouse_face_beg_y, Qnil);
0d487c52
GM
7291 dpyinfo->mouse_face_past_end
7292 = !fast_find_position (w, XFASTINT (after),
7293 &dpyinfo->mouse_face_end_col,
7294 &dpyinfo->mouse_face_end_row,
7295 &dpyinfo->mouse_face_end_x,
7e376260 7296 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7297 dpyinfo->mouse_face_window = window;
7298
7299 if (BUFFERP (object))
06a2c219
GM
7300 dpyinfo->mouse_face_face_id
7301 = face_at_buffer_position (w, pos, 0, 0,
7302 &ignore, pos + 1, 1);
7303
0d487c52
GM
7304 /* Display it as active. */
7305 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7306 cursor = None;
0d487c52
GM
7307 }
7308 else if (!NILP (mouse_face) && STRINGP (object))
7309 {
7310 Lisp_Object b, e;
7311 int ignore;
7d0393cf 7312
0d487c52
GM
7313 b = Fprevious_single_property_change (make_number (pos + 1),
7314 Qmouse_face,
7315 object, Qnil);
7316 e = Fnext_single_property_change (position, Qmouse_face,
7317 object, Qnil);
7318 if (NILP (b))
7319 b = make_number (0);
7320 if (NILP (e))
d5db4077 7321 e = make_number (SCHARS (object) - 1);
0d487c52 7322 fast_find_string_pos (w, XINT (b), object,
06a2c219
GM
7323 &dpyinfo->mouse_face_beg_col,
7324 &dpyinfo->mouse_face_beg_row,
7325 &dpyinfo->mouse_face_beg_x,
0d487c52
GM
7326 &dpyinfo->mouse_face_beg_y, 0);
7327 fast_find_string_pos (w, XINT (e), object,
7328 &dpyinfo->mouse_face_end_col,
7329 &dpyinfo->mouse_face_end_row,
7330 &dpyinfo->mouse_face_end_x,
7331 &dpyinfo->mouse_face_end_y, 1);
7332 dpyinfo->mouse_face_past_end = 0;
7333 dpyinfo->mouse_face_window = window;
7334 dpyinfo->mouse_face_face_id
7335 = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
7336 glyph->face_id, 1);
7337 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7338 cursor = None;
0d487c52 7339 }
7e376260
GM
7340 else if (STRINGP (object) && NILP (mouse_face))
7341 {
7342 /* A string which doesn't have mouse-face, but
7343 the text ``under'' it might have. */
7344 struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
7345 int start = MATRIX_ROW_START_CHARPOS (r);
7d0393cf 7346
7e376260
GM
7347 pos = string_buffer_position (w, object, start);
7348 if (pos > 0)
7349 mouse_face = get_char_property_and_overlay (make_number (pos),
7350 Qmouse_face,
7351 w->buffer,
7352 &overlay);
7353 if (!NILP (mouse_face) && !NILP (overlay))
7354 {
7355 Lisp_Object before = Foverlay_start (overlay);
7356 Lisp_Object after = Foverlay_end (overlay);
91c153e2 7357 int ignore;
7e376260
GM
7358
7359 /* Note that we might not be able to find position
7360 BEFORE in the glyph matrix if the overlay is
7361 entirely covered by a `display' property. In
7362 this case, we overshoot. So let's stop in
7363 the glyph matrix before glyphs for OBJECT. */
7364 fast_find_position (w, XFASTINT (before),
7365 &dpyinfo->mouse_face_beg_col,
7366 &dpyinfo->mouse_face_beg_row,
7367 &dpyinfo->mouse_face_beg_x,
7368 &dpyinfo->mouse_face_beg_y,
7369 object);
7d0393cf 7370
7e376260
GM
7371 dpyinfo->mouse_face_past_end
7372 = !fast_find_position (w, XFASTINT (after),
7373 &dpyinfo->mouse_face_end_col,
7374 &dpyinfo->mouse_face_end_row,
7375 &dpyinfo->mouse_face_end_x,
7376 &dpyinfo->mouse_face_end_y,
7377 Qnil);
7378 dpyinfo->mouse_face_window = window;
7379 dpyinfo->mouse_face_face_id
7380 = face_at_buffer_position (w, pos, 0, 0,
7381 &ignore, pos + 1, 1);
7382
7383 /* Display it as active. */
7384 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
7385 cursor = None;
7386 }
7387 }
0d487c52 7388 }
06a2c219 7389
8bd189fb
GM
7390 check_help_echo:
7391
0d487c52
GM
7392 /* Look for a `help-echo' property. */
7393 {
7394 Lisp_Object help, overlay;
06a2c219 7395
0d487c52
GM
7396 /* Check overlays first. */
7397 help = overlay = Qnil;
7398 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
7399 {
7400 overlay = overlay_vec[i];
7401 help = Foverlay_get (overlay, Qhelp_echo);
7402 }
be010514 7403
0d487c52
GM
7404 if (!NILP (help))
7405 {
7406 help_echo = help;
7407 help_echo_window = window;
7408 help_echo_object = overlay;
7409 help_echo_pos = pos;
7410 }
7411 else
7412 {
7413 Lisp_Object object = glyph->object;
7414 int charpos = glyph->charpos;
7d0393cf 7415
0d487c52
GM
7416 /* Try text properties. */
7417 if (STRINGP (object)
7418 && charpos >= 0
d5db4077 7419 && charpos < SCHARS (object))
0d487c52
GM
7420 {
7421 help = Fget_text_property (make_number (charpos),
7422 Qhelp_echo, object);
7423 if (NILP (help))
7424 {
7425 /* If the string itself doesn't specify a help-echo,
7426 see if the buffer text ``under'' it does. */
7427 struct glyph_row *r
7428 = MATRIX_ROW (w->current_matrix, vpos);
7429 int start = MATRIX_ROW_START_CHARPOS (r);
7430 int pos = string_buffer_position (w, object, start);
7431 if (pos > 0)
7432 {
7e376260 7433 help = Fget_char_property (make_number (pos),
0d487c52
GM
7434 Qhelp_echo, w->buffer);
7435 if (!NILP (help))
7436 {
7437 charpos = pos;
7438 object = w->buffer;
7439 }
7440 }
7441 }
7442 }
7443 else if (BUFFERP (object)
7444 && charpos >= BEGV
7445 && charpos < ZV)
7446 help = Fget_text_property (make_number (charpos), Qhelp_echo,
7447 object);
7d0393cf 7448
0d487c52
GM
7449 if (!NILP (help))
7450 {
7451 help_echo = help;
7452 help_echo_window = window;
7453 help_echo_object = object;
7454 help_echo_pos = charpos;
7455 }
7456 }
06a2c219 7457 }
7d0393cf 7458
0d487c52
GM
7459 BEGV = obegv;
7460 ZV = ozv;
7461 current_buffer = obuf;
06a2c219 7462 }
0d487c52 7463
fa262c07 7464 set_cursor:
7d0393cf 7465
0d487c52
GM
7466 if (cursor != None)
7467 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
06a2c219
GM
7468}
7469
7470static void
7471redo_mouse_highlight ()
7472{
7473 if (!NILP (last_mouse_motion_frame)
7474 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
7475 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
7476 last_mouse_motion_event.x,
7477 last_mouse_motion_event.y);
7478}
7479
7480
7481\f
7482/***********************************************************************
9ea173e8 7483 Tool-bars
06a2c219
GM
7484 ***********************************************************************/
7485
9ea173e8
GM
7486static int x_tool_bar_item P_ ((struct frame *, int, int,
7487 struct glyph **, int *, int *, int *));
06a2c219 7488
9ea173e8 7489/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
7490 or -1. */
7491
9ea173e8 7492static int last_tool_bar_item;
06a2c219
GM
7493
7494
9ea173e8
GM
7495/* Get information about the tool-bar item at position X/Y on frame F.
7496 Return in *GLYPH a pointer to the glyph of the tool-bar item in
7497 the current matrix of the tool-bar window of F, or NULL if not
7498 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
8daf1204 7499 item in F->tool_bar_items. Value is
06a2c219 7500
9ea173e8 7501 -1 if X/Y is not on a tool-bar item
06a2c219
GM
7502 0 if X/Y is on the same item that was highlighted before.
7503 1 otherwise. */
7504
7505static int
9ea173e8 7506x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
7507 struct frame *f;
7508 int x, y;
7509 struct glyph **glyph;
7510 int *hpos, *vpos, *prop_idx;
7511{
7512 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7513 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7514 int area;
7515
7516 /* Find the glyph under X/Y. */
f9db2310 7517 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
06a2c219
GM
7518 if (*glyph == NULL)
7519 return -1;
7520
9ea173e8 7521 /* Get the start of this tool-bar item's properties in
8daf1204 7522 f->tool_bar_items. */
9ea173e8 7523 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
7524 return -1;
7525
7526 /* Is mouse on the highlighted item? */
9ea173e8 7527 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
7528 && *vpos >= dpyinfo->mouse_face_beg_row
7529 && *vpos <= dpyinfo->mouse_face_end_row
7530 && (*vpos > dpyinfo->mouse_face_beg_row
7531 || *hpos >= dpyinfo->mouse_face_beg_col)
7532 && (*vpos < dpyinfo->mouse_face_end_row
7533 || *hpos < dpyinfo->mouse_face_end_col
7534 || dpyinfo->mouse_face_past_end))
7535 return 0;
7d0393cf 7536
06a2c219
GM
7537 return 1;
7538}
7539
7540
9ea173e8 7541/* Handle mouse button event on the tool-bar of frame F, at
6c4a22e6 7542 frame-relative coordinates X/Y. EVENT_TYPE is either ButtonPress
06a2c219
GM
7543 or ButtonRelase. */
7544
7545static void
9ea173e8 7546x_handle_tool_bar_click (f, button_event)
06a2c219
GM
7547 struct frame *f;
7548 XButtonEvent *button_event;
7549{
7550 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7551 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7552 int hpos, vpos, prop_idx;
7553 struct glyph *glyph;
7554 Lisp_Object enabled_p;
7555 int x = button_event->x;
7556 int y = button_event->y;
7d0393cf 7557
9ea173e8 7558 /* If not on the highlighted tool-bar item, return. */
06a2c219 7559 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 7560 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
7561 return;
7562
7563 /* If item is disabled, do nothing. */
8daf1204 7564 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7565 if (NILP (enabled_p))
7566 return;
7d0393cf 7567
06a2c219
GM
7568 if (button_event->type == ButtonPress)
7569 {
7570 /* Show item in pressed state. */
7571 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
7572 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 7573 last_tool_bar_item = prop_idx;
06a2c219
GM
7574 }
7575 else
7576 {
7577 Lisp_Object key, frame;
7578 struct input_event event;
7579
7580 /* Show item in released state. */
7581 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
7582 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
7583
8daf1204 7584 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
06a2c219
GM
7585
7586 XSETFRAME (frame, f);
9ea173e8 7587 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7588 event.frame_or_window = frame;
7589 event.arg = frame;
06a2c219
GM
7590 kbd_buffer_store_event (&event);
7591
9ea173e8 7592 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7593 event.frame_or_window = frame;
7594 event.arg = key;
06a2c219
GM
7595 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7596 button_event->state);
7597 kbd_buffer_store_event (&event);
9ea173e8 7598 last_tool_bar_item = -1;
06a2c219
GM
7599 }
7600}
7601
7602
9ea173e8
GM
7603/* Possibly highlight a tool-bar item on frame F when mouse moves to
7604 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
7605 note_mouse_highlight. */
7606
7607static void
9ea173e8 7608note_tool_bar_highlight (f, x, y)
06a2c219
GM
7609 struct frame *f;
7610 int x, y;
7611{
9ea173e8 7612 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
7613 struct window *w = XWINDOW (window);
7614 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7615 int hpos, vpos;
7616 struct glyph *glyph;
7617 struct glyph_row *row;
5c187dee 7618 int i;
06a2c219
GM
7619 Lisp_Object enabled_p;
7620 int prop_idx;
140330de 7621 enum draw_glyphs_face draw;
5c187dee 7622 int mouse_down_p, rc;
06a2c219
GM
7623
7624 /* Function note_mouse_highlight is called with negative x(y
7625 values when mouse moves outside of the frame. */
7626 if (x <= 0 || y <= 0)
7627 {
7628 clear_mouse_face (dpyinfo);
7629 return;
7630 }
7631
9ea173e8 7632 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
7633 if (rc < 0)
7634 {
9ea173e8 7635 /* Not on tool-bar item. */
06a2c219
GM
7636 clear_mouse_face (dpyinfo);
7637 return;
7638 }
7639 else if (rc == 0)
06a2c219 7640 goto set_help_echo;
b8009dd1 7641
06a2c219 7642 clear_mouse_face (dpyinfo);
7d0393cf 7643
9ea173e8 7644 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
7645 mouse_down_p = (dpyinfo->grabbed
7646 && f == last_mouse_frame
7647 && FRAME_LIVE_P (f));
7648 if (mouse_down_p
9ea173e8 7649 && last_tool_bar_item != prop_idx)
06a2c219
GM
7650 return;
7651
7652 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7653 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7d0393cf 7654
9ea173e8 7655 /* If tool-bar item is not enabled, don't highlight it. */
8daf1204 7656 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7657 if (!NILP (enabled_p))
7658 {
7659 /* Compute the x-position of the glyph. In front and past the
7660 image is a space. We include this is the highlighted area. */
7661 row = MATRIX_ROW (w->current_matrix, vpos);
7662 for (i = x = 0; i < hpos; ++i)
7663 x += row->glyphs[TEXT_AREA][i].pixel_width;
7d0393cf 7664
06a2c219
GM
7665 /* Record this as the current active region. */
7666 dpyinfo->mouse_face_beg_col = hpos;
7667 dpyinfo->mouse_face_beg_row = vpos;
7668 dpyinfo->mouse_face_beg_x = x;
7669 dpyinfo->mouse_face_beg_y = row->y;
7670 dpyinfo->mouse_face_past_end = 0;
7d0393cf 7671
06a2c219
GM
7672 dpyinfo->mouse_face_end_col = hpos + 1;
7673 dpyinfo->mouse_face_end_row = vpos;
7674 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7675 dpyinfo->mouse_face_end_y = row->y;
7676 dpyinfo->mouse_face_window = window;
9ea173e8 7677 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
7d0393cf 7678
06a2c219
GM
7679 /* Display it as active. */
7680 show_mouse_face (dpyinfo, draw);
7681 dpyinfo->mouse_face_image_state = draw;
b8009dd1 7682 }
7d0393cf 7683
06a2c219 7684 set_help_echo:
7d0393cf 7685
50590060 7686 /* Set help_echo to a help string to display for this tool-bar item.
06a2c219 7687 XTread_socket does the rest. */
7cea38bc 7688 help_echo_object = help_echo_window = Qnil;
be010514 7689 help_echo_pos = -1;
8daf1204 7690 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
b7e80413 7691 if (NILP (help_echo))
8daf1204 7692 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
b8009dd1 7693}
4d73d038 7694
06a2c219
GM
7695
7696\f
9f8531e5
GM
7697/* Find the glyph matrix position of buffer position CHARPOS in window
7698 *W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7699 current glyphs must be up to date. If CHARPOS is above window
7700 start return (0, 0, 0, 0). If CHARPOS is after end of W, return end
7701 of last line in W. In the row containing CHARPOS, stop before glyphs
7e376260 7702 having STOP as object. */
b8009dd1 7703
9f8531e5
GM
7704#if 0 /* This is a version of fast_find_position that's more correct
7705 in the presence of hscrolling, for example. I didn't install
7706 it right away because the problem fixed is minor, it failed
7d0393cf 7707 in 20.x as well, and I think it's too risky to install
9f8531e5
GM
7708 so near the release of 21.1. 2001-09-25 gerd. */
7709
7710static int
7711fast_find_position (w, charpos, hpos, vpos, x, y, stop)
7712 struct window *w;
7713 int charpos;
7714 int *hpos, *vpos, *x, *y;
7715 Lisp_Object stop;
7716{
7717 struct glyph_row *row, *first;
7718 struct glyph *glyph, *end;
7719 int i, past_end = 0;
7720
7721 first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
62e33982 7722 row = row_containing_pos (w, charpos, first, NULL, 0);
9f8531e5
GM
7723 if (row == NULL)
7724 {
7725 if (charpos < MATRIX_ROW_START_CHARPOS (first))
7726 {
7727 *x = *y = *hpos = *vpos = 0;
7728 return 0;
7729 }
7730 else
7731 {
7732 row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
7733 past_end = 1;
7734 }
7735 }
7736
7737 *x = row->x;
7738 *y = row->y;
7739 *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7d0393cf 7740
9f8531e5
GM
7741 glyph = row->glyphs[TEXT_AREA];
7742 end = glyph + row->used[TEXT_AREA];
7d0393cf 7743
9f8531e5
GM
7744 /* Skip over glyphs not having an object at the start of the row.
7745 These are special glyphs like truncation marks on terminal
7746 frames. */
7747 if (row->displays_text_p)
7748 while (glyph < end
7749 && INTEGERP (glyph->object)
7750 && !EQ (stop, glyph->object)
7751 && glyph->charpos < 0)
7752 {
7753 *x += glyph->pixel_width;
7754 ++glyph;
7755 }
7756
7757 while (glyph < end
7758 && !INTEGERP (glyph->object)
7759 && !EQ (stop, glyph->object)
7760 && (!BUFFERP (glyph->object)
7761 || glyph->charpos < charpos))
7762 {
7763 *x += glyph->pixel_width;
7764 ++glyph;
7765 }
7766
7767 *hpos = glyph - row->glyphs[TEXT_AREA];
7768 return past_end;
7769}
7770
7771#else /* not 0 */
7772
b8009dd1 7773static int
7e376260 7774fast_find_position (w, pos, hpos, vpos, x, y, stop)
06a2c219 7775 struct window *w;
b8009dd1 7776 int pos;
06a2c219 7777 int *hpos, *vpos, *x, *y;
7e376260 7778 Lisp_Object stop;
b8009dd1 7779{
b8009dd1 7780 int i;
bf1c0ba1 7781 int lastcol;
06a2c219
GM
7782 int maybe_next_line_p = 0;
7783 int line_start_position;
7784 int yb = window_text_bottom_y (w);
03d1a189
GM
7785 struct glyph_row *row, *best_row;
7786 int row_vpos, best_row_vpos;
06a2c219
GM
7787 int current_x;
7788
03d1a189
GM
7789 row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7790 row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7791
06a2c219 7792 while (row->y < yb)
b8009dd1 7793 {
06a2c219
GM
7794 if (row->used[TEXT_AREA])
7795 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7796 else
7797 line_start_position = 0;
7798
7799 if (line_start_position > pos)
b8009dd1 7800 break;
77b68646
RS
7801 /* If the position sought is the end of the buffer,
7802 don't include the blank lines at the bottom of the window. */
06a2c219
GM
7803 else if (line_start_position == pos
7804 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 7805 {
06a2c219 7806 maybe_next_line_p = 1;
77b68646
RS
7807 break;
7808 }
06a2c219
GM
7809 else if (line_start_position > 0)
7810 {
7811 best_row = row;
7812 best_row_vpos = row_vpos;
7813 }
4b0bb6f3
GM
7814
7815 if (row->y + row->height >= yb)
7816 break;
7d0393cf 7817
06a2c219
GM
7818 ++row;
7819 ++row_vpos;
b8009dd1 7820 }
7d0393cf 7821
06a2c219
GM
7822 /* Find the right column within BEST_ROW. */
7823 lastcol = 0;
7824 current_x = best_row->x;
7825 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 7826 {
06a2c219 7827 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7e376260 7828 int charpos = glyph->charpos;
06a2c219 7829
7e376260 7830 if (BUFFERP (glyph->object))
bf1c0ba1 7831 {
7e376260
GM
7832 if (charpos == pos)
7833 {
7834 *hpos = i;
7835 *vpos = best_row_vpos;
7836 *x = current_x;
7837 *y = best_row->y;
7838 return 1;
7839 }
7840 else if (charpos > pos)
7841 break;
bf1c0ba1 7842 }
7e376260 7843 else if (EQ (glyph->object, stop))
4d73d038 7844 break;
06a2c219 7845
7e376260
GM
7846 if (charpos > 0)
7847 lastcol = i;
06a2c219 7848 current_x += glyph->pixel_width;
bf1c0ba1 7849 }
b8009dd1 7850
77b68646
RS
7851 /* If we're looking for the end of the buffer,
7852 and we didn't find it in the line we scanned,
7853 use the start of the following line. */
06a2c219 7854 if (maybe_next_line_p)
77b68646 7855 {
06a2c219
GM
7856 ++best_row;
7857 ++best_row_vpos;
7858 lastcol = 0;
7859 current_x = best_row->x;
77b68646
RS
7860 }
7861
06a2c219
GM
7862 *vpos = best_row_vpos;
7863 *hpos = lastcol + 1;
7864 *x = current_x;
7865 *y = best_row->y;
b8009dd1
RS
7866 return 0;
7867}
7868
9f8531e5
GM
7869#endif /* not 0 */
7870
06a2c219 7871
269b7745 7872/* Find the position of the glyph for position POS in OBJECT in
7a4bce14
PJ
7873 window W's current matrix, and return in *X, *Y the pixel
7874 coordinates, and return in *HPOS, *VPOS the column/row of the glyph.
f9db2310
GM
7875
7876 RIGHT_P non-zero means return the position of the right edge of the
7877 glyph, RIGHT_P zero means return the left edge position.
7878
7879 If no glyph for POS exists in the matrix, return the position of
7880 the glyph with the next smaller position that is in the matrix, if
7881 RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS
7882 exists in the matrix, return the position of the glyph with the
7883 next larger position in OBJECT.
7884
7885 Value is non-zero if a glyph was found. */
7886
7887static int
7888fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
7889 struct window *w;
7890 int pos;
7891 Lisp_Object object;
7892 int *hpos, *vpos, *x, *y;
7893 int right_p;
7894{
7895 int yb = window_text_bottom_y (w);
7896 struct glyph_row *r;
7897 struct glyph *best_glyph = NULL;
7898 struct glyph_row *best_row = NULL;
7899 int best_x = 0;
7900
7901 for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7902 r->enabled_p && r->y < yb;
7903 ++r)
7904 {
7905 struct glyph *g = r->glyphs[TEXT_AREA];
7906 struct glyph *e = g + r->used[TEXT_AREA];
7907 int gx;
7908
7909 for (gx = r->x; g < e; gx += g->pixel_width, ++g)
7910 if (EQ (g->object, object))
7911 {
7912 if (g->charpos == pos)
7913 {
7914 best_glyph = g;
7915 best_x = gx;
7916 best_row = r;
7917 goto found;
7918 }
7919 else if (best_glyph == NULL
7920 || ((abs (g->charpos - pos)
7921 < abs (best_glyph->charpos - pos))
7922 && (right_p
7923 ? g->charpos < pos
7924 : g->charpos > pos)))
7925 {
7926 best_glyph = g;
7927 best_x = gx;
7928 best_row = r;
7929 }
7930 }
7931 }
7932
7933 found:
7934
7935 if (best_glyph)
7936 {
7937 *x = best_x;
7938 *hpos = best_glyph - best_row->glyphs[TEXT_AREA];
7939
7940 if (right_p)
7941 {
7942 *x += best_glyph->pixel_width;
7943 ++*hpos;
7944 }
7d0393cf 7945
f9db2310
GM
7946 *y = best_row->y;
7947 *vpos = best_row - w->current_matrix->rows;
7948 }
7949
7950 return best_glyph != NULL;
7951}
7952
7953
b8009dd1
RS
7954/* Display the active region described by mouse_face_*
7955 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7956
7957static void
06a2c219 7958show_mouse_face (dpyinfo, draw)
7a13e894 7959 struct x_display_info *dpyinfo;
06a2c219 7960 enum draw_glyphs_face draw;
b8009dd1 7961{
7a13e894 7962 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7963 struct frame *f = XFRAME (WINDOW_FRAME (w));
06a2c219 7964
b2bbd509
GM
7965 if (/* If window is in the process of being destroyed, don't bother
7966 to do anything. */
7967 w->current_matrix != NULL
66301061
KS
7968 /* Don't update mouse highlight if hidden */
7969 && (draw != DRAW_MOUSE_FACE || !dpyinfo->mouse_face_hidden)
b2bbd509
GM
7970 /* Recognize when we are called to operate on rows that don't exist
7971 anymore. This can happen when a window is split. */
7972 && dpyinfo->mouse_face_end_row < w->current_matrix->nrows)
06a2c219 7973 {
b2bbd509
GM
7974 int phys_cursor_on_p = w->phys_cursor_on_p;
7975 struct glyph_row *row, *first, *last;
06a2c219 7976
b2bbd509
GM
7977 first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row);
7978 last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row);
7d0393cf 7979
b2bbd509 7980 for (row = first; row <= last && row->enabled_p; ++row)
06a2c219 7981 {
b2bbd509 7982 int start_hpos, end_hpos, start_x;
06a2c219 7983
b2bbd509
GM
7984 /* For all but the first row, the highlight starts at column 0. */
7985 if (row == first)
7986 {
7987 start_hpos = dpyinfo->mouse_face_beg_col;
7988 start_x = dpyinfo->mouse_face_beg_x;
7989 }
7990 else
7991 {
7992 start_hpos = 0;
7993 start_x = 0;
7994 }
06a2c219 7995
b2bbd509
GM
7996 if (row == last)
7997 end_hpos = dpyinfo->mouse_face_end_col;
7998 else
7999 end_hpos = row->used[TEXT_AREA];
b8009dd1 8000
b2bbd509
GM
8001 if (end_hpos > start_hpos)
8002 {
7d0393cf 8003 x_draw_glyphs (w, start_x, row, TEXT_AREA,
b2bbd509 8004 start_hpos, end_hpos, draw, 0);
b8009dd1 8005
60626bab
GM
8006 row->mouse_face_p
8007 = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED;
b2bbd509
GM
8008 }
8009 }
2729a2b5 8010
b2bbd509
GM
8011 /* When we've written over the cursor, arrange for it to
8012 be displayed again. */
8013 if (phys_cursor_on_p && !w->phys_cursor_on_p)
8014 x_display_cursor (w, 1,
8015 w->phys_cursor.hpos, w->phys_cursor.vpos,
8016 w->phys_cursor.x, w->phys_cursor.y);
8017 }
fb3b7de5 8018
06a2c219
GM
8019 /* Change the mouse cursor. */
8020 if (draw == DRAW_NORMAL_TEXT)
8021 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8022 f->output_data.x->text_cursor);
8023 else if (draw == DRAW_MOUSE_FACE)
334208b7 8024 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 8025 f->output_data.x->cross_cursor);
27ead1d5 8026 else
334208b7 8027 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 8028 f->output_data.x->nontext_cursor);
b8009dd1
RS
8029}
8030
8031/* Clear out the mouse-highlighted active region.
fa262c07
GM
8032 Redraw it un-highlighted first. Value is non-zero if mouse
8033 face was actually drawn unhighlighted. */
b8009dd1 8034
fa262c07 8035static int
7a13e894
RS
8036clear_mouse_face (dpyinfo)
8037 struct x_display_info *dpyinfo;
b8009dd1 8038{
fa262c07 8039 int cleared = 0;
7d0393cf 8040
fa262c07
GM
8041 if (!NILP (dpyinfo->mouse_face_window))
8042 {
8043 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
8044 cleared = 1;
8045 }
b8009dd1 8046
7a13e894
RS
8047 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
8048 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
8049 dpyinfo->mouse_face_window = Qnil;
1b85dc1c 8050 dpyinfo->mouse_face_overlay = Qnil;
fa262c07 8051 return cleared;
b8009dd1 8052}
e687d06e 8053
71b8321e
GM
8054
8055/* Clear any mouse-face on window W. This function is part of the
8056 redisplay interface, and is called from try_window_id and similar
8057 functions to ensure the mouse-highlight is off. */
8058
8059static void
8060x_clear_mouse_face (w)
8061 struct window *w;
8062{
8063 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
8064 Lisp_Object window;
8065
2e636f9d 8066 BLOCK_INPUT;
71b8321e
GM
8067 XSETWINDOW (window, w);
8068 if (EQ (window, dpyinfo->mouse_face_window))
8069 clear_mouse_face (dpyinfo);
2e636f9d 8070 UNBLOCK_INPUT;
71b8321e
GM
8071}
8072
8073
e687d06e
RS
8074/* Just discard the mouse face information for frame F, if any.
8075 This is used when the size of F is changed. */
8076
dfcf069d 8077void
e687d06e
RS
8078cancel_mouse_face (f)
8079 FRAME_PTR f;
8080{
8081 Lisp_Object window;
8082 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
8083
8084 window = dpyinfo->mouse_face_window;
8085 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
8086 {
8087 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
8088 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
8089 dpyinfo->mouse_face_window = Qnil;
8090 }
8091}
b52b65bd 8092
b8009dd1 8093\f
b52b65bd
GM
8094static int glyph_rect P_ ((struct frame *f, int, int, XRectangle *));
8095
8096
8097/* Try to determine frame pixel position and size of the glyph under
8098 frame pixel coordinates X/Y on frame F . Return the position and
8099 size in *RECT. Value is non-zero if we could compute these
8100 values. */
8101
8102static int
8103glyph_rect (f, x, y, rect)
8104 struct frame *f;
8105 int x, y;
8106 XRectangle *rect;
8107{
8108 Lisp_Object window;
8109 int part, found = 0;
8110
8111 window = window_from_coordinates (f, x, y, &part, 0);
8112 if (!NILP (window))
8113 {
8114 struct window *w = XWINDOW (window);
8115 struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
8116 struct glyph_row *end = r + w->current_matrix->nrows - 1;
b52b65bd
GM
8117
8118 frame_to_window_pixel_xy (w, &x, &y);
7d0393cf 8119
b52b65bd
GM
8120 for (; !found && r < end && r->enabled_p; ++r)
8121 if (r->y >= y)
8122 {
8123 struct glyph *g = r->glyphs[TEXT_AREA];
8124 struct glyph *end = g + r->used[TEXT_AREA];
8125 int gx;
7d0393cf 8126
b52b65bd
GM
8127 for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
8128 if (gx >= x)
8129 {
8130 rect->width = g->pixel_width;
8131 rect->height = r->height;
8132 rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
8133 rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
8134 found = 1;
8135 }
8136 }
8137 }
8138
8139 return found;
8140}
8141
12ba150f 8142
90e65f07 8143/* Return the current position of the mouse.
b52b65bd 8144 *FP should be a frame which indicates which display to ask about.
90e65f07 8145
b52b65bd
GM
8146 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
8147 and *PART to the frame, window, and scroll bar part that the mouse
8148 is over. Set *X and *Y to the portion and whole of the mouse's
ab648270 8149 position on the scroll bar.
12ba150f 8150
b52b65bd
GM
8151 If the mouse movement started elsewhere, set *FP to the frame the
8152 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
12ba150f
JB
8153 the mouse is over.
8154
b52b65bd 8155 Set *TIME to the server time-stamp for the time at which the mouse
12ba150f
JB
8156 was at this position.
8157
a135645a
RS
8158 Don't store anything if we don't have a valid set of values to report.
8159
90e65f07 8160 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 8161 movement. */
90e65f07
JB
8162
8163static void
1cf412ec 8164XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 8165 FRAME_PTR *fp;
1cf412ec 8166 int insist;
12ba150f 8167 Lisp_Object *bar_window;
ab648270 8168 enum scroll_bar_part *part;
90e65f07 8169 Lisp_Object *x, *y;
e5d77022 8170 unsigned long *time;
90e65f07 8171{
a135645a
RS
8172 FRAME_PTR f1;
8173
90e65f07
JB
8174 BLOCK_INPUT;
8175
8bcee03e 8176 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 8177 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
8178 else
8179 {
12ba150f
JB
8180 Window root;
8181 int root_x, root_y;
90e65f07 8182
12ba150f
JB
8183 Window dummy_window;
8184 int dummy;
8185
39d8bb4d
KH
8186 Lisp_Object frame, tail;
8187
8188 /* Clear the mouse-moved flag for every frame on this display. */
8189 FOR_EACH_FRAME (tail, frame)
8190 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
8191 XFRAME (frame)->mouse_moved = 0;
8192
ab648270 8193 last_mouse_scroll_bar = Qnil;
12ba150f
JB
8194
8195 /* Figure out which root window we're on. */
334208b7
RS
8196 XQueryPointer (FRAME_X_DISPLAY (*fp),
8197 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
8198
8199 /* The root window which contains the pointer. */
8200 &root,
8201
8202 /* Trash which we can't trust if the pointer is on
8203 a different screen. */
8204 &dummy_window,
8205
8206 /* The position on that root window. */
58769bee 8207 &root_x, &root_y,
12ba150f
JB
8208
8209 /* More trash we can't trust. */
8210 &dummy, &dummy,
8211
8212 /* Modifier keys and pointer buttons, about which
8213 we don't care. */
8214 (unsigned int *) &dummy);
8215
8216 /* Now we have a position on the root; find the innermost window
8217 containing the pointer. */
8218 {
8219 Window win, child;
8220 int win_x, win_y;
06a2c219 8221 int parent_x = 0, parent_y = 0;
e99db5a1 8222 int count;
12ba150f
JB
8223
8224 win = root;
69388238 8225
2d7fc7e8
RS
8226 /* XTranslateCoordinates can get errors if the window
8227 structure is changing at the same time this function
8228 is running. So at least we must not crash from them. */
8229
e99db5a1 8230 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 8231
334208b7 8232 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 8233 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 8234 {
69388238
RS
8235 /* If mouse was grabbed on a frame, give coords for that frame
8236 even if the mouse is now outside it. */
334208b7 8237 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 8238
12ba150f 8239 /* From-window, to-window. */
69388238 8240 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
8241
8242 /* From-position, to-position. */
8243 root_x, root_y, &win_x, &win_y,
8244
8245 /* Child of win. */
8246 &child);
69388238
RS
8247 f1 = last_mouse_frame;
8248 }
8249 else
8250 {
8251 while (1)
8252 {
334208b7 8253 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 8254
69388238
RS
8255 /* From-window, to-window. */
8256 root, win,
12ba150f 8257
69388238
RS
8258 /* From-position, to-position. */
8259 root_x, root_y, &win_x, &win_y,
8260
8261 /* Child of win. */
8262 &child);
8263
9af3143a 8264 if (child == None || child == win)
69388238
RS
8265 break;
8266
8267 win = child;
8268 parent_x = win_x;
8269 parent_y = win_y;
8270 }
12ba150f 8271
69388238
RS
8272 /* Now we know that:
8273 win is the innermost window containing the pointer
8274 (XTC says it has no child containing the pointer),
8275 win_x and win_y are the pointer's position in it
8276 (XTC did this the last time through), and
8277 parent_x and parent_y are the pointer's position in win's parent.
8278 (They are what win_x and win_y were when win was child.
8279 If win is the root window, it has no parent, and
8280 parent_{x,y} are invalid, but that's okay, because we'll
8281 never use them in that case.) */
8282
8283 /* Is win one of our frames? */
19126e11 8284 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
aad0f6ab
GM
8285
8286#ifdef USE_X_TOOLKIT
8287 /* If we end up with the menu bar window, say it's not
8288 on the frame. */
8289 if (f1 != NULL
8290 && f1->output_data.x->menubar_widget
8291 && win == XtWindow (f1->output_data.x->menubar_widget))
8292 f1 = NULL;
8293#endif /* USE_X_TOOLKIT */
69388238 8294 }
58769bee 8295
2d7fc7e8
RS
8296 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
8297 f1 = 0;
8298
e99db5a1 8299 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 8300
ab648270 8301 /* If not, is it one of our scroll bars? */
a135645a 8302 if (! f1)
12ba150f 8303 {
ab648270 8304 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
8305
8306 if (bar)
8307 {
a135645a 8308 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
8309 win_x = parent_x;
8310 win_y = parent_y;
8311 }
8312 }
90e65f07 8313
8bcee03e 8314 if (f1 == 0 && insist > 0)
b86bd3dd 8315 f1 = SELECTED_FRAME ();
1cf412ec 8316
a135645a 8317 if (f1)
12ba150f 8318 {
06a2c219
GM
8319 /* Ok, we found a frame. Store all the values.
8320 last_mouse_glyph is a rectangle used to reduce the
8321 generation of mouse events. To not miss any motion
8322 events, we must divide the frame into rectangles of the
8323 size of the smallest character that could be displayed
8324 on it, i.e. into the same rectangles that matrices on
8325 the frame are divided into. */
8326
b52b65bd
GM
8327 int width, height, gx, gy;
8328 XRectangle rect;
7d0393cf 8329
b52b65bd
GM
8330 if (glyph_rect (f1, win_x, win_y, &rect))
8331 last_mouse_glyph = rect;
8332 else
8333 {
8334 width = FRAME_SMALLEST_CHAR_WIDTH (f1);
8335 height = FRAME_SMALLEST_FONT_HEIGHT (f1);
8336 gx = win_x;
8337 gy = win_y;
7d0393cf 8338
b52b65bd
GM
8339 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
8340 round down even for negative values. */
8341 if (gx < 0)
8342 gx -= width - 1;
4f00e84d 8343 if (gy < 0)
b52b65bd
GM
8344 gy -= height - 1;
8345 gx = (gx + width - 1) / width * width;
8346 gy = (gy + height - 1) / height * height;
7d0393cf 8347
b52b65bd
GM
8348 last_mouse_glyph.width = width;
8349 last_mouse_glyph.height = height;
8350 last_mouse_glyph.x = gx;
8351 last_mouse_glyph.y = gy;
8352 }
12ba150f
JB
8353
8354 *bar_window = Qnil;
8355 *part = 0;
334208b7 8356 *fp = f1;
e0c1aef2
KH
8357 XSETINT (*x, win_x);
8358 XSETINT (*y, win_y);
12ba150f
JB
8359 *time = last_mouse_movement_time;
8360 }
8361 }
8362 }
90e65f07
JB
8363
8364 UNBLOCK_INPUT;
8365}
f451eb13 8366
06a2c219 8367
06a2c219 8368#ifdef USE_X_TOOLKIT
bffcfca9
GM
8369
8370/* Atimer callback function for TIMER. Called every 0.1s to process
8371 Xt timeouts, if needed. We must avoid calling XtAppPending as
8372 much as possible because that function does an implicit XFlush
8373 that slows us down. */
8374
8375static void
8376x_process_timeouts (timer)
8377 struct atimer *timer;
8378{
8379 if (toolkit_scroll_bar_interaction || popup_activated_flag)
8380 {
8381 BLOCK_INPUT;
8382 while (XtAppPending (Xt_app_con) & XtIMTimer)
8383 XtAppProcessEvent (Xt_app_con, XtIMTimer);
8384 UNBLOCK_INPUT;
8385 }
06a2c219
GM
8386}
8387
bffcfca9 8388#endif /* USE_X_TOOLKIT */
06a2c219
GM
8389
8390\f
8391/* Scroll bar support. */
8392
8393/* Given an X window ID, find the struct scroll_bar which manages it.
8394 This can be called in GC, so we have to make sure to strip off mark
8395 bits. */
bffcfca9 8396
06a2c219
GM
8397static struct scroll_bar *
8398x_window_to_scroll_bar (window_id)
8399 Window window_id;
8400{
8401 Lisp_Object tail;
8402
8403 for (tail = Vframe_list;
8404 XGCTYPE (tail) == Lisp_Cons;
8e713be6 8405 tail = XCDR (tail))
06a2c219
GM
8406 {
8407 Lisp_Object frame, bar, condemned;
8408
8e713be6 8409 frame = XCAR (tail);
06a2c219
GM
8410 /* All elements of Vframe_list should be frames. */
8411 if (! GC_FRAMEP (frame))
8412 abort ();
8413
8414 /* Scan this frame's scroll bar list for a scroll bar with the
8415 right window ID. */
8416 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
8417 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
8418 /* This trick allows us to search both the ordinary and
8419 condemned scroll bar lists with one loop. */
8420 ! GC_NILP (bar) || (bar = condemned,
8421 condemned = Qnil,
8422 ! GC_NILP (bar));
8423 bar = XSCROLL_BAR (bar)->next)
8424 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
8425 return XSCROLL_BAR (bar);
8426 }
8427
8428 return 0;
8429}
8430
8431
01f67d2c 8432#if defined USE_LUCID
c95fc5f1
GM
8433
8434/* Return the Lucid menu bar WINDOW is part of. Return null
8435 if WINDOW is not part of a menu bar. */
8436
8437static Widget
8438x_window_to_menu_bar (window)
8439 Window window;
8440{
8441 Lisp_Object tail;
7d0393cf 8442
c95fc5f1
GM
8443 for (tail = Vframe_list;
8444 XGCTYPE (tail) == Lisp_Cons;
8445 tail = XCDR (tail))
8446 {
8447 Lisp_Object frame = XCAR (tail);
8448 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
7d0393cf 8449
c95fc5f1
GM
8450 if (menu_bar && xlwmenu_window_p (menu_bar, window))
8451 return menu_bar;
8452 }
8453
8454 return NULL;
8455}
8456
01f67d2c 8457#endif /* USE_LUCID */
c95fc5f1 8458
06a2c219
GM
8459\f
8460/************************************************************************
8461 Toolkit scroll bars
8462 ************************************************************************/
8463
eccc05db 8464#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8465
8466static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
8467static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
8468static void x_create_toolkit_scroll_bar P_ ((struct frame *,
8469 struct scroll_bar *));
8470static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
8471 int, int, int));
8472
8473
8474/* Id of action hook installed for scroll bars. */
8475
8476static XtActionHookId action_hook_id;
8477
8478/* Lisp window being scrolled. Set when starting to interact with
8479 a toolkit scroll bar, reset to nil when ending the interaction. */
8480
8481static Lisp_Object window_being_scrolled;
8482
8483/* Last scroll bar part sent in xm_scroll_callback. */
8484
8485static int last_scroll_bar_part;
8486
ec18280f
SM
8487/* Whether this is an Xaw with arrow-scrollbars. This should imply
8488 that movements of 1/20 of the screen size are mapped to up/down. */
8489
8490static Boolean xaw3d_arrow_scroll;
8491
8492/* Whether the drag scrolling maintains the mouse at the top of the
8493 thumb. If not, resizing the thumb needs to be done more carefully
8494 to avoid jerkyness. */
8495
8496static Boolean xaw3d_pick_top;
8497
06a2c219
GM
8498
8499/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 8500 bars are used.. The hook is responsible for detecting when
06a2c219 8501 the user ends an interaction with the scroll bar, and generates
3b8f9651 8502 a `end-scroll' SCROLL_BAR_CLICK_EVENT' event if so. */
06a2c219
GM
8503
8504static void
8505xt_action_hook (widget, client_data, action_name, event, params,
8506 num_params)
8507 Widget widget;
8508 XtPointer client_data;
8509 String action_name;
8510 XEvent *event;
8511 String *params;
8512 Cardinal *num_params;
8513{
8514 int scroll_bar_p;
8515 char *end_action;
7d0393cf 8516
06a2c219
GM
8517#ifdef USE_MOTIF
8518 scroll_bar_p = XmIsScrollBar (widget);
8519 end_action = "Release";
ec18280f 8520#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8521 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
8522 end_action = "EndScroll";
ec18280f 8523#endif /* USE_MOTIF */
06a2c219 8524
06a2c219
GM
8525 if (scroll_bar_p
8526 && strcmp (action_name, end_action) == 0
8527 && WINDOWP (window_being_scrolled))
8528 {
8529 struct window *w;
7d0393cf 8530
06a2c219
GM
8531 x_send_scroll_bar_event (window_being_scrolled,
8532 scroll_bar_end_scroll, 0, 0);
8533 w = XWINDOW (window_being_scrolled);
8534 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
8535 window_being_scrolled = Qnil;
8536 last_scroll_bar_part = -1;
bffcfca9
GM
8537
8538 /* Xt timeouts no longer needed. */
8539 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
8540 }
8541}
8542
07b3d16e
GM
8543/* A vector of windows used for communication between
8544 x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
8545
8546static struct window **scroll_bar_windows;
8547static int scroll_bar_windows_size;
8548
06a2c219
GM
8549
8550/* Send a client message with message type Xatom_Scrollbar for a
8551 scroll action to the frame of WINDOW. PART is a value identifying
8552 the part of the scroll bar that was clicked on. PORTION is the
8553 amount to scroll of a whole of WHOLE. */
8554
8555static void
8556x_send_scroll_bar_event (window, part, portion, whole)
8557 Lisp_Object window;
8558 int part, portion, whole;
8559{
8560 XEvent event;
8561 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
07b3d16e
GM
8562 struct window *w = XWINDOW (window);
8563 struct frame *f = XFRAME (w->frame);
8564 int i;
06a2c219 8565
07b3d16e 8566 BLOCK_INPUT;
7d0393cf 8567
06a2c219
GM
8568 /* Construct a ClientMessage event to send to the frame. */
8569 ev->type = ClientMessage;
8570 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
8571 ev->display = FRAME_X_DISPLAY (f);
8572 ev->window = FRAME_X_WINDOW (f);
8573 ev->format = 32;
07b3d16e
GM
8574
8575 /* We can only transfer 32 bits in the XClientMessageEvent, which is
8576 not enough to store a pointer or Lisp_Object on a 64 bit system.
8577 So, store the window in scroll_bar_windows and pass the index
8578 into that array in the event. */
8579 for (i = 0; i < scroll_bar_windows_size; ++i)
8580 if (scroll_bar_windows[i] == NULL)
8581 break;
8582
8583 if (i == scroll_bar_windows_size)
8584 {
8585 int new_size = max (10, 2 * scroll_bar_windows_size);
8586 size_t nbytes = new_size * sizeof *scroll_bar_windows;
8587 size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows;
7d0393cf 8588
07b3d16e
GM
8589 scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
8590 nbytes);
8591 bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
8592 scroll_bar_windows_size = new_size;
8593 }
8594
8595 scroll_bar_windows[i] = w;
8596 ev->data.l[0] = (long) i;
06a2c219
GM
8597 ev->data.l[1] = (long) part;
8598 ev->data.l[2] = (long) 0;
8599 ev->data.l[3] = (long) portion;
8600 ev->data.l[4] = (long) whole;
8601
bffcfca9
GM
8602 /* Make Xt timeouts work while the scroll bar is active. */
8603 toolkit_scroll_bar_interaction = 1;
8604
06a2c219
GM
8605 /* Setting the event mask to zero means that the message will
8606 be sent to the client that created the window, and if that
8607 window no longer exists, no event will be sent. */
06a2c219
GM
8608 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
8609 UNBLOCK_INPUT;
8610}
8611
8612
8613/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
8614 in *IEVENT. */
8615
8616static void
8617x_scroll_bar_to_input_event (event, ievent)
8618 XEvent *event;
8619 struct input_event *ievent;
8620{
8621 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
8622 Lisp_Object window;
8623 struct frame *f;
07b3d16e 8624 struct window *w;
7d0393cf 8625
07b3d16e
GM
8626 w = scroll_bar_windows[ev->data.l[0]];
8627 scroll_bar_windows[ev->data.l[0]] = NULL;
52e386c2 8628
07b3d16e
GM
8629 XSETWINDOW (window, w);
8630 f = XFRAME (w->frame);
7d0393cf 8631
3b8f9651 8632 ievent->kind = SCROLL_BAR_CLICK_EVENT;
06a2c219 8633 ievent->frame_or_window = window;
0f8aabe9 8634 ievent->arg = Qnil;
06a2c219
GM
8635 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
8636 ievent->part = ev->data.l[1];
8637 ievent->code = ev->data.l[2];
8638 ievent->x = make_number ((int) ev->data.l[3]);
8639 ievent->y = make_number ((int) ev->data.l[4]);
8640 ievent->modifiers = 0;
8641}
8642
8643
8644#ifdef USE_MOTIF
8645
8646/* Minimum and maximum values used for Motif scroll bars. */
8647
8648#define XM_SB_MIN 1
8649#define XM_SB_MAX 10000000
8650#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
8651
8652
8653/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
8654 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
4696802b 8655 CALL_DATA is a pointer to a XmScrollBarCallbackStruct. */
06a2c219
GM
8656
8657static void
8658xm_scroll_callback (widget, client_data, call_data)
8659 Widget widget;
8660 XtPointer client_data, call_data;
8661{
8662 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8663 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
06a2c219
GM
8664 int part = -1, whole = 0, portion = 0;
8665
8666 switch (cs->reason)
8667 {
8668 case XmCR_DECREMENT:
8669 bar->dragging = Qnil;
8670 part = scroll_bar_up_arrow;
8671 break;
8672
8673 case XmCR_INCREMENT:
8674 bar->dragging = Qnil;
8675 part = scroll_bar_down_arrow;
8676 break;
8677
8678 case XmCR_PAGE_DECREMENT:
8679 bar->dragging = Qnil;
8680 part = scroll_bar_above_handle;
8681 break;
8682
8683 case XmCR_PAGE_INCREMENT:
8684 bar->dragging = Qnil;
8685 part = scroll_bar_below_handle;
8686 break;
8687
8688 case XmCR_TO_TOP:
8689 bar->dragging = Qnil;
8690 part = scroll_bar_to_top;
8691 break;
7d0393cf 8692
06a2c219
GM
8693 case XmCR_TO_BOTTOM:
8694 bar->dragging = Qnil;
8695 part = scroll_bar_to_bottom;
8696 break;
8697
8698 case XmCR_DRAG:
8699 {
8700 int slider_size;
8701 int dragging_down_p = (INTEGERP (bar->dragging)
8702 && XINT (bar->dragging) <= cs->value);
8703
8704 /* Get the slider size. */
8705 BLOCK_INPUT;
8706 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
8707 UNBLOCK_INPUT;
8708
6f2a7a68
SM
8709 whole = XM_SB_RANGE - slider_size;
8710 portion = min (cs->value - XM_SB_MIN, whole);
8711 part = scroll_bar_handle;
8712 bar->dragging = make_number (cs->value);
06a2c219
GM
8713 }
8714 break;
7d0393cf 8715
06a2c219
GM
8716 case XmCR_VALUE_CHANGED:
8717 break;
8718 };
8719
8720 if (part >= 0)
8721 {
8722 window_being_scrolled = bar->window;
8723 last_scroll_bar_part = part;
8724 x_send_scroll_bar_event (bar->window, part, portion, whole);
8725 }
8726}
8727
8728
ec18280f 8729#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
8730
8731
ec18280f 8732/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
8733 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
8734 scroll bar struct. CALL_DATA is a pointer to a float saying where
8735 the thumb is. */
8736
8737static void
ec18280f 8738xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
8739 Widget widget;
8740 XtPointer client_data, call_data;
8741{
8742 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8743 float top = *(float *) call_data;
8744 float shown;
ec18280f
SM
8745 int whole, portion, height;
8746 int part;
06a2c219
GM
8747
8748 /* Get the size of the thumb, a value between 0 and 1. */
8749 BLOCK_INPUT;
ec18280f 8750 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
8751 UNBLOCK_INPUT;
8752
8753 whole = 10000000;
8754 portion = shown < 1 ? top * whole : 0;
06a2c219 8755
ec18280f
SM
8756 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
8757 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
8758 the bottom, so we force the scrolling whenever we see that we're
8759 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
8760 we try to ensure that we always stay two pixels away from the
8761 bottom). */
06a2c219
GM
8762 part = scroll_bar_down_arrow;
8763 else
8764 part = scroll_bar_handle;
8765
8766 window_being_scrolled = bar->window;
8767 bar->dragging = make_number (portion);
8768 last_scroll_bar_part = part;
8769 x_send_scroll_bar_event (bar->window, part, portion, whole);
8770}
8771
8772
ec18280f
SM
8773/* Xaw scroll bar callback. Invoked for incremental scrolling.,
8774 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
8775 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
8776 the scroll bar. CALL_DATA is an integer specifying the action that
8777 has taken place. It's magnitude is in the range 0..height of the
8778 scroll bar. Negative values mean scroll towards buffer start.
8779 Values < height of scroll bar mean line-wise movement. */
8780
8781static void
ec18280f 8782xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
8783 Widget widget;
8784 XtPointer client_data, call_data;
8785{
8786 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8787 int position = (int) call_data;
8788 Dimension height;
8789 int part;
8790
8791 /* Get the height of the scroll bar. */
8792 BLOCK_INPUT;
8793 XtVaGetValues (widget, XtNheight, &height, NULL);
8794 UNBLOCK_INPUT;
8795
ec18280f
SM
8796 if (abs (position) >= height)
8797 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
8798
8799 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
8800 it maps line-movement to call_data = max(5, height/20). */
8801 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
8802 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 8803 else
ec18280f 8804 part = scroll_bar_move_ratio;
06a2c219
GM
8805
8806 window_being_scrolled = bar->window;
8807 bar->dragging = Qnil;
8808 last_scroll_bar_part = part;
ec18280f 8809 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
8810}
8811
8812
8813#endif /* not USE_MOTIF */
8814
8815
8816/* Create the widget for scroll bar BAR on frame F. Record the widget
8817 and X window of the scroll bar in BAR. */
8818
8819static void
8820x_create_toolkit_scroll_bar (f, bar)
8821 struct frame *f;
8822 struct scroll_bar *bar;
8823{
8824 Window xwindow;
8825 Widget widget;
8826 Arg av[20];
8827 int ac = 0;
8828 char *scroll_bar_name = "verticalScrollBar";
8829 unsigned long pixel;
8830
8831 BLOCK_INPUT;
8832
8833#ifdef USE_MOTIF
06a2c219
GM
8834 /* Set resources. Create the widget. */
8835 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8836 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
8837 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
8838 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
8839 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
8840 XtSetArg (av[ac], XmNincrement, 1); ++ac;
8841 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
8842
8843 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8844 if (pixel != -1)
8845 {
8846 XtSetArg (av[ac], XmNforeground, pixel);
8847 ++ac;
8848 }
7d0393cf 8849
06a2c219
GM
8850 pixel = f->output_data.x->scroll_bar_background_pixel;
8851 if (pixel != -1)
8852 {
8853 XtSetArg (av[ac], XmNbackground, pixel);
8854 ++ac;
8855 }
7d0393cf 8856
06a2c219
GM
8857 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
8858 scroll_bar_name, av, ac);
8859
8860 /* Add one callback for everything that can happen. */
8861 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
8862 (XtPointer) bar);
8863 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
8864 (XtPointer) bar);
8865 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
8866 (XtPointer) bar);
8867 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
8868 (XtPointer) bar);
8869 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
8870 (XtPointer) bar);
8871 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
8872 (XtPointer) bar);
8873 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
8874 (XtPointer) bar);
7d0393cf 8875
06a2c219
GM
8876 /* Realize the widget. Only after that is the X window created. */
8877 XtRealizeWidget (widget);
8878
8879 /* Set the cursor to an arrow. I didn't find a resource to do that.
8880 And I'm wondering why it hasn't an arrow cursor by default. */
8881 XDefineCursor (XtDisplay (widget), XtWindow (widget),
8882 f->output_data.x->nontext_cursor);
7d0393cf 8883
ec18280f 8884#else /* !USE_MOTIF i.e. use Xaw */
7d0393cf 8885
06a2c219
GM
8886 /* Set resources. Create the widget. The background of the
8887 Xaw3d scroll bar widget is a little bit light for my taste.
8888 We don't alter it here to let users change it according
8889 to their taste with `emacs*verticalScrollBar.background: xxx'. */
8890 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8891 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
8892 /* For smoother scrolling with Xaw3d -sm */
8893 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
7d0393cf 8894
06a2c219
GM
8895 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8896 if (pixel != -1)
8897 {
8898 XtSetArg (av[ac], XtNforeground, pixel);
8899 ++ac;
8900 }
7d0393cf 8901
06a2c219
GM
8902 pixel = f->output_data.x->scroll_bar_background_pixel;
8903 if (pixel != -1)
8904 {
8905 XtSetArg (av[ac], XtNbackground, pixel);
8906 ++ac;
8907 }
7c1bef7a
MB
8908
8909 /* Top/bottom shadow colors. */
8910
8911 /* Allocate them, if necessary. */
8912 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
8913 {
8914 pixel = f->output_data.x->scroll_bar_background_pixel;
8915 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8916 &pixel, 1.2, 0x8000))
8917 pixel = -1;
8918 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
8919 }
8920 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8921 {
8922 pixel = f->output_data.x->scroll_bar_background_pixel;
8923 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8924 &pixel, 0.6, 0x4000))
8925 pixel = -1;
8926 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
8927 }
8928
8929 /* Tell the toolkit about them. */
8930 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
8931 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8932 /* We tried to allocate a color for the top/bottom shadow, and
8933 failed, so tell Xaw3d to use dithering instead. */
8934 {
8935 XtSetArg (av[ac], XtNbeNiceToColormap, True);
8936 ++ac;
8937 }
8938 else
8939 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
8940 be more consistent with other emacs 3d colors, and since Xaw3d is
8941 not good at dealing with allocation failure. */
8942 {
8943 /* This tells Xaw3d to use real colors instead of dithering for
8944 the shadows. */
8945 XtSetArg (av[ac], XtNbeNiceToColormap, False);
8946 ++ac;
8947
8948 /* Specify the colors. */
8949 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
8950 if (pixel != -1)
8951 {
8952 XtSetArg (av[ac], "topShadowPixel", pixel);
8953 ++ac;
8954 }
8955 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
8956 if (pixel != -1)
8957 {
8958 XtSetArg (av[ac], "bottomShadowPixel", pixel);
8959 ++ac;
8960 }
8961 }
8962
06a2c219
GM
8963 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
8964 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
8965
8966 {
8967 char *initial = "";
8968 char *val = initial;
8969 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
8970 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
8971 if (val == initial)
8972 { /* ARROW_SCROLL */
8973 xaw3d_arrow_scroll = True;
8974 /* Isn't that just a personal preference ? -sm */
8975 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
8976 }
8977 }
7d0393cf 8978
06a2c219 8979 /* Define callbacks. */
ec18280f
SM
8980 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
8981 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219 8982 (XtPointer) bar);
7d0393cf 8983
06a2c219
GM
8984 /* Realize the widget. Only after that is the X window created. */
8985 XtRealizeWidget (widget);
7d0393cf 8986
ec18280f 8987#endif /* !USE_MOTIF */
06a2c219 8988
2a51c026 8989 /* Install an action hook that lets us detect when the user
06a2c219
GM
8990 finishes interacting with a scroll bar. */
8991 if (action_hook_id == 0)
8992 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
7d0393cf 8993
06a2c219
GM
8994 /* Remember X window and widget in the scroll bar vector. */
8995 SET_SCROLL_BAR_X_WIDGET (bar, widget);
8996 xwindow = XtWindow (widget);
8997 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
8998
8999 UNBLOCK_INPUT;
9000}
9001
9002
9003/* Set the thumb size and position of scroll bar BAR. We are currently
9004 displaying PORTION out of a whole WHOLE, and our position POSITION. */
9005
9006static void
9007x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
9008 struct scroll_bar *bar;
9009 int portion, position, whole;
f451eb13 9010{
e83dc917
GM
9011 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
9012 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
06a2c219 9013 float top, shown;
f451eb13 9014
6f2a7a68
SM
9015 BLOCK_INPUT;
9016
9017#ifdef USE_MOTIF
9018
9019 /* We use an estimate of 30 chars per line rather than the real
9020 `portion' value. This has the disadvantage that the thumb size
9021 is not very representative, but it makes our life a lot easier.
9022 Otherwise, we have to constantly adjust the thumb size, which
9023 we can't always do quickly enough: while dragging, the size of
9024 the thumb might prevent the user from dragging the thumb all the
9025 way to the end. but Motif and some versions of Xaw3d don't allow
9026 updating the thumb size while dragging. Also, even if we can update
9027 its size, the update will often happen too late.
9028 If you don't believe it, check out revision 1.650 of xterm.c to see
9029 what hoops we were going through and the still poor behavior we got. */
9030 portion = XFASTINT (XWINDOW (bar->window)->height) * 30;
9031 /* When the thumb is at the bottom, position == whole.
9032 So we need to increase `whole' to make space for the thumb. */
9033 whole += portion;
9034
9035 if (whole <= 0)
06a2c219
GM
9036 top = 0, shown = 1;
9037 else
f451eb13 9038 {
06a2c219
GM
9039 top = (float) position / whole;
9040 shown = (float) portion / whole;
9041 }
f451eb13 9042
6f2a7a68
SM
9043 if (NILP (bar->dragging))
9044 {
9045 int size, value;
06a2c219 9046
6f2a7a68
SM
9047 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
9048 is the scroll bar's maximum and MIN is the scroll bar's minimum
9049 value. */
9050 size = shown * XM_SB_RANGE;
9051 size = min (size, XM_SB_RANGE);
9052 size = max (size, 1);
06a2c219 9053
6f2a7a68
SM
9054 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
9055 value = top * XM_SB_RANGE;
9056 value = min (value, XM_SB_MAX - size);
9057 value = max (value, XM_SB_MIN);
7d0393cf 9058
06a2c219 9059 XmScrollBarSetValues (widget, value, size, 0, 0, False);
6f2a7a68 9060 }
ec18280f 9061#else /* !USE_MOTIF i.e. use Xaw */
6f2a7a68
SM
9062
9063 if (whole == 0)
9064 top = 0, shown = 1;
9065 else
9066 {
9067 top = (float) position / whole;
9068 shown = (float) portion / whole;
9069 }
9070
06a2c219 9071 {
ec18280f
SM
9072 float old_top, old_shown;
9073 Dimension height;
9074 XtVaGetValues (widget,
9075 XtNtopOfThumb, &old_top,
9076 XtNshown, &old_shown,
9077 XtNheight, &height,
9078 NULL);
9079
9080 /* Massage the top+shown values. */
9081 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
9082 top = max (0, min (1, top));
9083 else
9084 top = old_top;
9085 /* Keep two pixels available for moving the thumb down. */
9086 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
9087
9088 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
9089 check that your system's configuration file contains a define
9090 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 9091 if (top != old_top || shown != old_shown)
eb393530 9092 {
ec18280f 9093 if (NILP (bar->dragging))
eb393530 9094 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
9095 else
9096 {
ec18280f
SM
9097#ifdef HAVE_XAW3D
9098 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 9099 int scroll_mode = 0;
7d0393cf 9100
ec18280f
SM
9101 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
9102 if (xaw3d_arrow_scroll)
9103 {
9104 /* Xaw3d stupidly ignores resize requests while dragging
9105 so we have to make it believe it's not in dragging mode. */
9106 scroll_mode = sb->scrollbar.scroll_mode;
9107 if (scroll_mode == 2)
9108 sb->scrollbar.scroll_mode = 0;
9109 }
9110#endif
9111 /* Try to make the scrolling a tad smoother. */
9112 if (!xaw3d_pick_top)
9113 shown = min (shown, old_shown);
7d0393cf 9114
ec18280f 9115 XawScrollbarSetThumb (widget, top, shown);
7d0393cf 9116
ec18280f
SM
9117#ifdef HAVE_XAW3D
9118 if (xaw3d_arrow_scroll && scroll_mode == 2)
9119 sb->scrollbar.scroll_mode = scroll_mode;
9120#endif
06a2c219 9121 }
06a2c219
GM
9122 }
9123 }
ec18280f 9124#endif /* !USE_MOTIF */
06a2c219
GM
9125
9126 UNBLOCK_INPUT;
f451eb13
JB
9127}
9128
06a2c219
GM
9129#endif /* USE_TOOLKIT_SCROLL_BARS */
9130
9131
9132\f
9133/************************************************************************
9134 Scroll bars, general
9135 ************************************************************************/
7d0393cf 9136
06a2c219
GM
9137/* Create a scroll bar and return the scroll bar vector for it. W is
9138 the Emacs window on which to create the scroll bar. TOP, LEFT,
f7ccf929 9139 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
06a2c219
GM
9140 scroll bar. */
9141
ab648270 9142static struct scroll_bar *
06a2c219
GM
9143x_scroll_bar_create (w, top, left, width, height)
9144 struct window *w;
f451eb13
JB
9145 int top, left, width, height;
9146{
06a2c219 9147 struct frame *f = XFRAME (w->frame);
334208b7
RS
9148 struct scroll_bar *bar
9149 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
9150
9151 BLOCK_INPUT;
9152
eccc05db 9153#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
9154 x_create_toolkit_scroll_bar (f, bar);
9155#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9156 {
9157 XSetWindowAttributes a;
9158 unsigned long mask;
5c187dee 9159 Window window;
06a2c219
GM
9160
9161 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
9162 if (a.background_pixel == -1)
9163 a.background_pixel = f->output_data.x->background_pixel;
7d0393cf 9164
12ba150f 9165 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 9166 | ButtonMotionMask | PointerMotionHintMask
12ba150f 9167 | ExposureMask);
7a13e894 9168 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 9169
dbc4e1c1 9170 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 9171
06a2c219
GM
9172 /* Clear the area of W that will serve as a scroll bar. This is
9173 for the case that a window has been split horizontally. In
9174 this case, no clear_frame is generated to reduce flickering. */
7b49b9d2
GM
9175 if (width > 0 && height > 0)
9176 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9177 left, top, width,
9178 window_box_height (w), False);
06a2c219
GM
9179
9180 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9181 /* Position and size of scroll bar. */
9182 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9183 top,
9184 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
9185 height,
9186 /* Border width, depth, class, and visual. */
9187 0,
9188 CopyFromParent,
9189 CopyFromParent,
9190 CopyFromParent,
9191 /* Attributes. */
9192 mask, &a);
9193 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 9194 }
06a2c219 9195#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9196
06a2c219 9197 XSETWINDOW (bar->window, w);
e0c1aef2
KH
9198 XSETINT (bar->top, top);
9199 XSETINT (bar->left, left);
9200 XSETINT (bar->width, width);
9201 XSETINT (bar->height, height);
9202 XSETINT (bar->start, 0);
9203 XSETINT (bar->end, 0);
12ba150f 9204 bar->dragging = Qnil;
f451eb13
JB
9205
9206 /* Add bar to its frame's list of scroll bars. */
334208b7 9207 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 9208 bar->prev = Qnil;
334208b7 9209 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 9210 if (!NILP (bar->next))
e0c1aef2 9211 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 9212
06a2c219 9213 /* Map the window/widget. */
eccc05db 9214#ifdef USE_TOOLKIT_SCROLL_BARS
f964b4d7
GM
9215 {
9216 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
9217 XtConfigureWidget (scroll_bar,
9218 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9219 top,
9220 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
9221 max (height, 1), 0);
9222 XtMapWidget (scroll_bar);
9223 }
06a2c219 9224#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 9225 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 9226#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9227
9228 UNBLOCK_INPUT;
12ba150f 9229 return bar;
f451eb13
JB
9230}
9231
06a2c219 9232
12ba150f 9233/* Draw BAR's handle in the proper position.
7d0393cf 9234
12ba150f
JB
9235 If the handle is already drawn from START to END, don't bother
9236 redrawing it, unless REBUILD is non-zero; in that case, always
9237 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 9238 events.)
12ba150f
JB
9239
9240 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
9241 fit inside its rectangle, but if the user is dragging the scroll
9242 bar handle, we want to let them drag it down all the way, so that
9243 the bar's top is as far down as it goes; otherwise, there's no way
9244 to move to the very end of the buffer. */
9245
5c187dee
GM
9246#ifndef USE_TOOLKIT_SCROLL_BARS
9247
f451eb13 9248static void
ab648270
JB
9249x_scroll_bar_set_handle (bar, start, end, rebuild)
9250 struct scroll_bar *bar;
f451eb13 9251 int start, end;
12ba150f 9252 int rebuild;
f451eb13 9253{
12ba150f 9254 int dragging = ! NILP (bar->dragging);
ab648270 9255 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9256 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9257 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
9258
9259 /* If the display is already accurate, do nothing. */
9260 if (! rebuild
9261 && start == XINT (bar->start)
9262 && end == XINT (bar->end))
9263 return;
9264
f451eb13
JB
9265 BLOCK_INPUT;
9266
9267 {
d9cdbb3d
RS
9268 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
9269 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
9270 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
9271
9272 /* Make sure the values are reasonable, and try to preserve
9273 the distance between start and end. */
12ba150f
JB
9274 {
9275 int length = end - start;
9276
9277 if (start < 0)
9278 start = 0;
9279 else if (start > top_range)
9280 start = top_range;
9281 end = start + length;
9282
9283 if (end < start)
9284 end = start;
9285 else if (end > top_range && ! dragging)
9286 end = top_range;
9287 }
f451eb13 9288
ab648270 9289 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
9290 XSETINT (bar->start, start);
9291 XSETINT (bar->end, end);
f451eb13 9292
12ba150f
JB
9293 /* Clip the end position, just for display. */
9294 if (end > top_range)
9295 end = top_range;
f451eb13 9296
ab648270 9297 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
9298 below top positions, to make sure the handle is always at least
9299 that many pixels tall. */
ab648270 9300 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 9301
12ba150f
JB
9302 /* Draw the empty space above the handle. Note that we can't clear
9303 zero-height areas; that means "clear to end of window." */
9304 if (0 < start)
c5e6e06b
GM
9305 x_clear_area (FRAME_X_DISPLAY (f), w,
9306 /* x, y, width, height, and exposures. */
9307 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9308 VERTICAL_SCROLL_BAR_TOP_BORDER,
9309 inside_width, start,
9310 False);
f451eb13 9311
06a2c219
GM
9312 /* Change to proper foreground color if one is specified. */
9313 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9314 XSetForeground (FRAME_X_DISPLAY (f), gc,
9315 f->output_data.x->scroll_bar_foreground_pixel);
9316
12ba150f 9317 /* Draw the handle itself. */
334208b7 9318 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
12ba150f 9319 /* x, y, width, height */
ab648270
JB
9320 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9321 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 9322 inside_width, end - start);
f451eb13 9323
06a2c219
GM
9324 /* Restore the foreground color of the GC if we changed it above. */
9325 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9326 XSetForeground (FRAME_X_DISPLAY (f), gc,
9327 f->output_data.x->foreground_pixel);
f451eb13 9328
12ba150f
JB
9329 /* Draw the empty space below the handle. Note that we can't
9330 clear zero-height areas; that means "clear to end of window." */
9331 if (end < inside_height)
c5e6e06b
GM
9332 x_clear_area (FRAME_X_DISPLAY (f), w,
9333 /* x, y, width, height, and exposures. */
9334 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9335 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
9336 inside_width, inside_height - end,
9337 False);
f451eb13 9338
f451eb13
JB
9339 }
9340
f451eb13
JB
9341 UNBLOCK_INPUT;
9342}
9343
5c187dee 9344#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 9345
06a2c219
GM
9346/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
9347 nil. */
58769bee 9348
12ba150f 9349static void
ab648270
JB
9350x_scroll_bar_remove (bar)
9351 struct scroll_bar *bar;
12ba150f 9352{
e83dc917 9353 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
9354 BLOCK_INPUT;
9355
eccc05db 9356#ifdef USE_TOOLKIT_SCROLL_BARS
e83dc917
GM
9357 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
9358#else
9359 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
9360#endif
7d0393cf 9361
ab648270
JB
9362 /* Disassociate this scroll bar from its window. */
9363 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
9364
9365 UNBLOCK_INPUT;
9366}
9367
06a2c219 9368
12ba150f
JB
9369/* Set the handle of the vertical scroll bar for WINDOW to indicate
9370 that we are displaying PORTION characters out of a total of WHOLE
ab648270 9371 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 9372 create one. */
06a2c219 9373
12ba150f 9374static void
06a2c219
GM
9375XTset_vertical_scroll_bar (w, portion, whole, position)
9376 struct window *w;
f451eb13
JB
9377 int portion, whole, position;
9378{
06a2c219 9379 struct frame *f = XFRAME (w->frame);
ab648270 9380 struct scroll_bar *bar;
3c6ede7b 9381 int top, height, left, sb_left, width, sb_width;
06a2c219 9382 int window_x, window_y, window_width, window_height;
06a2c219 9383
3c6ede7b 9384 /* Get window dimensions. */
06a2c219 9385 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
9386 top = window_y;
9387 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9388 height = window_height;
06a2c219 9389
3c6ede7b 9390 /* Compute the left edge of the scroll bar area. */
06a2c219 9391 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
9392 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
9393 else
9394 left = XFASTINT (w->left);
9395 left *= CANON_X_UNIT (f);
9396 left += FRAME_INTERNAL_BORDER_WIDTH (f);
9397
9398 /* Compute the width of the scroll bar which might be less than
9399 the width of the area reserved for the scroll bar. */
9400 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
9401 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 9402 else
3c6ede7b 9403 sb_width = width;
12ba150f 9404
3c6ede7b
GM
9405 /* Compute the left edge of the scroll bar. */
9406#ifdef USE_TOOLKIT_SCROLL_BARS
9407 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
7d0393cf 9408 sb_left = left + width - sb_width - (width - sb_width) / 2;
3c6ede7b
GM
9409 else
9410 sb_left = left + (width - sb_width) / 2;
9411#else
9412 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
7d0393cf 9413 sb_left = left + width - sb_width;
3c6ede7b
GM
9414 else
9415 sb_left = left;
9416#endif
7d0393cf 9417
ab648270 9418 /* Does the scroll bar exist yet? */
06a2c219 9419 if (NILP (w->vertical_scroll_bar))
3c6ede7b 9420 {
7b49b9d2 9421 if (width > 0 && height > 0)
b547b6e8
GM
9422 {
9423 BLOCK_INPUT;
9424 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9425 left, top, width, height, False);
9426 UNBLOCK_INPUT;
9427 }
7d0393cf 9428
3c6ede7b
GM
9429 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
9430 }
f451eb13 9431 else
12ba150f
JB
9432 {
9433 /* It may just need to be moved and resized. */
06a2c219 9434 unsigned int mask = 0;
7d0393cf 9435
06a2c219
GM
9436 bar = XSCROLL_BAR (w->vertical_scroll_bar);
9437
9438 BLOCK_INPUT;
9439
3c6ede7b 9440 if (sb_left != XINT (bar->left))
06a2c219 9441 mask |= CWX;
3c6ede7b 9442 if (top != XINT (bar->top))
06a2c219 9443 mask |= CWY;
3c6ede7b 9444 if (sb_width != XINT (bar->width))
06a2c219 9445 mask |= CWWidth;
7d0393cf 9446 if (height != XINT (bar->height))
06a2c219 9447 mask |= CWHeight;
7d0393cf 9448
06a2c219 9449#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
9450
9451 /* Since toolkit scroll bars are smaller than the space reserved
9452 for them on the frame, we have to clear "under" them. */
7b49b9d2 9453 if (width > 0 && height > 0)
f964b4d7
GM
9454 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9455 left, top, width, height, False);
06a2c219
GM
9456
9457 /* Move/size the scroll bar widget. */
9458 if (mask)
e83dc917 9459 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
3c6ede7b
GM
9460 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9461 top,
9462 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
f964b4d7 9463 max (height, 1), 0);
06a2c219
GM
9464
9465#else /* not USE_TOOLKIT_SCROLL_BARS */
7d0393cf 9466
357e7376
GM
9467 /* Clear areas not covered by the scroll bar because of
9468 VERTICAL_SCROLL_BAR_WIDTH_TRIM. */
e1f6572f
RS
9469 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
9470 {
c5e6e06b
GM
9471 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9472 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9473 height, False);
9474 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9475 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9476 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9477 height, False);
e1f6572f 9478 }
357e7376
GM
9479
9480 /* Clear areas not covered by the scroll bar because it's not as
f7ccf929 9481 wide as the area reserved for it. This makes sure a
357e7376
GM
9482 previous mode line display is cleared after C-x 2 C-x 1, for
9483 example. */
9484 {
9485 int area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9486 int rest = area_width - sb_width;
38d2af0c
GM
9487 if (rest > 0 && height > 0)
9488 {
9489 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
9490 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9491 left + area_width - rest, top,
9492 rest, height, False);
9493 else
9494 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9495 left, top, rest, height, False);
9496 }
357e7376 9497 }
7d0393cf 9498
06a2c219
GM
9499 /* Move/size the scroll bar window. */
9500 if (mask)
9501 {
9502 XWindowChanges wc;
7d0393cf 9503
3c6ede7b
GM
9504 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
9505 wc.y = top;
9506 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
9507 wc.height = height;
06a2c219
GM
9508 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
9509 mask, &wc);
9510 }
7d0393cf 9511
06a2c219
GM
9512#endif /* not USE_TOOLKIT_SCROLL_BARS */
9513
9514 /* Remember new settings. */
3c6ede7b
GM
9515 XSETINT (bar->left, sb_left);
9516 XSETINT (bar->top, top);
9517 XSETINT (bar->width, sb_width);
9518 XSETINT (bar->height, height);
7d0393cf 9519
06a2c219 9520 UNBLOCK_INPUT;
12ba150f 9521 }
f451eb13 9522
eccc05db 9523#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
9524 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
9525#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 9526 /* Set the scroll bar's current state, unless we're currently being
f451eb13 9527 dragged. */
12ba150f 9528 if (NILP (bar->dragging))
f451eb13 9529 {
92857db0 9530 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 9531
12ba150f 9532 if (whole == 0)
ab648270 9533 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
9534 else
9535 {
43f868f5
JB
9536 int start = ((double) position * top_range) / whole;
9537 int end = ((double) (position + portion) * top_range) / whole;
ab648270 9538 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 9539 }
f451eb13 9540 }
06a2c219 9541#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9542
06a2c219 9543 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
9544}
9545
12ba150f 9546
f451eb13 9547/* The following three hooks are used when we're doing a thorough
ab648270 9548 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 9549 are going to be deleted, because keeping track of when windows go
12ba150f
JB
9550 away is a real pain - "Can you say set-window-configuration, boys
9551 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 9552 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 9553 from the fiery pit when we actually redisplay its window. */
f451eb13 9554
ab648270
JB
9555/* Arrange for all scroll bars on FRAME to be removed at the next call
9556 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
9557 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
9558
58769bee 9559static void
ab648270 9560XTcondemn_scroll_bars (frame)
f451eb13
JB
9561 FRAME_PTR frame;
9562{
f9e24cb9
RS
9563 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
9564 while (! NILP (FRAME_SCROLL_BARS (frame)))
9565 {
9566 Lisp_Object bar;
9567 bar = FRAME_SCROLL_BARS (frame);
9568 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
9569 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
9570 XSCROLL_BAR (bar)->prev = Qnil;
9571 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
9572 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
9573 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
9574 }
f451eb13
JB
9575}
9576
fa2dfc30 9577
06a2c219 9578/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 9579 Note that WINDOW isn't necessarily condemned at all. */
fa2dfc30 9580
f451eb13 9581static void
ab648270 9582XTredeem_scroll_bar (window)
12ba150f 9583 struct window *window;
f451eb13 9584{
ab648270 9585 struct scroll_bar *bar;
fa2dfc30 9586 struct frame *f;
12ba150f 9587
ab648270
JB
9588 /* We can't redeem this window's scroll bar if it doesn't have one. */
9589 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
9590 abort ();
9591
ab648270 9592 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
9593
9594 /* Unlink it from the condemned list. */
fa2dfc30
GM
9595 f = XFRAME (WINDOW_FRAME (window));
9596 if (NILP (bar->prev))
9597 {
9598 /* If the prev pointer is nil, it must be the first in one of
9599 the lists. */
9600 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
9601 /* It's not condemned. Everything's fine. */
9602 return;
9603 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
9604 window->vertical_scroll_bar))
9605 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
9606 else
9607 /* If its prev pointer is nil, it must be at the front of
9608 one or the other! */
9609 abort ();
9610 }
9611 else
9612 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f 9613
fa2dfc30
GM
9614 if (! NILP (bar->next))
9615 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 9616
fa2dfc30
GM
9617 bar->next = FRAME_SCROLL_BARS (f);
9618 bar->prev = Qnil;
9619 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
9620 if (! NILP (bar->next))
9621 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13
JB
9622}
9623
ab648270
JB
9624/* Remove all scroll bars on FRAME that haven't been saved since the
9625 last call to `*condemn_scroll_bars_hook'. */
06a2c219 9626
f451eb13 9627static void
ab648270 9628XTjudge_scroll_bars (f)
12ba150f 9629 FRAME_PTR f;
f451eb13 9630{
12ba150f 9631 Lisp_Object bar, next;
f451eb13 9632
ab648270 9633 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
9634
9635 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
9636 more events on the hapless scroll bars. */
9637 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
9638
9639 for (; ! NILP (bar); bar = next)
f451eb13 9640 {
ab648270 9641 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 9642
ab648270 9643 x_scroll_bar_remove (b);
12ba150f
JB
9644
9645 next = b->next;
9646 b->next = b->prev = Qnil;
f451eb13 9647 }
12ba150f 9648
ab648270 9649 /* Now there should be no references to the condemned scroll bars,
12ba150f 9650 and they should get garbage-collected. */
f451eb13
JB
9651}
9652
9653
06a2c219
GM
9654/* Handle an Expose or GraphicsExpose event on a scroll bar. This
9655 is a no-op when using toolkit scroll bars.
ab648270
JB
9656
9657 This may be called from a signal handler, so we have to ignore GC
9658 mark bits. */
06a2c219 9659
f451eb13 9660static void
ab648270
JB
9661x_scroll_bar_expose (bar, event)
9662 struct scroll_bar *bar;
f451eb13
JB
9663 XEvent *event;
9664{
06a2c219
GM
9665#ifndef USE_TOOLKIT_SCROLL_BARS
9666
ab648270 9667 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9668 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9669 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 9670 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 9671
f451eb13
JB
9672 BLOCK_INPUT;
9673
ab648270 9674 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 9675
06a2c219 9676 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 9677 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
9678
9679 /* x, y, width, height */
d9cdbb3d 9680 0, 0,
3cbd2e0b 9681 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d 9682 XINT (bar->height) - 1);
7d0393cf 9683
f451eb13 9684 UNBLOCK_INPUT;
06a2c219
GM
9685
9686#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9687}
9688
ab648270 9689/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
3b8f9651 9690 is set to something other than NO_EVENT, it is enqueued.
ab648270
JB
9691
9692 This may be called from a signal handler, so we have to ignore GC
9693 mark bits. */
06a2c219 9694
5c187dee
GM
9695#ifndef USE_TOOLKIT_SCROLL_BARS
9696
f451eb13 9697static void
ab648270
JB
9698x_scroll_bar_handle_click (bar, event, emacs_event)
9699 struct scroll_bar *bar;
f451eb13
JB
9700 XEvent *event;
9701 struct input_event *emacs_event;
9702{
0299d313 9703 if (! GC_WINDOWP (bar->window))
12ba150f
JB
9704 abort ();
9705
3b8f9651 9706 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
69388238 9707 emacs_event->code = event->xbutton.button - Button1;
0299d313 9708 emacs_event->modifiers
7d0393cf 9709 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
0299d313
RS
9710 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
9711 event->xbutton.state)
9712 | (event->type == ButtonRelease
9713 ? up_modifier
9714 : down_modifier));
12ba150f 9715 emacs_event->frame_or_window = bar->window;
0f8aabe9 9716 emacs_event->arg = Qnil;
f451eb13 9717 emacs_event->timestamp = event->xbutton.time;
12ba150f 9718 {
06a2c219 9719#if 0
d9cdbb3d 9720 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 9721 int internal_height
d9cdbb3d 9722 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9723#endif
0299d313 9724 int top_range
d9cdbb3d 9725 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 9726 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
9727
9728 if (y < 0) y = 0;
9729 if (y > top_range) y = top_range;
9730
9731 if (y < XINT (bar->start))
ab648270
JB
9732 emacs_event->part = scroll_bar_above_handle;
9733 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9734 emacs_event->part = scroll_bar_handle;
12ba150f 9735 else
ab648270 9736 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
9737
9738 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
9739 they want to drag it. Lisp code needs to be able to decide
9740 whether or not we're dragging. */
929787e1 9741#if 0
12ba150f
JB
9742 /* If the user has just clicked on the handle, record where they're
9743 holding it. */
9744 if (event->type == ButtonPress
ab648270 9745 && emacs_event->part == scroll_bar_handle)
e0c1aef2 9746 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 9747#endif
12ba150f
JB
9748
9749 /* If the user has released the handle, set it to its final position. */
9750 if (event->type == ButtonRelease
9751 && ! NILP (bar->dragging))
9752 {
9753 int new_start = y - XINT (bar->dragging);
9754 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 9755
ab648270 9756 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
9757 bar->dragging = Qnil;
9758 }
f451eb13 9759
5116f055
JB
9760 /* Same deal here as the other #if 0. */
9761#if 0
58769bee 9762 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 9763 the handle. */
ab648270 9764 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
9765 emacs_event->x = bar->start;
9766 else
e0c1aef2 9767 XSETINT (emacs_event->x, y);
5116f055 9768#else
e0c1aef2 9769 XSETINT (emacs_event->x, y);
5116f055 9770#endif
f451eb13 9771
e0c1aef2 9772 XSETINT (emacs_event->y, top_range);
12ba150f
JB
9773 }
9774}
f451eb13 9775
ab648270
JB
9776/* Handle some mouse motion while someone is dragging the scroll bar.
9777
9778 This may be called from a signal handler, so we have to ignore GC
9779 mark bits. */
06a2c219 9780
f451eb13 9781static void
ab648270
JB
9782x_scroll_bar_note_movement (bar, event)
9783 struct scroll_bar *bar;
f451eb13
JB
9784 XEvent *event;
9785{
39d8bb4d
KH
9786 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
9787
f451eb13
JB
9788 last_mouse_movement_time = event->xmotion.time;
9789
39d8bb4d 9790 f->mouse_moved = 1;
e0c1aef2 9791 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
9792
9793 /* If we're dragging the bar, display it. */
ab648270 9794 if (! GC_NILP (bar->dragging))
f451eb13
JB
9795 {
9796 /* Where should the handle be now? */
12ba150f 9797 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 9798
12ba150f 9799 if (new_start != XINT (bar->start))
f451eb13 9800 {
12ba150f 9801 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 9802
ab648270 9803 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
9804 }
9805 }
f451eb13
JB
9806}
9807
5c187dee
GM
9808#endif /* !USE_TOOLKIT_SCROLL_BARS */
9809
12ba150f 9810/* Return information to the user about the current position of the mouse
ab648270 9811 on the scroll bar. */
06a2c219 9812
12ba150f 9813static void
334208b7
RS
9814x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
9815 FRAME_PTR *fp;
12ba150f 9816 Lisp_Object *bar_window;
ab648270 9817 enum scroll_bar_part *part;
12ba150f
JB
9818 Lisp_Object *x, *y;
9819 unsigned long *time;
9820{
ab648270 9821 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
9822 Window w = SCROLL_BAR_X_WINDOW (bar);
9823 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 9824 int win_x, win_y;
559cb2fb
JB
9825 Window dummy_window;
9826 int dummy_coord;
9827 unsigned int dummy_mask;
12ba150f 9828
cf7cb199
JB
9829 BLOCK_INPUT;
9830
ab648270 9831 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 9832 report that. */
334208b7 9833 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 9834
559cb2fb
JB
9835 /* Root, child, root x and root y. */
9836 &dummy_window, &dummy_window,
9837 &dummy_coord, &dummy_coord,
12ba150f 9838
559cb2fb
JB
9839 /* Position relative to scroll bar. */
9840 &win_x, &win_y,
12ba150f 9841
559cb2fb
JB
9842 /* Mouse buttons and modifier keys. */
9843 &dummy_mask))
7a13e894 9844 ;
559cb2fb
JB
9845 else
9846 {
06a2c219 9847#if 0
559cb2fb 9848 int inside_height
d9cdbb3d 9849 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9850#endif
559cb2fb 9851 int top_range
d9cdbb3d 9852 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
9853
9854 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
9855
9856 if (! NILP (bar->dragging))
9857 win_y -= XINT (bar->dragging);
9858
9859 if (win_y < 0)
9860 win_y = 0;
9861 if (win_y > top_range)
9862 win_y = top_range;
9863
334208b7 9864 *fp = f;
7a13e894 9865 *bar_window = bar->window;
559cb2fb
JB
9866
9867 if (! NILP (bar->dragging))
9868 *part = scroll_bar_handle;
9869 else if (win_y < XINT (bar->start))
9870 *part = scroll_bar_above_handle;
9871 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9872 *part = scroll_bar_handle;
9873 else
9874 *part = scroll_bar_below_handle;
12ba150f 9875
e0c1aef2
KH
9876 XSETINT (*x, win_y);
9877 XSETINT (*y, top_range);
12ba150f 9878
39d8bb4d 9879 f->mouse_moved = 0;
559cb2fb
JB
9880 last_mouse_scroll_bar = Qnil;
9881 }
12ba150f 9882
559cb2fb 9883 *time = last_mouse_movement_time;
cf7cb199 9884
cf7cb199 9885 UNBLOCK_INPUT;
12ba150f
JB
9886}
9887
f451eb13 9888
dbc4e1c1 9889/* The screen has been cleared so we may have changed foreground or
ab648270
JB
9890 background colors, and the scroll bars may need to be redrawn.
9891 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
9892 redraw them. */
9893
dfcf069d 9894void
ab648270 9895x_scroll_bar_clear (f)
dbc4e1c1
JB
9896 FRAME_PTR f;
9897{
06a2c219 9898#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
9899 Lisp_Object bar;
9900
b80c363e
RS
9901 /* We can have scroll bars even if this is 0,
9902 if we just turned off scroll bar mode.
9903 But in that case we should not clear them. */
9904 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
9905 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
9906 bar = XSCROLL_BAR (bar)->next)
c5e6e06b
GM
9907 XClearArea (FRAME_X_DISPLAY (f),
9908 SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
b80c363e 9909 0, 0, 0, 0, True);
06a2c219 9910#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
9911}
9912
06a2c219 9913/* This processes Expose events from the menu-bar specific X event
19126e11 9914 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 9915 when handling menu-bar or pop-up items. */
3afe33e7 9916
06a2c219 9917int
3afe33e7
RS
9918process_expose_from_menu (event)
9919 XEvent event;
9920{
9921 FRAME_PTR f;
19126e11 9922 struct x_display_info *dpyinfo;
06a2c219 9923 int frame_exposed_p = 0;
3afe33e7 9924
f94397b5
KH
9925 BLOCK_INPUT;
9926
19126e11
KH
9927 dpyinfo = x_display_info_for_display (event.xexpose.display);
9928 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
9929 if (f)
9930 {
9931 if (f->async_visible == 0)
9932 {
9933 f->async_visible = 1;
9934 f->async_iconified = 0;
06c488fd 9935 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
9936 SET_FRAME_GARBAGED (f);
9937 }
9938 else
9939 {
06a2c219
GM
9940 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
9941 event.xexpose.x, event.xexpose.y,
9942 event.xexpose.width, event.xexpose.height);
9943 frame_exposed_p = 1;
3afe33e7
RS
9944 }
9945 }
9946 else
9947 {
9948 struct scroll_bar *bar
9949 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9950
3afe33e7
RS
9951 if (bar)
9952 x_scroll_bar_expose (bar, &event);
9953 }
f94397b5
KH
9954
9955 UNBLOCK_INPUT;
06a2c219 9956 return frame_exposed_p;
3afe33e7 9957}
09756a85
RS
9958\f
9959/* Define a queue to save up SelectionRequest events for later handling. */
9960
9961struct selection_event_queue
9962 {
9963 XEvent event;
9964 struct selection_event_queue *next;
9965 };
9966
9967static struct selection_event_queue *queue;
9968
9969/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 9970
09756a85
RS
9971static int x_queue_selection_requests;
9972
9973/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 9974
09756a85 9975static void
334208b7
RS
9976x_queue_event (f, event)
9977 FRAME_PTR f;
09756a85
RS
9978 XEvent *event;
9979{
9980 struct selection_event_queue *queue_tmp
06a2c219 9981 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 9982
58769bee 9983 if (queue_tmp != NULL)
09756a85
RS
9984 {
9985 queue_tmp->event = *event;
9986 queue_tmp->next = queue;
9987 queue = queue_tmp;
9988 }
9989}
9990
9991/* Take all the queued events and put them back
9992 so that they get processed afresh. */
9993
9994static void
db3906fd
RS
9995x_unqueue_events (display)
9996 Display *display;
09756a85 9997{
58769bee 9998 while (queue != NULL)
09756a85
RS
9999 {
10000 struct selection_event_queue *queue_tmp = queue;
db3906fd 10001 XPutBackEvent (display, &queue_tmp->event);
09756a85 10002 queue = queue_tmp->next;
06a2c219 10003 xfree ((char *)queue_tmp);
09756a85
RS
10004 }
10005}
10006
10007/* Start queuing SelectionRequest events. */
10008
10009void
db3906fd
RS
10010x_start_queuing_selection_requests (display)
10011 Display *display;
09756a85
RS
10012{
10013 x_queue_selection_requests++;
10014}
10015
10016/* Stop queuing SelectionRequest events. */
10017
10018void
db3906fd
RS
10019x_stop_queuing_selection_requests (display)
10020 Display *display;
09756a85
RS
10021{
10022 x_queue_selection_requests--;
db3906fd 10023 x_unqueue_events (display);
09756a85 10024}
f451eb13
JB
10025\f
10026/* The main X event-reading loop - XTread_socket. */
dc6f92b8 10027
042c33d3 10028#if 0
06a2c219 10029/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
10030 but we have to put it out here, since static variables within functions
10031 sometimes don't work. */
06a2c219 10032
dc6f92b8 10033static Time enter_timestamp;
042c33d3 10034#endif
dc6f92b8 10035
11edeb03 10036/* This holds the state XLookupString needs to implement dead keys
58769bee 10037 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
10038 says that a portable program can't use this, but Stephen Gildea assures
10039 me that letting the compiler initialize it to zeros will work okay.
10040
10041 This must be defined outside of XTread_socket, for the same reasons
f7d40b3b 10042 given for enter_timestamp, above. */
06a2c219 10043
11edeb03
JB
10044static XComposeStatus compose_status;
10045
10e6549c
RS
10046/* Record the last 100 characters stored
10047 to help debug the loss-of-chars-during-GC problem. */
06a2c219 10048
2224b905
RS
10049static int temp_index;
10050static short temp_buffer[100];
10e6549c 10051
7a13e894
RS
10052/* Set this to nonzero to fake an "X I/O error"
10053 on a particular display. */
06a2c219 10054
7a13e894
RS
10055struct x_display_info *XTread_socket_fake_io_error;
10056
2224b905
RS
10057/* When we find no input here, we occasionally do a no-op command
10058 to verify that the X server is still running and we can still talk with it.
10059 We try all the open displays, one by one.
10060 This variable is used for cycling thru the displays. */
06a2c219 10061
2224b905
RS
10062static struct x_display_info *next_noop_dpyinfo;
10063
06a2c219
GM
10064#define SET_SAVED_MENU_EVENT(size) \
10065 do \
10066 { \
10067 if (f->output_data.x->saved_menu_event == 0) \
10068 f->output_data.x->saved_menu_event \
10069 = (XEvent *) xmalloc (sizeof (XEvent)); \
10070 bcopy (&event, f->output_data.x->saved_menu_event, size); \
10071 if (numchars >= 1) \
10072 { \
3b8f9651 10073 bufp->kind = MENU_BAR_ACTIVATE_EVENT; \
06a2c219 10074 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 10075 bufp->arg = Qnil; \
06a2c219
GM
10076 bufp++; \
10077 count++; \
10078 numchars--; \
10079 } \
10080 } \
10081 while (0)
10082
8805890a 10083#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 10084#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 10085
dc6f92b8
JB
10086/* Read events coming from the X server.
10087 This routine is called by the SIGIO handler.
10088 We return as soon as there are no more events to be read.
10089
10090 Events representing keys are stored in buffer BUFP,
10091 which can hold up to NUMCHARS characters.
10092 We return the number of characters stored into the buffer,
10093 thus pretending to be `read'.
10094
dc6f92b8
JB
10095 EXPECTED is nonzero if the caller knows input is available. */
10096
6f2a7a68 10097static int
f66868ba 10098XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 10099 register int sd;
8805890a
KH
10100 /* register */ struct input_event *bufp;
10101 /* register */ int numchars;
dc6f92b8
JB
10102 int expected;
10103{
10104 int count = 0;
10105 int nbytes = 0;
dc6f92b8 10106 XEvent event;
f676886a 10107 struct frame *f;
66f55a9d 10108 int event_found = 0;
334208b7 10109 struct x_display_info *dpyinfo;
379b5ac0 10110 struct coding_system coding;
dc6f92b8 10111
9ac0d9e0 10112 if (interrupt_input_blocked)
dc6f92b8 10113 {
9ac0d9e0 10114 interrupt_input_pending = 1;
dc6f92b8
JB
10115 return -1;
10116 }
10117
9ac0d9e0 10118 interrupt_input_pending = 0;
dc6f92b8 10119 BLOCK_INPUT;
c0a04927
RS
10120
10121 /* So people can tell when we have read the available input. */
10122 input_signal_count++;
10123
dc6f92b8 10124 if (numchars <= 0)
06a2c219 10125 abort (); /* Don't think this happens. */
dc6f92b8 10126
bde5503b 10127 ++handling_signal;
7d0393cf 10128
7a13e894
RS
10129 /* Find the display we are supposed to read input for.
10130 It's the one communicating on descriptor SD. */
10131 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
10132 {
10133#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 10134#ifdef FIOSNBIO
7a13e894
RS
10135 /* If available, Xlib uses FIOSNBIO to make the socket
10136 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 10137 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 10138 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 10139 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 10140#endif /* ! defined (FIOSNBIO) */
7a13e894 10141#endif
dc6f92b8 10142
7a13e894
RS
10143#if 0 /* This code can't be made to work, with multiple displays,
10144 and appears not to be used on any system any more.
10145 Also keyboard.c doesn't turn O_NDELAY on and off
10146 for X connections. */
dc6f92b8
JB
10147#ifndef SIGIO
10148#ifndef HAVE_SELECT
7a13e894
RS
10149 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
10150 {
10151 extern int read_alarm_should_throw;
10152 read_alarm_should_throw = 1;
10153 XPeekEvent (dpyinfo->display, &event);
10154 read_alarm_should_throw = 0;
10155 }
c118dd06
JB
10156#endif /* HAVE_SELECT */
10157#endif /* SIGIO */
7a13e894 10158#endif
dc6f92b8 10159
7a13e894
RS
10160 /* For debugging, this gives a way to fake an I/O error. */
10161 if (dpyinfo == XTread_socket_fake_io_error)
10162 {
10163 XTread_socket_fake_io_error = 0;
10164 x_io_error_quitter (dpyinfo->display);
10165 }
dc6f92b8 10166
5f30b957
JD
10167#ifdef HAVE_X_SM
10168 BLOCK_INPUT;
10169 count += x_session_check_input (bufp, &numchars);
10170 UNBLOCK_INPUT;
10171#endif
10172
06a2c219 10173 while (XPending (dpyinfo->display))
dc6f92b8 10174 {
7a13e894 10175 XNextEvent (dpyinfo->display, &event);
06a2c219 10176
531483fb 10177#ifdef HAVE_X_I18N
d1bc4182 10178 {
f2be1146
GM
10179 /* Filter events for the current X input method.
10180 XFilterEvent returns non-zero if the input method has
10181 consumed the event. We pass the frame's X window to
10182 XFilterEvent because that's the one for which the IC
10183 was created. */
f5d11644
GM
10184 struct frame *f1 = x_any_window_to_frame (dpyinfo,
10185 event.xclient.window);
10186 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
10187 break;
10188 }
0cd6403b 10189#endif
7a13e894
RS
10190 event_found = 1;
10191
10192 switch (event.type)
10193 {
10194 case ClientMessage:
c047688c 10195 {
7a13e894
RS
10196 if (event.xclient.message_type
10197 == dpyinfo->Xatom_wm_protocols
10198 && event.xclient.format == 32)
c047688c 10199 {
7a13e894
RS
10200 if (event.xclient.data.l[0]
10201 == dpyinfo->Xatom_wm_take_focus)
c047688c 10202 {
8c1a6a84
RS
10203 /* Use x_any_window_to_frame because this
10204 could be the shell widget window
10205 if the frame has no title bar. */
10206 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
10207#ifdef HAVE_X_I18N
10208 /* Not quite sure this is needed -pd */
8c1a6a84 10209 if (f && FRAME_XIC (f))
6c183ba5
RS
10210 XSetICFocus (FRAME_XIC (f));
10211#endif
f1da8f06
GM
10212#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
10213 instructs the WM to set the input focus automatically for
10214 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
10215 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
10216 it has set the focus. So, XSetInputFocus below is not
10217 needed.
10218
10219 The call to XSetInputFocus below has also caused trouble. In
10220 cases where the XSetInputFocus done by the WM and the one
10221 below are temporally close (on a fast machine), the call
10222 below can generate additional FocusIn events which confuse
10223 Emacs. */
7d0393cf 10224
bf7253f4
RS
10225 /* Since we set WM_TAKE_FOCUS, we must call
10226 XSetInputFocus explicitly. But not if f is null,
10227 since that might be an event for a deleted frame. */
7a13e894 10228 if (f)
bf7253f4
RS
10229 {
10230 Display *d = event.xclient.display;
10231 /* Catch and ignore errors, in case window has been
10232 iconified by a window manager such as GWM. */
10233 int count = x_catch_errors (d);
10234 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
10235 /* The ICCCM says this is
10236 the only valid choice. */
10237 RevertToParent,
bf7253f4
RS
10238 event.xclient.data.l[1]);
10239 /* This is needed to detect the error
10240 if there is an error. */
10241 XSync (d, False);
10242 x_uncatch_errors (d, count);
7d0393cf 10243 }
7a13e894 10244 /* Not certain about handling scroll bars here */
f1da8f06 10245#endif /* 0 */
c047688c 10246 }
7a13e894
RS
10247 else if (event.xclient.data.l[0]
10248 == dpyinfo->Xatom_wm_save_yourself)
10249 {
10250 /* Save state modify the WM_COMMAND property to
06a2c219 10251 something which can reinstate us. This notifies
7a13e894
RS
10252 the session manager, who's looking for such a
10253 PropertyNotify. Can restart processing when
06a2c219 10254 a keyboard or mouse event arrives. */
5f30b957
JD
10255 /* If we have a session manager, don't set this.
10256 KDE will then start two Emacsen, one for the
10257 session manager and one for this. */
10258 if (numchars > 0
10259#ifdef HAVE_X_SM
10260 && ! x_session_have_connection ()
10261#endif
10262 )
7a13e894 10263 {
19126e11
KH
10264 f = x_top_window_to_frame (dpyinfo,
10265 event.xclient.window);
7a13e894
RS
10266 /* This is just so we only give real data once
10267 for a single Emacs process. */
b86bd3dd 10268 if (f == SELECTED_FRAME ())
7a13e894
RS
10269 XSetCommand (FRAME_X_DISPLAY (f),
10270 event.xclient.window,
10271 initial_argv, initial_argc);
f000f5c5 10272 else if (f)
7a13e894
RS
10273 XSetCommand (FRAME_X_DISPLAY (f),
10274 event.xclient.window,
10275 0, 0);
10276 }
10277 }
10278 else if (event.xclient.data.l[0]
10279 == dpyinfo->Xatom_wm_delete_window)
1fb20991 10280 {
19126e11
KH
10281 struct frame *f
10282 = x_any_window_to_frame (dpyinfo,
10283 event.xclient.window);
1fb20991 10284
7a13e894
RS
10285 if (f)
10286 {
10287 if (numchars == 0)
10288 abort ();
1fb20991 10289
3b8f9651 10290 bufp->kind = DELETE_WINDOW_EVENT;
7a13e894 10291 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10292 bufp->arg = Qnil;
7a13e894
RS
10293 bufp++;
10294
10295 count += 1;
10296 numchars -= 1;
10297 }
1fb20991 10298 }
c047688c 10299 }
7a13e894
RS
10300 else if (event.xclient.message_type
10301 == dpyinfo->Xatom_wm_configure_denied)
10302 {
10303 }
10304 else if (event.xclient.message_type
10305 == dpyinfo->Xatom_wm_window_moved)
10306 {
10307 int new_x, new_y;
19126e11
KH
10308 struct frame *f
10309 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 10310
7a13e894
RS
10311 new_x = event.xclient.data.s[0];
10312 new_y = event.xclient.data.s[1];
1fb20991 10313
7a13e894
RS
10314 if (f)
10315 {
7556890b
RS
10316 f->output_data.x->left_pos = new_x;
10317 f->output_data.x->top_pos = new_y;
7a13e894 10318 }
1fb20991 10319 }
0fdff6bb 10320#ifdef HACK_EDITRES
7a13e894
RS
10321 else if (event.xclient.message_type
10322 == dpyinfo->Xatom_editres)
10323 {
19126e11
KH
10324 struct frame *f
10325 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 10326 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 10327 &event, NULL);
7a13e894 10328 }
0fdff6bb 10329#endif /* HACK_EDITRES */
06a2c219
GM
10330 else if ((event.xclient.message_type
10331 == dpyinfo->Xatom_DONE)
10332 || (event.xclient.message_type
10333 == dpyinfo->Xatom_PAGE))
10334 {
10335 /* Ghostview job completed. Kill it. We could
10336 reply with "Next" if we received "Page", but we
10337 currently never do because we are interested in
10338 images, only, which should have 1 page. */
06a2c219
GM
10339 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
10340 struct frame *f
10341 = x_window_to_frame (dpyinfo, event.xclient.window);
10342 x_kill_gs_process (pixmap, f);
10343 expose_frame (f, 0, 0, 0, 0);
10344 }
10345#ifdef USE_TOOLKIT_SCROLL_BARS
10346 /* Scroll bar callbacks send a ClientMessage from which
10347 we construct an input_event. */
10348 else if (event.xclient.message_type
10349 == dpyinfo->Xatom_Scrollbar)
10350 {
10351 x_scroll_bar_to_input_event (&event, bufp);
10352 ++bufp, ++count, --numchars;
10353 goto out;
10354 }
10355#endif /* USE_TOOLKIT_SCROLL_BARS */
10356 else
10357 goto OTHER;
7a13e894
RS
10358 }
10359 break;
dc6f92b8 10360
7a13e894 10361 case SelectionNotify:
3afe33e7 10362#ifdef USE_X_TOOLKIT
19126e11 10363 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 10364 goto OTHER;
3afe33e7 10365#endif /* not USE_X_TOOLKIT */
dfcf069d 10366 x_handle_selection_notify (&event.xselection);
7a13e894 10367 break;
d56a553a 10368
06a2c219 10369 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 10370#ifdef USE_X_TOOLKIT
19126e11 10371 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 10372 goto OTHER;
3afe33e7 10373#endif /* USE_X_TOOLKIT */
7a13e894
RS
10374 {
10375 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 10376
7a13e894
RS
10377 if (numchars == 0)
10378 abort ();
d56a553a 10379
3b8f9651 10380 bufp->kind = SELECTION_CLEAR_EVENT;
7a13e894
RS
10381 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10382 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10383 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10384 bufp->frame_or_window = Qnil;
0f8aabe9 10385 bufp->arg = Qnil;
7a13e894 10386 bufp++;
d56a553a 10387
7a13e894
RS
10388 count += 1;
10389 numchars -= 1;
10390 }
10391 break;
dc6f92b8 10392
06a2c219 10393 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 10394#ifdef USE_X_TOOLKIT
19126e11 10395 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 10396 goto OTHER;
3afe33e7 10397#endif /* USE_X_TOOLKIT */
7a13e894 10398 if (x_queue_selection_requests)
19126e11 10399 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
10400 &event);
10401 else
10402 {
1d2b2268
GM
10403 XSelectionRequestEvent *eventp
10404 = (XSelectionRequestEvent *) &event;
dc6f92b8 10405
7a13e894
RS
10406 if (numchars == 0)
10407 abort ();
10408
3b8f9651 10409 bufp->kind = SELECTION_REQUEST_EVENT;
7a13e894
RS
10410 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10411 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
10412 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10413 SELECTION_EVENT_TARGET (bufp) = eventp->target;
10414 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
10415 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10416 bufp->frame_or_window = Qnil;
0f8aabe9 10417 bufp->arg = Qnil;
7a13e894
RS
10418 bufp++;
10419
10420 count += 1;
10421 numchars -= 1;
10422 }
10423 break;
10424
10425 case PropertyNotify:
1d2b2268
GM
10426#if 0 /* This is plain wrong. In the case that we are waiting for a
10427 PropertyNotify used as an ACK in incremental selection
10428 transfer, the property will be on the receiver's window. */
10429#if defined USE_X_TOOLKIT
19126e11 10430 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 10431 goto OTHER;
1d2b2268
GM
10432#endif
10433#endif
dfcf069d 10434 x_handle_property_notify (&event.xproperty);
1d2b2268 10435 goto OTHER;
dc6f92b8 10436
7a13e894 10437 case ReparentNotify:
19126e11 10438 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
10439 if (f)
10440 {
10441 int x, y;
7556890b 10442 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 10443 x_real_positions (f, &x, &y);
7556890b
RS
10444 f->output_data.x->left_pos = x;
10445 f->output_data.x->top_pos = y;
f7d43438 10446 goto OTHER;
7a13e894
RS
10447 }
10448 break;
3bd330d4 10449
7a13e894 10450 case Expose:
19126e11 10451 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 10452 if (f)
dc6f92b8 10453 {
d0fa3e56
EZ
10454 x_check_fullscreen (f);
10455
7a13e894
RS
10456 if (f->async_visible == 0)
10457 {
10458 f->async_visible = 1;
10459 f->async_iconified = 0;
06c488fd 10460 f->output_data.x->has_been_visible = 1;
7a13e894
RS
10461 SET_FRAME_GARBAGED (f);
10462 }
10463 else
06a2c219
GM
10464 expose_frame (x_window_to_frame (dpyinfo,
10465 event.xexpose.window),
10466 event.xexpose.x, event.xexpose.y,
10467 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
10468 }
10469 else
7a13e894 10470 {
12949a7f
EZ
10471#ifndef USE_TOOLKIT_SCROLL_BARS
10472 struct scroll_bar *bar;
10473#endif
01f67d2c 10474#if defined USE_LUCID
c95fc5f1
GM
10475 /* Submenus of the Lucid menu bar aren't widgets
10476 themselves, so there's no way to dispatch events
10477 to them. Recognize this case separately. */
10478 {
10479 Widget widget
10480 = x_window_to_menu_bar (event.xexpose.window);
10481 if (widget)
10482 xlwmenu_redisplay (widget);
10483 }
01f67d2c
PJ
10484#endif /* USE_LUCID */
10485
06a2c219
GM
10486#ifdef USE_TOOLKIT_SCROLL_BARS
10487 /* Dispatch event to the widget. */
10488 goto OTHER;
10489#else /* not USE_TOOLKIT_SCROLL_BARS */
12949a7f 10490 bar = x_window_to_scroll_bar (event.xexpose.window);
58769bee 10491
7a13e894
RS
10492 if (bar)
10493 x_scroll_bar_expose (bar, &event);
3afe33e7 10494#ifdef USE_X_TOOLKIT
7a13e894
RS
10495 else
10496 goto OTHER;
3afe33e7 10497#endif /* USE_X_TOOLKIT */
06a2c219 10498#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10499 }
10500 break;
dc6f92b8 10501
7a13e894 10502 case GraphicsExpose: /* This occurs when an XCopyArea's
d624284c
PJ
10503 source area was obscured or not
10504 available. */
19126e11 10505 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
10506 if (f)
10507 {
06a2c219
GM
10508 expose_frame (f,
10509 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
10510 event.xgraphicsexpose.width,
10511 event.xgraphicsexpose.height);
7a13e894 10512 }
3afe33e7 10513#ifdef USE_X_TOOLKIT
7a13e894
RS
10514 else
10515 goto OTHER;
3afe33e7 10516#endif /* USE_X_TOOLKIT */
7a13e894 10517 break;
dc6f92b8 10518
7a13e894 10519 case NoExpose: /* This occurs when an XCopyArea's
06a2c219 10520 source area was completely
d624284c 10521 available. */
7a13e894 10522 break;
dc6f92b8 10523
7a13e894 10524 case UnmapNotify:
06a2c219
GM
10525 /* Redo the mouse-highlight after the tooltip has gone. */
10526 if (event.xmap.window == tip_window)
10527 {
10528 tip_window = 0;
10529 redo_mouse_highlight ();
10530 }
7d0393cf 10531
91ea2a7a 10532 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894 10533 if (f) /* F may no longer exist if
d624284c 10534 the frame was deleted. */
7a13e894
RS
10535 {
10536 /* While a frame is unmapped, display generation is
10537 disabled; you don't want to spend time updating a
10538 display that won't ever be seen. */
10539 f->async_visible = 0;
10540 /* We can't distinguish, from the event, whether the window
10541 has become iconified or invisible. So assume, if it
10542 was previously visible, than now it is iconified.
1aa6072f
RS
10543 But x_make_frame_invisible clears both
10544 the visible flag and the iconified flag;
10545 and that way, we know the window is not iconified now. */
7a13e894 10546 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
10547 {
10548 f->async_iconified = 1;
bddd097c 10549
3b8f9651 10550 bufp->kind = ICONIFY_EVENT;
1aa6072f 10551 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10552 bufp->arg = Qnil;
1aa6072f
RS
10553 bufp++;
10554 count++;
10555 numchars--;
10556 }
7a13e894 10557 }
7a13e894 10558 goto OTHER;
dc6f92b8 10559
7a13e894 10560 case MapNotify:
06a2c219
GM
10561 if (event.xmap.window == tip_window)
10562 /* The tooltip has been drawn already. Avoid
10563 the SET_FRAME_GARBAGED below. */
10564 goto OTHER;
7d0393cf 10565
06a2c219
GM
10566 /* We use x_top_window_to_frame because map events can
10567 come for sub-windows and they don't mean that the
10568 frame is visible. */
19126e11 10569 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
10570 if (f)
10571 {
10572 f->async_visible = 1;
10573 f->async_iconified = 0;
06c488fd 10574 f->output_data.x->has_been_visible = 1;
dc6f92b8 10575
7a13e894
RS
10576 /* wait_reading_process_input will notice this and update
10577 the frame's display structures. */
10578 SET_FRAME_GARBAGED (f);
bddd097c 10579
d806e720
RS
10580 if (f->iconified)
10581 {
3b8f9651 10582 bufp->kind = DEICONIFY_EVENT;
d806e720 10583 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10584 bufp->arg = Qnil;
d806e720
RS
10585 bufp++;
10586 count++;
10587 numchars--;
10588 }
e73ec6fa 10589 else if (! NILP (Vframe_list)
8e713be6 10590 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
10591 /* Force a redisplay sooner or later
10592 to update the frame titles
10593 in case this is the second frame. */
10594 record_asynch_buffer_change ();
7a13e894 10595 }
7a13e894 10596 goto OTHER;
dc6f92b8 10597
7a13e894 10598 case KeyPress:
2a793c0c
PJ
10599
10600 /* Dispatch KeyPress events when in menu. */
10601 if (popup_activated_flag)
10602 goto OTHER;
10603
19126e11 10604 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 10605
66301061
KS
10606 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
10607 {
10608 dpyinfo->mouse_face_hidden = 1;
10609 clear_mouse_face (dpyinfo);
10610 }
10611
eccc05db 10612#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
10613 if (f == 0)
10614 {
2564ea1b
GM
10615 /* Scroll bars consume key events, but we want
10616 the keys to go to the scroll bar's frame. */
06a2c219
GM
10617 Widget widget = XtWindowToWidget (dpyinfo->display,
10618 event.xkey.window);
10619 if (widget && XmIsScrollBar (widget))
10620 {
10621 widget = XtParent (widget);
10622 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
10623 }
10624 }
eccc05db 10625#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
06a2c219 10626
7a13e894
RS
10627 if (f != 0)
10628 {
10629 KeySym keysym, orig_keysym;
379b5ac0
KH
10630 /* al%imercury@uunet.uu.net says that making this 81
10631 instead of 80 fixed a bug whereby meta chars made
10632 his Emacs hang.
10633
10634 It seems that some version of XmbLookupString has
10635 a bug of not returning XBufferOverflow in
10636 status_return even if the input is too long to
10637 fit in 81 bytes. So, we must prepare sufficient
10638 bytes for copy_buffer. 513 bytes (256 chars for
6c4a22e6 10639 two-byte character set) seems to be a fairly good
379b5ac0
KH
10640 approximation. -- 2000.8.10 handa@etl.go.jp */
10641 unsigned char copy_buffer[513];
10642 unsigned char *copy_bufptr = copy_buffer;
10643 int copy_bufsiz = sizeof (copy_buffer);
7a13e894 10644 int modifiers;
c997eae5 10645 Lisp_Object coding_system = Qlatin_1;
64bb1782 10646
7a13e894
RS
10647 event.xkey.state
10648 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
10649 extra_keyboard_modifiers);
10650 modifiers = event.xkey.state;
3a2712f9 10651
7a13e894 10652 /* This will have to go some day... */
752a043f 10653
7a13e894
RS
10654 /* make_lispy_event turns chars into control chars.
10655 Don't do it here because XLookupString is too eager. */
10656 event.xkey.state &= ~ControlMask;
5d46f928
RS
10657 event.xkey.state &= ~(dpyinfo->meta_mod_mask
10658 | dpyinfo->super_mod_mask
10659 | dpyinfo->hyper_mod_mask
10660 | dpyinfo->alt_mod_mask);
10661
1cf4a0d1
RS
10662 /* In case Meta is ComposeCharacter,
10663 clear its status. According to Markus Ehrnsperger
10664 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
10665 this enables ComposeCharacter to work whether or
10666 not it is combined with Meta. */
10667 if (modifiers & dpyinfo->meta_mod_mask)
10668 bzero (&compose_status, sizeof (compose_status));
10669
6c183ba5
RS
10670#ifdef HAVE_X_I18N
10671 if (FRAME_XIC (f))
10672 {
f5d11644
GM
10673 Status status_return;
10674
c997eae5 10675 coding_system = Vlocale_coding_system;
6c183ba5 10676 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
10677 &event.xkey, copy_bufptr,
10678 copy_bufsiz, &keysym,
6c183ba5 10679 &status_return);
f5d11644
GM
10680 if (status_return == XBufferOverflow)
10681 {
10682 copy_bufsiz = nbytes + 1;
10683 copy_bufptr = (char *) alloca (copy_bufsiz);
10684 nbytes = XmbLookupString (FRAME_XIC (f),
10685 &event.xkey, copy_bufptr,
10686 copy_bufsiz, &keysym,
10687 &status_return);
10688 }
96035dca
SM
10689/* Xutf8LookupString is a new but already deprecated interface. -stef */
10690#if 0 && defined X_HAVE_UTF8_STRING
c997eae5
SM
10691 else if (status_return == XLookupKeySym)
10692 { /* Try again but with utf-8. */
10693 coding_system = Qutf_8;
10694 nbytes = Xutf8LookupString (FRAME_XIC (f),
10695 &event.xkey, copy_bufptr,
10696 copy_bufsiz, &keysym,
10697 &status_return);
10698 if (status_return == XBufferOverflow)
10699 {
10700 copy_bufsiz = nbytes + 1;
10701 copy_bufptr = (char *) alloca (copy_bufsiz);
10702 nbytes = Xutf8LookupString (FRAME_XIC (f),
10703 &event.xkey,
10704 copy_bufptr,
10705 copy_bufsiz, &keysym,
10706 &status_return);
10707 }
10708 }
10709#endif
f5d11644 10710
1decb680
PE
10711 if (status_return == XLookupNone)
10712 break;
10713 else if (status_return == XLookupChars)
fdd9d55e
GM
10714 {
10715 keysym = NoSymbol;
10716 modifiers = 0;
10717 }
1decb680
PE
10718 else if (status_return != XLookupKeySym
10719 && status_return != XLookupBoth)
10720 abort ();
6c183ba5
RS
10721 }
10722 else
379b5ac0
KH
10723 nbytes = XLookupString (&event.xkey, copy_bufptr,
10724 copy_bufsiz, &keysym,
10725 &compose_status);
6c183ba5 10726#else
379b5ac0
KH
10727 nbytes = XLookupString (&event.xkey, copy_bufptr,
10728 copy_bufsiz, &keysym,
10729 &compose_status);
6c183ba5 10730#endif
dc6f92b8 10731
7a13e894 10732 orig_keysym = keysym;
55123275 10733
7a13e894
RS
10734 if (numchars > 1)
10735 {
10736 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
10737 || keysym == XK_Delete
1097aea0 10738#ifdef XK_ISO_Left_Tab
441affdb 10739 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 10740#endif
852bff8f 10741 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
10742 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
10743 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 10744#ifdef HPUX
7a13e894
RS
10745 /* This recognizes the "extended function keys".
10746 It seems there's no cleaner way.
10747 Test IsModifierKey to avoid handling mode_switch
10748 incorrectly. */
10749 || ((unsigned) (keysym) >= XK_Select
10750 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
10751#endif
10752#ifdef XK_dead_circumflex
7a13e894 10753 || orig_keysym == XK_dead_circumflex
69388238
RS
10754#endif
10755#ifdef XK_dead_grave
7a13e894 10756 || orig_keysym == XK_dead_grave
69388238
RS
10757#endif
10758#ifdef XK_dead_tilde
7a13e894 10759 || orig_keysym == XK_dead_tilde
69388238
RS
10760#endif
10761#ifdef XK_dead_diaeresis
7a13e894 10762 || orig_keysym == XK_dead_diaeresis
69388238
RS
10763#endif
10764#ifdef XK_dead_macron
7a13e894 10765 || orig_keysym == XK_dead_macron
69388238
RS
10766#endif
10767#ifdef XK_dead_degree
7a13e894 10768 || orig_keysym == XK_dead_degree
69388238
RS
10769#endif
10770#ifdef XK_dead_acute
7a13e894 10771 || orig_keysym == XK_dead_acute
69388238
RS
10772#endif
10773#ifdef XK_dead_cedilla
7a13e894 10774 || orig_keysym == XK_dead_cedilla
69388238
RS
10775#endif
10776#ifdef XK_dead_breve
7a13e894 10777 || orig_keysym == XK_dead_breve
69388238
RS
10778#endif
10779#ifdef XK_dead_ogonek
7a13e894 10780 || orig_keysym == XK_dead_ogonek
69388238
RS
10781#endif
10782#ifdef XK_dead_caron
7a13e894 10783 || orig_keysym == XK_dead_caron
69388238
RS
10784#endif
10785#ifdef XK_dead_doubleacute
7a13e894 10786 || orig_keysym == XK_dead_doubleacute
69388238
RS
10787#endif
10788#ifdef XK_dead_abovedot
7a13e894 10789 || orig_keysym == XK_dead_abovedot
c34790e0 10790#endif
7a13e894
RS
10791 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
10792 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
10793 /* Any "vendor-specific" key is ok. */
f0e299de
GM
10794 || (orig_keysym & (1 << 28))
10795 || (keysym != NoSymbol && nbytes == 0))
7a13e894 10796 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
10797#ifndef HAVE_X11R5
10798#ifdef XK_Mode_switch
7a13e894 10799 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
10800#endif
10801#ifdef XK_Num_Lock
7a13e894 10802 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
10803#endif
10804#endif /* not HAVE_X11R5 */
7ef18d79
EZ
10805 /* The symbols from XK_ISO_Lock to
10806 XK_ISO_Last_Group_Lock doesn't have real
10807 modifiers but should be treated similarly
10808 to Mode_switch by Emacs. */
10809#if defined XK_ISO_Lock && defined XK_ISO_Last_Group_Lock
10810 || ((unsigned)(orig_keysym) >= XK_ISO_Lock
10811 && (unsigned)(orig_keysym) <= XK_ISO_Last_Group_Lock)
10812#endif
7a13e894 10813 ))
dc6f92b8 10814 {
10e6549c
RS
10815 if (temp_index == sizeof temp_buffer / sizeof (short))
10816 temp_index = 0;
7a13e894 10817 temp_buffer[temp_index++] = keysym;
3b8f9651 10818 bufp->kind = NON_ASCII_KEYSTROKE_EVENT;
7a13e894 10819 bufp->code = keysym;
e0c1aef2 10820 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10821 bufp->arg = Qnil;
334208b7
RS
10822 bufp->modifiers
10823 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10824 modifiers);
1113d9db 10825 bufp->timestamp = event.xkey.time;
dc6f92b8 10826 bufp++;
7a13e894
RS
10827 count++;
10828 numchars--;
dc6f92b8 10829 }
7a13e894
RS
10830 else if (numchars > nbytes)
10831 {
10832 register int i;
379b5ac0 10833 register int c;
379b5ac0 10834 int nchars, len;
7a13e894 10835
c997eae5
SM
10836 /* The input should be decoded with `coding_system'
10837 which depends on which X*LookupString function
10838 we used just above and the locale. */
10839 setup_coding_system (coding_system, &coding);
10840 coding.src_multibyte = 0;
10841 coding.dst_multibyte = 1;
10842 /* The input is converted to events, thus we can't
10843 handle composition. Anyway, there's no XIM that
10844 gives us composition information. */
10845 coding.composing = COMPOSITION_DISABLED;
10846
7a13e894
RS
10847 for (i = 0; i < nbytes; i++)
10848 {
379b5ac0
KH
10849 if (temp_index == (sizeof temp_buffer
10850 / sizeof (short)))
7a13e894 10851 temp_index = 0;
379b5ac0
KH
10852 temp_buffer[temp_index++] = copy_bufptr[i];
10853 }
10854
c997eae5
SM
10855 {
10856 /* Decode the input data. */
10857 int require;
10858 unsigned char *p;
10859
10860 require = decoding_buffer_size (&coding, nbytes);
10861 p = (unsigned char *) alloca (require);
10862 coding.mode |= CODING_MODE_LAST_BLOCK;
d337aad5
KH
10863 /* We explicitely disable composition
10864 handling because key data should
10865 not contain any composition
10866 sequence. */
10867 coding.composing = COMPOSITION_DISABLED;
c997eae5
SM
10868 decode_coding (&coding, copy_bufptr, p,
10869 nbytes, require);
10870 nbytes = coding.produced;
10871 nchars = coding.produced_char;
10872 copy_bufptr = p;
10873 }
379b5ac0
KH
10874
10875 /* Convert the input data to a sequence of
10876 character events. */
10877 for (i = 0; i < nbytes; i += len)
10878 {
fee2aedc
GM
10879 if (nchars == nbytes)
10880 c = copy_bufptr[i], len = 1;
10881 else
10882 c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
10883 nbytes - i, len);
7d0393cf 10884
379b5ac0 10885 bufp->kind = (SINGLE_BYTE_CHAR_P (c)
3b8f9651
PJ
10886 ? ASCII_KEYSTROKE_EVENT
10887 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
379b5ac0 10888 bufp->code = c;
7a13e894 10889 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10890 bufp->arg = Qnil;
7a13e894
RS
10891 bufp->modifiers
10892 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10893 modifiers);
10894 bufp->timestamp = event.xkey.time;
10895 bufp++;
10896 }
10897
379b5ac0
KH
10898 count += nchars;
10899 numchars -= nchars;
1decb680
PE
10900
10901 if (keysym == NoSymbol)
10902 break;
7a13e894
RS
10903 }
10904 else
10905 abort ();
dc6f92b8 10906 }
10e6549c
RS
10907 else
10908 abort ();
dc6f92b8 10909 }
59ddecde
GM
10910#ifdef HAVE_X_I18N
10911 /* Don't dispatch this event since XtDispatchEvent calls
10912 XFilterEvent, and two calls in a row may freeze the
10913 client. */
10914 break;
10915#else
717ca130 10916 goto OTHER;
59ddecde 10917#endif
f451eb13 10918
f5d11644 10919 case KeyRelease:
59ddecde
GM
10920#ifdef HAVE_X_I18N
10921 /* Don't dispatch this event since XtDispatchEvent calls
10922 XFilterEvent, and two calls in a row may freeze the
10923 client. */
10924 break;
10925#else
f5d11644 10926 goto OTHER;
59ddecde 10927#endif
f5d11644 10928
7a13e894 10929 case EnterNotify:
06a2c219 10930 {
cab34f50
JD
10931 int n;
10932
10933 n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
10934 if (n > 0)
10935 {
10936 bufp += n, count += n, numchars -= n;
10937 }
7d0393cf 10938
06a2c219
GM
10939 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
10940
2c850e26 10941#if 0
582c60f8 10942 if (event.xcrossing.focus)
06a2c219
GM
10943 {
10944 /* Avoid nasty pop/raise loops. */
10945 if (f && (!(f->auto_raise)
10946 || !(f->auto_lower)
10947 || (event.xcrossing.time - enter_timestamp) > 500))
10948 {
10949 x_new_focus_frame (dpyinfo, f);
10950 enter_timestamp = event.xcrossing.time;
10951 }
10952 }
10953 else if (f == dpyinfo->x_focus_frame)
10954 x_new_focus_frame (dpyinfo, 0);
2c850e26
RS
10955#endif
10956
06a2c219
GM
10957 /* EnterNotify counts as mouse movement,
10958 so update things that depend on mouse position. */
2533c408 10959 if (f && !f->output_data.x->hourglass_p)
06a2c219
GM
10960 note_mouse_movement (f, &event.xmotion);
10961 goto OTHER;
10962 }
dc6f92b8 10963
7a13e894 10964 case FocusIn:
fd42232c 10965 {
cab34f50 10966 int n;
eb72635f 10967
cab34f50
JD
10968 n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
10969 if (n > 0)
fd42232c
JD
10970 {
10971 bufp += n, count += n, numchars -= n;
10972 }
10973 }
f9e24cb9 10974
7a13e894 10975 goto OTHER;
10c5e63d 10976
7a13e894 10977 case LeaveNotify:
cab34f50
JD
10978 {
10979 int n;
10980
10981 n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
10982 if (n > 0)
10983 {
10984 bufp += n, count += n, numchars -= n;
10985 }
10986 }
10987
19126e11 10988 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 10989 if (f)
10c5e63d 10990 {
7a13e894 10991 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
10992 {
10993 /* If we move outside the frame, then we're
10994 certainly no longer on any text in the frame. */
10995 clear_mouse_face (dpyinfo);
10996 dpyinfo->mouse_face_mouse_frame = 0;
10997 }
10998
10999 /* Generate a nil HELP_EVENT to cancel a help-echo.
11000 Do it only if there's something to cancel.
11001 Otherwise, the startup message is cleared when
11002 the mouse leaves the frame. */
11003 if (any_help_event_p)
11004 {
be010514
GM
11005 Lisp_Object frame;
11006 int n;
11007
06a2c219 11008 XSETFRAME (frame, f);
82c5d67a 11009 help_echo = Qnil;
5ab2570d
GM
11010 n = gen_help_event (bufp, numchars,
11011 Qnil, frame, Qnil, Qnil, 0);
be010514 11012 bufp += n, count += n, numchars -= n;
06a2c219 11013 }
7a13e894 11014
10c5e63d 11015 }
7a13e894 11016 goto OTHER;
dc6f92b8 11017
7a13e894 11018 case FocusOut:
cab34f50
JD
11019 {
11020 int n;
11021
11022 n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
11023 if (n > 0)
11024 {
11025 bufp += n, count += n, numchars -= n;
11026 }
11027 }
6c183ba5 11028
7a13e894 11029 goto OTHER;
dc6f92b8 11030
7a13e894 11031 case MotionNotify:
dc6f92b8 11032 {
06a2c219 11033 previous_help_echo = help_echo;
7cea38bc 11034 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 11035 help_echo_pos = -1;
7d0393cf 11036
7a13e894
RS
11037 if (dpyinfo->grabbed && last_mouse_frame
11038 && FRAME_LIVE_P (last_mouse_frame))
11039 f = last_mouse_frame;
11040 else
19126e11 11041 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 11042
66301061
KS
11043 if (dpyinfo->mouse_face_hidden)
11044 {
11045 dpyinfo->mouse_face_hidden = 0;
11046 clear_mouse_face (dpyinfo);
11047 }
11048
7a13e894 11049 if (f)
5bc62483
PJ
11050 {
11051
11052 /* Generate SELECT_WINDOW_EVENTs when needed. */
ee8ceff8 11053 if (mouse_autoselect_window)
5bc62483
PJ
11054 {
11055 Lisp_Object window;
11056 int area;
11057
11058 window = window_from_coordinates (f,
0fc8f792 11059 event.xmotion.x, event.xmotion.y,
5bc62483
PJ
11060 &area, 0);
11061
11062 /* Window will be selected only when it is not selected now and
11063 last mouse movement event was not in it. Minibuffer window
11064 will be selected iff it is active. */
ce1295bd
PJ
11065 if (WINDOWP(window)
11066 && !EQ (window, last_window)
5bc62483
PJ
11067 && !EQ (window, selected_window)
11068 && numchars > 0)
11069 {
11070 bufp->kind = SELECT_WINDOW_EVENT;
11071 bufp->frame_or_window = window;
11072 bufp->arg = Qnil;
11073 ++bufp, ++count, --numchars;
11074 }
11075
11076 last_window=window;
11077 }
11078 note_mouse_movement (f, &event.xmotion);
11079 }
7a13e894
RS
11080 else
11081 {
e88b3c50 11082#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
11083 struct scroll_bar *bar
11084 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 11085
7a13e894
RS
11086 if (bar)
11087 x_scroll_bar_note_movement (bar, &event);
e88b3c50 11088#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 11089
06a2c219
GM
11090 /* If we move outside the frame, then we're
11091 certainly no longer on any text in the frame. */
7a13e894
RS
11092 clear_mouse_face (dpyinfo);
11093 }
06a2c219
GM
11094
11095 /* If the contents of the global variable help_echo
11096 has changed, generate a HELP_EVENT. */
b7e80413
SM
11097 if (!NILP (help_echo)
11098 || !NILP (previous_help_echo))
06a2c219
GM
11099 {
11100 Lisp_Object frame;
be010514 11101 int n;
06a2c219
GM
11102
11103 if (f)
11104 XSETFRAME (frame, f);
11105 else
11106 frame = Qnil;
11107
11108 any_help_event_p = 1;
5ab2570d 11109 n = gen_help_event (bufp, numchars, help_echo, frame,
7cea38bc
GM
11110 help_echo_window, help_echo_object,
11111 help_echo_pos);
be010514 11112 bufp += n, count += n, numchars -= n;
06a2c219 11113 }
7d0393cf 11114
06a2c219 11115 goto OTHER;
dc6f92b8 11116 }
dc6f92b8 11117
7a13e894 11118 case ConfigureNotify:
9829ddba
RS
11119 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
11120 if (f)
af395ec1 11121 {
7a4bce14 11122#ifndef USE_X_TOOLKIT
d0fa3e56
EZ
11123 /* If there is a pending resize for fullscreen, don't
11124 do this one, the right one will come later.
11125 The toolkit version doesn't seem to need this, but we
7a4bce14 11126 need to reset it below. */
d0fa3e56
EZ
11127 int dont_resize =
11128 ((f->output_data.x->want_fullscreen & FULLSCREEN_WAIT)
11129 && FRAME_NEW_WIDTH (f) != 0);
bf1b7b30
KH
11130 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
11131 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
d0fa3e56
EZ
11132 if (dont_resize)
11133 goto OTHER;
7d0393cf 11134
2d7fc7e8
RS
11135 /* In the toolkit version, change_frame_size
11136 is called by the code that handles resizing
11137 of the EmacsFrame widget. */
7a13e894 11138
7a13e894
RS
11139 /* Even if the number of character rows and columns has
11140 not changed, the font size may have changed, so we need
11141 to check the pixel dimensions as well. */
11142 if (columns != f->width
11143 || rows != f->height
7556890b
RS
11144 || event.xconfigure.width != f->output_data.x->pixel_width
11145 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 11146 {
7d1e984f 11147 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 11148 SET_FRAME_GARBAGED (f);
e687d06e 11149 cancel_mouse_face (f);
7a13e894 11150 }
2d7fc7e8 11151#endif
af395ec1 11152
7556890b
RS
11153 f->output_data.x->pixel_width = event.xconfigure.width;
11154 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
11155
11156 /* What we have now is the position of Emacs's own window.
11157 Convert that to the position of the window manager window. */
dcb07ae9
RS
11158 x_real_positions (f, &f->output_data.x->left_pos,
11159 &f->output_data.x->top_pos);
11160
d0fa3e56
EZ
11161 x_check_fullscreen_move(f);
11162 if (f->output_data.x->want_fullscreen & FULLSCREEN_WAIT)
11163 f->output_data.x->want_fullscreen &=
11164 ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH);
f5d11644
GM
11165#ifdef HAVE_X_I18N
11166 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
11167 xic_set_statusarea (f);
11168#endif
11169
dcb07ae9
RS
11170 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
11171 {
11172 /* Since the WM decorations come below top_pos now,
11173 we must put them below top_pos in the future. */
11174 f->output_data.x->win_gravity = NorthWestGravity;
11175 x_wm_set_size_hint (f, (long) 0, 0);
11176 }
7a13e894 11177 }
2d7fc7e8 11178 goto OTHER;
dc6f92b8 11179
7a13e894
RS
11180 case ButtonPress:
11181 case ButtonRelease:
11182 {
11183 /* If we decide we want to generate an event to be seen
11184 by the rest of Emacs, we put it here. */
11185 struct input_event emacs_event;
9ea173e8 11186 int tool_bar_p = 0;
7d0393cf 11187
3b8f9651 11188 emacs_event.kind = NO_EVENT;
7a13e894 11189 bzero (&compose_status, sizeof (compose_status));
9b07615b 11190
06a2c219
GM
11191 if (dpyinfo->grabbed
11192 && last_mouse_frame
9f67f20b
RS
11193 && FRAME_LIVE_P (last_mouse_frame))
11194 f = last_mouse_frame;
11195 else
2224b905 11196 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 11197
06a2c219
GM
11198 if (f)
11199 {
9ea173e8
GM
11200 /* Is this in the tool-bar? */
11201 if (WINDOWP (f->tool_bar_window)
11202 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
11203 {
11204 Lisp_Object window;
11205 int p, x, y;
11206
11207 x = event.xbutton.x;
11208 y = event.xbutton.y;
11209
11210 /* Set x and y. */
11211 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 11212 if (EQ (window, f->tool_bar_window))
06a2c219 11213 {
9ea173e8
GM
11214 x_handle_tool_bar_click (f, &event.xbutton);
11215 tool_bar_p = 1;
06a2c219
GM
11216 }
11217 }
11218
9ea173e8 11219 if (!tool_bar_p)
06a2c219
GM
11220 if (!dpyinfo->x_focus_frame
11221 || f == dpyinfo->x_focus_frame)
11222 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
11223 }
11224 else
11225 {
06a2c219 11226#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
11227 struct scroll_bar *bar
11228 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 11229
7a13e894
RS
11230 if (bar)
11231 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 11232#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
11233 }
11234
11235 if (event.type == ButtonPress)
11236 {
11237 dpyinfo->grabbed |= (1 << event.xbutton.button);
11238 last_mouse_frame = f;
edad46f6
KH
11239 /* Ignore any mouse motion that happened
11240 before this event; any subsequent mouse-movement
11241 Emacs events should reflect only motion after
11242 the ButtonPress. */
a00e91cd
KH
11243 if (f != 0)
11244 f->mouse_moved = 0;
7d0393cf 11245
9ea173e8
GM
11246 if (!tool_bar_p)
11247 last_tool_bar_item = -1;
7a13e894 11248 }
3afe33e7
RS
11249 else
11250 {
7a13e894 11251 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 11252 }
23faf38f 11253
3b8f9651 11254 if (numchars >= 1 && emacs_event.kind != NO_EVENT)
7a13e894
RS
11255 {
11256 bcopy (&emacs_event, bufp, sizeof (struct input_event));
11257 bufp++;
11258 count++;
11259 numchars--;
11260 }
3afe33e7
RS
11261
11262#ifdef USE_X_TOOLKIT
2224b905
RS
11263 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
11264 /* For a down-event in the menu bar,
11265 don't pass it to Xt right now.
11266 Instead, save it away
11267 and we will pass it to Xt from kbd_buffer_get_event.
11268 That way, we can run some Lisp code first. */
91375f8f
RS
11269 if (f && event.type == ButtonPress
11270 /* Verify the event is really within the menu bar
11271 and not just sent to it due to grabbing. */
11272 && event.xbutton.x >= 0
11273 && event.xbutton.x < f->output_data.x->pixel_width
11274 && event.xbutton.y >= 0
11275 && event.xbutton.y < f->output_data.x->menubar_height
11276 && event.xbutton.same_screen)
2224b905 11277 {
8805890a 11278 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
11279 XSETFRAME (last_mouse_press_frame, f);
11280 }
11281 else if (event.type == ButtonPress)
11282 {
11283 last_mouse_press_frame = Qnil;
30e671c3 11284 goto OTHER;
ce89ef46 11285 }
06a2c219 11286
2237cac9
RS
11287#ifdef USE_MOTIF /* This should do not harm for Lucid,
11288 but I am trying to be cautious. */
ce89ef46
RS
11289 else if (event.type == ButtonRelease)
11290 {
2237cac9 11291 if (!NILP (last_mouse_press_frame))
f10ded1c 11292 {
2237cac9
RS
11293 f = XFRAME (last_mouse_press_frame);
11294 if (f->output_data.x)
06a2c219 11295 SET_SAVED_BUTTON_EVENT;
f10ded1c 11296 }
06a2c219 11297 else
30e671c3 11298 goto OTHER;
2224b905 11299 }
2237cac9 11300#endif /* USE_MOTIF */
2224b905
RS
11301 else
11302 goto OTHER;
3afe33e7 11303#endif /* USE_X_TOOLKIT */
7a13e894
RS
11304 }
11305 break;
dc6f92b8 11306
7a13e894 11307 case CirculateNotify:
06a2c219 11308 goto OTHER;
7d0393cf 11309
7a13e894 11310 case CirculateRequest:
06a2c219
GM
11311 goto OTHER;
11312
11313 case VisibilityNotify:
11314 goto OTHER;
dc6f92b8 11315
7a13e894
RS
11316 case MappingNotify:
11317 /* Someone has changed the keyboard mapping - update the
11318 local cache. */
11319 switch (event.xmapping.request)
11320 {
11321 case MappingModifier:
11322 x_find_modifier_meanings (dpyinfo);
11323 /* This is meant to fall through. */
11324 case MappingKeyboard:
11325 XRefreshKeyboardMapping (&event.xmapping);
11326 }
7a13e894 11327 goto OTHER;
dc6f92b8 11328
7a13e894 11329 default:
7a13e894 11330 OTHER:
717ca130 11331#ifdef USE_X_TOOLKIT
7a13e894
RS
11332 BLOCK_INPUT;
11333 XtDispatchEvent (&event);
11334 UNBLOCK_INPUT;
3afe33e7 11335#endif /* USE_X_TOOLKIT */
7a13e894
RS
11336 break;
11337 }
dc6f92b8
JB
11338 }
11339 }
11340
06a2c219
GM
11341 out:;
11342
9a5196d0
RS
11343 /* On some systems, an X bug causes Emacs to get no more events
11344 when the window is destroyed. Detect that. (1994.) */
58769bee 11345 if (! event_found)
ef2a22d0 11346 {
ef2a22d0
RS
11347 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
11348 One XNOOP in 100 loops will make Emacs terminate.
11349 B. Bretthauer, 1994 */
11350 x_noop_count++;
58769bee 11351 if (x_noop_count >= 100)
ef2a22d0
RS
11352 {
11353 x_noop_count=0;
2224b905
RS
11354
11355 if (next_noop_dpyinfo == 0)
11356 next_noop_dpyinfo = x_display_list;
11357
11358 XNoOp (next_noop_dpyinfo->display);
11359
11360 /* Each time we get here, cycle through the displays now open. */
11361 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
11362 }
11363 }
502add23 11364
06a2c219 11365 /* If the focus was just given to an auto-raising frame,
0134a210 11366 raise it now. */
7a13e894 11367 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
11368 if (pending_autoraise_frame)
11369 {
11370 x_raise_frame (pending_autoraise_frame);
11371 pending_autoraise_frame = 0;
11372 }
0134a210 11373
dc6f92b8 11374 UNBLOCK_INPUT;
bde5503b 11375 --handling_signal;
dc6f92b8
JB
11376 return count;
11377}
06a2c219
GM
11378
11379
11380
dc6f92b8 11381\f
06a2c219
GM
11382/***********************************************************************
11383 Text Cursor
11384 ***********************************************************************/
11385
60626bab
GM
11386/* Notice when the text cursor of window W has been completely
11387 overwritten by a drawing operation that outputs glyphs in AREA
11388 starting at X0 and ending at X1 in the line starting at Y0 and
11389 ending at Y1. X coordinates are area-relative. X1 < 0 means all
11390 the rest of the line after X0 has been written. Y coordinates
11391 are window-relative. */
06a2c219
GM
11392
11393static void
60626bab 11394notice_overwritten_cursor (w, area, x0, x1, y0, y1)
06a2c219 11395 struct window *w;
60626bab
GM
11396 enum glyph_row_area area;
11397 int x0, y0, x1, y1;
06a2c219 11398{
b3738089
GM
11399 if (area == TEXT_AREA && w->phys_cursor_on_p)
11400 {
11401 int cx0 = w->phys_cursor.x;
11402 int cx1 = cx0 + w->phys_cursor_width;
11403 int cy0 = w->phys_cursor.y;
11404 int cy1 = cy0 + w->phys_cursor_height;
11405
11406 if (x0 <= cx0 && (x1 < 0 || x1 >= cx1))
11407 {
11408 /* The cursor image will be completely removed from the
11409 screen if the output area intersects the cursor area in
11410 y-direction. When we draw in [y0 y1[, and some part of
11411 the cursor is at y < y0, that part must have been drawn
11412 before. When scrolling, the cursor is erased before
11413 actually scrolling, so we don't come here. When not
11414 scrolling, the rows above the old cursor row must have
11415 changed, and in this case these rows must have written
516074a1
GM
11416 over the cursor image.
11417
11418 Likewise if part of the cursor is below y1, with the
11419 exception of the cursor being in the first blank row at
11420 the buffer and window end because update_text_area
4398e673
GM
11421 doesn't draw that row. (Except when it does, but
11422 that's handled in update_text_area.) */
7d0393cf 11423
f7c5994d 11424 if (((y0 >= cy0 && y0 < cy1) || (y1 > cy0 && y1 < cy1))
516074a1 11425 && w->current_matrix->rows[w->phys_cursor.vpos].displays_text_p)
b3738089
GM
11426 w->phys_cursor_on_p = 0;
11427 }
11428 }
06a2c219 11429}
f451eb13
JB
11430
11431
06a2c219
GM
11432/* Set clipping for output in glyph row ROW. W is the window in which
11433 we operate. GC is the graphics context to set clipping in.
11434 WHOLE_LINE_P non-zero means include the areas used for truncation
11435 mark display and alike in the clipping rectangle.
11436
11437 ROW may be a text row or, e.g., a mode line. Text rows must be
11438 clipped to the interior of the window dedicated to text display,
11439 mode lines must be clipped to the whole window. */
dc6f92b8
JB
11440
11441static void
06a2c219
GM
11442x_clip_to_row (w, row, gc, whole_line_p)
11443 struct window *w;
11444 struct glyph_row *row;
11445 GC gc;
11446 int whole_line_p;
dc6f92b8 11447{
06a2c219
GM
11448 struct frame *f = XFRAME (WINDOW_FRAME (w));
11449 XRectangle clip_rect;
11450 int window_x, window_y, window_width, window_height;
dc6f92b8 11451
06a2c219 11452 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 11453
06a2c219
GM
11454 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
11455 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
11456 clip_rect.y = max (clip_rect.y, window_y);
11457 clip_rect.width = window_width;
11458 clip_rect.height = row->visible_height;
5c1aae96 11459
06a2c219
GM
11460 /* If clipping to the whole line, including trunc marks, extend
11461 the rectangle to the left and increase its width. */
11462 if (whole_line_p)
11463 {
3f332ef3
KS
11464 clip_rect.x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
11465 clip_rect.width += FRAME_X_FRINGE_WIDTH (f);
06a2c219 11466 }
5c1aae96 11467
06a2c219 11468 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
11469}
11470
06a2c219
GM
11471
11472/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
11473
11474static void
06a2c219
GM
11475x_draw_hollow_cursor (w, row)
11476 struct window *w;
11477 struct glyph_row *row;
dc6f92b8 11478{
06a2c219
GM
11479 struct frame *f = XFRAME (WINDOW_FRAME (w));
11480 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11481 Display *dpy = FRAME_X_DISPLAY (f);
11482 int x, y, wd, h;
11483 XGCValues xgcv;
11484 struct glyph *cursor_glyph;
11485 GC gc;
11486
11487 /* Compute frame-relative coordinates from window-relative
11488 coordinates. */
11489 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11490 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
11491 + row->ascent - w->phys_cursor_ascent);
11492 h = row->height - 1;
11493
11494 /* Get the glyph the cursor is on. If we can't tell because
11495 the current matrix is invalid or such, give up. */
11496 cursor_glyph = get_phys_cursor_glyph (w);
11497 if (cursor_glyph == NULL)
dc6f92b8
JB
11498 return;
11499
06a2c219
GM
11500 /* Compute the width of the rectangle to draw. If on a stretch
11501 glyph, and `x-stretch-block-cursor' is nil, don't draw a
11502 rectangle as wide as the glyph, but use a canonical character
11503 width instead. */
11504 wd = cursor_glyph->pixel_width - 1;
11505 if (cursor_glyph->type == STRETCH_GLYPH
11506 && !x_stretch_cursor_p)
11507 wd = min (CANON_X_UNIT (f), wd);
b3738089 11508 w->phys_cursor_width = wd;
7d0393cf 11509
06a2c219
GM
11510 /* The foreground of cursor_gc is typically the same as the normal
11511 background color, which can cause the cursor box to be invisible. */
11512 xgcv.foreground = f->output_data.x->cursor_pixel;
11513 if (dpyinfo->scratch_cursor_gc)
11514 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
11515 else
11516 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
11517 GCForeground, &xgcv);
11518 gc = dpyinfo->scratch_cursor_gc;
11519
11520 /* Set clipping, draw the rectangle, and reset clipping again. */
11521 x_clip_to_row (w, row, gc, 0);
11522 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
11523 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
11524}
11525
06a2c219
GM
11526
11527/* Draw a bar cursor on window W in glyph row ROW.
11528
11529 Implementation note: One would like to draw a bar cursor with an
11530 angle equal to the one given by the font property XA_ITALIC_ANGLE.
11531 Unfortunately, I didn't find a font yet that has this property set.
11532 --gerd. */
dc6f92b8
JB
11533
11534static void
65c26775 11535x_draw_bar_cursor (w, row, width, kind)
06a2c219
GM
11536 struct window *w;
11537 struct glyph_row *row;
f02d8aa0 11538 int width;
65c26775 11539 enum text_cursor_kinds kind;
dc6f92b8 11540{
92f424df
GM
11541 struct frame *f = XFRAME (w->frame);
11542 struct glyph *cursor_glyph;
7d0393cf 11543
92f424df
GM
11544 /* If cursor is out of bounds, don't draw garbage. This can happen
11545 in mini-buffer windows when switching between echo area glyphs
11546 and mini-buffer. */
11547 cursor_glyph = get_phys_cursor_glyph (w);
11548 if (cursor_glyph == NULL)
11549 return;
06a2c219 11550
92f424df
GM
11551 /* If on an image, draw like a normal cursor. That's usually better
11552 visible than drawing a bar, esp. if the image is large so that
11553 the bar might not be in the window. */
11554 if (cursor_glyph->type == IMAGE_GLYPH)
11555 {
11556 struct glyph_row *row;
11557 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
11558 x_draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
11559 }
11560 else
11561 {
34e5d0af
GM
11562 Display *dpy = FRAME_X_DISPLAY (f);
11563 Window window = FRAME_X_WINDOW (f);
11564 GC gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
11565 unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures;
11566 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
11567 XGCValues xgcv;
11568
11569 /* If the glyph's background equals the color we normally draw
11570 the bar cursor in, the bar cursor in its normal color is
11571 invisible. Use the glyph's foreground color instead in this
11572 case, on the assumption that the glyph's colors are chosen so
11573 that the glyph is legible. */
11574 if (face->background == f->output_data.x->cursor_pixel)
11575 xgcv.background = xgcv.foreground = face->foreground;
11576 else
11577 xgcv.background = xgcv.foreground = f->output_data.x->cursor_pixel;
06a2c219 11578 xgcv.graphics_exposures = 0;
7d0393cf 11579
06a2c219
GM
11580 if (gc)
11581 XChangeGC (dpy, gc, mask, &xgcv);
11582 else
11583 {
11584 gc = XCreateGC (dpy, window, mask, &xgcv);
11585 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
11586 }
7d0393cf 11587
f02d8aa0 11588 if (width < 0)
fdbe859c 11589 width = FRAME_CURSOR_WIDTH (f);
34e5d0af 11590 width = min (cursor_glyph->pixel_width, width);
7d0393cf 11591
b3738089 11592 w->phys_cursor_width = width;
06a2c219 11593 x_clip_to_row (w, row, gc, 0);
7d0393cf 11594
65c26775
EZ
11595 if (kind == BAR_CURSOR)
11596 XFillRectangle (dpy, window, gc,
11597 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
11598 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
11599 width, row->height);
11600 else
11601 XFillRectangle (dpy, window, gc,
11602 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
11603 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
11604 row->height - width),
11605 cursor_glyph->pixel_width,
11606 width);
11607
06a2c219
GM
11608 XSetClipMask (dpy, gc, None);
11609 }
dc6f92b8
JB
11610}
11611
06a2c219
GM
11612
11613/* Clear the cursor of window W to background color, and mark the
11614 cursor as not shown. This is used when the text where the cursor
11615 is is about to be rewritten. */
11616
dc6f92b8 11617static void
06a2c219
GM
11618x_clear_cursor (w)
11619 struct window *w;
dc6f92b8 11620{
06a2c219
GM
11621 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
11622 x_update_window_cursor (w, 0);
11623}
90e65f07 11624
dbc4e1c1 11625
06a2c219
GM
11626/* Draw the cursor glyph of window W in glyph row ROW. See the
11627 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 11628
06a2c219
GM
11629static void
11630x_draw_phys_cursor_glyph (w, row, hl)
11631 struct window *w;
11632 struct glyph_row *row;
11633 enum draw_glyphs_face hl;
11634{
11635 /* If cursor hpos is out of bounds, don't draw garbage. This can
11636 happen in mini-buffer windows when switching between echo area
11637 glyphs and mini-buffer. */
11638 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e 11639 {
f0a48a01 11640 int on_p = w->phys_cursor_on_p;
56a0382c 11641 int x1;
7d0393cf 11642
56a0382c
GM
11643 x1 = x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
11644 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
11645 hl, 0);
f0a48a01 11646 w->phys_cursor_on_p = on_p;
66ac4b0e 11647
b3738089 11648 if (hl == DRAW_CURSOR)
56a0382c 11649 w->phys_cursor_width = x1 - w->phys_cursor.x;
b3738089 11650
66ac4b0e
GM
11651 /* When we erase the cursor, and ROW is overlapped by other
11652 rows, make sure that these overlapping parts of other rows
11653 are redrawn. */
b3738089 11654 else if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
66ac4b0e
GM
11655 {
11656 if (row > w->current_matrix->rows
11657 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
11658 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
11659
11660 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
11661 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
11662 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
11663 }
11664 }
06a2c219 11665}
dbc4e1c1 11666
eea6af04 11667
06a2c219 11668/* Erase the image of a cursor of window W from the screen. */
eea6af04 11669
06a2c219
GM
11670static void
11671x_erase_phys_cursor (w)
11672 struct window *w;
11673{
11674 struct frame *f = XFRAME (w->frame);
11675 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11676 int hpos = w->phys_cursor.hpos;
11677 int vpos = w->phys_cursor.vpos;
11678 int mouse_face_here_p = 0;
11679 struct glyph_matrix *active_glyphs = w->current_matrix;
11680 struct glyph_row *cursor_row;
11681 struct glyph *cursor_glyph;
11682 enum draw_glyphs_face hl;
11683
11684 /* No cursor displayed or row invalidated => nothing to do on the
11685 screen. */
11686 if (w->phys_cursor_type == NO_CURSOR)
11687 goto mark_cursor_off;
7d0393cf 11688
06a2c219
GM
11689 /* VPOS >= active_glyphs->nrows means that window has been resized.
11690 Don't bother to erase the cursor. */
11691 if (vpos >= active_glyphs->nrows)
11692 goto mark_cursor_off;
11693
11694 /* If row containing cursor is marked invalid, there is nothing we
11695 can do. */
11696 cursor_row = MATRIX_ROW (active_glyphs, vpos);
11697 if (!cursor_row->enabled_p)
11698 goto mark_cursor_off;
7d0393cf 11699
a2c6de8e
KS
11700 /* If row is completely invisible, don't attempt to delete a cursor which
11701 isn't there. This can happen if cursor is at top of a window, and
11702 we switch to a buffer with a header line in that window. */
11703 if (cursor_row->visible_height <= 0)
11704 goto mark_cursor_off;
7d0393cf 11705
06a2c219
GM
11706 /* This can happen when the new row is shorter than the old one.
11707 In this case, either x_draw_glyphs or clear_end_of_line
11708 should have cleared the cursor. Note that we wouldn't be
11709 able to erase the cursor in this case because we don't have a
11710 cursor glyph at hand. */
11711 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
11712 goto mark_cursor_off;
7d0393cf 11713
06a2c219
GM
11714 /* If the cursor is in the mouse face area, redisplay that when
11715 we clear the cursor. */
8801a864
KR
11716 if (! NILP (dpyinfo->mouse_face_window)
11717 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
11718 && (vpos > dpyinfo->mouse_face_beg_row
11719 || (vpos == dpyinfo->mouse_face_beg_row
11720 && hpos >= dpyinfo->mouse_face_beg_col))
11721 && (vpos < dpyinfo->mouse_face_end_row
11722 || (vpos == dpyinfo->mouse_face_end_row
11723 && hpos < dpyinfo->mouse_face_end_col))
11724 /* Don't redraw the cursor's spot in mouse face if it is at the
11725 end of a line (on a newline). The cursor appears there, but
11726 mouse highlighting does not. */
11727 && cursor_row->used[TEXT_AREA] > hpos)
11728 mouse_face_here_p = 1;
11729
11730 /* Maybe clear the display under the cursor. */
11731 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
11732 {
11733 int x;
045dee35 11734 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 11735
06a2c219
GM
11736 cursor_glyph = get_phys_cursor_glyph (w);
11737 if (cursor_glyph == NULL)
11738 goto mark_cursor_off;
dbc4e1c1 11739
e0300d33 11740 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
7d0393cf 11741
c5e6e06b
GM
11742 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11743 x,
11744 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
11745 cursor_row->y)),
11746 cursor_glyph->pixel_width,
11747 cursor_row->visible_height,
11748 False);
dbc4e1c1 11749 }
7d0393cf 11750
06a2c219
GM
11751 /* Erase the cursor by redrawing the character underneath it. */
11752 if (mouse_face_here_p)
11753 hl = DRAW_MOUSE_FACE;
06a2c219
GM
11754 else
11755 hl = DRAW_NORMAL_TEXT;
11756 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 11757
06a2c219
GM
11758 mark_cursor_off:
11759 w->phys_cursor_on_p = 0;
11760 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
11761}
11762
11763
b7f83f9e
GM
11764/* Non-zero if physical cursor of window W is within mouse face. */
11765
11766static int
11767cursor_in_mouse_face_p (w)
11768 struct window *w;
11769{
11770 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
11771 int in_mouse_face = 0;
7d0393cf 11772
b7f83f9e
GM
11773 if (WINDOWP (dpyinfo->mouse_face_window)
11774 && XWINDOW (dpyinfo->mouse_face_window) == w)
11775 {
11776 int hpos = w->phys_cursor.hpos;
11777 int vpos = w->phys_cursor.vpos;
11778
11779 if (vpos >= dpyinfo->mouse_face_beg_row
11780 && vpos <= dpyinfo->mouse_face_end_row
11781 && (vpos > dpyinfo->mouse_face_beg_row
11782 || hpos >= dpyinfo->mouse_face_beg_col)
11783 && (vpos < dpyinfo->mouse_face_end_row
11784 || hpos < dpyinfo->mouse_face_end_col
11785 || dpyinfo->mouse_face_past_end))
11786 in_mouse_face = 1;
11787 }
11788
11789 return in_mouse_face;
11790}
11791
11792
06a2c219
GM
11793/* Display or clear cursor of window W. If ON is zero, clear the
11794 cursor. If it is non-zero, display the cursor. If ON is nonzero,
11795 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 11796
06a2c219
GM
11797void
11798x_display_and_set_cursor (w, on, hpos, vpos, x, y)
11799 struct window *w;
11800 int on, hpos, vpos, x, y;
dbc4e1c1 11801{
06a2c219
GM
11802 struct frame *f = XFRAME (w->frame);
11803 int new_cursor_type;
f02d8aa0 11804 int new_cursor_width;
06a2c219
GM
11805 struct glyph_matrix *current_glyphs;
11806 struct glyph_row *glyph_row;
11807 struct glyph *glyph;
dbc4e1c1 11808
49d838ea 11809 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
11810 windows and frames; in the latter case, the frame or window may
11811 be in the midst of changing its size, and x and y may be off the
11812 window. */
11813 if (! FRAME_VISIBLE_P (f)
11814 || FRAME_GARBAGED_P (f)
11815 || vpos >= w->current_matrix->nrows
11816 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
11817 return;
11818
11819 /* If cursor is off and we want it off, return quickly. */
06a2c219 11820 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
11821 return;
11822
06a2c219
GM
11823 current_glyphs = w->current_matrix;
11824 glyph_row = MATRIX_ROW (current_glyphs, vpos);
11825 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
7d0393cf
JB
11826
11827 /* If cursor row is not enabled, we don't really know where to
06a2c219
GM
11828 display the cursor. */
11829 if (!glyph_row->enabled_p)
11830 {
11831 w->phys_cursor_on_p = 0;
11832 return;
11833 }
11834
11835 xassert (interrupt_input_blocked);
11836
fdbe859c
KS
11837 /* Set new_cursor_type to the cursor we want to be displayed. */
11838 new_cursor_type = get_window_cursor_type (w, &new_cursor_width);
f7e039de 11839
06a2c219
GM
11840 /* If cursor is currently being shown and we don't want it to be or
11841 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 11842 erase it. */
06a2c219 11843 if (w->phys_cursor_on_p
dc6f92b8 11844 && (!on
06a2c219
GM
11845 || w->phys_cursor.x != x
11846 || w->phys_cursor.y != y
e1429afe 11847 || new_cursor_type != w->phys_cursor_type
fdbe859c 11848 || ((new_cursor_type == BAR_CURSOR || new_cursor_type == HBAR_CURSOR)
e1429afe 11849 && new_cursor_width != w->phys_cursor_width)))
06a2c219
GM
11850 x_erase_phys_cursor (w);
11851
56a0382c
GM
11852 /* Don't check phys_cursor_on_p here because that flag is only set
11853 to zero in some cases where we know that the cursor has been
11854 completely erased, to avoid the extra work of erasing the cursor
11855 twice. In other words, phys_cursor_on_p can be 1 and the cursor
11856 still not be visible, or it has only been partly erased. */
11857 if (on)
06a2c219
GM
11858 {
11859 w->phys_cursor_ascent = glyph_row->ascent;
11860 w->phys_cursor_height = glyph_row->height;
7d0393cf 11861
06a2c219
GM
11862 /* Set phys_cursor_.* before x_draw_.* is called because some
11863 of them may need the information. */
11864 w->phys_cursor.x = x;
11865 w->phys_cursor.y = glyph_row->y;
11866 w->phys_cursor.hpos = hpos;
11867 w->phys_cursor.vpos = vpos;
11868 w->phys_cursor_type = new_cursor_type;
11869 w->phys_cursor_on_p = 1;
11870
11871 switch (new_cursor_type)
dc6f92b8 11872 {
06a2c219
GM
11873 case HOLLOW_BOX_CURSOR:
11874 x_draw_hollow_cursor (w, glyph_row);
11875 break;
11876
11877 case FILLED_BOX_CURSOR:
11878 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
11879 break;
11880
11881 case BAR_CURSOR:
65c26775
EZ
11882 x_draw_bar_cursor (w, glyph_row, new_cursor_width, BAR_CURSOR);
11883 break;
11884
11885 case HBAR_CURSOR:
b3738089 11886 x_draw_bar_cursor (w, glyph_row, new_cursor_width, HBAR_CURSOR);
06a2c219
GM
11887 break;
11888
11889 case NO_CURSOR:
4398e673 11890 w->phys_cursor_width = 0;
06a2c219 11891 break;
dc6f92b8 11892
06a2c219
GM
11893 default:
11894 abort ();
11895 }
7d0393cf 11896
59ddecde
GM
11897#ifdef HAVE_X_I18N
11898 if (w == XWINDOW (f->selected_window))
11899 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
11900 xic_set_preeditarea (w, x, y);
11901#endif
dc6f92b8
JB
11902 }
11903
06a2c219 11904#ifndef XFlush
f676886a 11905 if (updating_frame != f)
334208b7 11906 XFlush (FRAME_X_DISPLAY (f));
06a2c219 11907#endif
dc6f92b8
JB
11908}
11909
06a2c219
GM
11910
11911/* Display the cursor on window W, or clear it. X and Y are window
11912 relative pixel coordinates. HPOS and VPOS are glyph matrix
11913 positions. If W is not the selected window, display a hollow
11914 cursor. ON non-zero means display the cursor at X, Y which
11915 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 11916
dfcf069d 11917void
06a2c219
GM
11918x_display_cursor (w, on, hpos, vpos, x, y)
11919 struct window *w;
11920 int on, hpos, vpos, x, y;
dc6f92b8 11921{
f94397b5 11922 BLOCK_INPUT;
06a2c219 11923 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
11924 UNBLOCK_INPUT;
11925}
11926
06a2c219
GM
11927
11928/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
11929 Don't change the cursor's position. */
11930
dfcf069d 11931void
06a2c219 11932x_update_cursor (f, on_p)
5d46f928 11933 struct frame *f;
5d46f928 11934{
06a2c219
GM
11935 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
11936}
11937
11938
11939/* Call x_update_window_cursor with parameter ON_P on all leaf windows
11940 in the window tree rooted at W. */
11941
11942static void
11943x_update_cursor_in_window_tree (w, on_p)
11944 struct window *w;
11945 int on_p;
11946{
11947 while (w)
11948 {
11949 if (!NILP (w->hchild))
11950 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
11951 else if (!NILP (w->vchild))
11952 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
11953 else
11954 x_update_window_cursor (w, on_p);
11955
11956 w = NILP (w->next) ? 0 : XWINDOW (w->next);
11957 }
11958}
5d46f928 11959
f94397b5 11960
06a2c219
GM
11961/* Switch the display of W's cursor on or off, according to the value
11962 of ON. */
11963
11964static void
11965x_update_window_cursor (w, on)
11966 struct window *w;
11967 int on;
11968{
16b5d424
GM
11969 /* Don't update cursor in windows whose frame is in the process
11970 of being deleted. */
11971 if (w->current_matrix)
11972 {
11973 BLOCK_INPUT;
11974 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
11975 w->phys_cursor.x, w->phys_cursor.y);
11976 UNBLOCK_INPUT;
11977 }
dc6f92b8 11978}
06a2c219
GM
11979
11980
11981
dc6f92b8
JB
11982\f
11983/* Icons. */
11984
dbc4e1c1 11985/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
11986
11987int
990ba854 11988x_bitmap_icon (f, file)
f676886a 11989 struct frame *f;
990ba854 11990 Lisp_Object file;
dc6f92b8 11991{
06a2c219 11992 int bitmap_id;
dc6f92b8 11993
c118dd06 11994 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11995 return 1;
11996
990ba854 11997 /* Free up our existing icon bitmap if any. */
7556890b
RS
11998 if (f->output_data.x->icon_bitmap > 0)
11999 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
12000 f->output_data.x->icon_bitmap = 0;
990ba854
RS
12001
12002 if (STRINGP (file))
7f2ae036
RS
12003 bitmap_id = x_create_bitmap_from_file (f, file);
12004 else
12005 {
990ba854 12006 /* Create the GNU bitmap if necessary. */
5bf01b68 12007 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
12008 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
12009 = x_create_bitmap_from_data (f, gnu_bits,
12010 gnu_width, gnu_height);
990ba854
RS
12011
12012 /* The first time we create the GNU bitmap,
06a2c219 12013 this increments the ref-count one extra time.
990ba854
RS
12014 As a result, the GNU bitmap is never freed.
12015 That way, we don't have to worry about allocating it again. */
334208b7 12016 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 12017
334208b7 12018 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
12019 }
12020
12021 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 12022 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
12023
12024 return 0;
12025}
12026
12027
1be2d067
KH
12028/* Make the x-window of frame F use a rectangle with text.
12029 Use ICON_NAME as the text. */
dc6f92b8
JB
12030
12031int
f676886a
JB
12032x_text_icon (f, icon_name)
12033 struct frame *f;
dc6f92b8
JB
12034 char *icon_name;
12035{
c118dd06 12036 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
12037 return 1;
12038
1be2d067
KH
12039#ifdef HAVE_X11R4
12040 {
12041 XTextProperty text;
12042 text.value = (unsigned char *) icon_name;
12043 text.encoding = XA_STRING;
12044 text.format = 8;
12045 text.nitems = strlen (icon_name);
12046#ifdef USE_X_TOOLKIT
7556890b 12047 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
12048 &text);
12049#else /* not USE_X_TOOLKIT */
12050 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
12051#endif /* not USE_X_TOOLKIT */
12052 }
12053#else /* not HAVE_X11R4 */
12054 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
12055#endif /* not HAVE_X11R4 */
58769bee 12056
7556890b
RS
12057 if (f->output_data.x->icon_bitmap > 0)
12058 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
12059 f->output_data.x->icon_bitmap = 0;
b1c884c3 12060 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
12061
12062 return 0;
12063}
12064\f
e99db5a1
RS
12065#define X_ERROR_MESSAGE_SIZE 200
12066
12067/* If non-nil, this should be a string.
12068 It means catch X errors and store the error message in this string. */
12069
12070static Lisp_Object x_error_message_string;
12071
12072/* An X error handler which stores the error message in
12073 x_error_message_string. This is called from x_error_handler if
12074 x_catch_errors is in effect. */
12075
06a2c219 12076static void
e99db5a1
RS
12077x_error_catcher (display, error)
12078 Display *display;
12079 XErrorEvent *error;
12080{
12081 XGetErrorText (display, error->error_code,
d5db4077 12082 SDATA (x_error_message_string),
e99db5a1
RS
12083 X_ERROR_MESSAGE_SIZE);
12084}
12085
12086/* Begin trapping X errors for display DPY. Actually we trap X errors
12087 for all displays, but DPY should be the display you are actually
12088 operating on.
12089
12090 After calling this function, X protocol errors no longer cause
12091 Emacs to exit; instead, they are recorded in the string
12092 stored in x_error_message_string.
12093
12094 Calling x_check_errors signals an Emacs error if an X error has
12095 occurred since the last call to x_catch_errors or x_check_errors.
12096
12097 Calling x_uncatch_errors resumes the normal error handling. */
12098
12099void x_check_errors ();
12100static Lisp_Object x_catch_errors_unwind ();
12101
12102int
12103x_catch_errors (dpy)
12104 Display *dpy;
12105{
aed13378 12106 int count = SPECPDL_INDEX ();
e99db5a1
RS
12107
12108 /* Make sure any errors from previous requests have been dealt with. */
12109 XSync (dpy, False);
12110
12111 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
12112
12113 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
7da167cd 12114 SSET (x_error_message_string, 0, 0);
e99db5a1
RS
12115
12116 return count;
12117}
12118
12119/* Unbind the binding that we made to check for X errors. */
12120
12121static Lisp_Object
12122x_catch_errors_unwind (old_val)
12123 Lisp_Object old_val;
12124{
12125 x_error_message_string = old_val;
12126 return Qnil;
12127}
12128
12129/* If any X protocol errors have arrived since the last call to
12130 x_catch_errors or x_check_errors, signal an Emacs error using
12131 sprintf (a buffer, FORMAT, the x error message text) as the text. */
12132
12133void
12134x_check_errors (dpy, format)
12135 Display *dpy;
12136 char *format;
12137{
12138 /* Make sure to catch any errors incurred so far. */
12139 XSync (dpy, False);
12140
d5db4077
KR
12141 if (SREF (x_error_message_string, 0))
12142 error (format, SDATA (x_error_message_string));
e99db5a1
RS
12143}
12144
9829ddba
RS
12145/* Nonzero if we had any X protocol errors
12146 since we did x_catch_errors on DPY. */
e99db5a1
RS
12147
12148int
12149x_had_errors_p (dpy)
12150 Display *dpy;
12151{
12152 /* Make sure to catch any errors incurred so far. */
12153 XSync (dpy, False);
12154
d5db4077 12155 return SREF (x_error_message_string, 0) != 0;
e99db5a1
RS
12156}
12157
9829ddba
RS
12158/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
12159
06a2c219 12160void
9829ddba
RS
12161x_clear_errors (dpy)
12162 Display *dpy;
12163{
7da167cd 12164 SSET (x_error_message_string, 0, 0);
9829ddba
RS
12165}
12166
e99db5a1
RS
12167/* Stop catching X protocol errors and let them make Emacs die.
12168 DPY should be the display that was passed to x_catch_errors.
12169 COUNT should be the value that was returned by
12170 the corresponding call to x_catch_errors. */
12171
12172void
12173x_uncatch_errors (dpy, count)
12174 Display *dpy;
12175 int count;
12176{
12177 unbind_to (count, Qnil);
12178}
12179
12180#if 0
12181static unsigned int x_wire_count;
12182x_trace_wire ()
12183{
12184 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
12185}
12186#endif /* ! 0 */
12187
12188\f
12189/* Handle SIGPIPE, which can happen when the connection to a server
12190 simply goes away. SIGPIPE is handled by x_connection_signal.
7d0393cf 12191 Don't need to do anything, because the write which caused the
e99db5a1 12192 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 12193 which will do the appropriate cleanup for us. */
7d0393cf 12194
e99db5a1
RS
12195static SIGTYPE
12196x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 12197 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
12198{
12199#ifdef USG
12200 /* USG systems forget handlers when they are used;
12201 must reestablish each time */
12202 signal (signalnum, x_connection_signal);
12203#endif /* USG */
12204}
0da1ab50 12205
e99db5a1 12206\f
0da1ab50
GM
12207/************************************************************************
12208 Handling X errors
12209 ************************************************************************/
4746118a 12210
f0e299de
GM
12211/* Error message passed to x_connection_closed. */
12212
12213static char *error_msg;
12214
a7248e4f 12215/* Function installed as fatal_error_signal_hook in
f0e299de
GM
12216 x_connection_closed. Print the X error message, and exit normally,
12217 instead of dumping core when XtCloseDisplay fails. */
12218
12219static void
12220x_fatal_error_signal ()
12221{
12222 fprintf (stderr, "%s\n", error_msg);
12223 exit (70);
12224}
12225
0da1ab50
GM
12226/* Handle the loss of connection to display DPY. ERROR_MESSAGE is
12227 the text of an error message that lead to the connection loss. */
16bd92ea 12228
4746118a 12229static SIGTYPE
5978125e
GM
12230x_connection_closed (dpy, error_message)
12231 Display *dpy;
7a13e894 12232 char *error_message;
4746118a 12233{
5978125e 12234 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
7a13e894 12235 Lisp_Object frame, tail;
0da1ab50 12236 int count;
7d0393cf 12237
f0e299de
GM
12238 error_msg = (char *) alloca (strlen (error_message) + 1);
12239 strcpy (error_msg, error_message);
1a532e54 12240 handling_signal = 0;
7d0393cf 12241
0da1ab50
GM
12242 /* Prevent being called recursively because of an error condition
12243 below. Otherwise, we might end up with printing ``can't find per
12244 display information'' in the recursive call instead of printing
12245 the original message here. */
12246 count = x_catch_errors (dpy);
7d0393cf 12247
8a4f36cc
GM
12248 /* We have to close the display to inform Xt that it doesn't
12249 exist anymore. If we don't, Xt will continue to wait for
12250 events from the display. As a consequence, a sequence of
12251
12252 M-x make-frame-on-display RET :1 RET
12253 ...kill the new frame, so that we get an IO error...
12254 M-x make-frame-on-display RET :1 RET
12255
12256 will indefinitely wait in Xt for events for display `:1', opened
12257 in the first class to make-frame-on-display.
6186a4a0 12258
8a4f36cc
GM
12259 Closing the display is reported to lead to a bus error on
12260 OpenWindows in certain situations. I suspect that is a bug
12261 in OpenWindows. I don't know how to cicumvent it here. */
7d0393cf 12262
f613a4c8 12263#ifdef USE_X_TOOLKIT
ae24cb3b
GM
12264 /* If DPYINFO is null, this means we didn't open the display
12265 in the first place, so don't try to close it. */
12266 if (dpyinfo)
f0e299de
GM
12267 {
12268 extern void (*fatal_error_signal_hook) P_ ((void));
12269 fatal_error_signal_hook = x_fatal_error_signal;
12270 XtCloseDisplay (dpy);
12271 fatal_error_signal_hook = NULL;
12272 }
f613a4c8 12273#endif
adabc3a9 12274
8a4f36cc 12275 /* Indicate that this display is dead. */
9e80b57d
KR
12276 if (dpyinfo)
12277 dpyinfo->display = 0;
6186a4a0 12278
06a2c219 12279 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
12280 that are on the dead display. */
12281 FOR_EACH_FRAME (tail, frame)
12282 {
12283 Lisp_Object minibuf_frame;
12284 minibuf_frame
12285 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
12286 if (FRAME_X_P (XFRAME (frame))
12287 && FRAME_X_P (XFRAME (minibuf_frame))
12288 && ! EQ (frame, minibuf_frame)
12289 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
12290 Fdelete_frame (frame, Qt);
12291 }
12292
12293 /* Now delete all remaining frames on the dead display.
06a2c219 12294 We are now sure none of these is used as the mini-buffer
7a13e894
RS
12295 for another frame that we need to delete. */
12296 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
12297 if (FRAME_X_P (XFRAME (frame))
12298 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
12299 {
12300 /* Set this to t so that Fdelete_frame won't get confused
12301 trying to find a replacement. */
12302 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
12303 Fdelete_frame (frame, Qt);
12304 }
7a13e894 12305
482a1bd2
KH
12306 if (dpyinfo)
12307 x_delete_display (dpyinfo);
7a13e894 12308
0da1ab50 12309 x_uncatch_errors (dpy, count);
7d0393cf 12310
7a13e894
RS
12311 if (x_display_list == 0)
12312 {
f0e299de 12313 fprintf (stderr, "%s\n", error_msg);
7a13e894
RS
12314 shut_down_emacs (0, 0, Qnil);
12315 exit (70);
12316 }
12ba150f 12317
7a13e894
RS
12318 /* Ordinary stack unwind doesn't deal with these. */
12319#ifdef SIGIO
12320 sigunblock (sigmask (SIGIO));
12321#endif
12322 sigunblock (sigmask (SIGALRM));
12323 TOTALLY_UNBLOCK_INPUT;
12324
aa4d9a9e 12325 clear_waiting_for_input ();
f0e299de 12326 error ("%s", error_msg);
4746118a
JB
12327}
12328
0da1ab50 12329
7a13e894
RS
12330/* This is the usual handler for X protocol errors.
12331 It kills all frames on the display that we got the error for.
12332 If that was the only one, it prints an error message and kills Emacs. */
12333
06a2c219 12334static void
c118dd06
JB
12335x_error_quitter (display, error)
12336 Display *display;
12337 XErrorEvent *error;
12338{
7a13e894 12339 char buf[256], buf1[356];
dc6f92b8 12340
58769bee 12341 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 12342 original error handler. */
dc6f92b8 12343
c118dd06 12344 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 12345 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 12346 buf, error->request_code);
7a13e894 12347 x_connection_closed (display, buf1);
dc6f92b8
JB
12348}
12349
0da1ab50 12350
e99db5a1
RS
12351/* This is the first-level handler for X protocol errors.
12352 It calls x_error_quitter or x_error_catcher. */
7a13e894 12353
8922af5f 12354static int
e99db5a1 12355x_error_handler (display, error)
8922af5f 12356 Display *display;
e99db5a1 12357 XErrorEvent *error;
8922af5f 12358{
e99db5a1
RS
12359 if (! NILP (x_error_message_string))
12360 x_error_catcher (display, error);
12361 else
12362 x_error_quitter (display, error);
06a2c219 12363 return 0;
f9e24cb9 12364}
c118dd06 12365
e99db5a1
RS
12366/* This is the handler for X IO errors, always.
12367 It kills all frames on the display that we lost touch with.
12368 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 12369
c118dd06 12370static int
e99db5a1 12371x_io_error_quitter (display)
c118dd06 12372 Display *display;
c118dd06 12373{
e99db5a1 12374 char buf[256];
dc6f92b8 12375
e99db5a1
RS
12376 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
12377 x_connection_closed (display, buf);
06a2c219 12378 return 0;
dc6f92b8 12379}
dc6f92b8 12380\f
f451eb13
JB
12381/* Changing the font of the frame. */
12382
76bcdf39
RS
12383/* Give frame F the font named FONTNAME as its default font, and
12384 return the full name of that font. FONTNAME may be a wildcard
12385 pattern; in that case, we choose some font that fits the pattern.
12386 The return value shows which font we chose. */
12387
b5cf7a0e 12388Lisp_Object
f676886a
JB
12389x_new_font (f, fontname)
12390 struct frame *f;
dc6f92b8
JB
12391 register char *fontname;
12392{
dc43ef94 12393 struct font_info *fontp
ee569018 12394 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 12395
dc43ef94
KH
12396 if (!fontp)
12397 return Qnil;
2224a5fc 12398
dc43ef94 12399 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 12400 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94 12401 f->output_data.x->fontset = -1;
976b73d7
KS
12402
12403 x_compute_fringe_widths (f, 1);
12404
b2cad826
KH
12405 /* Compute the scroll bar width in character columns. */
12406 if (f->scroll_bar_pixel_width > 0)
12407 {
7556890b 12408 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
12409 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
12410 }
12411 else
4e61bddf
RS
12412 {
12413 int wid = FONT_WIDTH (f->output_data.x->font);
12414 f->scroll_bar_cols = (14 + wid - 1) / wid;
12415 }
b2cad826 12416
f676886a 12417 /* Now make the frame display the given font. */
c118dd06 12418 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 12419 {
7556890b
RS
12420 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
12421 f->output_data.x->font->fid);
12422 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
12423 f->output_data.x->font->fid);
12424 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
12425 f->output_data.x->font->fid);
f676886a 12426
a27f9f86 12427 frame_update_line_height (f);
3497f73e
GM
12428
12429 /* Don't change the size of a tip frame; there's no point in
12430 doing it because it's done in Fx_show_tip, and it leads to
12431 problems because the tip frame has no widget. */
12432 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
12433 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 12434 }
a27f9f86
RS
12435 else
12436 /* If we are setting a new frame's font for the first time,
12437 there are no faces yet, so this font's height is the line height. */
7556890b 12438 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 12439
dc43ef94
KH
12440 return build_string (fontp->full_name);
12441}
12442
12443/* Give frame F the fontset named FONTSETNAME as its default font, and
12444 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
12445 pattern; in that case, we choose some fontset that fits the pattern.
12446 The return value shows which fontset we chose. */
b5cf7a0e 12447
dc43ef94
KH
12448Lisp_Object
12449x_new_fontset (f, fontsetname)
12450 struct frame *f;
12451 char *fontsetname;
12452{
ee569018 12453 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 12454 Lisp_Object result;
b5cf7a0e 12455
dc43ef94
KH
12456 if (fontset < 0)
12457 return Qnil;
b5cf7a0e 12458
2da424f1
KH
12459 if (f->output_data.x->fontset == fontset)
12460 /* This fontset is already set in frame F. There's nothing more
12461 to do. */
ee569018 12462 return fontset_name (fontset);
dc43ef94 12463
d5db4077 12464 result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
dc43ef94
KH
12465
12466 if (!STRINGP (result))
12467 /* Can't load ASCII font. */
12468 return Qnil;
12469
12470 /* Since x_new_font doesn't update any fontset information, do it now. */
12471 f->output_data.x->fontset = fontset;
dc43ef94 12472
f5d11644
GM
12473#ifdef HAVE_X_I18N
12474 if (FRAME_XIC (f)
12475 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
d5db4077 12476 xic_set_xfontset (f, SDATA (fontset_ascii (fontset)));
f5d11644 12477#endif
7d0393cf 12478
dc43ef94 12479 return build_string (fontsetname);
dc6f92b8 12480}
f5d11644 12481
976b73d7
KS
12482/* Compute actual fringe widths */
12483
12484void
12485x_compute_fringe_widths (f, redraw)
12486 struct frame *f;
12487 int redraw;
12488{
12489 int o_left = f->output_data.x->left_fringe_width;
12490 int o_right = f->output_data.x->right_fringe_width;
12491 int o_cols = f->output_data.x->fringe_cols;
12492
12493 Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist);
12494 Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist);
12495 int left_fringe_width, right_fringe_width;
12496
12497 if (!NILP (left_fringe))
12498 left_fringe = Fcdr (left_fringe);
12499 if (!NILP (right_fringe))
12500 right_fringe = Fcdr (right_fringe);
12501
12502 left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 :
12503 XINT (left_fringe));
12504 right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 :
12505 XINT (right_fringe));
12506
12507 if (left_fringe_width || right_fringe_width)
12508 {
12509 int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width;
12510 int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width;
12511 int conf_wid = left_wid + right_wid;
12512 int font_wid = FONT_WIDTH (f->output_data.x->font);
12513 int cols = (left_wid + right_wid + font_wid-1) / font_wid;
12514 int real_wid = cols * font_wid;
12515 if (left_wid && right_wid)
12516 {
12517 if (left_fringe_width < 0)
12518 {
12519 /* Left fringe width is fixed, adjust right fringe if necessary */
12520 f->output_data.x->left_fringe_width = left_wid;
12521 f->output_data.x->right_fringe_width = real_wid - left_wid;
12522 }
12523 else if (right_fringe_width < 0)
12524 {
12525 /* Right fringe width is fixed, adjust left fringe if necessary */
12526 f->output_data.x->left_fringe_width = real_wid - right_wid;
12527 f->output_data.x->right_fringe_width = right_wid;
12528 }
12529 else
12530 {
12531 /* Adjust both fringes with an equal amount.
12532 Note that we are doing integer arithmetic here, so don't
12533 lose a pixel if the total width is an odd number. */
12534 int fill = real_wid - conf_wid;
12535 f->output_data.x->left_fringe_width = left_wid + fill/2;
12536 f->output_data.x->right_fringe_width = right_wid + fill - fill/2;
12537 }
12538 }
12539 else if (left_fringe_width)
12540 {
12541 f->output_data.x->left_fringe_width = real_wid;
12542 f->output_data.x->right_fringe_width = 0;
12543 }
12544 else
12545 {
12546 f->output_data.x->left_fringe_width = 0;
12547 f->output_data.x->right_fringe_width = real_wid;
12548 }
12549 f->output_data.x->fringe_cols = cols;
12550 f->output_data.x->fringes_extra = real_wid;
12551 }
12552 else
12553 {
12554 f->output_data.x->left_fringe_width = 0;
12555 f->output_data.x->right_fringe_width = 0;
12556 f->output_data.x->fringe_cols = 0;
12557 f->output_data.x->fringes_extra = 0;
12558 }
12559
12560 if (redraw && FRAME_VISIBLE_P (f))
12561 if (o_left != f->output_data.x->left_fringe_width ||
12562 o_right != f->output_data.x->right_fringe_width ||
12563 o_cols != f->output_data.x->fringe_cols)
12564 redraw_frame (f);
12565}
f5d11644
GM
12566\f
12567/***********************************************************************
12568 X Input Methods
12569 ***********************************************************************/
12570
12571#ifdef HAVE_X_I18N
12572
12573#ifdef HAVE_X11R6
12574
12575/* XIM destroy callback function, which is called whenever the
12576 connection to input method XIM dies. CLIENT_DATA contains a
12577 pointer to the x_display_info structure corresponding to XIM. */
12578
12579static void
12580xim_destroy_callback (xim, client_data, call_data)
12581 XIM xim;
12582 XPointer client_data;
12583 XPointer call_data;
12584{
12585 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
12586 Lisp_Object frame, tail;
7d0393cf 12587
f5d11644 12588 BLOCK_INPUT;
7d0393cf 12589
f5d11644
GM
12590 /* No need to call XDestroyIC.. */
12591 FOR_EACH_FRAME (tail, frame)
12592 {
12593 struct frame *f = XFRAME (frame);
12594 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
12595 {
12596 FRAME_XIC (f) = NULL;
12597 if (FRAME_XIC_FONTSET (f))
12598 {
12599 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
12600 FRAME_XIC_FONTSET (f) = NULL;
12601 }
12602 }
12603 }
7d0393cf 12604
f5d11644
GM
12605 /* No need to call XCloseIM. */
12606 dpyinfo->xim = NULL;
12607 XFree (dpyinfo->xim_styles);
12608 UNBLOCK_INPUT;
12609}
12610
12611#endif /* HAVE_X11R6 */
12612
12613/* Open the connection to the XIM server on display DPYINFO.
12614 RESOURCE_NAME is the resource name Emacs uses. */
12615
12616static void
12617xim_open_dpy (dpyinfo, resource_name)
12618 struct x_display_info *dpyinfo;
12619 char *resource_name;
12620{
287f7dd6 12621#ifdef USE_XIM
f5d11644
GM
12622 XIM xim;
12623
12624 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
12625 dpyinfo->xim = xim;
12626
12627 if (xim)
12628 {
f5d11644
GM
12629#ifdef HAVE_X11R6
12630 XIMCallback destroy;
12631#endif
7d0393cf 12632
f5d11644
GM
12633 /* Get supported styles and XIM values. */
12634 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
7d0393cf 12635
f5d11644
GM
12636#ifdef HAVE_X11R6
12637 destroy.callback = xim_destroy_callback;
12638 destroy.client_data = (XPointer)dpyinfo;
cea2ad76 12639 /* This isn't prototyped in OSF 5.0. */
f5d11644
GM
12640 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
12641#endif
12642 }
7d0393cf 12643
287f7dd6
GM
12644#else /* not USE_XIM */
12645 dpyinfo->xim = NULL;
12646#endif /* not USE_XIM */
f5d11644
GM
12647}
12648
12649
b9de836c 12650#ifdef HAVE_X11R6_XIM
f5d11644
GM
12651
12652struct xim_inst_t
12653{
12654 struct x_display_info *dpyinfo;
12655 char *resource_name;
12656};
12657
12658/* XIM instantiate callback function, which is called whenever an XIM
12659 server is available. DISPLAY is teh display of the XIM.
12660 CLIENT_DATA contains a pointer to an xim_inst_t structure created
12661 when the callback was registered. */
12662
12663static void
12664xim_instantiate_callback (display, client_data, call_data)
12665 Display *display;
12666 XPointer client_data;
12667 XPointer call_data;
12668{
12669 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
12670 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
12671
12672 /* We don't support multiple XIM connections. */
12673 if (dpyinfo->xim)
12674 return;
7d0393cf 12675
f5d11644
GM
12676 xim_open_dpy (dpyinfo, xim_inst->resource_name);
12677
12678 /* Create XIC for the existing frames on the same display, as long
12679 as they have no XIC. */
12680 if (dpyinfo->xim && dpyinfo->reference_count > 0)
12681 {
12682 Lisp_Object tail, frame;
12683
12684 BLOCK_INPUT;
12685 FOR_EACH_FRAME (tail, frame)
12686 {
12687 struct frame *f = XFRAME (frame);
7d0393cf 12688
f5d11644
GM
12689 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
12690 if (FRAME_XIC (f) == NULL)
12691 {
12692 create_frame_xic (f);
12693 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
12694 xic_set_statusarea (f);
12695 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
12696 {
12697 struct window *w = XWINDOW (f->selected_window);
12698 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
12699 }
12700 }
12701 }
7d0393cf 12702
f5d11644
GM
12703 UNBLOCK_INPUT;
12704 }
12705}
12706
b9de836c 12707#endif /* HAVE_X11R6_XIM */
f5d11644
GM
12708
12709
12710/* Open a connection to the XIM server on display DPYINFO.
12711 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
12712 connection only at the first time. On X11R6, open the connection
12713 in the XIM instantiate callback function. */
12714
12715static void
12716xim_initialize (dpyinfo, resource_name)
12717 struct x_display_info *dpyinfo;
12718 char *resource_name;
12719{
287f7dd6 12720#ifdef USE_XIM
b9de836c 12721#ifdef HAVE_X11R6_XIM
f5d11644
GM
12722 struct xim_inst_t *xim_inst;
12723 int len;
7d0393cf 12724
f5d11644
GM
12725 dpyinfo->xim = NULL;
12726 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
12727 xim_inst->dpyinfo = dpyinfo;
12728 len = strlen (resource_name);
12729 xim_inst->resource_name = (char *) xmalloc (len + 1);
12730 bcopy (resource_name, xim_inst->resource_name, len + 1);
12731 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12732 resource_name, EMACS_CLASS,
12733 xim_instantiate_callback,
2ebb2f8b
DL
12734 /* Fixme: This is XPointer in
12735 XFree86 but (XPointer *) on
12736 Tru64, at least. */
12737 (XPointer) xim_inst);
b9de836c 12738#else /* not HAVE_X11R6_XIM */
f5d11644
GM
12739 dpyinfo->xim = NULL;
12740 xim_open_dpy (dpyinfo, resource_name);
b9de836c 12741#endif /* not HAVE_X11R6_XIM */
7d0393cf 12742
287f7dd6
GM
12743#else /* not USE_XIM */
12744 dpyinfo->xim = NULL;
12745#endif /* not USE_XIM */
f5d11644
GM
12746}
12747
12748
12749/* Close the connection to the XIM server on display DPYINFO. */
12750
12751static void
12752xim_close_dpy (dpyinfo)
12753 struct x_display_info *dpyinfo;
12754{
287f7dd6 12755#ifdef USE_XIM
b9de836c 12756#ifdef HAVE_X11R6_XIM
8a4f36cc
GM
12757 if (dpyinfo->display)
12758 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12759 NULL, EMACS_CLASS,
12760 xim_instantiate_callback, NULL);
b9de836c 12761#endif /* not HAVE_X11R6_XIM */
8a4f36cc
GM
12762 if (dpyinfo->display)
12763 XCloseIM (dpyinfo->xim);
f5d11644
GM
12764 dpyinfo->xim = NULL;
12765 XFree (dpyinfo->xim_styles);
287f7dd6 12766#endif /* USE_XIM */
f5d11644
GM
12767}
12768
b9de836c 12769#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
12770
12771
dc6f92b8 12772\f
2e365682
RS
12773/* Calculate the absolute position in frame F
12774 from its current recorded position values and gravity. */
12775
dfcf069d 12776void
43bca5d5 12777x_calc_absolute_position (f)
f676886a 12778 struct frame *f;
dc6f92b8 12779{
06a2c219 12780 Window child;
6dba1858 12781 int win_x = 0, win_y = 0;
7556890b 12782 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
12783 int this_window;
12784
9829ddba
RS
12785 /* We have nothing to do if the current position
12786 is already for the top-left corner. */
12787 if (! ((flags & XNegative) || (flags & YNegative)))
12788 return;
12789
c81412a0 12790#ifdef USE_X_TOOLKIT
7556890b 12791 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
12792#else
12793 this_window = FRAME_X_WINDOW (f);
12794#endif
6dba1858
RS
12795
12796 /* Find the position of the outside upper-left corner of
9829ddba
RS
12797 the inner window, with respect to the outer window.
12798 But do this only if we will need the results. */
7556890b 12799 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 12800 {
9829ddba
RS
12801 int count;
12802
6dba1858 12803 BLOCK_INPUT;
9829ddba
RS
12804 count = x_catch_errors (FRAME_X_DISPLAY (f));
12805 while (1)
12806 {
12807 x_clear_errors (FRAME_X_DISPLAY (f));
12808 XTranslateCoordinates (FRAME_X_DISPLAY (f),
12809
12810 /* From-window, to-window. */
12811 this_window,
12812 f->output_data.x->parent_desc,
12813
12814 /* From-position, to-position. */
12815 0, 0, &win_x, &win_y,
12816
12817 /* Child of win. */
12818 &child);
12819 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12820 {
12821 Window newroot, newparent = 0xdeadbeef;
12822 Window *newchildren;
2ebb2f8b 12823 unsigned int nchildren;
9829ddba
RS
12824
12825 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
12826 &newparent, &newchildren, &nchildren))
12827 break;
58769bee 12828
7c3c78a3 12829 XFree ((char *) newchildren);
6dba1858 12830
9829ddba
RS
12831 f->output_data.x->parent_desc = newparent;
12832 }
12833 else
12834 break;
12835 }
6dba1858 12836
9829ddba 12837 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
12838 UNBLOCK_INPUT;
12839 }
12840
12841 /* Treat negative positions as relative to the leftmost bottommost
12842 position that fits on the screen. */
20f55f9a 12843 if (flags & XNegative)
7556890b 12844 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
12845 - 2 * f->output_data.x->border_width - win_x
12846 - PIXEL_WIDTH (f)
12847 + f->output_data.x->left_pos);
dc6f92b8 12848
7708ced0
GM
12849 {
12850 int height = PIXEL_HEIGHT (f);
06a2c219 12851
7708ced0
GM
12852#if defined USE_X_TOOLKIT && defined USE_MOTIF
12853 /* Something is fishy here. When using Motif, starting Emacs with
12854 `-g -0-0', the frame appears too low by a few pixels.
12855
12856 This seems to be so because initially, while Emacs is starting,
12857 the column widget's height and the frame's pixel height are
12858 different. The column widget's height is the right one. In
12859 later invocations, when Emacs is up, the frame's pixel height
12860 is right, though.
12861
12862 It's not obvious where the initial small difference comes from.
12863 2000-12-01, gerd. */
7d0393cf 12864
7708ced0 12865 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
06a2c219 12866#endif
2e365682 12867
7708ced0
GM
12868 if (flags & YNegative)
12869 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
12870 - 2 * f->output_data.x->border_width
12871 - win_y
12872 - height
12873 + f->output_data.x->top_pos);
12874 }
7d0393cf 12875
3a35ab44
RS
12876 /* The left_pos and top_pos
12877 are now relative to the top and left screen edges,
12878 so the flags should correspond. */
7556890b 12879 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
12880}
12881
3a35ab44
RS
12882/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
12883 to really change the position, and 0 when calling from
12884 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
12885 position values). It is -1 when calling from x_set_frame_parameters,
12886 which means, do adjust for borders but don't change the gravity. */
3a35ab44 12887
dfcf069d 12888void
dc05a16b 12889x_set_offset (f, xoff, yoff, change_gravity)
f676886a 12890 struct frame *f;
dc6f92b8 12891 register int xoff, yoff;
dc05a16b 12892 int change_gravity;
dc6f92b8 12893{
4a4cbdd5
KH
12894 int modified_top, modified_left;
12895
aa3ff7c9 12896 if (change_gravity > 0)
3a35ab44 12897 {
7556890b
RS
12898 f->output_data.x->top_pos = yoff;
12899 f->output_data.x->left_pos = xoff;
12900 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 12901 if (xoff < 0)
7556890b 12902 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 12903 if (yoff < 0)
7556890b
RS
12904 f->output_data.x->size_hint_flags |= YNegative;
12905 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 12906 }
43bca5d5 12907 x_calc_absolute_position (f);
dc6f92b8
JB
12908
12909 BLOCK_INPUT;
c32cdd9a 12910 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 12911
7556890b
RS
12912 modified_left = f->output_data.x->left_pos;
12913 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
12914#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
12915 this seems to be unnecessary and incorrect. rms, 4/17/97. */
12916 /* It is a mystery why we need to add the border_width here
12917 when the frame is already visible, but experiment says we do. */
aa3ff7c9 12918 if (change_gravity != 0)
4a4cbdd5 12919 {
7556890b
RS
12920 modified_left += f->output_data.x->border_width;
12921 modified_top += f->output_data.x->border_width;
4a4cbdd5 12922 }
e73ec6fa 12923#endif
4a4cbdd5 12924
3afe33e7 12925#ifdef USE_X_TOOLKIT
7556890b 12926 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 12927 modified_left, modified_top);
3afe33e7 12928#else /* not USE_X_TOOLKIT */
334208b7 12929 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 12930 modified_left, modified_top);
3afe33e7 12931#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12932 UNBLOCK_INPUT;
12933}
12934
d0fa3e56
EZ
12935/* Check if we need to resize the frame due to a fullscreen request.
12936 If so needed, resize the frame. */
12937static void
12938x_check_fullscreen (f)
12939 struct frame *f;
12940{
12941 if (f->output_data.x->want_fullscreen & FULLSCREEN_BOTH)
12942 {
12943 int width, height, ign;
7d0393cf 12944
d0fa3e56
EZ
12945 x_real_positions (f, &f->output_data.x->left_pos,
12946 &f->output_data.x->top_pos);
12947
12948 x_fullscreen_adjust (f, &width, &height, &ign, &ign);
7d0393cf 12949
d0fa3e56
EZ
12950 /* We do not need to move the window, it shall be taken care of
12951 when setting WM manager hints.
12952 If the frame is visible already, the position is checked by
12953 x_check_fullscreen_move. */
12954 if (f->width != width || f->height != height)
12955 {
12956 change_frame_size (f, height, width, 0, 1, 0);
12957 SET_FRAME_GARBAGED (f);
12958 cancel_mouse_face (f);
12959
12960 /* Wait for the change of frame size to occur */
12961 f->output_data.x->want_fullscreen |= FULLSCREEN_WAIT;
7d0393cf 12962
d0fa3e56
EZ
12963 }
12964 }
12965}
12966
12967/* If frame parameters are set after the frame is mapped, we need to move
12968 the window. This is done in xfns.c.
12969 Some window managers moves the window to the right position, some
12970 moves the outer window manager window to the specified position.
12971 Here we check that we are in the right spot. If not, make a second
12972 move, assuming we are dealing with the second kind of window manager. */
12973static void
12974x_check_fullscreen_move (f)
12975 struct frame *f;
12976{
12977 if (f->output_data.x->want_fullscreen & FULLSCREEN_MOVE_WAIT)
12978 {
12979 int expect_top = f->output_data.x->top_pos;
12980 int expect_left = f->output_data.x->left_pos;
12981
12982 if (f->output_data.x->want_fullscreen & FULLSCREEN_HEIGHT)
12983 expect_top = 0;
12984 if (f->output_data.x->want_fullscreen & FULLSCREEN_WIDTH)
12985 expect_left = 0;
7d0393cf 12986
d0fa3e56
EZ
12987 if (expect_top != f->output_data.x->top_pos
12988 || expect_left != f->output_data.x->left_pos)
12989 x_set_offset (f, expect_left, expect_top, 1);
12990
12991 /* Just do this once */
12992 f->output_data.x->want_fullscreen &= ~FULLSCREEN_MOVE_WAIT;
12993 }
12994}
12995
12996
12997/* Calculate fullscreen size. Return in *TOP_POS and *LEFT_POS the
12998 wanted positions of the WM window (not emacs window).
12999 Return in *WIDTH and *HEIGHT the wanted width and height of Emacs
13000 window (FRAME_X_WINDOW).
13001 */
13002void
13003x_fullscreen_adjust (f, width, height, top_pos, left_pos)
13004 struct frame *f;
13005 int *width;
13006 int *height;
13007 int *top_pos;
13008 int *left_pos;
13009{
13010 int newwidth = f->width, newheight = f->height;
13011
13012 *top_pos = f->output_data.x->top_pos;
13013 *left_pos = f->output_data.x->left_pos;
7d0393cf 13014
d0fa3e56
EZ
13015 if (f->output_data.x->want_fullscreen & FULLSCREEN_HEIGHT)
13016 {
13017 int ph;
7d0393cf 13018
d0fa3e56
EZ
13019 ph = FRAME_X_DISPLAY_INFO (f)->height;
13020 newheight = PIXEL_TO_CHAR_HEIGHT (f, ph);
13021 ph = CHAR_TO_PIXEL_HEIGHT (f, newheight)
13022 - f->output_data.x->y_pixels_diff;
13023 newheight = PIXEL_TO_CHAR_HEIGHT (f, ph);
13024 *top_pos = 0;
13025 }
13026
13027 if (f->output_data.x->want_fullscreen & FULLSCREEN_WIDTH)
13028 {
13029 int pw;
7d0393cf 13030
d0fa3e56
EZ
13031 pw = FRAME_X_DISPLAY_INFO (f)->width;
13032 newwidth = PIXEL_TO_CHAR_WIDTH (f, pw);
13033 pw = CHAR_TO_PIXEL_WIDTH (f, newwidth)
13034 - f->output_data.x->x_pixels_diff;
13035 newwidth = PIXEL_TO_CHAR_WIDTH (f, pw);
13036 *left_pos = 0;
13037 }
13038
13039 *width = newwidth;
13040 *height = newheight;
13041}
13042
dc6f92b8 13043
499b1844
GM
13044/* Change the size of frame F's X window to COLS/ROWS in the case F
13045 doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
13046 top-left-corner window gravity for this size change and subsequent
13047 size changes. Otherwise we leave the window gravity unchanged. */
13048
13049static void
13050x_set_window_size_1 (f, change_gravity, cols, rows)
f676886a 13051 struct frame *f;
bc20ebbf 13052 int change_gravity;
b1c884c3 13053 int cols, rows;
dc6f92b8
JB
13054{
13055 int pixelwidth, pixelheight;
80fd1fe2 13056
b1c884c3 13057 check_frame_size (f, &rows, &cols);
7556890b 13058 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
13059 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
13060 ? 0
13061 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 13062 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 13063 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
976b73d7
KS
13064
13065 x_compute_fringe_widths (f, 0);
13066
f451eb13
JB
13067 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
13068 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 13069
7556890b 13070 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 13071 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 13072
334208b7
RS
13073 XSync (FRAME_X_DISPLAY (f), False);
13074 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
13075 pixelwidth, pixelheight);
b1c884c3
JB
13076
13077 /* Now, strictly speaking, we can't be sure that this is accurate,
13078 but the window manager will get around to dealing with the size
13079 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
13080 ConfigureNotify event gets here.
13081
13082 We could just not bother storing any of this information here,
13083 and let the ConfigureNotify event set everything up, but that
fddd5ceb 13084 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 13085 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
13086 point in the future when the ConfigureNotify event arrives.
13087
13088 We pass 1 for DELAY since we can't run Lisp code inside of
13089 a BLOCK_INPUT. */
7d1e984f 13090 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
13091 PIXEL_WIDTH (f) = pixelwidth;
13092 PIXEL_HEIGHT (f) = pixelheight;
13093
aee9a898
RS
13094 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
13095 receive in the ConfigureNotify event; if we get what we asked
13096 for, then the event won't cause the screen to become garbaged, so
13097 we have to make sure to do it here. */
13098 SET_FRAME_GARBAGED (f);
13099
13100 XFlush (FRAME_X_DISPLAY (f));
499b1844
GM
13101}
13102
13103
13104/* Call this to change the size of frame F's x-window.
13105 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
13106 for this size change and subsequent size changes.
13107 Otherwise we leave the window gravity unchanged. */
aee9a898 13108
499b1844
GM
13109void
13110x_set_window_size (f, change_gravity, cols, rows)
13111 struct frame *f;
13112 int change_gravity;
13113 int cols, rows;
13114{
13115 BLOCK_INPUT;
13116
13117#ifdef USE_X_TOOLKIT
7d0393cf 13118
f1f4d345 13119 if (f->output_data.x->widget != NULL)
499b1844
GM
13120 {
13121 /* The x and y position of the widget is clobbered by the
13122 call to XtSetValues within EmacsFrameSetCharSize.
13123 This is a real kludge, but I don't understand Xt so I can't
13124 figure out a correct fix. Can anyone else tell me? -- rms. */
13125 int xpos = f->output_data.x->widget->core.x;
13126 int ypos = f->output_data.x->widget->core.y;
13127 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
13128 f->output_data.x->widget->core.x = xpos;
13129 f->output_data.x->widget->core.y = ypos;
13130 }
13131 else
13132 x_set_window_size_1 (f, change_gravity, cols, rows);
7d0393cf 13133
499b1844 13134#else /* not USE_X_TOOLKIT */
7d0393cf 13135
499b1844 13136 x_set_window_size_1 (f, change_gravity, cols, rows);
7d0393cf 13137
aee9a898
RS
13138#endif /* not USE_X_TOOLKIT */
13139
4d73d038 13140 /* If cursor was outside the new size, mark it as off. */
06a2c219 13141 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 13142
aee9a898 13143 /* Clear out any recollection of where the mouse highlighting was,
7d0393cf 13144 since it might be in a place that's outside the new frame size.
aee9a898
RS
13145 Actually checking whether it is outside is a pain in the neck,
13146 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 13147 cancel_mouse_face (f);
dbc4e1c1 13148
dc6f92b8
JB
13149 UNBLOCK_INPUT;
13150}
dc6f92b8 13151\f
d047c4eb 13152/* Mouse warping. */
dc6f92b8 13153
9b378208 13154void
f676886a
JB
13155x_set_mouse_position (f, x, y)
13156 struct frame *f;
dc6f92b8
JB
13157 int x, y;
13158{
13159 int pix_x, pix_y;
13160
7556890b
RS
13161 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
13162 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
13163
13164 if (pix_x < 0) pix_x = 0;
13165 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
13166
13167 if (pix_y < 0) pix_y = 0;
13168 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
13169
13170 BLOCK_INPUT;
dc6f92b8 13171
334208b7
RS
13172 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
13173 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
13174 UNBLOCK_INPUT;
13175}
13176
9b378208
RS
13177/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
13178
13179void
13180x_set_mouse_pixel_position (f, pix_x, pix_y)
13181 struct frame *f;
13182 int pix_x, pix_y;
13183{
13184 BLOCK_INPUT;
13185
334208b7
RS
13186 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
13187 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
13188 UNBLOCK_INPUT;
13189}
d047c4eb
KH
13190\f
13191/* focus shifting, raising and lowering. */
9b378208 13192
dfcf069d 13193void
f676886a
JB
13194x_focus_on_frame (f)
13195 struct frame *f;
dc6f92b8 13196{
1fb20991 13197#if 0 /* This proves to be unpleasant. */
f676886a 13198 x_raise_frame (f);
1fb20991 13199#endif
6d4238f3
JB
13200#if 0
13201 /* I don't think that the ICCCM allows programs to do things like this
13202 without the interaction of the window manager. Whatever you end up
f676886a 13203 doing with this code, do it to x_unfocus_frame too. */
334208b7 13204 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 13205 RevertToPointerRoot, CurrentTime);
c118dd06 13206#endif /* ! 0 */
dc6f92b8
JB
13207}
13208
dfcf069d 13209void
f676886a
JB
13210x_unfocus_frame (f)
13211 struct frame *f;
dc6f92b8 13212{
6d4238f3 13213#if 0
f676886a 13214 /* Look at the remarks in x_focus_on_frame. */
0f941935 13215 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 13216 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 13217 RevertToPointerRoot, CurrentTime);
c118dd06 13218#endif /* ! 0 */
dc6f92b8
JB
13219}
13220
f676886a 13221/* Raise frame F. */
dc6f92b8 13222
dfcf069d 13223void
f676886a
JB
13224x_raise_frame (f)
13225 struct frame *f;
dc6f92b8 13226{
3a88c238 13227 if (f->async_visible)
dc6f92b8
JB
13228 {
13229 BLOCK_INPUT;
3afe33e7 13230#ifdef USE_X_TOOLKIT
7556890b 13231 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 13232#else /* not USE_X_TOOLKIT */
334208b7 13233 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 13234#endif /* not USE_X_TOOLKIT */
334208b7 13235 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
13236 UNBLOCK_INPUT;
13237 }
13238}
13239
f676886a 13240/* Lower frame F. */
dc6f92b8 13241
dfcf069d 13242void
f676886a
JB
13243x_lower_frame (f)
13244 struct frame *f;
dc6f92b8 13245{
3a88c238 13246 if (f->async_visible)
dc6f92b8
JB
13247 {
13248 BLOCK_INPUT;
3afe33e7 13249#ifdef USE_X_TOOLKIT
7556890b 13250 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 13251#else /* not USE_X_TOOLKIT */
334208b7 13252 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 13253#endif /* not USE_X_TOOLKIT */
334208b7 13254 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
13255 UNBLOCK_INPUT;
13256 }
13257}
13258
dbc4e1c1 13259static void
6b0442dc 13260XTframe_raise_lower (f, raise_flag)
dbc4e1c1 13261 FRAME_PTR f;
6b0442dc 13262 int raise_flag;
dbc4e1c1 13263{
6b0442dc 13264 if (raise_flag)
dbc4e1c1
JB
13265 x_raise_frame (f);
13266 else
13267 x_lower_frame (f);
13268}
d047c4eb
KH
13269\f
13270/* Change of visibility. */
dc6f92b8 13271
9382638d
KH
13272/* This tries to wait until the frame is really visible.
13273 However, if the window manager asks the user where to position
13274 the frame, this will return before the user finishes doing that.
13275 The frame will not actually be visible at that time,
13276 but it will become visible later when the window manager
13277 finishes with it. */
13278
dfcf069d 13279void
f676886a
JB
13280x_make_frame_visible (f)
13281 struct frame *f;
dc6f92b8 13282{
990ba854 13283 Lisp_Object type;
1aa6072f 13284 int original_top, original_left;
31be9251
GM
13285 int retry_count = 2;
13286
13287 retry:
dc6f92b8 13288
dc6f92b8 13289 BLOCK_INPUT;
dc6f92b8 13290
990ba854
RS
13291 type = x_icon_type (f);
13292 if (!NILP (type))
13293 x_bitmap_icon (f, type);
bdcd49ba 13294
f676886a 13295 if (! FRAME_VISIBLE_P (f))
90e65f07 13296 {
1aa6072f
RS
13297 /* We test FRAME_GARBAGED_P here to make sure we don't
13298 call x_set_offset a second time
13299 if we get to x_make_frame_visible a second time
13300 before the window gets really visible. */
13301 if (! FRAME_ICONIFIED_P (f)
13302 && ! f->output_data.x->asked_for_visible)
13303 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
13304
13305 f->output_data.x->asked_for_visible = 1;
13306
90e65f07 13307 if (! EQ (Vx_no_window_manager, Qt))
f676886a 13308 x_wm_set_window_state (f, NormalState);
3afe33e7 13309#ifdef USE_X_TOOLKIT
d7a38a2e 13310 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 13311 XtMapWidget (f->output_data.x->widget);
3afe33e7 13312#else /* not USE_X_TOOLKIT */
7f9c7f94 13313 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 13314#endif /* not USE_X_TOOLKIT */
0134a210
RS
13315#if 0 /* This seems to bring back scroll bars in the wrong places
13316 if the window configuration has changed. They seem
13317 to come back ok without this. */
ab648270 13318 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 13319 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 13320#endif
90e65f07 13321 }
dc6f92b8 13322
334208b7 13323 XFlush (FRAME_X_DISPLAY (f));
90e65f07 13324
0dacf791
RS
13325 /* Synchronize to ensure Emacs knows the frame is visible
13326 before we do anything else. We do this loop with input not blocked
13327 so that incoming events are handled. */
13328 {
13329 Lisp_Object frame;
12ce2351 13330 int count;
28c01ffe
RS
13331 /* This must be before UNBLOCK_INPUT
13332 since events that arrive in response to the actions above
13333 will set it when they are handled. */
13334 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
13335
13336 original_left = f->output_data.x->left_pos;
13337 original_top = f->output_data.x->top_pos;
c0a04927
RS
13338
13339 /* This must come after we set COUNT. */
13340 UNBLOCK_INPUT;
13341
2745e6c4 13342 /* We unblock here so that arriving X events are processed. */
1aa6072f 13343
dcb07ae9
RS
13344 /* Now move the window back to where it was "supposed to be".
13345 But don't do it if the gravity is negative.
13346 When the gravity is negative, this uses a position
28c01ffe
RS
13347 that is 3 pixels too low. Perhaps that's really the border width.
13348
13349 Don't do this if the window has never been visible before,
13350 because the window manager may choose the position
13351 and we don't want to override it. */
1aa6072f 13352
4d3f5d9a 13353 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 13354 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 13355 && previously_visible)
1aa6072f 13356 {
2745e6c4
RS
13357 Drawable rootw;
13358 int x, y;
13359 unsigned int width, height, border, depth;
7d0393cf 13360
1aa6072f 13361 BLOCK_INPUT;
9829ddba 13362
06a2c219
GM
13363 /* On some window managers (such as FVWM) moving an existing
13364 window, even to the same place, causes the window manager
13365 to introduce an offset. This can cause the window to move
13366 to an unexpected location. Check the geometry (a little
13367 slow here) and then verify that the window is in the right
13368 place. If the window is not in the right place, move it
13369 there, and take the potential window manager hit. */
2745e6c4
RS
13370 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
13371 &rootw, &x, &y, &width, &height, &border, &depth);
13372
13373 if (original_left != x || original_top != y)
13374 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
13375 original_left, original_top);
13376
1aa6072f
RS
13377 UNBLOCK_INPUT;
13378 }
9829ddba 13379
e0c1aef2 13380 XSETFRAME (frame, f);
c0a04927 13381
12ce2351
GM
13382 /* Wait until the frame is visible. Process X events until a
13383 MapNotify event has been seen, or until we think we won't get a
13384 MapNotify at all.. */
13385 for (count = input_signal_count + 10;
13386 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 13387 {
12ce2351 13388 /* Force processing of queued events. */
334208b7 13389 x_sync (f);
12ce2351
GM
13390
13391 /* Machines that do polling rather than SIGIO have been
13392 observed to go into a busy-wait here. So we'll fake an
13393 alarm signal to let the handler know that there's something
13394 to be read. We used to raise a real alarm, but it seems
13395 that the handler isn't always enabled here. This is
13396 probably a bug. */
8b2f8d4e 13397 if (input_polling_used ())
3b2fa4e6 13398 {
12ce2351
GM
13399 /* It could be confusing if a real alarm arrives while
13400 processing the fake one. Turn it off and let the
13401 handler reset it. */
3e71d8f2 13402 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
13403 int old_poll_suppress_count = poll_suppress_count;
13404 poll_suppress_count = 1;
13405 poll_for_input_1 ();
13406 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 13407 }
12ce2351
GM
13408
13409 /* See if a MapNotify event has been processed. */
13410 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 13411 }
31be9251
GM
13412
13413 /* 2000-09-28: In
13414
13415 (let ((f (selected-frame)))
13416 (iconify-frame f)
13417 (raise-frame f))
13418
13419 the frame is not raised with various window managers on
13420 FreeBSD, Linux and Solaris. It turns out that, for some
13421 unknown reason, the call to XtMapWidget is completely ignored.
13422 Mapping the widget a second time works. */
7d0393cf 13423
31be9251
GM
13424 if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
13425 goto retry;
0dacf791 13426 }
dc6f92b8
JB
13427}
13428
06a2c219 13429/* Change from mapped state to withdrawn state. */
dc6f92b8 13430
d047c4eb
KH
13431/* Make the frame visible (mapped and not iconified). */
13432
dfcf069d 13433void
f676886a
JB
13434x_make_frame_invisible (f)
13435 struct frame *f;
dc6f92b8 13436{
546e6d5b
RS
13437 Window window;
13438
13439#ifdef USE_X_TOOLKIT
13440 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 13441 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
13442#else /* not USE_X_TOOLKIT */
13443 window = FRAME_X_WINDOW (f);
13444#endif /* not USE_X_TOOLKIT */
dc6f92b8 13445
9319ae23 13446 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
13447 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
13448 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 13449
5627c40e 13450#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 13451 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 13452 return;
5627c40e 13453#endif
dc6f92b8
JB
13454
13455 BLOCK_INPUT;
c118dd06 13456
af31d76f
RS
13457 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
13458 that the current position of the window is user-specified, rather than
13459 program-specified, so that when the window is mapped again, it will be
13460 placed at the same location, without forcing the user to position it
13461 by hand again (they have already done that once for this window.) */
c32cdd9a 13462 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 13463
c118dd06
JB
13464#ifdef HAVE_X11R4
13465
334208b7
RS
13466 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
13467 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
13468 {
13469 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13470 error ("Can't notify window manager of window withdrawal");
c118dd06 13471 }
c118dd06 13472#else /* ! defined (HAVE_X11R4) */
16bd92ea 13473
c118dd06 13474 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
13475 if (! EQ (Vx_no_window_manager, Qt))
13476 {
16bd92ea 13477 XEvent unmap;
dc6f92b8 13478
16bd92ea 13479 unmap.xunmap.type = UnmapNotify;
546e6d5b 13480 unmap.xunmap.window = window;
334208b7 13481 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 13482 unmap.xunmap.from_configure = False;
334208b7
RS
13483 if (! XSendEvent (FRAME_X_DISPLAY (f),
13484 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 13485 False,
06a2c219 13486 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
13487 &unmap))
13488 {
13489 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13490 error ("Can't notify window manager of withdrawal");
16bd92ea 13491 }
dc6f92b8
JB
13492 }
13493
16bd92ea 13494 /* Unmap the window ourselves. Cheeky! */
334208b7 13495 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 13496#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 13497
5627c40e
RS
13498 /* We can't distinguish this from iconification
13499 just by the event that we get from the server.
13500 So we can't win using the usual strategy of letting
13501 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
13502 and synchronize with the server to make sure we agree. */
13503 f->visible = 0;
13504 FRAME_ICONIFIED_P (f) = 0;
13505 f->async_visible = 0;
13506 f->async_iconified = 0;
13507
334208b7 13508 x_sync (f);
5627c40e 13509
dc6f92b8
JB
13510 UNBLOCK_INPUT;
13511}
13512
06a2c219 13513/* Change window state from mapped to iconified. */
dc6f92b8 13514
dfcf069d 13515void
f676886a
JB
13516x_iconify_frame (f)
13517 struct frame *f;
dc6f92b8 13518{
3afe33e7 13519 int result;
990ba854 13520 Lisp_Object type;
dc6f92b8 13521
9319ae23 13522 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
13523 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
13524 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 13525
3a88c238 13526 if (f->async_iconified)
dc6f92b8
JB
13527 return;
13528
3afe33e7 13529 BLOCK_INPUT;
546e6d5b 13530
9af3143a
RS
13531 FRAME_SAMPLE_VISIBILITY (f);
13532
990ba854
RS
13533 type = x_icon_type (f);
13534 if (!NILP (type))
13535 x_bitmap_icon (f, type);
bdcd49ba
RS
13536
13537#ifdef USE_X_TOOLKIT
13538
546e6d5b
RS
13539 if (! FRAME_VISIBLE_P (f))
13540 {
13541 if (! EQ (Vx_no_window_manager, Qt))
13542 x_wm_set_window_state (f, IconicState);
13543 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 13544 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
13545 /* The server won't give us any event to indicate
13546 that an invisible frame was changed to an icon,
13547 so we have to record it here. */
13548 f->iconified = 1;
1e6bc770 13549 f->visible = 1;
9cf30a30 13550 f->async_iconified = 1;
1e6bc770 13551 f->async_visible = 0;
546e6d5b
RS
13552 UNBLOCK_INPUT;
13553 return;
13554 }
13555
334208b7 13556 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 13557 XtWindow (f->output_data.x->widget),
334208b7 13558 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
13559 UNBLOCK_INPUT;
13560
13561 if (!result)
546e6d5b 13562 error ("Can't notify window manager of iconification");
3afe33e7
RS
13563
13564 f->async_iconified = 1;
1e6bc770
RS
13565 f->async_visible = 0;
13566
8c002a25
KH
13567
13568 BLOCK_INPUT;
334208b7 13569 XFlush (FRAME_X_DISPLAY (f));
8c002a25 13570 UNBLOCK_INPUT;
3afe33e7
RS
13571#else /* not USE_X_TOOLKIT */
13572
fd13dbb2
RS
13573 /* Make sure the X server knows where the window should be positioned,
13574 in case the user deiconifies with the window manager. */
13575 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 13576 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 13577
16bd92ea
JB
13578 /* Since we don't know which revision of X we're running, we'll use both
13579 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
13580
13581 /* X11R4: send a ClientMessage to the window manager using the
13582 WM_CHANGE_STATE type. */
13583 {
13584 XEvent message;
58769bee 13585
c118dd06 13586 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 13587 message.xclient.type = ClientMessage;
334208b7 13588 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
13589 message.xclient.format = 32;
13590 message.xclient.data.l[0] = IconicState;
13591
334208b7
RS
13592 if (! XSendEvent (FRAME_X_DISPLAY (f),
13593 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
13594 False,
13595 SubstructureRedirectMask | SubstructureNotifyMask,
13596 &message))
dc6f92b8
JB
13597 {
13598 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13599 error ("Can't notify window manager of iconification");
dc6f92b8 13600 }
16bd92ea 13601 }
dc6f92b8 13602
58769bee 13603 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
13604 IconicState. */
13605 x_wm_set_window_state (f, IconicState);
dc6f92b8 13606
a9c00105
RS
13607 if (!FRAME_VISIBLE_P (f))
13608 {
13609 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 13610 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
13611 }
13612
3a88c238 13613 f->async_iconified = 1;
1e6bc770 13614 f->async_visible = 0;
dc6f92b8 13615
334208b7 13616 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 13617 UNBLOCK_INPUT;
8c002a25 13618#endif /* not USE_X_TOOLKIT */
dc6f92b8 13619}
19f71add 13620
d047c4eb 13621\f
19f71add 13622/* Free X resources of frame F. */
dc6f92b8 13623
dfcf069d 13624void
19f71add 13625x_free_frame_resources (f)
f676886a 13626 struct frame *f;
dc6f92b8 13627{
7f9c7f94 13628 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
c6ea2775
EZ
13629 Lisp_Object bar;
13630 struct scroll_bar *b;
7f9c7f94 13631
dc6f92b8 13632 BLOCK_INPUT;
c0ff3fab 13633
6186a4a0
RS
13634 /* If a display connection is dead, don't try sending more
13635 commands to the X server. */
19f71add 13636 if (dpyinfo->display)
6186a4a0 13637 {
19f71add 13638 if (f->output_data.x->icon_desc)
6186a4a0 13639 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
c6ea2775
EZ
13640
13641#ifdef USE_X_TOOLKIT
13642 /* Explicitly destroy the scroll bars of the frame. Without
13643 this, we get "BadDrawable" errors from the toolkit later on,
13644 presumably from expose events generated for the disappearing
13645 toolkit scroll bars. */
13646 for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next)
13647 {
13648 b = XSCROLL_BAR (bar);
13649 x_scroll_bar_remove (b);
13650 }
13651#endif
13652
31f41daf 13653#ifdef HAVE_X_I18N
f5d11644
GM
13654 if (FRAME_XIC (f))
13655 free_frame_xic (f);
31f41daf 13656#endif
c6ea2775 13657
3afe33e7 13658#ifdef USE_X_TOOLKIT
06a2c219 13659 if (f->output_data.x->widget)
30ca89f5
GM
13660 {
13661 XtDestroyWidget (f->output_data.x->widget);
13662 f->output_data.x->widget = NULL;
13663 }
c6ea2775
EZ
13664 /* Tooltips don't have widgets, only a simple X window, even if
13665 we are using a toolkit. */
13666 else if (FRAME_X_WINDOW (f))
13667 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13668
6186a4a0 13669 free_frame_menubar (f);
c6ea2775
EZ
13670#else /* !USE_X_TOOLKIT */
13671 if (FRAME_X_WINDOW (f))
13672 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13673#endif /* !USE_X_TOOLKIT */
3afe33e7 13674
3e71d8f2
GM
13675 unload_color (f, f->output_data.x->foreground_pixel);
13676 unload_color (f, f->output_data.x->background_pixel);
13677 unload_color (f, f->output_data.x->cursor_pixel);
13678 unload_color (f, f->output_data.x->cursor_foreground_pixel);
13679 unload_color (f, f->output_data.x->border_pixel);
13680 unload_color (f, f->output_data.x->mouse_pixel);
c6ea2775 13681
3e71d8f2
GM
13682 if (f->output_data.x->scroll_bar_background_pixel != -1)
13683 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
13684 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
13685 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
7c1bef7a
MB
13686#ifdef USE_TOOLKIT_SCROLL_BARS
13687 /* Scrollbar shadow colors. */
13688 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
13689 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
13690 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
13691 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
13692#endif /* USE_TOOLKIT_SCROLL_BARS */
3e71d8f2
GM
13693 if (f->output_data.x->white_relief.allocated_p)
13694 unload_color (f, f->output_data.x->white_relief.pixel);
13695 if (f->output_data.x->black_relief.allocated_p)
13696 unload_color (f, f->output_data.x->black_relief.pixel);
4ca78676 13697
19f71add
GM
13698 if (FRAME_FACE_CACHE (f))
13699 free_frame_faces (f);
7d0393cf 13700
4ca78676 13701 x_free_gcs (f);
6186a4a0
RS
13702 XFlush (FRAME_X_DISPLAY (f));
13703 }
dc6f92b8 13704
df89d8a4 13705 if (f->output_data.x->saved_menu_event)
06a2c219 13706 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 13707
7556890b 13708 xfree (f->output_data.x);
19f71add 13709 f->output_data.x = NULL;
7d0393cf 13710
0f941935
KH
13711 if (f == dpyinfo->x_focus_frame)
13712 dpyinfo->x_focus_frame = 0;
13713 if (f == dpyinfo->x_focus_event_frame)
13714 dpyinfo->x_focus_event_frame = 0;
13715 if (f == dpyinfo->x_highlight_frame)
13716 dpyinfo->x_highlight_frame = 0;
c0ff3fab 13717
7f9c7f94 13718 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 13719 {
7f9c7f94
RS
13720 dpyinfo->mouse_face_beg_row
13721 = dpyinfo->mouse_face_beg_col = -1;
13722 dpyinfo->mouse_face_end_row
13723 = dpyinfo->mouse_face_end_col = -1;
13724 dpyinfo->mouse_face_window = Qnil;
21323706
RS
13725 dpyinfo->mouse_face_deferred_gc = 0;
13726 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 13727 }
0134a210 13728
c0ff3fab 13729 UNBLOCK_INPUT;
dc6f92b8 13730}
19f71add
GM
13731
13732
13733/* Destroy the X window of frame F. */
13734
13735void
13736x_destroy_window (f)
13737 struct frame *f;
13738{
13739 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13740
13741 /* If a display connection is dead, don't try sending more
13742 commands to the X server. */
13743 if (dpyinfo->display != 0)
13744 x_free_frame_resources (f);
13745
13746 dpyinfo->reference_count--;
13747}
13748
dc6f92b8 13749\f
f451eb13
JB
13750/* Setting window manager hints. */
13751
af31d76f
RS
13752/* Set the normal size hints for the window manager, for frame F.
13753 FLAGS is the flags word to use--or 0 meaning preserve the flags
13754 that the window now has.
13755 If USER_POSITION is nonzero, we set the USPosition
13756 flag (this is useful when FLAGS is 0). */
6dba1858 13757
dfcf069d 13758void
af31d76f 13759x_wm_set_size_hint (f, flags, user_position)
f676886a 13760 struct frame *f;
af31d76f
RS
13761 long flags;
13762 int user_position;
dc6f92b8
JB
13763{
13764 XSizeHints size_hints;
3afe33e7
RS
13765
13766#ifdef USE_X_TOOLKIT
7e4f2521
FP
13767 Arg al[2];
13768 int ac = 0;
13769 Dimension widget_width, widget_height;
7556890b 13770 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 13771#else /* not USE_X_TOOLKIT */
c118dd06 13772 Window window = FRAME_X_WINDOW (f);
3afe33e7 13773#endif /* not USE_X_TOOLKIT */
dc6f92b8 13774
b72a58fd
RS
13775 /* Setting PMaxSize caused various problems. */
13776 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 13777
7556890b
RS
13778 size_hints.x = f->output_data.x->left_pos;
13779 size_hints.y = f->output_data.x->top_pos;
7553a6b7 13780
7e4f2521
FP
13781#ifdef USE_X_TOOLKIT
13782 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
13783 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 13784 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
13785 size_hints.height = widget_height;
13786 size_hints.width = widget_width;
13787#else /* not USE_X_TOOLKIT */
f676886a
JB
13788 size_hints.height = PIXEL_HEIGHT (f);
13789 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 13790#endif /* not USE_X_TOOLKIT */
7553a6b7 13791
7556890b
RS
13792 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
13793 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
13794 size_hints.max_width
13795 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
13796 size_hints.max_height
13797 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 13798
d067ea8b
KH
13799 /* Calculate the base and minimum sizes.
13800
13801 (When we use the X toolkit, we don't do it here.
13802 Instead we copy the values that the widgets are using, below.) */
13803#ifndef USE_X_TOOLKIT
b1c884c3 13804 {
b0342f17 13805 int base_width, base_height;
0134a210 13806 int min_rows = 0, min_cols = 0;
b0342f17 13807
f451eb13
JB
13808 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
13809 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 13810
0134a210 13811 check_frame_size (f, &min_rows, &min_cols);
b0342f17 13812
0134a210
RS
13813 /* The window manager uses the base width hints to calculate the
13814 current number of rows and columns in the frame while
13815 resizing; min_width and min_height aren't useful for this
13816 purpose, since they might not give the dimensions for a
13817 zero-row, zero-column frame.
58769bee 13818
0134a210
RS
13819 We use the base_width and base_height members if we have
13820 them; otherwise, we set the min_width and min_height members
13821 to the size for a zero x zero frame. */
b0342f17
JB
13822
13823#ifdef HAVE_X11R4
0134a210
RS
13824 size_hints.flags |= PBaseSize;
13825 size_hints.base_width = base_width;
13826 size_hints.base_height = base_height;
13827 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
13828 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 13829#else
0134a210
RS
13830 size_hints.min_width = base_width;
13831 size_hints.min_height = base_height;
b0342f17 13832#endif
b1c884c3 13833 }
dc6f92b8 13834
d067ea8b 13835 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 13836 if (flags)
dc6f92b8 13837 {
d067ea8b
KH
13838 size_hints.flags |= flags;
13839 goto no_read;
13840 }
13841#endif /* not USE_X_TOOLKIT */
13842
13843 {
13844 XSizeHints hints; /* Sometimes I hate X Windows... */
13845 long supplied_return;
13846 int value;
af31d76f
RS
13847
13848#ifdef HAVE_X11R4
d067ea8b
KH
13849 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
13850 &supplied_return);
af31d76f 13851#else
d067ea8b 13852 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 13853#endif
58769bee 13854
d067ea8b
KH
13855#ifdef USE_X_TOOLKIT
13856 size_hints.base_height = hints.base_height;
13857 size_hints.base_width = hints.base_width;
13858 size_hints.min_height = hints.min_height;
13859 size_hints.min_width = hints.min_width;
13860#endif
13861
13862 if (flags)
13863 size_hints.flags |= flags;
13864 else
13865 {
13866 if (value == 0)
13867 hints.flags = 0;
13868 if (hints.flags & PSize)
13869 size_hints.flags |= PSize;
13870 if (hints.flags & PPosition)
13871 size_hints.flags |= PPosition;
13872 if (hints.flags & USPosition)
13873 size_hints.flags |= USPosition;
13874 if (hints.flags & USSize)
13875 size_hints.flags |= USSize;
13876 }
13877 }
13878
06a2c219 13879#ifndef USE_X_TOOLKIT
d067ea8b 13880 no_read:
06a2c219 13881#endif
0134a210 13882
af31d76f 13883#ifdef PWinGravity
7556890b 13884 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 13885 size_hints.flags |= PWinGravity;
dc05a16b 13886
af31d76f 13887 if (user_position)
6dba1858 13888 {
af31d76f
RS
13889 size_hints.flags &= ~ PPosition;
13890 size_hints.flags |= USPosition;
6dba1858 13891 }
2554751d 13892#endif /* PWinGravity */
6dba1858 13893
b0342f17 13894#ifdef HAVE_X11R4
334208b7 13895 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13896#else
334208b7 13897 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13898#endif
dc6f92b8
JB
13899}
13900
13901/* Used for IconicState or NormalState */
06a2c219 13902
dfcf069d 13903void
f676886a
JB
13904x_wm_set_window_state (f, state)
13905 struct frame *f;
dc6f92b8
JB
13906 int state;
13907{
3afe33e7 13908#ifdef USE_X_TOOLKIT
546e6d5b
RS
13909 Arg al[1];
13910
13911 XtSetArg (al[0], XtNinitialState, state);
7556890b 13912 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 13913#else /* not USE_X_TOOLKIT */
c118dd06 13914 Window window = FRAME_X_WINDOW (f);
dc6f92b8 13915
7556890b
RS
13916 f->output_data.x->wm_hints.flags |= StateHint;
13917 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 13918
7556890b 13919 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 13920#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13921}
13922
dfcf069d 13923void
7f2ae036 13924x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 13925 struct frame *f;
7f2ae036 13926 int pixmap_id;
dc6f92b8 13927{
d2bd6bc4
RS
13928 Pixmap icon_pixmap;
13929
06a2c219 13930#ifndef USE_X_TOOLKIT
c118dd06 13931 Window window = FRAME_X_WINDOW (f);
75231bad 13932#endif
dc6f92b8 13933
7f2ae036 13934 if (pixmap_id > 0)
dbc4e1c1 13935 {
d2bd6bc4 13936 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 13937 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
13938 }
13939 else
68568555
RS
13940 {
13941 /* It seems there is no way to turn off use of an icon pixmap.
13942 The following line does it, only if no icon has yet been created,
13943 for some window managers. But with mwm it crashes.
13944 Some people say it should clear the IconPixmapHint bit in this case,
13945 but that doesn't work, and the X consortium said it isn't the
13946 right thing at all. Since there is no way to win,
13947 best to explicitly give up. */
13948#if 0
13949 f->output_data.x->wm_hints.icon_pixmap = None;
13950#else
13951 return;
13952#endif
13953 }
b1c884c3 13954
d2bd6bc4
RS
13955#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
13956
13957 {
13958 Arg al[1];
13959 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
13960 XtSetValues (f->output_data.x->widget, al, 1);
13961 }
13962
13963#else /* not USE_X_TOOLKIT */
7d0393cf 13964
7556890b
RS
13965 f->output_data.x->wm_hints.flags |= IconPixmapHint;
13966 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
13967
13968#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13969}
13970
dfcf069d 13971void
f676886a
JB
13972x_wm_set_icon_position (f, icon_x, icon_y)
13973 struct frame *f;
dc6f92b8
JB
13974 int icon_x, icon_y;
13975{
75231bad 13976#ifdef USE_X_TOOLKIT
7556890b 13977 Window window = XtWindow (f->output_data.x->widget);
75231bad 13978#else
c118dd06 13979 Window window = FRAME_X_WINDOW (f);
75231bad 13980#endif
dc6f92b8 13981
7556890b
RS
13982 f->output_data.x->wm_hints.flags |= IconPositionHint;
13983 f->output_data.x->wm_hints.icon_x = icon_x;
13984 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 13985
7556890b 13986 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
13987}
13988
13989\f
06a2c219
GM
13990/***********************************************************************
13991 Fonts
13992 ***********************************************************************/
dc43ef94
KH
13993
13994/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 13995
dc43ef94
KH
13996struct font_info *
13997x_get_font_info (f, font_idx)
13998 FRAME_PTR f;
13999 int font_idx;
14000{
14001 return (FRAME_X_FONT_TABLE (f) + font_idx);
14002}
14003
14004
9c11f79e
GM
14005/* Return a list of names of available fonts matching PATTERN on frame F.
14006
14007 If SIZE is > 0, it is the size (maximum bounds width) of fonts
14008 to be listed.
14009
14010 SIZE < 0 means include scalable fonts.
14011
14012 Frame F null means we have not yet created any frame on X, and
14013 consult the first display in x_display_list. MAXNAMES sets a limit
14014 on how many fonts to match. */
dc43ef94
KH
14015
14016Lisp_Object
14017x_list_fonts (f, pattern, size, maxnames)
9c11f79e 14018 struct frame *f;
dc43ef94
KH
14019 Lisp_Object pattern;
14020 int size;
14021 int maxnames;
14022{
06a2c219
GM
14023 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
14024 Lisp_Object tem, second_best;
9c11f79e
GM
14025 struct x_display_info *dpyinfo
14026 = f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
14027 Display *dpy = dpyinfo->display;
09c6077f 14028 int try_XLoadQueryFont = 0;
53ca4657 14029 int count;
9c11f79e
GM
14030 int allow_scalable_fonts_p = 0;
14031
14032 if (size < 0)
14033 {
14034 allow_scalable_fonts_p = 1;
14035 size = 0;
14036 }
dc43ef94 14037
6b0efe73 14038 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
14039 if (NILP (patterns))
14040 patterns = Fcons (pattern, Qnil);
81ba44e5 14041
09c6077f
KH
14042 if (maxnames == 1 && !size)
14043 /* We can return any single font matching PATTERN. */
14044 try_XLoadQueryFont = 1;
9a32686f 14045
8e713be6 14046 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 14047 {
dc43ef94 14048 int num_fonts;
3e71d8f2 14049 char **names = NULL;
dc43ef94 14050
8e713be6 14051 pattern = XCAR (patterns);
536f4067
RS
14052 /* See if we cached the result for this particular query.
14053 The cache is an alist of the form:
9c11f79e
GM
14054 ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */
14055 tem = XCDR (dpyinfo->name_list_element);
14056 key = Fcons (Fcons (pattern, make_number (maxnames)),
14057 allow_scalable_fonts_p ? Qt : Qnil);
14058 list = Fassoc (key, tem);
14059 if (!NILP (list))
b5210ea7
KH
14060 {
14061 list = Fcdr_safe (list);
14062 /* We have a cashed list. Don't have to get the list again. */
14063 goto label_cached;
14064 }
14065
14066 /* At first, put PATTERN in the cache. */
09c6077f 14067
dc43ef94 14068 BLOCK_INPUT;
17d85edc
KH
14069 count = x_catch_errors (dpy);
14070
09c6077f
KH
14071 if (try_XLoadQueryFont)
14072 {
14073 XFontStruct *font;
14074 unsigned long value;
14075
d5db4077 14076 font = XLoadQueryFont (dpy, SDATA (pattern));
17d85edc
KH
14077 if (x_had_errors_p (dpy))
14078 {
14079 /* This error is perhaps due to insufficient memory on X
14080 server. Let's just ignore it. */
14081 font = NULL;
14082 x_clear_errors (dpy);
14083 }
14084
09c6077f
KH
14085 if (font
14086 && XGetFontProperty (font, XA_FONT, &value))
14087 {
14088 char *name = (char *) XGetAtomName (dpy, (Atom) value);
14089 int len = strlen (name);
01c752b5 14090 char *tmp;
09c6077f 14091
6f6512e8
KH
14092 /* If DXPC (a Differential X Protocol Compressor)
14093 Ver.3.7 is running, XGetAtomName will return null
14094 string. We must avoid such a name. */
14095 if (len == 0)
14096 try_XLoadQueryFont = 0;
14097 else
14098 {
14099 num_fonts = 1;
14100 names = (char **) alloca (sizeof (char *));
14101 /* Some systems only allow alloca assigned to a
14102 simple var. */
14103 tmp = (char *) alloca (len + 1); names[0] = tmp;
14104 bcopy (name, names[0], len + 1);
14105 XFree (name);
14106 }
09c6077f
KH
14107 }
14108 else
14109 try_XLoadQueryFont = 0;
a083fd23
RS
14110
14111 if (font)
14112 XFreeFont (dpy, font);
09c6077f
KH
14113 }
14114
14115 if (!try_XLoadQueryFont)
17d85edc
KH
14116 {
14117 /* We try at least 10 fonts because XListFonts will return
14118 auto-scaled fonts at the head. */
d5db4077 14119 names = XListFonts (dpy, SDATA (pattern), max (maxnames, 10),
17d85edc
KH
14120 &num_fonts);
14121 if (x_had_errors_p (dpy))
14122 {
14123 /* This error is perhaps due to insufficient memory on X
14124 server. Let's just ignore it. */
14125 names = NULL;
14126 x_clear_errors (dpy);
14127 }
14128 }
14129
14130 x_uncatch_errors (dpy, count);
dc43ef94
KH
14131 UNBLOCK_INPUT;
14132
14133 if (names)
14134 {
14135 int i;
dc43ef94
KH
14136
14137 /* Make a list of all the fonts we got back.
14138 Store that in the font cache for the display. */
14139 for (i = 0; i < num_fonts; i++)
14140 {
06a2c219 14141 int width = 0;
dc43ef94 14142 char *p = names[i];
06a2c219 14143 int average_width = -1, dashes = 0;
7d0393cf 14144
dc43ef94 14145 /* Count the number of dashes in NAMES[I]. If there are
9c11f79e
GM
14146 14 dashes, and the field value following 12th dash
14147 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
14148 is usually too ugly to be used for editing. Let's
14149 ignore it. */
dc43ef94
KH
14150 while (*p)
14151 if (*p++ == '-')
14152 {
14153 dashes++;
14154 if (dashes == 7) /* PIXEL_SIZE field */
14155 width = atoi (p);
14156 else if (dashes == 12) /* AVERAGE_WIDTH field */
14157 average_width = atoi (p);
14158 }
7d0393cf 14159
9c11f79e
GM
14160 if (allow_scalable_fonts_p
14161 || dashes < 14 || average_width != 0)
dc43ef94
KH
14162 {
14163 tem = build_string (names[i]);
14164 if (NILP (Fassoc (tem, list)))
14165 {
14166 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
14167 && ((fast_c_string_match_ignore_case
14168 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
14169 >= 0))
14170 /* We can set the value of PIXEL_SIZE to the
b5210ea7 14171 width of this font. */
dc43ef94
KH
14172 list = Fcons (Fcons (tem, make_number (width)), list);
14173 else
14174 /* For the moment, width is not known. */
14175 list = Fcons (Fcons (tem, Qnil), list);
14176 }
14177 }
14178 }
7d0393cf 14179
09c6077f 14180 if (!try_XLoadQueryFont)
e38f4136
GM
14181 {
14182 BLOCK_INPUT;
14183 XFreeFontNames (names);
14184 UNBLOCK_INPUT;
14185 }
dc43ef94
KH
14186 }
14187
b5210ea7 14188 /* Now store the result in the cache. */
f3fbd155
KR
14189 XSETCDR (dpyinfo->name_list_element,
14190 Fcons (Fcons (key, list), XCDR (dpyinfo->name_list_element)));
dc43ef94 14191
b5210ea7
KH
14192 label_cached:
14193 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 14194
b5210ea7
KH
14195 newlist = second_best = Qnil;
14196 /* Make a list of the fonts that have the right width. */
8e713be6 14197 for (; CONSP (list); list = XCDR (list))
b5210ea7 14198 {
536f4067
RS
14199 int found_size;
14200
8e713be6 14201 tem = XCAR (list);
dc43ef94 14202
8e713be6 14203 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
14204 continue;
14205 if (!size)
14206 {
8e713be6 14207 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
14208 continue;
14209 }
dc43ef94 14210
8e713be6 14211 if (!INTEGERP (XCDR (tem)))
dc43ef94 14212 {
b5210ea7 14213 /* Since we have not yet known the size of this font, we
9c11f79e 14214 must try slow function call XLoadQueryFont. */
dc43ef94
KH
14215 XFontStruct *thisinfo;
14216
14217 BLOCK_INPUT;
17d85edc 14218 count = x_catch_errors (dpy);
dc43ef94 14219 thisinfo = XLoadQueryFont (dpy,
d5db4077 14220 SDATA (XCAR (tem)));
17d85edc
KH
14221 if (x_had_errors_p (dpy))
14222 {
14223 /* This error is perhaps due to insufficient memory on X
14224 server. Let's just ignore it. */
14225 thisinfo = NULL;
14226 x_clear_errors (dpy);
14227 }
14228 x_uncatch_errors (dpy, count);
dc43ef94
KH
14229 UNBLOCK_INPUT;
14230
14231 if (thisinfo)
14232 {
f3fbd155
KR
14233 XSETCDR (tem,
14234 (thisinfo->min_bounds.width == 0
14235 ? make_number (0)
14236 : make_number (thisinfo->max_bounds.width)));
e38f4136 14237 BLOCK_INPUT;
dc43ef94 14238 XFreeFont (dpy, thisinfo);
e38f4136 14239 UNBLOCK_INPUT;
dc43ef94
KH
14240 }
14241 else
b5210ea7 14242 /* For unknown reason, the previous call of XListFont had
06a2c219 14243 returned a font which can't be opened. Record the size
b5210ea7 14244 as 0 not to try to open it again. */
f3fbd155 14245 XSETCDR (tem, make_number (0));
dc43ef94 14246 }
536f4067 14247
8e713be6 14248 found_size = XINT (XCDR (tem));
536f4067 14249 if (found_size == size)
8e713be6 14250 newlist = Fcons (XCAR (tem), newlist);
536f4067 14251 else if (found_size > 0)
b5210ea7 14252 {
536f4067 14253 if (NILP (second_best))
b5210ea7 14254 second_best = tem;
536f4067
RS
14255 else if (found_size < size)
14256 {
8e713be6
KR
14257 if (XINT (XCDR (second_best)) > size
14258 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
14259 second_best = tem;
14260 }
14261 else
14262 {
8e713be6
KR
14263 if (XINT (XCDR (second_best)) > size
14264 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
14265 second_best = tem;
14266 }
b5210ea7
KH
14267 }
14268 }
14269 if (!NILP (newlist))
14270 break;
14271 else if (!NILP (second_best))
14272 {
8e713be6 14273 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 14274 break;
dc43ef94 14275 }
dc43ef94
KH
14276 }
14277
14278 return newlist;
7d0393cf 14279}
dc43ef94 14280
06a2c219
GM
14281
14282#if GLYPH_DEBUG
14283
14284/* Check that FONT is valid on frame F. It is if it can be found in F's
14285 font table. */
14286
14287static void
14288x_check_font (f, font)
14289 struct frame *f;
14290 XFontStruct *font;
14291{
14292 int i;
14293 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14294
14295 xassert (font != NULL);
14296
14297 for (i = 0; i < dpyinfo->n_fonts; i++)
7d0393cf 14298 if (dpyinfo->font_table[i].name
06a2c219
GM
14299 && font == dpyinfo->font_table[i].font)
14300 break;
14301
14302 xassert (i < dpyinfo->n_fonts);
14303}
14304
14305#endif /* GLYPH_DEBUG != 0 */
14306
14307/* Set *W to the minimum width, *H to the minimum font height of FONT.
14308 Note: There are (broken) X fonts out there with invalid XFontStruct
14309 min_bounds contents. For example, handa@etl.go.jp reports that
14310 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
14311 have font->min_bounds.width == 0. */
14312
14313static INLINE void
14314x_font_min_bounds (font, w, h)
14315 XFontStruct *font;
14316 int *w, *h;
14317{
14318 *h = FONT_HEIGHT (font);
14319 *w = font->min_bounds.width;
14320
14321 /* Try to handle the case where FONT->min_bounds has invalid
14322 contents. Since the only font known to have invalid min_bounds
14323 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
14324 if (*w <= 0)
14325 *w = font->max_bounds.width;
14326}
14327
14328
14329/* Compute the smallest character width and smallest font height over
14330 all fonts available on frame F. Set the members smallest_char_width
14331 and smallest_font_height in F's x_display_info structure to
14332 the values computed. Value is non-zero if smallest_font_height or
14333 smallest_char_width become smaller than they were before. */
14334
14335static int
14336x_compute_min_glyph_bounds (f)
14337 struct frame *f;
14338{
14339 int i;
14340 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14341 XFontStruct *font;
14342 int old_width = dpyinfo->smallest_char_width;
14343 int old_height = dpyinfo->smallest_font_height;
7d0393cf 14344
06a2c219
GM
14345 dpyinfo->smallest_font_height = 100000;
14346 dpyinfo->smallest_char_width = 100000;
7d0393cf 14347
06a2c219
GM
14348 for (i = 0; i < dpyinfo->n_fonts; ++i)
14349 if (dpyinfo->font_table[i].name)
14350 {
14351 struct font_info *fontp = dpyinfo->font_table + i;
14352 int w, h;
7d0393cf 14353
06a2c219
GM
14354 font = (XFontStruct *) fontp->font;
14355 xassert (font != (XFontStruct *) ~0);
14356 x_font_min_bounds (font, &w, &h);
7d0393cf 14357
06a2c219
GM
14358 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
14359 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
14360 }
14361
14362 xassert (dpyinfo->smallest_char_width > 0
14363 && dpyinfo->smallest_font_height > 0);
14364
14365 return (dpyinfo->n_fonts == 1
14366 || dpyinfo->smallest_char_width < old_width
14367 || dpyinfo->smallest_font_height < old_height);
14368}
14369
14370
dc43ef94
KH
14371/* Load font named FONTNAME of the size SIZE for frame F, and return a
14372 pointer to the structure font_info while allocating it dynamically.
14373 If SIZE is 0, load any size of font.
14374 If loading is failed, return NULL. */
14375
14376struct font_info *
14377x_load_font (f, fontname, size)
14378 struct frame *f;
14379 register char *fontname;
14380 int size;
14381{
14382 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14383 Lisp_Object font_names;
d645aaa4 14384 int count;
dc43ef94
KH
14385
14386 /* Get a list of all the fonts that match this name. Once we
14387 have a list of matching fonts, we compare them against the fonts
14388 we already have by comparing names. */
09c6077f 14389 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
14390
14391 if (!NILP (font_names))
14392 {
14393 Lisp_Object tail;
14394 int i;
14395
14396 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 14397 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
14398 if (dpyinfo->font_table[i].name
14399 && (!strcmp (dpyinfo->font_table[i].name,
d5db4077 14400 SDATA (XCAR (tail)))
06a2c219 14401 || !strcmp (dpyinfo->font_table[i].full_name,
d5db4077 14402 SDATA (XCAR (tail)))))
dc43ef94
KH
14403 return (dpyinfo->font_table + i);
14404 }
14405
14406 /* Load the font and add it to the table. */
14407 {
14408 char *full_name;
14409 XFontStruct *font;
14410 struct font_info *fontp;
14411 unsigned long value;
06a2c219 14412 int i;
dc43ef94 14413
2da424f1
KH
14414 /* If we have found fonts by x_list_font, load one of them. If
14415 not, we still try to load a font by the name given as FONTNAME
14416 because XListFonts (called in x_list_font) of some X server has
14417 a bug of not finding a font even if the font surely exists and
14418 is loadable by XLoadQueryFont. */
e1d6d5b9 14419 if (size > 0 && !NILP (font_names))
d5db4077 14420 fontname = (char *) SDATA (XCAR (font_names));
dc43ef94
KH
14421
14422 BLOCK_INPUT;
d645aaa4 14423 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 14424 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
14425 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
14426 {
14427 /* This error is perhaps due to insufficient memory on X
14428 server. Let's just ignore it. */
14429 font = NULL;
14430 x_clear_errors (FRAME_X_DISPLAY (f));
14431 }
14432 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 14433 UNBLOCK_INPUT;
b5210ea7 14434 if (!font)
dc43ef94
KH
14435 return NULL;
14436
06a2c219
GM
14437 /* Find a free slot in the font table. */
14438 for (i = 0; i < dpyinfo->n_fonts; ++i)
14439 if (dpyinfo->font_table[i].name == NULL)
14440 break;
14441
14442 /* If no free slot found, maybe enlarge the font table. */
14443 if (i == dpyinfo->n_fonts
14444 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 14445 {
06a2c219
GM
14446 int sz;
14447 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
14448 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 14449 dpyinfo->font_table
06a2c219 14450 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
14451 }
14452
06a2c219
GM
14453 fontp = dpyinfo->font_table + i;
14454 if (i == dpyinfo->n_fonts)
14455 ++dpyinfo->n_fonts;
dc43ef94
KH
14456
14457 /* Now fill in the slots of *FONTP. */
14458 BLOCK_INPUT;
14459 fontp->font = font;
06a2c219 14460 fontp->font_idx = i;
dc43ef94
KH
14461 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
14462 bcopy (fontname, fontp->name, strlen (fontname) + 1);
14463
14464 /* Try to get the full name of FONT. Put it in FULL_NAME. */
14465 full_name = 0;
14466 if (XGetFontProperty (font, XA_FONT, &value))
14467 {
14468 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
14469 char *p = name;
14470 int dashes = 0;
14471
14472 /* Count the number of dashes in the "full name".
14473 If it is too few, this isn't really the font's full name,
14474 so don't use it.
14475 In X11R4, the fonts did not come with their canonical names
14476 stored in them. */
14477 while (*p)
14478 {
14479 if (*p == '-')
14480 dashes++;
14481 p++;
14482 }
14483
14484 if (dashes >= 13)
14485 {
14486 full_name = (char *) xmalloc (p - name + 1);
14487 bcopy (name, full_name, p - name + 1);
14488 }
14489
14490 XFree (name);
14491 }
7d0393cf 14492
dc43ef94
KH
14493 if (full_name != 0)
14494 fontp->full_name = full_name;
14495 else
14496 fontp->full_name = fontp->name;
14497
14498 fontp->size = font->max_bounds.width;
d5749adb 14499 fontp->height = FONT_HEIGHT (font);
dc43ef94 14500
2da424f1
KH
14501 if (NILP (font_names))
14502 {
14503 /* We come here because of a bug of XListFonts mentioned at
14504 the head of this block. Let's store this information in
14505 the cache for x_list_fonts. */
14506 Lisp_Object lispy_name = build_string (fontname);
14507 Lisp_Object lispy_full_name = build_string (fontp->full_name);
9c11f79e
GM
14508 Lisp_Object key = Fcons (Fcons (lispy_name, make_number (256)),
14509 Qnil);
2da424f1 14510
f3fbd155
KR
14511 XSETCDR (dpyinfo->name_list_element,
14512 Fcons (Fcons (key,
14513 Fcons (Fcons (lispy_full_name,
14514 make_number (fontp->size)),
14515 Qnil)),
14516 XCDR (dpyinfo->name_list_element)));
2da424f1 14517 if (full_name)
9c11f79e
GM
14518 {
14519 key = Fcons (Fcons (lispy_full_name, make_number (256)),
14520 Qnil);
f3fbd155
KR
14521 XSETCDR (dpyinfo->name_list_element,
14522 Fcons (Fcons (key,
14523 Fcons (Fcons (lispy_full_name,
14524 make_number (fontp->size)),
14525 Qnil)),
14526 XCDR (dpyinfo->name_list_element)));
9c11f79e 14527 }
2da424f1
KH
14528 }
14529
dc43ef94
KH
14530 /* The slot `encoding' specifies how to map a character
14531 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
14532 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
14533 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 14534 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 14535 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
14536 which is never used by any charset. If mapping can't be
14537 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
14538 fontp->encoding[1]
14539 = (font->max_byte1 == 0
14540 /* 1-byte font */
14541 ? (font->min_char_or_byte2 < 0x80
14542 ? (font->max_char_or_byte2 < 0x80
14543 ? 0 /* 0x20..0x7F */
8ff102bd 14544 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
14545 : 1) /* 0xA0..0xFF */
14546 /* 2-byte font */
14547 : (font->min_byte1 < 0x80
14548 ? (font->max_byte1 < 0x80
14549 ? (font->min_char_or_byte2 < 0x80
14550 ? (font->max_char_or_byte2 < 0x80
14551 ? 0 /* 0x2020..0x7F7F */
8ff102bd 14552 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 14553 : 3) /* 0x20A0..0x7FFF */
8ff102bd 14554 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
14555 : (font->min_char_or_byte2 < 0x80
14556 ? (font->max_char_or_byte2 < 0x80
14557 ? 2 /* 0xA020..0xFF7F */
8ff102bd 14558 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
14559 : 1))); /* 0xA0A0..0xFFFF */
14560
14561 fontp->baseline_offset
14562 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
14563 ? (long) value : 0);
14564 fontp->relative_compose
14565 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
14566 ? (long) value : 0);
f78798df
KH
14567 fontp->default_ascent
14568 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
14569 ? (long) value : 0);
dc43ef94 14570
06a2c219
GM
14571 /* Set global flag fonts_changed_p to non-zero if the font loaded
14572 has a character with a smaller width than any other character
437dfb9f 14573 before, or if the font loaded has a smaller height than any
06a2c219
GM
14574 other font loaded before. If this happens, it will make a
14575 glyph matrix reallocation necessary. */
437dfb9f 14576 fonts_changed_p |= x_compute_min_glyph_bounds (f);
dc43ef94 14577 UNBLOCK_INPUT;
dc43ef94
KH
14578 return fontp;
14579 }
14580}
14581
06a2c219
GM
14582
14583/* Return a pointer to struct font_info of a font named FONTNAME for
14584 frame F. If no such font is loaded, return NULL. */
14585
dc43ef94
KH
14586struct font_info *
14587x_query_font (f, fontname)
14588 struct frame *f;
14589 register char *fontname;
14590{
14591 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14592 int i;
14593
14594 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
14595 if (dpyinfo->font_table[i].name
14596 && (!strcmp (dpyinfo->font_table[i].name, fontname)
14597 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
14598 return (dpyinfo->font_table + i);
14599 return NULL;
14600}
14601
06a2c219
GM
14602
14603/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
14604 `encoder' of the structure. */
14605
14606void
14607x_find_ccl_program (fontp)
14608 struct font_info *fontp;
14609{
a42f54e6 14610 Lisp_Object list, elt;
a6582676 14611
f9b5db02 14612 elt = Qnil;
8e713be6 14613 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 14614 {
8e713be6 14615 elt = XCAR (list);
a6582676 14616 if (CONSP (elt)
8e713be6 14617 && STRINGP (XCAR (elt))
9f2feff6
KH
14618 && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
14619 >= 0)
14620 || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
14621 >= 0)))
a42f54e6
KH
14622 break;
14623 }
7d0393cf 14624
a42f54e6
KH
14625 if (! NILP (list))
14626 {
d27f8ca7
KH
14627 struct ccl_program *ccl
14628 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 14629
8e713be6 14630 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
14631 xfree (ccl);
14632 else
14633 fontp->font_encoder = ccl;
a6582676
KH
14634 }
14635}
14636
06a2c219 14637
dc43ef94 14638\f
06a2c219
GM
14639/***********************************************************************
14640 Initialization
14641 ***********************************************************************/
f451eb13 14642
3afe33e7
RS
14643#ifdef USE_X_TOOLKIT
14644static XrmOptionDescRec emacs_options[] = {
14645 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
14646 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
14647
14648 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
14649 XrmoptionSepArg, NULL},
14650 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
14651
14652 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14653 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14654 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14655 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14656 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14657 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
14658 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
14659};
14660#endif /* USE_X_TOOLKIT */
14661
7a13e894
RS
14662static int x_initialized;
14663
29b38361
KH
14664#ifdef MULTI_KBOARD
14665/* Test whether two display-name strings agree up to the dot that separates
14666 the screen number from the server number. */
14667static int
14668same_x_server (name1, name2)
59ab1dc7 14669 const char *name1, *name2;
29b38361
KH
14670{
14671 int seen_colon = 0;
59ab1dc7 14672 const unsigned char *system_name = SDATA (Vsystem_name);
cf591cc1
RS
14673 int system_name_length = strlen (system_name);
14674 int length_until_period = 0;
14675
14676 while (system_name[length_until_period] != 0
14677 && system_name[length_until_period] != '.')
14678 length_until_period++;
14679
14680 /* Treat `unix' like an empty host name. */
14681 if (! strncmp (name1, "unix:", 5))
14682 name1 += 4;
14683 if (! strncmp (name2, "unix:", 5))
14684 name2 += 4;
14685 /* Treat this host's name like an empty host name. */
14686 if (! strncmp (name1, system_name, system_name_length)
14687 && name1[system_name_length] == ':')
14688 name1 += system_name_length;
14689 if (! strncmp (name2, system_name, system_name_length)
14690 && name2[system_name_length] == ':')
14691 name2 += system_name_length;
14692 /* Treat this host's domainless name like an empty host name. */
14693 if (! strncmp (name1, system_name, length_until_period)
14694 && name1[length_until_period] == ':')
14695 name1 += length_until_period;
14696 if (! strncmp (name2, system_name, length_until_period)
14697 && name2[length_until_period] == ':')
14698 name2 += length_until_period;
14699
29b38361
KH
14700 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
14701 {
14702 if (*name1 == ':')
14703 seen_colon++;
14704 if (seen_colon && *name1 == '.')
14705 return 1;
14706 }
14707 return (seen_colon
14708 && (*name1 == '.' || *name1 == '\0')
14709 && (*name2 == '.' || *name2 == '\0'));
14710}
14711#endif
14712
334208b7 14713struct x_display_info *
1f8255f2 14714x_term_init (display_name, xrm_option, resource_name)
334208b7 14715 Lisp_Object display_name;
1f8255f2
RS
14716 char *xrm_option;
14717 char *resource_name;
dc6f92b8 14718{
334208b7 14719 int connection;
7a13e894 14720 Display *dpy;
334208b7
RS
14721 struct x_display_info *dpyinfo;
14722 XrmDatabase xrdb;
14723
60439948
KH
14724 BLOCK_INPUT;
14725
7a13e894
RS
14726 if (!x_initialized)
14727 {
14728 x_initialize ();
14729 x_initialized = 1;
14730 }
dc6f92b8 14731
3afe33e7 14732#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
14733 /* weiner@footloose.sps.mot.com reports that this causes
14734 errors with X11R5:
14735 X protocol error: BadAtom (invalid Atom parameter)
14736 on protocol request 18skiloaf.
14737 So let's not use it until R6. */
14738#ifdef HAVE_X11XTR6
bdcd49ba
RS
14739 XtSetLanguageProc (NULL, NULL, NULL);
14740#endif
14741
7f9c7f94
RS
14742 {
14743 int argc = 0;
14744 char *argv[3];
14745
14746 argv[0] = "";
14747 argc = 1;
14748 if (xrm_option)
14749 {
14750 argv[argc++] = "-xrm";
14751 argv[argc++] = xrm_option;
14752 }
5dbb3f46 14753 stop_polling ();
d5db4077 14754 dpy = XtOpenDisplay (Xt_app_con, SDATA (display_name),
7f9c7f94
RS
14755 resource_name, EMACS_CLASS,
14756 emacs_options, XtNumber (emacs_options),
14757 &argc, argv);
5dbb3f46 14758 start_polling ();
39d8bb4d
KH
14759
14760#ifdef HAVE_X11XTR6
10537cb1 14761 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 14762 fixup_locale ();
39d8bb4d 14763#endif
7f9c7f94 14764 }
3afe33e7
RS
14765
14766#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
14767#ifdef HAVE_X11R5
14768 XSetLocaleModifiers ("");
14769#endif
d5db4077 14770 dpy = XOpenDisplay (SDATA (display_name));
3afe33e7 14771#endif /* not USE_X_TOOLKIT */
334208b7 14772
7a13e894
RS
14773 /* Detect failure. */
14774 if (dpy == 0)
60439948
KH
14775 {
14776 UNBLOCK_INPUT;
14777 return 0;
14778 }
7a13e894
RS
14779
14780 /* We have definitely succeeded. Record the new connection. */
14781
14782 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
f04e1297 14783 bzero (dpyinfo, sizeof *dpyinfo);
7a13e894 14784
29b38361
KH
14785#ifdef MULTI_KBOARD
14786 {
14787 struct x_display_info *share;
14788 Lisp_Object tail;
14789
14790 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6 14791 share = share->next, tail = XCDR (tail))
d5db4077
KR
14792 if (same_x_server (SDATA (XCAR (XCAR (tail))),
14793 SDATA (display_name)))
29b38361
KH
14794 break;
14795 if (share)
14796 dpyinfo->kboard = share->kboard;
14797 else
14798 {
14799 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
14800 init_kboard (dpyinfo->kboard);
59e755be
KH
14801 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
14802 {
14803 char *vendor = ServerVendor (dpy);
9b6ed9f3 14804 UNBLOCK_INPUT;
59e755be
KH
14805 dpyinfo->kboard->Vsystem_key_alist
14806 = call1 (Qvendor_specific_keysyms,
14807 build_string (vendor ? vendor : ""));
9b6ed9f3 14808 BLOCK_INPUT;
59e755be
KH
14809 }
14810
29b38361
KH
14811 dpyinfo->kboard->next_kboard = all_kboards;
14812 all_kboards = dpyinfo->kboard;
0ad5446c
KH
14813 /* Don't let the initial kboard remain current longer than necessary.
14814 That would cause problems if a file loaded on startup tries to
06a2c219 14815 prompt in the mini-buffer. */
0ad5446c
KH
14816 if (current_kboard == initial_kboard)
14817 current_kboard = dpyinfo->kboard;
29b38361
KH
14818 }
14819 dpyinfo->kboard->reference_count++;
14820 }
b9737ad3
KH
14821#endif
14822
7a13e894
RS
14823 /* Put this display on the chain. */
14824 dpyinfo->next = x_display_list;
14825 x_display_list = dpyinfo;
14826
7d0393cf 14827 /* Put it on x_display_name_list as well, to keep them parallel. */
7a13e894
RS
14828 x_display_name_list = Fcons (Fcons (display_name, Qnil),
14829 x_display_name_list);
8e713be6 14830 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
14831
14832 dpyinfo->display = dpy;
dc6f92b8 14833
dc6f92b8 14834#if 0
7a13e894 14835 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 14836#endif /* ! 0 */
7a13e894
RS
14837
14838 dpyinfo->x_id_name
d5db4077
KR
14839 = (char *) xmalloc (SBYTES (Vinvocation_name)
14840 + SBYTES (Vsystem_name)
7a13e894
RS
14841 + 2);
14842 sprintf (dpyinfo->x_id_name, "%s@%s",
d5db4077 14843 SDATA (Vinvocation_name), SDATA (Vsystem_name));
28430d3c
JB
14844
14845 /* Figure out which modifier bits mean what. */
334208b7 14846 x_find_modifier_meanings (dpyinfo);
f451eb13 14847
ab648270 14848 /* Get the scroll bar cursor. */
7a13e894 14849 dpyinfo->vertical_scroll_bar_cursor
334208b7 14850 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 14851
334208b7
RS
14852 xrdb = x_load_resources (dpyinfo->display, xrm_option,
14853 resource_name, EMACS_CLASS);
14854#ifdef HAVE_XRMSETDATABASE
14855 XrmSetDatabase (dpyinfo->display, xrdb);
14856#else
14857 dpyinfo->display->db = xrdb;
14858#endif
547d9db8 14859 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
14860 all versions. */
14861 dpyinfo->xrdb = xrdb;
334208b7
RS
14862
14863 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
14864 DefaultScreen (dpyinfo->display));
5ff67d81 14865 select_visual (dpyinfo);
43bd1b2b 14866 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
14867 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
14868 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
14869 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
14870 dpyinfo->grabbed = 0;
14871 dpyinfo->reference_count = 0;
14872 dpyinfo->icon_bitmap_id = -1;
06a2c219 14873 dpyinfo->font_table = NULL;
7a13e894
RS
14874 dpyinfo->n_fonts = 0;
14875 dpyinfo->font_table_size = 0;
14876 dpyinfo->bitmaps = 0;
14877 dpyinfo->bitmaps_size = 0;
14878 dpyinfo->bitmaps_last = 0;
14879 dpyinfo->scratch_cursor_gc = 0;
14880 dpyinfo->mouse_face_mouse_frame = 0;
14881 dpyinfo->mouse_face_deferred_gc = 0;
14882 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
14883 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 14884 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894 14885 dpyinfo->mouse_face_window = Qnil;
0a61c667 14886 dpyinfo->mouse_face_overlay = Qnil;
7a13e894
RS
14887 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
14888 dpyinfo->mouse_face_defer = 0;
66301061 14889 dpyinfo->mouse_face_hidden = 0;
0f941935
KH
14890 dpyinfo->x_focus_frame = 0;
14891 dpyinfo->x_focus_event_frame = 0;
14892 dpyinfo->x_highlight_frame = 0;
06a2c219 14893 dpyinfo->image_cache = make_image_cache ();
334208b7 14894
43bd1b2b 14895 /* See if a private colormap is requested. */
5ff67d81
GM
14896 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
14897 {
14898 if (dpyinfo->visual->class == PseudoColor)
14899 {
14900 Lisp_Object value;
14901 value = display_x_get_resource (dpyinfo,
14902 build_string ("privateColormap"),
14903 build_string ("PrivateColormap"),
14904 Qnil, Qnil);
14905 if (STRINGP (value)
d5db4077
KR
14906 && (!strcmp (SDATA (value), "true")
14907 || !strcmp (SDATA (value), "on")))
5ff67d81
GM
14908 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
14909 }
43bd1b2b 14910 }
5ff67d81
GM
14911 else
14912 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
14913 dpyinfo->visual, AllocNone);
7d0393cf 14914
06a2c219
GM
14915 {
14916 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
14917 double pixels = DisplayHeight (dpyinfo->display, screen_number);
14918 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
14919 dpyinfo->resy = pixels * 25.4 / mm;
14920 pixels = DisplayWidth (dpyinfo->display, screen_number);
14921 mm = DisplayWidthMM (dpyinfo->display, screen_number);
14922 dpyinfo->resx = pixels * 25.4 / mm;
14923 }
7d0393cf 14924
334208b7
RS
14925 dpyinfo->Xatom_wm_protocols
14926 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
14927 dpyinfo->Xatom_wm_take_focus
14928 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
14929 dpyinfo->Xatom_wm_save_yourself
14930 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
14931 dpyinfo->Xatom_wm_delete_window
14932 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
14933 dpyinfo->Xatom_wm_change_state
14934 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
14935 dpyinfo->Xatom_wm_configure_denied
14936 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
14937 dpyinfo->Xatom_wm_window_moved
14938 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
14939 dpyinfo->Xatom_editres
14940 = XInternAtom (dpyinfo->display, "Editres", False);
14941 dpyinfo->Xatom_CLIPBOARD
14942 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
14943 dpyinfo->Xatom_TIMESTAMP
14944 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
14945 dpyinfo->Xatom_TEXT
14946 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
14947 dpyinfo->Xatom_COMPOUND_TEXT
14948 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
c62525b7
KH
14949 dpyinfo->Xatom_UTF8_STRING
14950 = XInternAtom (dpyinfo->display, "UTF8_STRING", False);
334208b7
RS
14951 dpyinfo->Xatom_DELETE
14952 = XInternAtom (dpyinfo->display, "DELETE", False);
14953 dpyinfo->Xatom_MULTIPLE
14954 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
14955 dpyinfo->Xatom_INCR
14956 = XInternAtom (dpyinfo->display, "INCR", False);
14957 dpyinfo->Xatom_EMACS_TMP
14958 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
14959 dpyinfo->Xatom_TARGETS
14960 = XInternAtom (dpyinfo->display, "TARGETS", False);
14961 dpyinfo->Xatom_NULL
14962 = XInternAtom (dpyinfo->display, "NULL", False);
14963 dpyinfo->Xatom_ATOM_PAIR
14964 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
14965 /* For properties of font. */
14966 dpyinfo->Xatom_PIXEL_SIZE
14967 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
14968 dpyinfo->Xatom_MULE_BASELINE_OFFSET
14969 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
14970 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
14971 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
14972 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
14973 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 14974
06a2c219
GM
14975 /* Ghostscript support. */
14976 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
14977 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
7d0393cf 14978
06a2c219
GM
14979 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
14980 False);
14981
547d9db8
KH
14982 dpyinfo->cut_buffers_initialized = 0;
14983
334208b7
RS
14984 connection = ConnectionNumber (dpyinfo->display);
14985 dpyinfo->connection = connection;
14986
dc43ef94 14987 {
5d7cc324
RS
14988 char null_bits[1];
14989
14990 null_bits[0] = 0x00;
dc43ef94
KH
14991
14992 dpyinfo->null_pixel
7d0393cf 14993 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
dc43ef94
KH
14994 null_bits, 1, 1, (long) 0, (long) 0,
14995 1);
14996 }
14997
06a2c219
GM
14998 {
14999 extern int gray_bitmap_width, gray_bitmap_height;
10659c77 15000 extern char *gray_bitmap_bits;
06a2c219
GM
15001 dpyinfo->gray
15002 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
15003 gray_bitmap_bits,
15004 gray_bitmap_width, gray_bitmap_height,
15005 (unsigned long) 1, (unsigned long) 0, 1);
15006 }
15007
f5d11644
GM
15008#ifdef HAVE_X_I18N
15009 xim_initialize (dpyinfo, resource_name);
15010#endif
7d0393cf 15011
87485d6f
MW
15012#ifdef subprocesses
15013 /* This is only needed for distinguishing keyboard and process input. */
334208b7 15014 if (connection != 0)
7a13e894 15015 add_keyboard_wait_descriptor (connection);
87485d6f 15016#endif
6d4238f3 15017
041b69ac 15018#ifndef F_SETOWN_BUG
dc6f92b8 15019#ifdef F_SETOWN
dc6f92b8 15020#ifdef F_SETOWN_SOCK_NEG
61c3ce62 15021 /* stdin is a socket here */
334208b7 15022 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 15023#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 15024 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
15025#endif /* ! defined (F_SETOWN_SOCK_NEG) */
15026#endif /* ! defined (F_SETOWN) */
041b69ac 15027#endif /* F_SETOWN_BUG */
dc6f92b8
JB
15028
15029#ifdef SIGIO
eee20f6a
KH
15030 if (interrupt_input)
15031 init_sigio (connection);
c118dd06 15032#endif /* ! defined (SIGIO) */
dc6f92b8 15033
51b592fb 15034#ifdef USE_LUCID
f8c39f51 15035#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
15036 /* Make sure that we have a valid font for dialog boxes
15037 so that Xt does not crash. */
15038 {
15039 Display *dpy = dpyinfo->display;
15040 XrmValue d, fr, to;
15041 Font font;
e99db5a1 15042 int count;
7d0393cf 15043
51b592fb
RS
15044 d.addr = (XPointer)&dpy;
15045 d.size = sizeof (Display *);
15046 fr.addr = XtDefaultFont;
15047 fr.size = sizeof (XtDefaultFont);
15048 to.size = sizeof (Font *);
15049 to.addr = (XPointer)&font;
e99db5a1 15050 count = x_catch_errors (dpy);
51b592fb
RS
15051 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
15052 abort ();
15053 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
15054 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 15055 x_uncatch_errors (dpy, count);
51b592fb
RS
15056 }
15057#endif
f8c39f51 15058#endif
51b592fb 15059
34e23e5a
GM
15060 /* See if we should run in synchronous mode. This is useful
15061 for debugging X code. */
15062 {
15063 Lisp_Object value;
15064 value = display_x_get_resource (dpyinfo,
15065 build_string ("synchronous"),
15066 build_string ("Synchronous"),
15067 Qnil, Qnil);
15068 if (STRINGP (value)
d5db4077
KR
15069 && (!strcmp (SDATA (value), "true")
15070 || !strcmp (SDATA (value), "on")))
34e23e5a
GM
15071 XSynchronize (dpyinfo->display, True);
15072 }
7d0393cf 15073
60439948
KH
15074 UNBLOCK_INPUT;
15075
7a13e894
RS
15076 return dpyinfo;
15077}
15078\f
15079/* Get rid of display DPYINFO, assuming all frames are already gone,
15080 and without sending any more commands to the X server. */
dc6f92b8 15081
7a13e894
RS
15082void
15083x_delete_display (dpyinfo)
15084 struct x_display_info *dpyinfo;
15085{
15086 delete_keyboard_wait_descriptor (dpyinfo->connection);
15087
15088 /* Discard this display from x_display_name_list and x_display_list.
15089 We can't use Fdelq because that can quit. */
15090 if (! NILP (x_display_name_list)
8e713be6
KR
15091 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
15092 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
15093 else
15094 {
15095 Lisp_Object tail;
15096
15097 tail = x_display_name_list;
8e713be6 15098 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 15099 {
bffcfca9 15100 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 15101 {
f3fbd155 15102 XSETCDR (tail, XCDR (XCDR (tail)));
7a13e894
RS
15103 break;
15104 }
8e713be6 15105 tail = XCDR (tail);
7a13e894
RS
15106 }
15107 }
15108
9bda743f
GM
15109 if (next_noop_dpyinfo == dpyinfo)
15110 next_noop_dpyinfo = dpyinfo->next;
15111
7a13e894
RS
15112 if (x_display_list == dpyinfo)
15113 x_display_list = dpyinfo->next;
7f9c7f94
RS
15114 else
15115 {
15116 struct x_display_info *tail;
7a13e894 15117
7f9c7f94
RS
15118 for (tail = x_display_list; tail; tail = tail->next)
15119 if (tail->next == dpyinfo)
15120 tail->next = tail->next->next;
15121 }
7a13e894 15122
0d777288
RS
15123#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
15124#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
15125 XrmDestroyDatabase (dpyinfo->xrdb);
15126#endif
0d777288 15127#endif
29b38361
KH
15128#ifdef MULTI_KBOARD
15129 if (--dpyinfo->kboard->reference_count == 0)
39f79001 15130 delete_kboard (dpyinfo->kboard);
b9737ad3 15131#endif
f5d11644
GM
15132#ifdef HAVE_X_I18N
15133 if (dpyinfo->xim)
15134 xim_close_dpy (dpyinfo);
15135#endif
7d0393cf 15136
b9737ad3
KH
15137 xfree (dpyinfo->font_table);
15138 xfree (dpyinfo->x_id_name);
f04e1297 15139 xfree (dpyinfo->color_cells);
b9737ad3 15140 xfree (dpyinfo);
7a13e894 15141}
f04e1297 15142
7a13e894
RS
15143\f
15144/* Set up use of X before we make the first connection. */
15145
06a2c219
GM
15146static struct redisplay_interface x_redisplay_interface =
15147{
15148 x_produce_glyphs,
15149 x_write_glyphs,
15150 x_insert_glyphs,
15151 x_clear_end_of_line,
15152 x_scroll_run,
15153 x_after_update_window_line,
15154 x_update_window_begin,
15155 x_update_window_end,
15156 XTcursor_to,
15157 x_flush,
71b8321e 15158 x_clear_mouse_face,
66ac4b0e
GM
15159 x_get_glyph_overhangs,
15160 x_fix_overlapping_area
06a2c219
GM
15161};
15162
dfcf069d 15163void
7a13e894
RS
15164x_initialize ()
15165{
06a2c219
GM
15166 rif = &x_redisplay_interface;
15167
15168 clear_frame_hook = x_clear_frame;
15169 ins_del_lines_hook = x_ins_del_lines;
06a2c219 15170 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
15171 ring_bell_hook = XTring_bell;
15172 reset_terminal_modes_hook = XTreset_terminal_modes;
15173 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
15174 update_begin_hook = x_update_begin;
15175 update_end_hook = x_update_end;
dc6f92b8
JB
15176 set_terminal_window_hook = XTset_terminal_window;
15177 read_socket_hook = XTread_socket;
b8009dd1 15178 frame_up_to_date_hook = XTframe_up_to_date;
90e65f07 15179 mouse_position_hook = XTmouse_position;
f451eb13 15180 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 15181 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
15182 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
15183 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
15184 redeem_scroll_bar_hook = XTredeem_scroll_bar;
15185 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 15186 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 15187
f676886a 15188 scroll_region_ok = 1; /* we'll scroll partial frames */
9017309f 15189 char_ins_del_ok = 1;
dc6f92b8
JB
15190 line_ins_del_ok = 1; /* we'll just blt 'em */
15191 fast_clear_end_of_line = 1; /* X does this well */
58769bee 15192 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
15193 off the bottom */
15194 baud_rate = 19200;
15195
7a13e894 15196 x_noop_count = 0;
9ea173e8 15197 last_tool_bar_item = -1;
06a2c219 15198 any_help_event_p = 0;
7d0393cf 15199
b30b24cb
RS
15200 /* Try to use interrupt input; if we can't, then start polling. */
15201 Fset_input_mode (Qt, Qnil, Qt, Qnil);
15202
7f9c7f94
RS
15203#ifdef USE_X_TOOLKIT
15204 XtToolkitInitialize ();
651f03b6 15205
7f9c7f94 15206 Xt_app_con = XtCreateApplicationContext ();
7d0393cf 15207
651f03b6
GM
15208 /* Register a converter from strings to pixels, which uses
15209 Emacs' color allocation infrastructure. */
15210 XtAppSetTypeConverter (Xt_app_con,
15211 XtRString, XtRPixel, cvt_string_to_pixel,
15212 cvt_string_to_pixel_args,
15213 XtNumber (cvt_string_to_pixel_args),
15214 XtCacheByDisplay, cvt_pixel_dtor);
15215
665881ad 15216 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
15217
15218 /* Install an asynchronous timer that processes Xt timeout events
15219 every 0.1s. This is necessary because some widget sets use
15220 timeouts internally, for example the LessTif menu bar, or the
15221 Xaw3d scroll bar. When Xt timouts aren't processed, these
15222 widgets don't behave normally. */
15223 {
15224 EMACS_TIME interval;
15225 EMACS_SET_SECS_USECS (interval, 0, 100000);
15226 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
15227 }
db74249b 15228#endif
7d0393cf 15229
eccc05db 15230#ifdef USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
15231 xaw3d_arrow_scroll = False;
15232 xaw3d_pick_top = True;
7f9c7f94
RS
15233#endif
15234
58769bee 15235 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 15236 original error handler. */
e99db5a1 15237 XSetErrorHandler (x_error_handler);
334208b7 15238 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 15239
06a2c219 15240 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
15241#ifdef SIGWINCH
15242 signal (SIGWINCH, SIG_DFL);
a59facca 15243#endif /* SIGWINCH */
dc6f92b8 15244
92e2441b 15245 signal (SIGPIPE, x_connection_signal);
5f30b957
JD
15246
15247#ifdef HAVE_X_SM
15248 x_session_initialize ();
15249#endif
dc6f92b8 15250}
55123275 15251
06a2c219 15252
55123275
JB
15253void
15254syms_of_xterm ()
15255{
e99db5a1
RS
15256 staticpro (&x_error_message_string);
15257 x_error_message_string = Qnil;
15258
7a13e894
RS
15259 staticpro (&x_display_name_list);
15260 x_display_name_list = Qnil;
334208b7 15261
ab648270 15262 staticpro (&last_mouse_scroll_bar);
e53cb100 15263 last_mouse_scroll_bar = Qnil;
59e755be
KH
15264
15265 staticpro (&Qvendor_specific_keysyms);
15266 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9 15267
c997eae5
SM
15268 staticpro (&Qutf_8);
15269 Qutf_8 = intern ("utf-8");
15270 staticpro (&Qlatin_1);
15271 Qlatin_1 = intern ("latin-1");
15272
2237cac9
RS
15273 staticpro (&last_mouse_press_frame);
15274 last_mouse_press_frame = Qnil;
06a2c219 15275
06a2c219 15276 help_echo = Qnil;
be010514
GM
15277 staticpro (&help_echo);
15278 help_echo_object = Qnil;
15279 staticpro (&help_echo_object);
7cea38bc
GM
15280 help_echo_window = Qnil;
15281 staticpro (&help_echo_window);
06a2c219 15282 previous_help_echo = Qnil;
be010514
GM
15283 staticpro (&previous_help_echo);
15284 help_echo_pos = -1;
06a2c219 15285
ee8ceff8 15286 DEFVAR_BOOL ("mouse-autoselect-window", &mouse_autoselect_window,
503e457e 15287 doc: /* *Non-nil means autoselect window with mouse pointer. */);
ee8ceff8 15288 mouse_autoselect_window = 0;
503e457e 15289
7ee72033
MB
15290 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
15291 doc: /* *Non-nil means draw block cursor as wide as the glyph under it.
228299fa
GM
15292For example, if a block cursor is over a tab, it will be drawn as
15293wide as that tab on the display. */);
06a2c219
GM
15294 x_stretch_cursor_p = 0;
15295
a72d5ce5 15296 DEFVAR_BOOL ("x-use-underline-position-properties",
7ee72033
MB
15297 &x_use_underline_position_properties,
15298 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
f0529b5b 15299nil means ignore them. If you encounter fonts with bogus
228299fa
GM
15300UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
15301to 4.1, set this to nil. */);
a72d5ce5
GM
15302 x_use_underline_position_properties = 1;
15303
7ee72033
MB
15304 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
15305 doc: /* What X toolkit scroll bars Emacs uses.
228299fa
GM
15306A value of nil means Emacs doesn't use X toolkit scroll bars.
15307Otherwise, value is a symbol describing the X toolkit. */);
eccc05db 15308#ifdef USE_TOOLKIT_SCROLL_BARS
5bf04520
GM
15309#ifdef USE_MOTIF
15310 Vx_toolkit_scroll_bars = intern ("motif");
15311#elif defined HAVE_XAW3D
15312 Vx_toolkit_scroll_bars = intern ("xaw3d");
15313#else
15314 Vx_toolkit_scroll_bars = intern ("xaw");
15315#endif
06a2c219 15316#else
5bf04520 15317 Vx_toolkit_scroll_bars = Qnil;
06a2c219
GM
15318#endif
15319
06a2c219
GM
15320 staticpro (&last_mouse_motion_frame);
15321 last_mouse_motion_frame = Qnil;
7d0393cf 15322
98659da6
KG
15323 Qmodifier_value = intern ("modifier-value");
15324 Qalt = intern ("alt");
15325 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
15326 Qhyper = intern ("hyper");
15327 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
15328 Qmeta = intern ("meta");
15329 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
15330 Qsuper = intern ("super");
15331 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7d0393cf 15332
98659da6
KG
15333 DEFVAR_LISP ("x-alt-keysym", &Vx_alt_keysym,
15334 doc: /* Which keys Emacs uses for the alt modifier.
15335This should be one of the symbols `alt', `hyper', `meta', `super'.
15336For example, `alt' means use the Alt_L and Alt_R keysyms. The default
15337is nil, which is the same as `alt'. */);
15338 Vx_alt_keysym = Qnil;
7d0393cf 15339
98659da6
KG
15340 DEFVAR_LISP ("x-hyper-keysym", &Vx_hyper_keysym,
15341 doc: /* Which keys Emacs uses for the hyper modifier.
15342This should be one of the symbols `alt', `hyper', `meta', `super'.
15343For example, `hyper' means use the Hyper_L and Hyper_R keysyms. The
15344default is nil, which is the same as `hyper'. */);
15345 Vx_hyper_keysym = Qnil;
7d0393cf 15346
98659da6
KG
15347 DEFVAR_LISP ("x-meta-keysym", &Vx_meta_keysym,
15348 doc: /* Which keys Emacs uses for the meta modifier.
15349This should be one of the symbols `alt', `hyper', `meta', `super'.
15350For example, `meta' means use the Meta_L and Meta_R keysyms. The
15351default is nil, which is the same as `meta'. */);
15352 Vx_meta_keysym = Qnil;
7d0393cf 15353
98659da6
KG
15354 DEFVAR_LISP ("x-super-keysym", &Vx_super_keysym,
15355 doc: /* Which keys Emacs uses for the super modifier.
15356This should be one of the symbols `alt', `hyper', `meta', `super'.
15357For example, `super' means use the Super_L and Super_R keysyms. The
15358default is nil, which is the same as `super'. */);
15359 Vx_super_keysym = Qnil;
15360
55123275 15361}
6cf0ae86 15362
1d6c120a 15363#endif /* HAVE_X_WINDOWS */