More updates.
[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
PJ
100#ifdef USE_LUCID
101extern int xlwmenu_window_p (Widget w, Window window);
102extern void xlwmenu_redisplay P_ ((Widget));
103#endif
104
3afe33e7 105#ifdef USE_X_TOOLKIT
06a2c219 106
952291d9
GM
107extern void free_frame_menubar P_ ((struct frame *));
108extern struct frame *x_menubar_window_to_frame P_ ((struct x_display_info *,
109 int));
06a2c219 110
0fdff6bb
RS
111#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
112#define HACK_EDITRES
113extern void _XEditResCheckMessages ();
114#endif /* not NO_EDITRES */
06a2c219
GM
115
116/* Include toolkit specific headers for the scroll bar widget. */
117
118#ifdef USE_TOOLKIT_SCROLL_BARS
119#if defined USE_MOTIF
120#include <Xm/Xm.h> /* for LESSTIF_VERSION */
121#include <Xm/ScrollBar.h>
ec18280f
SM
122#else /* !USE_MOTIF i.e. use Xaw */
123
124#ifdef HAVE_XAW3D
06a2c219 125#include <X11/Xaw3d/Simple.h>
06a2c219
GM
126#include <X11/Xaw3d/Scrollbar.h>
127#define ARROW_SCROLLBAR
128#include <X11/Xaw3d/ScrollbarP.h>
ec18280f
SM
129#else /* !HAVE_XAW3D */
130#include <X11/Xaw/Simple.h>
131#include <X11/Xaw/Scrollbar.h>
132#endif /* !HAVE_XAW3D */
133#ifndef XtNpickTop
134#define XtNpickTop "pickTop"
135#endif /* !XtNpickTop */
136#endif /* !USE_MOTIF */
06a2c219
GM
137#endif /* USE_TOOLKIT_SCROLL_BARS */
138
3afe33e7
RS
139#endif /* USE_X_TOOLKIT */
140
b849c413
RS
141#ifndef USE_X_TOOLKIT
142#define x_any_window_to_frame x_window_to_frame
5627c40e 143#define x_top_window_to_frame x_window_to_frame
b849c413
RS
144#endif
145
546e6d5b 146#ifdef USE_X_TOOLKIT
d067ea8b 147#include "widget.h"
546e6d5b
RS
148#ifndef XtNinitialState
149#define XtNinitialState "initialState"
150#endif
151#endif
152
06a2c219
GM
153#define abs(x) ((x) < 0 ? -(x) : (x))
154
155#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
156
157\f
3f332ef3 158/* Fringe bitmaps. */
06a2c219 159
3f332ef3 160enum fringe_bitmap_type
06a2c219 161{
3f332ef3 162 NO_FRINGE_BITMAP,
06a2c219
GM
163 LEFT_TRUNCATION_BITMAP,
164 RIGHT_TRUNCATION_BITMAP,
165 OVERLAY_ARROW_BITMAP,
166 CONTINUED_LINE_BITMAP,
167 CONTINUATION_LINE_BITMAP,
168 ZV_LINE_BITMAP
169};
170
171/* Bitmap drawn to indicate lines not displaying text if
172 `indicate-empty-lines' is non-nil. */
173
174#define zv_width 8
976b73d7
KS
175#define zv_height 72
176#define zv_period 3
06a2c219 177static unsigned char zv_bits[] = {
976b73d7
KS
178 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
179 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
180 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
181 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
182 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
183 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
184 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
185 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00};
06a2c219
GM
186
187/* An arrow like this: `<-'. */
188
189#define left_width 8
190#define left_height 8
191static unsigned char left_bits[] = {
192 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
193
110859fc
GM
194/* Right truncation arrow bitmap `->'. */
195
196#define right_width 8
197#define right_height 8
198static unsigned char right_bits[] = {
199 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
200
06a2c219
GM
201/* Marker for continued lines. */
202
203#define continued_width 8
204#define continued_height 8
205static unsigned char continued_bits[] = {
110859fc
GM
206 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
207
208/* Marker for continuation lines. */
06a2c219
GM
209
210#define continuation_width 8
211#define continuation_height 8
212static unsigned char continuation_bits[] = {
110859fc 213 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
06a2c219 214
110859fc 215/* Overlay arrow bitmap. */
06a2c219 216
110859fc
GM
217#if 0
218/* A bomb. */
06a2c219
GM
219#define ov_width 8
220#define ov_height 8
221static unsigned char ov_bits[] = {
222 0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
06a2c219 223#else
110859fc 224/* A triangular arrow. */
06a2c219
GM
225#define ov_width 8
226#define ov_height 8
227static unsigned char ov_bits[] = {
110859fc
GM
228 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
229
e4b68333 230#endif
06a2c219
GM
231
232extern Lisp_Object Qhelp_echo;
233
69388238 234\f
5bf04520 235/* Non-nil means Emacs uses toolkit scroll bars. */
06a2c219 236
5bf04520 237Lisp_Object Vx_toolkit_scroll_bars;
06a2c219
GM
238
239/* If a string, XTread_socket generates an event to display that string.
240 (The display is done in read_char.) */
241
242static Lisp_Object help_echo;
7cea38bc 243static Lisp_Object help_echo_window;
be010514
GM
244static Lisp_Object help_echo_object;
245static int help_echo_pos;
06a2c219
GM
246
247/* Temporary variable for XTread_socket. */
248
249static Lisp_Object previous_help_echo;
250
251/* Non-zero means that a HELP_EVENT has been generated since Emacs
252 start. */
253
254static int any_help_event_p;
255
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
06a2c219
GM
302/* Nominal cursor position -- where to draw output.
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
KH
396static Lisp_Object Qvendor_specific_keysyms;
397
952291d9
GM
398extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
399extern Lisp_Object x_icon_type P_ ((struct frame *));
c32cdd9a 400
7a13e894 401
06a2c219
GM
402/* Enumeration for overriding/changing the face to use for drawing
403 glyphs in x_draw_glyphs. */
404
405enum draw_glyphs_face
406{
407 DRAW_NORMAL_TEXT,
408 DRAW_INVERSE_VIDEO,
409 DRAW_CURSOR,
410 DRAW_MOUSE_FACE,
411 DRAW_IMAGE_RAISED,
412 DRAW_IMAGE_SUNKEN
413};
414
b7f83f9e 415static int cursor_in_mouse_face_p P_ ((struct window *));
fa262c07 416static int clear_mouse_face P_ ((struct x_display_info *));
651f03b6 417static int x_alloc_nearest_color_1 P_ ((Display *, Colormap, XColor *));
499b1844 418static void x_set_window_size_1 P_ ((struct frame *, int, int, int));
651f03b6 419static const XColor *x_color_cells P_ ((Display *, int *));
71b8321e 420static void x_update_window_end P_ ((struct window *, int, int));
06a2c219
GM
421static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
422void x_delete_display P_ ((struct x_display_info *));
423static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
424 unsigned));
425static int fast_find_position P_ ((struct window *, int, int *, int *,
7e376260 426 int *, int *, Lisp_Object));
f9db2310
GM
427static int fast_find_string_pos P_ ((struct window *, int, Lisp_Object,
428 int *, int *, int *, int *, int));
06a2c219
GM
429static void set_output_cursor P_ ((struct cursor_pos *));
430static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
f9db2310 431 int *, int *, int *, int));
b436feb6
GM
432static void note_mode_line_or_margin_highlight P_ ((struct window *, int,
433 int, int));
06a2c219 434static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
435static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
436static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
437static void show_mouse_face P_ ((struct x_display_info *,
438 enum draw_glyphs_face));
439static int x_io_error_quitter P_ ((Display *));
440int x_catch_errors P_ ((Display *));
441void x_uncatch_errors P_ ((Display *, int));
442void x_lower_frame P_ ((struct frame *));
443void x_scroll_bar_clear P_ ((struct frame *));
444int x_had_errors_p P_ ((Display *));
445void x_wm_set_size_hint P_ ((struct frame *, long, int));
446void x_raise_frame P_ ((struct frame *));
447void x_set_window_size P_ ((struct frame *, int, int, int));
448void x_wm_set_window_state P_ ((struct frame *, int));
449void x_wm_set_icon_pixmap P_ ((struct frame *, int));
450void x_initialize P_ ((void));
451static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
452static int x_compute_min_glyph_bounds P_ ((struct frame *));
453static void x_draw_phys_cursor_glyph P_ ((struct window *,
454 struct glyph_row *,
455 enum draw_glyphs_face));
456static void x_update_end P_ ((struct frame *));
457static void XTframe_up_to_date P_ ((struct frame *));
06a2c219
GM
458static void XTset_terminal_modes P_ ((void));
459static void XTreset_terminal_modes P_ ((void));
460static void XTcursor_to P_ ((int, int, int, int));
461static void x_write_glyphs P_ ((struct glyph *, int));
462static void x_clear_end_of_line P_ ((int));
463static void x_clear_frame P_ ((void));
464static void x_clear_cursor P_ ((struct window *));
465static void frame_highlight P_ ((struct frame *));
466static void frame_unhighlight P_ ((struct frame *));
467static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
468static void XTframe_rehighlight P_ ((struct frame *));
469static void x_frame_rehighlight P_ ((struct x_display_info *));
470static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
f02d8aa0 471static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
06a2c219
GM
472static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
473 XRectangle *));
474static void expose_frame P_ ((struct frame *, int, int, int, int));
82f053ab 475static int expose_window_tree P_ ((struct window *, XRectangle *));
a39202f6 476static int expose_window P_ ((struct window *, XRectangle *));
06a2c219
GM
477static void expose_area P_ ((struct window *, struct glyph_row *,
478 XRectangle *, enum glyph_row_area));
82f053ab 479static int expose_line P_ ((struct window *, struct glyph_row *,
06a2c219
GM
480 XRectangle *));
481static void x_update_cursor_in_window_tree P_ ((struct window *, int));
482static void x_update_window_cursor P_ ((struct window *, int));
483static void x_erase_phys_cursor P_ ((struct window *));
484void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
3f332ef3 485static void x_draw_fringe_bitmap P_ ((struct window *, struct glyph_row *,
976b73d7 486 enum fringe_bitmap_type, int left_p));
06a2c219
GM
487
488static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
489 GC, int));
490static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
3f332ef3 491static void x_draw_row_fringe_bitmaps P_ ((struct window *, struct glyph_row *));
60626bab
GM
492static void notice_overwritten_cursor P_ ((struct window *, enum glyph_row_area,
493 int, int, int, int));
06a2c219 494static void x_flush P_ ((struct frame *f));
952291d9
GM
495static void x_update_begin P_ ((struct frame *));
496static void x_update_window_begin P_ ((struct window *));
497static void x_draw_vertical_border P_ ((struct window *));
498static void x_after_update_window_line P_ ((struct glyph_row *));
499static INLINE void take_vertical_position_into_account P_ ((struct it *));
500static void x_produce_stretch_glyph P_ ((struct it *));
b52b65bd
GM
501static struct scroll_bar *x_window_to_scroll_bar P_ ((Window));
502static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
503 enum scroll_bar_part *,
504 Lisp_Object *, Lisp_Object *,
505 unsigned long *));
d0fa3e56
EZ
506static void x_check_fullscreen P_ ((struct frame *));
507static void x_check_fullscreen_move P_ ((struct frame *));
06a2c219
GM
508
509/* Flush display of frame F, or of all frames if F is null. */
510
511static void
512x_flush (f)
513 struct frame *f;
514{
515 BLOCK_INPUT;
516 if (f == NULL)
517 {
518 Lisp_Object rest, frame;
519 FOR_EACH_FRAME (rest, frame)
520 x_flush (XFRAME (frame));
521 }
522 else if (FRAME_X_P (f))
523 XFlush (FRAME_X_DISPLAY (f));
524 UNBLOCK_INPUT;
525}
526
dc6f92b8 527
06a2c219
GM
528/* Remove calls to XFlush by defining XFlush to an empty replacement.
529 Calls to XFlush should be unnecessary because the X output buffer
530 is flushed automatically as needed by calls to XPending,
531 XNextEvent, or XWindowEvent according to the XFlush man page.
532 XTread_socket calls XPending. Removing XFlush improves
533 performance. */
534
535#define XFlush(DISPLAY) (void) 0
b8009dd1 536
334208b7 537\f
06a2c219
GM
538/***********************************************************************
539 Debugging
540 ***********************************************************************/
541
9382638d 542#if 0
06a2c219
GM
543
544/* This is a function useful for recording debugging information about
545 the sequence of occurrences in this file. */
9382638d
KH
546
547struct record
548{
549 char *locus;
550 int type;
551};
552
553struct record event_record[100];
554
555int event_record_index;
556
557record_event (locus, type)
558 char *locus;
559 int type;
560{
561 if (event_record_index == sizeof (event_record) / sizeof (struct record))
562 event_record_index = 0;
563
564 event_record[event_record_index].locus = locus;
565 event_record[event_record_index].type = type;
566 event_record_index++;
567}
568
569#endif /* 0 */
06a2c219
GM
570
571
9382638d 572\f
334208b7
RS
573/* Return the struct x_display_info corresponding to DPY. */
574
575struct x_display_info *
576x_display_info_for_display (dpy)
577 Display *dpy;
578{
579 struct x_display_info *dpyinfo;
580
581 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
582 if (dpyinfo->display == dpy)
583 return dpyinfo;
16bd92ea 584
334208b7
RS
585 return 0;
586}
f451eb13 587
06a2c219
GM
588
589\f
590/***********************************************************************
591 Starting and ending an update
592 ***********************************************************************/
593
594/* Start an update of frame F. This function is installed as a hook
595 for update_begin, i.e. it is called when update_begin is called.
596 This function is called prior to calls to x_update_window_begin for
597 each window being updated. Currently, there is nothing to do here
598 because all interesting stuff is done on a window basis. */
dc6f92b8 599
dfcf069d 600static void
06a2c219 601x_update_begin (f)
f676886a 602 struct frame *f;
58769bee 603{
06a2c219
GM
604 /* Nothing to do. */
605}
dc6f92b8 606
dc6f92b8 607
06a2c219
GM
608/* Start update of window W. Set the global variable updated_window
609 to the window being updated and set output_cursor to the cursor
610 position of W. */
dc6f92b8 611
06a2c219
GM
612static void
613x_update_window_begin (w)
614 struct window *w;
615{
616 struct frame *f = XFRAME (WINDOW_FRAME (w));
617 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
618
619 updated_window = w;
620 set_output_cursor (&w->cursor);
b8009dd1 621
06a2c219 622 BLOCK_INPUT;
d1bc4182 623
06a2c219 624 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 625 {
514e4681 626 /* Don't do highlighting for mouse motion during the update. */
06a2c219 627 display_info->mouse_face_defer = 1;
37c2c98b 628
06a2c219
GM
629 /* If F needs to be redrawn, simply forget about any prior mouse
630 highlighting. */
9f67f20b 631 if (FRAME_GARBAGED_P (f))
06a2c219
GM
632 display_info->mouse_face_window = Qnil;
633
64f26cf5
GM
634#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
635 their mouse_face_p flag set, which means that they are always
636 unequal to rows in a desired matrix which never have that
637 flag set. So, rows containing mouse-face glyphs are never
638 scrolled, and we don't have to switch the mouse highlight off
639 here to prevent it from being scrolled. */
640
06a2c219
GM
641 /* Can we tell that this update does not affect the window
642 where the mouse highlight is? If so, no need to turn off.
643 Likewise, don't do anything if the frame is garbaged;
644 in that case, the frame's current matrix that we would use
645 is all wrong, and we will redisplay that line anyway. */
646 if (!NILP (display_info->mouse_face_window)
647 && w == XWINDOW (display_info->mouse_face_window))
514e4681 648 {
06a2c219 649 int i;
514e4681 650
06a2c219
GM
651 for (i = 0; i < w->desired_matrix->nrows; ++i)
652 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
653 break;
654
06a2c219
GM
655 if (i < w->desired_matrix->nrows)
656 clear_mouse_face (display_info);
514e4681 657 }
64f26cf5 658#endif /* 0 */
b8009dd1 659 }
6ccf47d1 660
dc6f92b8
JB
661 UNBLOCK_INPUT;
662}
663
06a2c219
GM
664
665/* Draw a vertical window border to the right of window W if W doesn't
666 have vertical scroll bars. */
667
dfcf069d 668static void
06a2c219
GM
669x_draw_vertical_border (w)
670 struct window *w;
58769bee 671{
06a2c219
GM
672 struct frame *f = XFRAME (WINDOW_FRAME (w));
673
674 /* Redraw borders between horizontally adjacent windows. Don't
675 do it for frames with vertical scroll bars because either the
676 right scroll bar of a window, or the left scroll bar of its
677 neighbor will suffice as a border. */
678 if (!WINDOW_RIGHTMOST_P (w)
679 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
680 {
681 int x0, x1, y0, y1;
dc6f92b8 682
06a2c219 683 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
3f332ef3 684 x1 += FRAME_X_RIGHT_FRINGE_WIDTH (f);
06a2c219
GM
685 y1 -= 1;
686
687 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
688 f->output_data.x->normal_gc, x1, y0, x1, y1);
689 }
690}
691
692
71b8321e
GM
693/* End update of window W (which is equal to updated_window).
694
695 Draw vertical borders between horizontally adjacent windows, and
696 display W's cursor if CURSOR_ON_P is non-zero.
697
698 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
699 glyphs in mouse-face were overwritten. In that case we have to
700 make sure that the mouse-highlight is properly redrawn.
701
702 W may be a menu bar pseudo-window in case we don't have X toolkit
703 support. Such windows don't have a cursor, so don't display it
704 here. */
06a2c219
GM
705
706static void
71b8321e 707x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 708 struct window *w;
71b8321e 709 int cursor_on_p, mouse_face_overwritten_p;
06a2c219 710{
140330de
GM
711 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
712
06a2c219
GM
713 if (!w->pseudo_window_p)
714 {
715 BLOCK_INPUT;
71b8321e 716
06a2c219
GM
717 if (cursor_on_p)
718 x_display_and_set_cursor (w, 1, output_cursor.hpos,
719 output_cursor.vpos,
720 output_cursor.x, output_cursor.y);
71b8321e 721
06a2c219
GM
722 x_draw_vertical_border (w);
723 UNBLOCK_INPUT;
724 }
725
140330de
GM
726 /* If a row with mouse-face was overwritten, arrange for
727 XTframe_up_to_date to redisplay the mouse highlight. */
728 if (mouse_face_overwritten_p)
729 {
730 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
731 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
732 dpyinfo->mouse_face_window = Qnil;
733 }
734
06a2c219
GM
735 updated_window = NULL;
736}
dc6f92b8 737
dc6f92b8 738
06a2c219
GM
739/* End update of frame F. This function is installed as a hook in
740 update_end. */
741
742static void
743x_update_end (f)
744 struct frame *f;
745{
746 /* Mouse highlight may be displayed again. */
aa8bff2e 747 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 748
06a2c219 749 BLOCK_INPUT;
334208b7 750 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
751 UNBLOCK_INPUT;
752}
b8009dd1 753
06a2c219
GM
754
755/* This function is called from various places in xdisp.c whenever a
756 complete update has been performed. The global variable
757 updated_window is not available here. */
b8009dd1 758
dfcf069d 759static void
b8009dd1 760XTframe_up_to_date (f)
06a2c219 761 struct frame *f;
b8009dd1 762{
06a2c219 763 if (FRAME_X_P (f))
514e4681 764 {
06a2c219 765 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 766
06a2c219
GM
767 if (dpyinfo->mouse_face_deferred_gc
768 || f == dpyinfo->mouse_face_mouse_frame)
769 {
770 BLOCK_INPUT;
771 if (dpyinfo->mouse_face_mouse_frame)
772 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
773 dpyinfo->mouse_face_mouse_x,
774 dpyinfo->mouse_face_mouse_y);
775 dpyinfo->mouse_face_deferred_gc = 0;
776 UNBLOCK_INPUT;
777 }
514e4681 778 }
b8009dd1 779}
06a2c219
GM
780
781
782/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
3f332ef3 783 arrow bitmaps, or clear the fringes if no bitmaps are required
06a2c219
GM
784 before DESIRED_ROW is made current. The window being updated is
785 found in updated_window. This function It is called from
786 update_window_line only if it is known that there are differences
787 between bitmaps to be drawn between current row and DESIRED_ROW. */
788
789static void
790x_after_update_window_line (desired_row)
791 struct glyph_row *desired_row;
792{
793 struct window *w = updated_window;
ef253080 794 struct frame *f;
259cf6bc 795 int width, height;
06a2c219
GM
796
797 xassert (w);
798
799 if (!desired_row->mode_line_p && !w->pseudo_window_p)
800 {
801 BLOCK_INPUT;
3f332ef3 802 x_draw_row_fringe_bitmaps (w, desired_row);
ef253080
GM
803 UNBLOCK_INPUT;
804 }
805
806 /* When a window has disappeared, make sure that no rest of
807 full-width rows stays visible in the internal border. Could
808 check here if updated_window is the leftmost/rightmost window,
809 but I guess it's not worth doing since vertically split windows
810 are almost never used, internal border is rarely set, and the
811 overhead is very small. */
812 if (windows_or_buffers_changed
813 && desired_row->full_width_p
814 && (f = XFRAME (w->frame),
815 width = FRAME_INTERNAL_BORDER_WIDTH (f),
259cf6bc
GM
816 width != 0)
817 && (height = desired_row->visible_height,
818 height > 0))
ef253080 819 {
ef253080 820 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
06a2c219 821
ef253080
GM
822 /* Internal border is drawn below the tool bar. */
823 if (WINDOWP (f->tool_bar_window)
824 && w == XWINDOW (f->tool_bar_window))
825 y -= width;
06a2c219 826
ef253080
GM
827 BLOCK_INPUT;
828 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
829 0, y, width, height, False);
830 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
831 f->output_data.x->pixel_width - width,
832 y, width, height, False);
06a2c219
GM
833 UNBLOCK_INPUT;
834 }
835}
836
837
3f332ef3 838/* Draw the bitmap WHICH in one of the left or right fringes of
06a2c219
GM
839 window W. ROW is the glyph row for which to display the bitmap; it
840 determines the vertical position at which the bitmap has to be
841 drawn. */
842
843static void
976b73d7 844x_draw_fringe_bitmap (w, row, which, left_p)
06a2c219
GM
845 struct window *w;
846 struct glyph_row *row;
3f332ef3 847 enum fringe_bitmap_type which;
976b73d7 848 int left_p;
06a2c219
GM
849{
850 struct frame *f = XFRAME (WINDOW_FRAME (w));
851 Display *display = FRAME_X_DISPLAY (f);
852 Window window = FRAME_X_WINDOW (f);
853 int x, y, wd, h, dy;
976b73d7 854 int b1, b2;
b436feb6 855 unsigned char *bits = NULL;
06a2c219
GM
856 Pixmap pixmap;
857 GC gc = f->output_data.x->normal_gc;
858 struct face *face;
859 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
860
861 /* Must clip because of partially visible lines. */
862 x_clip_to_row (w, row, gc, 1);
863
976b73d7
KS
864 /* Convert row to frame coordinates. */
865 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
866
06a2c219
GM
867 switch (which)
868 {
976b73d7
KS
869 case NO_FRINGE_BITMAP:
870 wd = 0;
871 h = 0;
872 break;
873
06a2c219
GM
874 case LEFT_TRUNCATION_BITMAP:
875 wd = left_width;
876 h = left_height;
877 bits = left_bits;
06a2c219
GM
878 break;
879
880 case OVERLAY_ARROW_BITMAP:
976b73d7
KS
881 wd = ov_width;
882 h = ov_height;
06a2c219 883 bits = ov_bits;
06a2c219
GM
884 break;
885
886 case RIGHT_TRUNCATION_BITMAP:
887 wd = right_width;
888 h = right_height;
889 bits = right_bits;
06a2c219
GM
890 break;
891
892 case CONTINUED_LINE_BITMAP:
976b73d7
KS
893 wd = continued_width;
894 h = continued_height;
06a2c219 895 bits = continued_bits;
06a2c219
GM
896 break;
897
898 case CONTINUATION_LINE_BITMAP:
899 wd = continuation_width;
900 h = continuation_height;
901 bits = continuation_bits;
06a2c219
GM
902 break;
903
904 case ZV_LINE_BITMAP:
905 wd = zv_width;
976b73d7
KS
906 h = zv_height - (y % zv_period);
907 bits = zv_bits + (y % zv_period);
06a2c219
GM
908 break;
909
910 default:
911 abort ();
912 }
913
976b73d7
KS
914 /* Clip bitmap if too high. */
915 if (h > row->height)
916 h = row->height;
917
918 /* Set dy to the offset in the row to start drawing the bitmap. */
06a2c219
GM
919 dy = (row->height - h) / 2;
920
976b73d7
KS
921 face = FACE_FROM_ID (f, FRINGE_FACE_ID);
922 PREPARE_FACE_FOR_DISPLAY (f, face);
923
924 /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill
925 the fringe. */
dbdc9702 926 b1 = b2 = -1;
976b73d7
KS
927 if (left_p)
928 {
929 if (wd > FRAME_X_LEFT_FRINGE_WIDTH (f))
930 wd = FRAME_X_LEFT_FRINGE_WIDTH (f);
931 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
932 - wd
933 - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2);
934 if (wd < FRAME_X_LEFT_FRINGE_WIDTH (f) || row->height > h)
935 {
936 /* If W has a vertical border to its left, don't draw over it. */
937 int border = ((XFASTINT (w->left) > 0
938 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
939 ? 1 : 0);
940 b1 = (window_box_left (w, -1)
941 - FRAME_X_LEFT_FRINGE_WIDTH (f)
942 + border);
943 b2 = (FRAME_X_LEFT_FRINGE_WIDTH (f) - border);
944 }
945 }
946 else
947 {
948 if (wd > FRAME_X_RIGHT_FRINGE_WIDTH (f))
949 wd = FRAME_X_RIGHT_FRINGE_WIDTH (f);
950 x = (window_box_right (w, -1)
951 + (FRAME_X_RIGHT_FRINGE_WIDTH (f) - wd) / 2);
952 /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill
953 the fringe. */
954 if (wd < FRAME_X_RIGHT_FRINGE_WIDTH (f) || row->height > h)
955 {
956 b1 = window_box_right (w, -1);
957 b2 = FRAME_X_RIGHT_FRINGE_WIDTH (f);
958 }
959 }
960
961 if (b1 >= 0)
962 {
963 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
964
965 /* In case the same realized face is used for fringes and
966 for something displayed in the text (e.g. face `region' on
967 mono-displays, the fill style may have been changed to
968 FillSolid in x_draw_glyph_string_background. */
969 if (face->stipple)
970 XSetFillStyle (display, face->gc, FillOpaqueStippled);
971 else
972 XSetForeground (display, face->gc, face->background);
973
974 XFillRectangle (display, window, face->gc,
975 b1,
976 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
977 row->y)),
978 b2,
979 row->visible_height);
980 if (!face->stipple)
981 XSetForeground (display, face->gc, face->foreground);
982 }
983
dbdc9702
GM
984 if (which != NO_FRINGE_BITMAP)
985 {
986 /* Draw the bitmap. I believe these small pixmaps can be cached
987 by the server. */
988 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
989 face->foreground,
990 face->background, depth);
991 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
992 XFreePixmap (display, pixmap);
993 }
994
06a2c219
GM
995 XSetClipMask (display, gc, None);
996}
997
998
3f332ef3 999/* Draw fringe bitmaps for glyph row ROW on window W. Call this
06a2c219
GM
1000 function with input blocked. */
1001
1002static void
3f332ef3 1003x_draw_row_fringe_bitmaps (w, row)
06a2c219
GM
1004 struct window *w;
1005 struct glyph_row *row;
1006{
1007 struct frame *f = XFRAME (w->frame);
3f332ef3 1008 enum fringe_bitmap_type bitmap;
06a2c219
GM
1009
1010 xassert (interrupt_input_blocked);
1011
1012 /* If row is completely invisible, because of vscrolling, we
1013 don't have to draw anything. */
1014 if (row->visible_height <= 0)
1015 return;
1016
976b73d7
KS
1017 if (FRAME_X_LEFT_FRINGE_WIDTH (f) != 0)
1018 {
1019 /* Decide which bitmap to draw in the left fringe. */
1020 if (row->overlay_arrow_p)
1021 bitmap = OVERLAY_ARROW_BITMAP;
1022 else if (row->truncated_on_left_p)
1023 bitmap = LEFT_TRUNCATION_BITMAP;
1024 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
1025 bitmap = CONTINUATION_LINE_BITMAP;
1026 else if (row->indicate_empty_line_p)
1027 bitmap = ZV_LINE_BITMAP;
dcd08bfb 1028 else
976b73d7 1029 bitmap = NO_FRINGE_BITMAP;
06a2c219 1030
976b73d7
KS
1031 x_draw_fringe_bitmap (w, row, bitmap, 1);
1032 }
06a2c219 1033
976b73d7 1034 if (FRAME_X_RIGHT_FRINGE_WIDTH (f) != 0)
06a2c219 1035 {
976b73d7
KS
1036 /* Decide which bitmap to draw in the right fringe. */
1037 if (row->truncated_on_right_p)
1038 bitmap = RIGHT_TRUNCATION_BITMAP;
1039 else if (row->continued_p)
1040 bitmap = CONTINUED_LINE_BITMAP;
1041 else if (row->indicate_empty_line_p && FRAME_X_LEFT_FRINGE_WIDTH (f) == 0)
1042 bitmap = ZV_LINE_BITMAP;
dcd08bfb 1043 else
976b73d7 1044 bitmap = NO_FRINGE_BITMAP;
06a2c219 1045
976b73d7
KS
1046 x_draw_fringe_bitmap (w, row, bitmap, 0);
1047 }
06a2c219
GM
1048}
1049
dc6f92b8 1050\f
06a2c219
GM
1051
1052/* This is called when starting Emacs and when restarting after
1053 suspend. When starting Emacs, no X window is mapped. And nothing
1054 must be done to Emacs's own window if it is suspended (though that
1055 rarely happens). */
dc6f92b8 1056
dfcf069d 1057static void
dc6f92b8
JB
1058XTset_terminal_modes ()
1059{
1060}
1061
06a2c219
GM
1062/* This is called when exiting or suspending Emacs. Exiting will make
1063 the X-windows go away, and suspending requires no action. */
dc6f92b8 1064
dfcf069d 1065static void
dc6f92b8
JB
1066XTreset_terminal_modes ()
1067{
dc6f92b8 1068}
06a2c219
GM
1069
1070
dc6f92b8 1071\f
06a2c219
GM
1072/***********************************************************************
1073 Output Cursor
1074 ***********************************************************************/
1075
1076/* Set the global variable output_cursor to CURSOR. All cursor
1077 positions are relative to updated_window. */
dc6f92b8 1078
dfcf069d 1079static void
06a2c219
GM
1080set_output_cursor (cursor)
1081 struct cursor_pos *cursor;
dc6f92b8 1082{
06a2c219
GM
1083 output_cursor.hpos = cursor->hpos;
1084 output_cursor.vpos = cursor->vpos;
1085 output_cursor.x = cursor->x;
1086 output_cursor.y = cursor->y;
1087}
1088
1089
1090/* Set a nominal cursor position.
dc6f92b8 1091
06a2c219
GM
1092 HPOS and VPOS are column/row positions in a window glyph matrix. X
1093 and Y are window text area relative pixel positions.
1094
1095 If this is done during an update, updated_window will contain the
1096 window that is being updated and the position is the future output
1097 cursor position for that window. If updated_window is null, use
1098 selected_window and display the cursor at the given position. */
1099
1100static void
1101XTcursor_to (vpos, hpos, y, x)
1102 int vpos, hpos, y, x;
1103{
1104 struct window *w;
1105
1106 /* If updated_window is not set, work on selected_window. */
1107 if (updated_window)
1108 w = updated_window;
1109 else
1110 w = XWINDOW (selected_window);
dbcb258a 1111
06a2c219
GM
1112 /* Set the output cursor. */
1113 output_cursor.hpos = hpos;
1114 output_cursor.vpos = vpos;
1115 output_cursor.x = x;
1116 output_cursor.y = y;
dc6f92b8 1117
06a2c219
GM
1118 /* If not called as part of an update, really display the cursor.
1119 This will also set the cursor position of W. */
1120 if (updated_window == NULL)
dc6f92b8
JB
1121 {
1122 BLOCK_INPUT;
06a2c219 1123 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1124 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1125 UNBLOCK_INPUT;
1126 }
1127}
dc43ef94 1128
06a2c219
GM
1129
1130\f
1131/***********************************************************************
1132 Display Iterator
1133 ***********************************************************************/
1134
1135/* Function prototypes of this page. */
1136
1137static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1138 struct glyph *,
ee569018
KH
1139 XChar2b *,
1140 int *));
06a2c219 1141static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
abfb6b46
GM
1142 int, XChar2b *, int,
1143 int));
06a2c219
GM
1144static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1145static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1146static void x_append_glyph P_ ((struct it *));
b4192550 1147static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1148static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1149 int, int, double));
1150static void x_produce_glyphs P_ ((struct it *));
06a2c219 1151static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1152
1153
e2ef8ee6
GM
1154/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1155 is not contained in the font. */
dc43ef94 1156
06a2c219 1157static INLINE XCharStruct *
ee569018 1158x_per_char_metric (font, char2b)
06a2c219
GM
1159 XFontStruct *font;
1160 XChar2b *char2b;
1161{
1162 /* The result metric information. */
1163 XCharStruct *pcm = NULL;
dc6f92b8 1164
06a2c219 1165 xassert (font && char2b);
dc6f92b8 1166
06a2c219 1167 if (font->per_char != NULL)
dc6f92b8 1168 {
06a2c219 1169 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1170 {
06a2c219
GM
1171 /* min_char_or_byte2 specifies the linear character index
1172 corresponding to the first element of the per_char array,
1173 max_char_or_byte2 is the index of the last character. A
1174 character with non-zero CHAR2B->byte1 is not in the font.
1175 A character with byte2 less than min_char_or_byte2 or
1176 greater max_char_or_byte2 is not in the font. */
1177 if (char2b->byte1 == 0
1178 && char2b->byte2 >= font->min_char_or_byte2
1179 && char2b->byte2 <= font->max_char_or_byte2)
1180 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1181 }
06a2c219 1182 else
dc6f92b8 1183 {
06a2c219
GM
1184 /* If either min_byte1 or max_byte1 are nonzero, both
1185 min_char_or_byte2 and max_char_or_byte2 are less than
1186 256, and the 2-byte character index values corresponding
1187 to the per_char array element N (counting from 0) are:
1188
1189 byte1 = N/D + min_byte1
1190 byte2 = N\D + min_char_or_byte2
1191
1192 where:
1193
1194 D = max_char_or_byte2 - min_char_or_byte2 + 1
1195 / = integer division
1196 \ = integer modulus */
1197 if (char2b->byte1 >= font->min_byte1
1198 && char2b->byte1 <= font->max_byte1
1199 && char2b->byte2 >= font->min_char_or_byte2
1200 && char2b->byte2 <= font->max_char_or_byte2)
1201 {
1202 pcm = (font->per_char
1203 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1204 * (char2b->byte1 - font->min_byte1))
1205 + (char2b->byte2 - font->min_char_or_byte2));
1206 }
dc6f92b8 1207 }
06a2c219
GM
1208 }
1209 else
1210 {
1211 /* If the per_char pointer is null, all glyphs between the first
1212 and last character indexes inclusive have the same
1213 information, as given by both min_bounds and max_bounds. */
1214 if (char2b->byte2 >= font->min_char_or_byte2
1215 && char2b->byte2 <= font->max_char_or_byte2)
1216 pcm = &font->max_bounds;
1217 }
dc6f92b8 1218
ee569018 1219 return ((pcm == NULL
3e71d8f2 1220 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1221 ? NULL : pcm);
06a2c219 1222}
b73b6aaf 1223
57b03282 1224
06a2c219
GM
1225/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1226 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1227
06a2c219
GM
1228static INLINE void
1229x_encode_char (c, char2b, font_info)
1230 int c;
1231 XChar2b *char2b;
1232 struct font_info *font_info;
1233{
1234 int charset = CHAR_CHARSET (c);
1235 XFontStruct *font = font_info->font;
1236
1237 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1238 This may be either a program in a special encoder language or a
1239 fixed encoding. */
1240 if (font_info->font_encoder)
1241 {
1242 /* It's a program. */
1243 struct ccl_program *ccl = font_info->font_encoder;
1244
1245 if (CHARSET_DIMENSION (charset) == 1)
1246 {
1247 ccl->reg[0] = charset;
1248 ccl->reg[1] = char2b->byte2;
1249 }
1250 else
1251 {
1252 ccl->reg[0] = charset;
1253 ccl->reg[1] = char2b->byte1;
1254 ccl->reg[2] = char2b->byte2;
1255 }
1256
1257 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1258
1259 /* We assume that MSBs are appropriately set/reset by CCL
1260 program. */
1261 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1262 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1263 else
1264 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1265 }
1266 else if (font_info->encoding[charset])
1267 {
1268 /* Fixed encoding scheme. See fontset.h for the meaning of the
1269 encoding numbers. */
1270 int enc = font_info->encoding[charset];
1271
1272 if ((enc == 1 || enc == 2)
1273 && CHARSET_DIMENSION (charset) == 2)
1274 char2b->byte1 |= 0x80;
1275
1276 if (enc == 1 || enc == 3)
1277 char2b->byte2 |= 0x80;
1278 }
1279}
1280
1281
1282/* Get face and two-byte form of character C in face FACE_ID on frame
1283 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
abfb6b46
GM
1284 means we want to display multibyte text. DISPLAY_P non-zero means
1285 make sure that X resources for the face returned are allocated.
1286 Value is a pointer to a realized face that is ready for display if
1287 DISPLAY_P is non-zero. */
06a2c219
GM
1288
1289static INLINE struct face *
abfb6b46 1290x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p)
06a2c219
GM
1291 struct frame *f;
1292 int c, face_id;
1293 XChar2b *char2b;
abfb6b46 1294 int multibyte_p, display_p;
06a2c219
GM
1295{
1296 struct face *face = FACE_FROM_ID (f, face_id);
1297
1298 if (!multibyte_p)
1299 {
1300 /* Unibyte case. We don't have to encode, but we have to make
1301 sure to use a face suitable for unibyte. */
1302 char2b->byte1 = 0;
1303 char2b->byte2 = c;
ee569018
KH
1304 face_id = FACE_FOR_CHAR (f, face, c);
1305 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1306 }
1307 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1308 {
1309 /* Case of ASCII in a face known to fit ASCII. */
1310 char2b->byte1 = 0;
1311 char2b->byte2 = c;
1312 }
1313 else
1314 {
1315 int c1, c2, charset;
1316
1317 /* Split characters into bytes. If c2 is -1 afterwards, C is
1318 really a one-byte character so that byte1 is zero. */
1319 SPLIT_CHAR (c, charset, c1, c2);
1320 if (c2 > 0)
1321 char2b->byte1 = c1, char2b->byte2 = c2;
1322 else
1323 char2b->byte1 = 0, char2b->byte2 = c1;
1324
06a2c219 1325 /* Maybe encode the character in *CHAR2B. */
ee569018 1326 if (face->font != NULL)
06a2c219
GM
1327 {
1328 struct font_info *font_info
1329 = FONT_INFO_FROM_ID (f, face->font_info_id);
1330 if (font_info)
ee569018 1331 x_encode_char (c, char2b, font_info);
06a2c219
GM
1332 }
1333 }
1334
1335 /* Make sure X resources of the face are allocated. */
abfb6b46
GM
1336 if (display_p)
1337 {
1338 xassert (face != NULL);
1339 PREPARE_FACE_FOR_DISPLAY (f, face);
1340 }
06a2c219
GM
1341
1342 return face;
1343}
1344
1345
1346/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1347 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1348 a pointer to a realized face that is ready for display. */
1349
1350static INLINE struct face *
ee569018 1351x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1352 struct frame *f;
1353 struct glyph *glyph;
1354 XChar2b *char2b;
ee569018 1355 int *two_byte_p;
06a2c219
GM
1356{
1357 struct face *face;
1358
1359 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1360 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1361
ee569018
KH
1362 if (two_byte_p)
1363 *two_byte_p = 0;
1364
06a2c219
GM
1365 if (!glyph->multibyte_p)
1366 {
1367 /* Unibyte case. We don't have to encode, but we have to make
1368 sure to use a face suitable for unibyte. */
1369 char2b->byte1 = 0;
43d120d8 1370 char2b->byte2 = glyph->u.ch;
06a2c219 1371 }
43d120d8
KH
1372 else if (glyph->u.ch < 128
1373 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1374 {
1375 /* Case of ASCII in a face known to fit ASCII. */
1376 char2b->byte1 = 0;
43d120d8 1377 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1378 }
1379 else
1380 {
1381 int c1, c2, charset;
1382
1383 /* Split characters into bytes. If c2 is -1 afterwards, C is
1384 really a one-byte character so that byte1 is zero. */
43d120d8 1385 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1386 if (c2 > 0)
1387 char2b->byte1 = c1, char2b->byte2 = c2;
1388 else
1389 char2b->byte1 = 0, char2b->byte2 = c1;
1390
1391 /* Maybe encode the character in *CHAR2B. */
1392 if (charset != CHARSET_ASCII)
1393 {
1394 struct font_info *font_info
1395 = FONT_INFO_FROM_ID (f, face->font_info_id);
1396 if (font_info)
1397 {
43d120d8 1398 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1399 if (two_byte_p)
1400 *two_byte_p
1401 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1402 }
1403 }
1404 }
1405
1406 /* Make sure X resources of the face are allocated. */
1407 xassert (face != NULL);
1408 PREPARE_FACE_FOR_DISPLAY (f, face);
1409 return face;
1410}
1411
1412
1413/* Store one glyph for IT->char_to_display in IT->glyph_row.
1414 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1415
1416static INLINE void
1417x_append_glyph (it)
1418 struct it *it;
1419{
1420 struct glyph *glyph;
1421 enum glyph_row_area area = it->area;
1422
1423 xassert (it->glyph_row);
1424 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1425
1426 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1427 if (glyph < it->glyph_row->glyphs[area + 1])
1428 {
06a2c219
GM
1429 glyph->charpos = CHARPOS (it->position);
1430 glyph->object = it->object;
88d75730 1431 glyph->pixel_width = it->pixel_width;
06a2c219 1432 glyph->voffset = it->voffset;
88d75730 1433 glyph->type = CHAR_GLYPH;
06a2c219 1434 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1435 glyph->left_box_line_p = it->start_of_box_run_p;
1436 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1437 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1438 || it->phys_descent > it->descent);
88d75730 1439 glyph->padding_p = 0;
ee569018 1440 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1441 glyph->face_id = it->face_id;
1442 glyph->u.ch = it->char_to_display;
06a2c219
GM
1443 ++it->glyph_row->used[area];
1444 }
1445}
1446
b4192550
KH
1447/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1448 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1449
1450static INLINE void
1451x_append_composite_glyph (it)
1452 struct it *it;
1453{
1454 struct glyph *glyph;
1455 enum glyph_row_area area = it->area;
1456
1457 xassert (it->glyph_row);
1458
1459 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1460 if (glyph < it->glyph_row->glyphs[area + 1])
1461 {
b4192550
KH
1462 glyph->charpos = CHARPOS (it->position);
1463 glyph->object = it->object;
88d75730 1464 glyph->pixel_width = it->pixel_width;
b4192550 1465 glyph->voffset = it->voffset;
88d75730 1466 glyph->type = COMPOSITE_GLYPH;
b4192550 1467 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1468 glyph->left_box_line_p = it->start_of_box_run_p;
1469 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1470 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1471 || it->phys_descent > it->descent);
88d75730
GM
1472 glyph->padding_p = 0;
1473 glyph->glyph_not_available_p = 0;
1474 glyph->face_id = it->face_id;
1475 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1476 ++it->glyph_row->used[area];
1477 }
1478}
1479
06a2c219
GM
1480
1481/* Change IT->ascent and IT->height according to the setting of
1482 IT->voffset. */
1483
1484static INLINE void
1485take_vertical_position_into_account (it)
1486 struct it *it;
1487{
1488 if (it->voffset)
1489 {
1490 if (it->voffset < 0)
1491 /* Increase the ascent so that we can display the text higher
1492 in the line. */
1493 it->ascent += abs (it->voffset);
1494 else
1495 /* Increase the descent so that we can display the text lower
1496 in the line. */
1497 it->descent += it->voffset;
1498 }
1499}
1500
1501
1502/* Produce glyphs/get display metrics for the image IT is loaded with.
1503 See the description of struct display_iterator in dispextern.h for
1504 an overview of struct display_iterator. */
1505
1506static void
1507x_produce_image_glyph (it)
1508 struct it *it;
1509{
1510 struct image *img;
1511 struct face *face;
1512
1513 xassert (it->what == IT_IMAGE);
1514
1515 face = FACE_FROM_ID (it->f, it->face_id);
1516 img = IMAGE_FROM_ID (it->f, it->image_id);
1517 xassert (img);
1518
1519 /* Make sure X resources of the face and image are loaded. */
1520 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1521 prepare_image_for_display (it->f, img);
1522
95af8492 1523 it->ascent = it->phys_ascent = image_ascent (img, face);
22d650b8
GM
1524 it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
1525 it->pixel_width = img->width + 2 * img->hmargin;
06a2c219
GM
1526
1527 it->nglyphs = 1;
1528
1529 if (face->box != FACE_NO_BOX)
1530 {
ea2ba0d4
KH
1531 if (face->box_line_width > 0)
1532 {
1533 it->ascent += face->box_line_width;
1534 it->descent += face->box_line_width;
1535 }
06a2c219
GM
1536
1537 if (it->start_of_box_run_p)
ea2ba0d4 1538 it->pixel_width += abs (face->box_line_width);
06a2c219 1539 if (it->end_of_box_run_p)
ea2ba0d4 1540 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1541 }
1542
1543 take_vertical_position_into_account (it);
1544
1545 if (it->glyph_row)
1546 {
1547 struct glyph *glyph;
1548 enum glyph_row_area area = it->area;
1549
1550 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1551 if (glyph < it->glyph_row->glyphs[area + 1])
1552 {
06a2c219
GM
1553 glyph->charpos = CHARPOS (it->position);
1554 glyph->object = it->object;
88d75730 1555 glyph->pixel_width = it->pixel_width;
06a2c219 1556 glyph->voffset = it->voffset;
88d75730 1557 glyph->type = IMAGE_GLYPH;
06a2c219 1558 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1559 glyph->left_box_line_p = it->start_of_box_run_p;
1560 glyph->right_box_line_p = it->end_of_box_run_p;
1561 glyph->overlaps_vertically_p = 0;
1562 glyph->padding_p = 0;
1563 glyph->glyph_not_available_p = 0;
1564 glyph->face_id = it->face_id;
1565 glyph->u.img_id = img->id;
06a2c219
GM
1566 ++it->glyph_row->used[area];
1567 }
1568 }
1569}
1570
1571
1572/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1573 of the glyph, WIDTH and HEIGHT are the width and height of the
1574 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1575 ascent of the glyph (0 <= ASCENT <= 1). */
1576
1577static void
1578x_append_stretch_glyph (it, object, width, height, ascent)
1579 struct it *it;
1580 Lisp_Object object;
1581 int width, height;
1582 double ascent;
1583{
1584 struct glyph *glyph;
1585 enum glyph_row_area area = it->area;
1586
1587 xassert (ascent >= 0 && ascent <= 1);
1588
1589 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1590 if (glyph < it->glyph_row->glyphs[area + 1])
1591 {
06a2c219
GM
1592 glyph->charpos = CHARPOS (it->position);
1593 glyph->object = object;
88d75730 1594 glyph->pixel_width = width;
06a2c219 1595 glyph->voffset = it->voffset;
88d75730 1596 glyph->type = STRETCH_GLYPH;
06a2c219 1597 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1598 glyph->left_box_line_p = it->start_of_box_run_p;
1599 glyph->right_box_line_p = it->end_of_box_run_p;
1600 glyph->overlaps_vertically_p = 0;
1601 glyph->padding_p = 0;
1602 glyph->glyph_not_available_p = 0;
1603 glyph->face_id = it->face_id;
1604 glyph->u.stretch.ascent = height * ascent;
1605 glyph->u.stretch.height = height;
06a2c219
GM
1606 ++it->glyph_row->used[area];
1607 }
1608}
1609
1610
1611/* Produce a stretch glyph for iterator IT. IT->object is the value
1612 of the glyph property displayed. The value must be a list
1613 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1614 being recognized:
1615
1616 1. `:width WIDTH' specifies that the space should be WIDTH *
1617 canonical char width wide. WIDTH may be an integer or floating
1618 point number.
1619
1620 2. `:relative-width FACTOR' specifies that the width of the stretch
1621 should be computed from the width of the first character having the
1622 `glyph' property, and should be FACTOR times that width.
1623
1624 3. `:align-to HPOS' specifies that the space should be wide enough
1625 to reach HPOS, a value in canonical character units.
1626
1627 Exactly one of the above pairs must be present.
1628
1629 4. `:height HEIGHT' specifies that the height of the stretch produced
1630 should be HEIGHT, measured in canonical character units.
1631
269b7745 1632 5. `:relative-height FACTOR' specifies that the height of the
06a2c219
GM
1633 stretch should be FACTOR times the height of the characters having
1634 the glyph property.
1635
1636 Either none or exactly one of 4 or 5 must be present.
1637
1638 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1639 of the stretch should be used for the ascent of the stretch.
1640 ASCENT must be in the range 0 <= ASCENT <= 100. */
1641
1642#define NUMVAL(X) \
1643 ((INTEGERP (X) || FLOATP (X)) \
1644 ? XFLOATINT (X) \
1645 : - 1)
1646
1647
1648static void
1649x_produce_stretch_glyph (it)
1650 struct it *it;
1651{
1652 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1653#if GLYPH_DEBUG
1654 extern Lisp_Object Qspace;
1655#endif
1656 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1657 extern Lisp_Object QCrelative_width, QCrelative_height;
1658 extern Lisp_Object QCalign_to;
1659 Lisp_Object prop, plist;
1660 double width = 0, height = 0, ascent = 0;
1661 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1662 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1663
1664 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1665
1666 /* List should start with `space'. */
1667 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1668 plist = XCDR (it->object);
1669
1670 /* Compute the width of the stretch. */
1671 if (prop = Fplist_get (plist, QCwidth),
1672 NUMVAL (prop) > 0)
1673 /* Absolute width `:width WIDTH' specified and valid. */
1674 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1675 else if (prop = Fplist_get (plist, QCrelative_width),
1676 NUMVAL (prop) > 0)
1677 {
1678 /* Relative width `:relative-width FACTOR' specified and valid.
1679 Compute the width of the characters having the `glyph'
1680 property. */
1681 struct it it2;
1682 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1683
1684 it2 = *it;
1685 if (it->multibyte_p)
1686 {
1687 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1688 - IT_BYTEPOS (*it));
1689 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1690 }
1691 else
1692 it2.c = *p, it2.len = 1;
1693
1694 it2.glyph_row = NULL;
1695 it2.what = IT_CHARACTER;
1696 x_produce_glyphs (&it2);
1697 width = NUMVAL (prop) * it2.pixel_width;
1698 }
1699 else if (prop = Fplist_get (plist, QCalign_to),
1700 NUMVAL (prop) > 0)
1701 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1702 else
1703 /* Nothing specified -> width defaults to canonical char width. */
1704 width = CANON_X_UNIT (it->f);
1705
1706 /* Compute height. */
1707 if (prop = Fplist_get (plist, QCheight),
1708 NUMVAL (prop) > 0)
1709 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1710 else if (prop = Fplist_get (plist, QCrelative_height),
1711 NUMVAL (prop) > 0)
1712 height = FONT_HEIGHT (font) * NUMVAL (prop);
1713 else
1714 height = FONT_HEIGHT (font);
1715
1716 /* Compute percentage of height used for ascent. If
1717 `:ascent ASCENT' is present and valid, use that. Otherwise,
1718 derive the ascent from the font in use. */
1719 if (prop = Fplist_get (plist, QCascent),
1720 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1721 ascent = NUMVAL (prop) / 100.0;
1722 else
1723 ascent = (double) font->ascent / FONT_HEIGHT (font);
1724
1725 if (width <= 0)
1726 width = 1;
1727 if (height <= 0)
1728 height = 1;
1729
1730 if (it->glyph_row)
1731 {
1732 Lisp_Object object = it->stack[it->sp - 1].string;
1733 if (!STRINGP (object))
1734 object = it->w->buffer;
1735 x_append_stretch_glyph (it, object, width, height, ascent);
1736 }
1737
1738 it->pixel_width = width;
66ac4b0e
GM
1739 it->ascent = it->phys_ascent = height * ascent;
1740 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1741 it->nglyphs = 1;
1742
1743 if (face->box != FACE_NO_BOX)
1744 {
ea2ba0d4
KH
1745 if (face->box_line_width > 0)
1746 {
1747 it->ascent += face->box_line_width;
1748 it->descent += face->box_line_width;
1749 }
06a2c219
GM
1750
1751 if (it->start_of_box_run_p)
ea2ba0d4 1752 it->pixel_width += abs (face->box_line_width);
06a2c219 1753 if (it->end_of_box_run_p)
ea2ba0d4 1754 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1755 }
1756
1757 take_vertical_position_into_account (it);
1758}
1759
b4192550
KH
1760/* Return proper value to be used as baseline offset of font that has
1761 ASCENT and DESCENT to draw characters by the font at the vertical
1762 center of the line of frame F.
1763
1764 Here, out task is to find the value of BOFF in the following figure;
1765
1766 -------------------------+-----------+-
1767 -+-+---------+-+ | |
1768 | | | | | |
1769 | | | | F_ASCENT F_HEIGHT
1770 | | | ASCENT | |
1771 HEIGHT | | | | |
1772 | | |-|-+------+-----------|------- baseline
1773 | | | | BOFF | |
1774 | |---------|-+-+ | |
1775 | | | DESCENT | |
1776 -+-+---------+-+ F_DESCENT |
1777 -------------------------+-----------+-
1778
1779 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1780 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1781 DESCENT = FONT->descent
1782 HEIGHT = FONT_HEIGHT (FONT)
1783 F_DESCENT = (F->output_data.x->font->descent
1784 - F->output_data.x->baseline_offset)
1785 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1786*/
1787
458f45fa
KH
1788#define VCENTER_BASELINE_OFFSET(FONT, F) \
1789 ((FONT)->descent \
1790 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT)) \
1791 + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \
1792 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1793
1794/* Produce glyphs/get display metrics for the display element IT is
1795 loaded with. See the description of struct display_iterator in
1796 dispextern.h for an overview of struct display_iterator. */
1797
1798static void
1799x_produce_glyphs (it)
1800 struct it *it;
1801{
ee569018
KH
1802 it->glyph_not_available_p = 0;
1803
06a2c219
GM
1804 if (it->what == IT_CHARACTER)
1805 {
1806 XChar2b char2b;
1807 XFontStruct *font;
ee569018 1808 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1809 XCharStruct *pcm;
06a2c219 1810 int font_not_found_p;
b4192550
KH
1811 struct font_info *font_info;
1812 int boff; /* baseline offset */
a4249304
KH
1813 /* We may change it->multibyte_p upon unibyte<->multibyte
1814 conversion. So, save the current value now and restore it
1815 later.
1816
1817 Note: It seems that we don't have to record multibyte_p in
1818 struct glyph because the character code itself tells if or
1819 not the character is multibyte. Thus, in the future, we must
1820 consider eliminating the field `multibyte_p' in the struct
c347a1c3 1821 glyph. */
a4249304 1822 int saved_multibyte_p = it->multibyte_p;
06a2c219 1823
ee569018
KH
1824 /* Maybe translate single-byte characters to multibyte, or the
1825 other way. */
06a2c219 1826 it->char_to_display = it->c;
ee569018 1827 if (!ASCII_BYTE_P (it->c))
06a2c219 1828 {
ee569018
KH
1829 if (unibyte_display_via_language_environment
1830 && SINGLE_BYTE_CHAR_P (it->c)
1831 && (it->c >= 0240
1832 || !NILP (Vnonascii_translation_table)))
1833 {
1834 it->char_to_display = unibyte_char_to_multibyte (it->c);
a4249304 1835 it->multibyte_p = 1;
ee569018
KH
1836 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1837 face = FACE_FROM_ID (it->f, it->face_id);
1838 }
1839 else if (!SINGLE_BYTE_CHAR_P (it->c)
1840 && !it->multibyte_p)
1841 {
c347a1c3 1842 it->multibyte_p = 1;
ee569018
KH
1843 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1844 face = FACE_FROM_ID (it->f, it->face_id);
1845 }
06a2c219
GM
1846 }
1847
ee569018
KH
1848 /* Get font to use. Encode IT->char_to_display. */
1849 x_get_char_face_and_encoding (it->f, it->char_to_display,
1850 it->face_id, &char2b,
abfb6b46 1851 it->multibyte_p, 0);
06a2c219
GM
1852 font = face->font;
1853
1854 /* When no suitable font found, use the default font. */
1855 font_not_found_p = font == NULL;
1856 if (font_not_found_p)
b4192550
KH
1857 {
1858 font = FRAME_FONT (it->f);
1859 boff = it->f->output_data.x->baseline_offset;
1860 font_info = NULL;
1861 }
1862 else
1863 {
1864 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1865 boff = font_info->baseline_offset;
1866 if (font_info->vertical_centering)
1867 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1868 }
06a2c219
GM
1869
1870 if (it->char_to_display >= ' '
1871 && (!it->multibyte_p || it->char_to_display < 128))
1872 {
1873 /* Either unibyte or ASCII. */
1874 int stretched_p;
1875
1876 it->nglyphs = 1;
06a2c219
GM
1877
1878 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1879 it->ascent = font->ascent + boff;
1880 it->descent = font->descent - boff;
474848ac
GM
1881
1882 if (pcm)
1883 {
1884 it->phys_ascent = pcm->ascent + boff;
1885 it->phys_descent = pcm->descent - boff;
1886 it->pixel_width = pcm->width;
1887 }
1888 else
1889 {
1890 it->glyph_not_available_p = 1;
1891 it->phys_ascent = font->ascent + boff;
1892 it->phys_descent = font->descent - boff;
1893 it->pixel_width = FONT_WIDTH (font);
1894 }
06a2c219
GM
1895
1896 /* If this is a space inside a region of text with
1897 `space-width' property, change its width. */
1898 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1899 if (stretched_p)
1900 it->pixel_width *= XFLOATINT (it->space_width);
1901
1902 /* If face has a box, add the box thickness to the character
1903 height. If character has a box line to the left and/or
1904 right, add the box line width to the character's width. */
1905 if (face->box != FACE_NO_BOX)
1906 {
1907 int thick = face->box_line_width;
1908
ea2ba0d4
KH
1909 if (thick > 0)
1910 {
1911 it->ascent += thick;
1912 it->descent += thick;
1913 }
1914 else
1915 thick = -thick;
1916
06a2c219
GM
1917 if (it->start_of_box_run_p)
1918 it->pixel_width += thick;
1919 if (it->end_of_box_run_p)
1920 it->pixel_width += thick;
1921 }
1922
1923 /* If face has an overline, add the height of the overline
1924 (1 pixel) and a 1 pixel margin to the character height. */
1925 if (face->overline_p)
1926 it->ascent += 2;
1927
1928 take_vertical_position_into_account (it);
1929
1930 /* If we have to actually produce glyphs, do it. */
1931 if (it->glyph_row)
1932 {
1933 if (stretched_p)
1934 {
1935 /* Translate a space with a `space-width' property
1936 into a stretch glyph. */
1937 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1938 x_append_stretch_glyph (it, it->object, it->pixel_width,
1939 it->ascent + it->descent, ascent);
1940 }
1941 else
1942 x_append_glyph (it);
1943
1944 /* If characters with lbearing or rbearing are displayed
1945 in this line, record that fact in a flag of the
1946 glyph row. This is used to optimize X output code. */
1c7e22fd 1947 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1948 it->glyph_row->contains_overlapping_glyphs_p = 1;
1949 }
1950 }
1951 else if (it->char_to_display == '\n')
1952 {
1953 /* A newline has no width but we need the height of the line. */
1954 it->pixel_width = 0;
1955 it->nglyphs = 0;
b4192550
KH
1956 it->ascent = it->phys_ascent = font->ascent + boff;
1957 it->descent = it->phys_descent = font->descent - boff;
06a2c219 1958
ea2ba0d4
KH
1959 if (face->box != FACE_NO_BOX
1960 && face->box_line_width > 0)
06a2c219 1961 {
ea2ba0d4
KH
1962 it->ascent += face->box_line_width;
1963 it->descent += face->box_line_width;
06a2c219
GM
1964 }
1965 }
1966 else if (it->char_to_display == '\t')
1967 {
1968 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1969 int x = it->current_x + it->continuation_lines_width;
06a2c219 1970 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
2a32b5ea
GM
1971
1972 /* If the distance from the current position to the next tab
1973 stop is less than a canonical character width, use the
1974 tab stop after that. */
1975 if (next_tab_x - x < CANON_X_UNIT (it->f))
1976 next_tab_x += tab_width;
06a2c219
GM
1977
1978 it->pixel_width = next_tab_x - x;
1979 it->nglyphs = 1;
b4192550
KH
1980 it->ascent = it->phys_ascent = font->ascent + boff;
1981 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1982
1983 if (it->glyph_row)
1984 {
1985 double ascent = (double) it->ascent / (it->ascent + it->descent);
1986 x_append_stretch_glyph (it, it->object, it->pixel_width,
1987 it->ascent + it->descent, ascent);
1988 }
1989 }
1990 else
1991 {
1992 /* A multi-byte character. Assume that the display width of the
1993 character is the width of the character multiplied by the
b4192550 1994 width of the font. */
06a2c219 1995
b4192550
KH
1996 /* If we found a font, this font should give us the right
1997 metrics. If we didn't find a font, use the frame's
1998 default font and calculate the width of the character
1999 from the charset width; this is what old redisplay code
2000 did. */
2001 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
2002 if (font_not_found_p || !pcm)
2003 {
2004 int charset = CHAR_CHARSET (it->char_to_display);
2005
2006 it->glyph_not_available_p = 1;
2007 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
2008 * CHARSET_WIDTH (charset));
2009 it->phys_ascent = font->ascent + boff;
2010 it->phys_descent = font->descent - boff;
2011 }
2012 else
2013 {
2014 it->pixel_width = pcm->width;
2015 it->phys_ascent = pcm->ascent + boff;
2016 it->phys_descent = pcm->descent - boff;
2017 if (it->glyph_row
2018 && (pcm->lbearing < 0
2019 || pcm->rbearing > pcm->width))
2020 it->glyph_row->contains_overlapping_glyphs_p = 1;
2021 }
b4192550
KH
2022 it->nglyphs = 1;
2023 it->ascent = font->ascent + boff;
2024 it->descent = font->descent - boff;
06a2c219
GM
2025 if (face->box != FACE_NO_BOX)
2026 {
2027 int thick = face->box_line_width;
ea2ba0d4
KH
2028
2029 if (thick > 0)
2030 {
2031 it->ascent += thick;
2032 it->descent += thick;
2033 }
2034 else
2035 thick = - thick;
06a2c219
GM
2036
2037 if (it->start_of_box_run_p)
2038 it->pixel_width += thick;
2039 if (it->end_of_box_run_p)
2040 it->pixel_width += thick;
2041 }
2042
2043 /* If face has an overline, add the height of the overline
2044 (1 pixel) and a 1 pixel margin to the character height. */
2045 if (face->overline_p)
2046 it->ascent += 2;
2047
2048 take_vertical_position_into_account (it);
2049
2050 if (it->glyph_row)
2051 x_append_glyph (it);
2052 }
a4249304 2053 it->multibyte_p = saved_multibyte_p;
06a2c219 2054 }
b4192550
KH
2055 else if (it->what == IT_COMPOSITION)
2056 {
2057 /* Note: A composition is represented as one glyph in the
2058 glyph matrix. There are no padding glyphs. */
2059 XChar2b char2b;
2060 XFontStruct *font;
ee569018 2061 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2062 XCharStruct *pcm;
2063 int font_not_found_p;
2064 struct font_info *font_info;
2065 int boff; /* baseline offset */
2066 struct composition *cmp = composition_table[it->cmp_id];
2067
2068 /* Maybe translate single-byte characters to multibyte. */
2069 it->char_to_display = it->c;
2070 if (unibyte_display_via_language_environment
2071 && SINGLE_BYTE_CHAR_P (it->c)
2072 && (it->c >= 0240
2073 || (it->c >= 0200
2074 && !NILP (Vnonascii_translation_table))))
2075 {
2076 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2077 }
2078
2079 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2080 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2081 face = FACE_FROM_ID (it->f, it->face_id);
2082 x_get_char_face_and_encoding (it->f, it->char_to_display,
abfb6b46 2083 it->face_id, &char2b, it->multibyte_p, 0);
b4192550
KH
2084 font = face->font;
2085
2086 /* When no suitable font found, use the default font. */
2087 font_not_found_p = font == NULL;
2088 if (font_not_found_p)
2089 {
2090 font = FRAME_FONT (it->f);
2091 boff = it->f->output_data.x->baseline_offset;
2092 font_info = NULL;
2093 }
2094 else
2095 {
2096 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2097 boff = font_info->baseline_offset;
2098 if (font_info->vertical_centering)
2099 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2100 }
2101
2102 /* There are no padding glyphs, so there is only one glyph to
2103 produce for the composition. Important is that pixel_width,
2104 ascent and descent are the values of what is drawn by
2105 draw_glyphs (i.e. the values of the overall glyphs composed). */
2106 it->nglyphs = 1;
2107
2108 /* If we have not yet calculated pixel size data of glyphs of
2109 the composition for the current face font, calculate them
2110 now. Theoretically, we have to check all fonts for the
2111 glyphs, but that requires much time and memory space. So,
2112 here we check only the font of the first glyph. This leads
2113 to incorrect display very rarely, and C-l (recenter) can
2114 correct the display anyway. */
2115 if (cmp->font != (void *) font)
2116 {
2117 /* Ascent and descent of the font of the first character of
2118 this composition (adjusted by baseline offset). Ascent
2119 and descent of overall glyphs should not be less than
2120 them respectively. */
2121 int font_ascent = font->ascent + boff;
2122 int font_descent = font->descent - boff;
2123 /* Bounding box of the overall glyphs. */
2124 int leftmost, rightmost, lowest, highest;
329bed06 2125 int i, width, ascent, descent;
b4192550
KH
2126
2127 cmp->font = (void *) font;
2128
2129 /* Initialize the bounding box. */
1bdeec2e
KH
2130 if (font_info
2131 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2132 {
2133 width = pcm->width;
2134 ascent = pcm->ascent;
2135 descent = pcm->descent;
2136 }
2137 else
2138 {
2139 width = FONT_WIDTH (font);
2140 ascent = font->ascent;
2141 descent = font->descent;
2142 }
2143
2144 rightmost = width;
2145 lowest = - descent + boff;
2146 highest = ascent + boff;
b4192550 2147 leftmost = 0;
329bed06 2148
b4192550
KH
2149 if (font_info
2150 && font_info->default_ascent
2151 && CHAR_TABLE_P (Vuse_default_ascent)
2152 && !NILP (Faref (Vuse_default_ascent,
2153 make_number (it->char_to_display))))
2154 highest = font_info->default_ascent + boff;
2155
2156 /* Draw the first glyph at the normal position. It may be
2157 shifted to right later if some other glyphs are drawn at
2158 the left. */
2159 cmp->offsets[0] = 0;
2160 cmp->offsets[1] = boff;
2161
2162 /* Set cmp->offsets for the remaining glyphs. */
2163 for (i = 1; i < cmp->glyph_len; i++)
2164 {
2165 int left, right, btm, top;
2166 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2167 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2168
2169 face = FACE_FROM_ID (it->f, face_id);
2170 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
abfb6b46 2171 it->multibyte_p, 0);
b4192550
KH
2172 font = face->font;
2173 if (font == NULL)
2174 {
2175 font = FRAME_FONT (it->f);
2176 boff = it->f->output_data.x->baseline_offset;
2177 font_info = NULL;
2178 }
2179 else
2180 {
2181 font_info
2182 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2183 boff = font_info->baseline_offset;
2184 if (font_info->vertical_centering)
2185 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2186 }
2187
1bdeec2e
KH
2188 if (font_info
2189 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2190 {
2191 width = pcm->width;
2192 ascent = pcm->ascent;
2193 descent = pcm->descent;
2194 }
2195 else
2196 {
2197 width = FONT_WIDTH (font);
1bdeec2e
KH
2198 ascent = 1;
2199 descent = 0;
329bed06 2200 }
b4192550
KH
2201
2202 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2203 {
2204 /* Relative composition with or without
2205 alternate chars. */
329bed06
GM
2206 left = (leftmost + rightmost - width) / 2;
2207 btm = - descent + boff;
b4192550
KH
2208 if (font_info && font_info->relative_compose
2209 && (! CHAR_TABLE_P (Vignore_relative_composition)
2210 || NILP (Faref (Vignore_relative_composition,
2211 make_number (ch)))))
2212 {
2213
329bed06 2214 if (- descent >= font_info->relative_compose)
b4192550
KH
2215 /* One extra pixel between two glyphs. */
2216 btm = highest + 1;
329bed06 2217 else if (ascent <= 0)
b4192550 2218 /* One extra pixel between two glyphs. */
329bed06 2219 btm = lowest - 1 - ascent - descent;
b4192550
KH
2220 }
2221 }
2222 else
2223 {
2224 /* A composition rule is specified by an integer
2225 value that encodes global and new reference
2226 points (GREF and NREF). GREF and NREF are
2227 specified by numbers as below:
2228
2229 0---1---2 -- ascent
2230 | |
2231 | |
2232 | |
2233 9--10--11 -- center
2234 | |
2235 ---3---4---5--- baseline
2236 | |
2237 6---7---8 -- descent
2238 */
2239 int rule = COMPOSITION_RULE (cmp, i);
2240 int gref, nref, grefx, grefy, nrefx, nrefy;
2241
2242 COMPOSITION_DECODE_RULE (rule, gref, nref);
2243 grefx = gref % 3, nrefx = nref % 3;
2244 grefy = gref / 3, nrefy = nref / 3;
2245
2246 left = (leftmost
2247 + grefx * (rightmost - leftmost) / 2
329bed06 2248 - nrefx * width / 2);
b4192550
KH
2249 btm = ((grefy == 0 ? highest
2250 : grefy == 1 ? 0
2251 : grefy == 2 ? lowest
2252 : (highest + lowest) / 2)
329bed06
GM
2253 - (nrefy == 0 ? ascent + descent
2254 : nrefy == 1 ? descent - boff
b4192550 2255 : nrefy == 2 ? 0
329bed06 2256 : (ascent + descent) / 2));
b4192550
KH
2257 }
2258
2259 cmp->offsets[i * 2] = left;
329bed06 2260 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2261
2262 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2263 right = left + width;
2264 top = btm + descent + ascent;
b4192550
KH
2265 if (left < leftmost)
2266 leftmost = left;
2267 if (right > rightmost)
2268 rightmost = right;
2269 if (top > highest)
2270 highest = top;
2271 if (btm < lowest)
2272 lowest = btm;
2273 }
2274
2275 /* If there are glyphs whose x-offsets are negative,
2276 shift all glyphs to the right and make all x-offsets
2277 non-negative. */
2278 if (leftmost < 0)
2279 {
2280 for (i = 0; i < cmp->glyph_len; i++)
2281 cmp->offsets[i * 2] -= leftmost;
2282 rightmost -= leftmost;
2283 }
2284
2285 cmp->pixel_width = rightmost;
2286 cmp->ascent = highest;
2287 cmp->descent = - lowest;
2288 if (cmp->ascent < font_ascent)
2289 cmp->ascent = font_ascent;
2290 if (cmp->descent < font_descent)
2291 cmp->descent = font_descent;
2292 }
2293
2294 it->pixel_width = cmp->pixel_width;
2295 it->ascent = it->phys_ascent = cmp->ascent;
2296 it->descent = it->phys_descent = cmp->descent;
2297
2298 if (face->box != FACE_NO_BOX)
2299 {
2300 int thick = face->box_line_width;
ea2ba0d4
KH
2301
2302 if (thick > 0)
2303 {
2304 it->ascent += thick;
2305 it->descent += thick;
2306 }
2307 else
2308 thick = - thick;
b4192550
KH
2309
2310 if (it->start_of_box_run_p)
2311 it->pixel_width += thick;
2312 if (it->end_of_box_run_p)
2313 it->pixel_width += thick;
2314 }
2315
2316 /* If face has an overline, add the height of the overline
2317 (1 pixel) and a 1 pixel margin to the character height. */
2318 if (face->overline_p)
2319 it->ascent += 2;
2320
2321 take_vertical_position_into_account (it);
2322
2323 if (it->glyph_row)
2324 x_append_composite_glyph (it);
2325 }
06a2c219
GM
2326 else if (it->what == IT_IMAGE)
2327 x_produce_image_glyph (it);
2328 else if (it->what == IT_STRETCH)
2329 x_produce_stretch_glyph (it);
2330
3017fdd1
GM
2331 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2332 because this isn't true for images with `:ascent 100'. */
2333 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2334 if (it->area == TEXT_AREA)
2335 it->current_x += it->pixel_width;
66ac4b0e 2336
d365f5bb
GM
2337 it->descent += it->extra_line_spacing;
2338
06a2c219
GM
2339 it->max_ascent = max (it->max_ascent, it->ascent);
2340 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2341 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2342 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2343}
2344
2345
2346/* Estimate the pixel height of the mode or top line on frame F.
2347 FACE_ID specifies what line's height to estimate. */
2348
2349int
2350x_estimate_mode_line_height (f, face_id)
2351 struct frame *f;
2352 enum face_id face_id;
2353{
43281ee3 2354 int height = FONT_HEIGHT (FRAME_FONT (f));
06a2c219
GM
2355
2356 /* This function is called so early when Emacs starts that the face
2357 cache and mode line face are not yet initialized. */
2358 if (FRAME_FACE_CACHE (f))
2359 {
2360 struct face *face = FACE_FROM_ID (f, face_id);
2361 if (face)
43281ee3
GM
2362 {
2363 if (face->font)
2364 height = FONT_HEIGHT (face->font);
ea2ba0d4
KH
2365 if (face->box_line_width > 0)
2366 height += 2 * face->box_line_width;
43281ee3 2367 }
06a2c219
GM
2368 }
2369
2370 return height;
2371}
2372
2373\f
2374/***********************************************************************
2375 Glyph display
2376 ***********************************************************************/
2377
2378/* A sequence of glyphs to be drawn in the same face.
2379
2380 This data structure is not really completely X specific, so it
2381 could possibly, at least partially, be useful for other systems. It
2382 is currently not part of the external redisplay interface because
2383 it's not clear what other systems will need. */
2384
2385struct glyph_string
2386{
2387 /* X-origin of the string. */
2388 int x;
2389
2390 /* Y-origin and y-position of the base line of this string. */
2391 int y, ybase;
2392
2393 /* The width of the string, not including a face extension. */
2394 int width;
2395
2396 /* The width of the string, including a face extension. */
2397 int background_width;
2398
2399 /* The height of this string. This is the height of the line this
2400 string is drawn in, and can be different from the height of the
2401 font the string is drawn in. */
2402 int height;
2403
2404 /* Number of pixels this string overwrites in front of its x-origin.
2405 This number is zero if the string has an lbearing >= 0; it is
2406 -lbearing, if the string has an lbearing < 0. */
2407 int left_overhang;
2408
2409 /* Number of pixels this string overwrites past its right-most
2410 nominal x-position, i.e. x + width. Zero if the string's
2411 rbearing is <= its nominal width, rbearing - width otherwise. */
2412 int right_overhang;
2413
2414 /* The frame on which the glyph string is drawn. */
2415 struct frame *f;
2416
2417 /* The window on which the glyph string is drawn. */
2418 struct window *w;
2419
2420 /* X display and window for convenience. */
2421 Display *display;
2422 Window window;
2423
2424 /* The glyph row for which this string was built. It determines the
2425 y-origin and height of the string. */
2426 struct glyph_row *row;
2427
2428 /* The area within row. */
2429 enum glyph_row_area area;
2430
2431 /* Characters to be drawn, and number of characters. */
2432 XChar2b *char2b;
2433 int nchars;
2434
06a2c219
GM
2435 /* A face-override for drawing cursors, mouse face and similar. */
2436 enum draw_glyphs_face hl;
2437
2438 /* Face in which this string is to be drawn. */
2439 struct face *face;
2440
2441 /* Font in which this string is to be drawn. */
2442 XFontStruct *font;
2443
2444 /* Font info for this string. */
2445 struct font_info *font_info;
2446
b4192550
KH
2447 /* Non-null means this string describes (part of) a composition.
2448 All characters from char2b are drawn composed. */
2449 struct composition *cmp;
06a2c219
GM
2450
2451 /* Index of this glyph string's first character in the glyph
b4192550
KH
2452 definition of CMP. If this is zero, this glyph string describes
2453 the first character of a composition. */
06a2c219
GM
2454 int gidx;
2455
2456 /* 1 means this glyph strings face has to be drawn to the right end
2457 of the window's drawing area. */
2458 unsigned extends_to_end_of_line_p : 1;
2459
2460 /* 1 means the background of this string has been drawn. */
2461 unsigned background_filled_p : 1;
2462
2463 /* 1 means glyph string must be drawn with 16-bit functions. */
2464 unsigned two_byte_p : 1;
2465
2466 /* 1 means that the original font determined for drawing this glyph
2467 string could not be loaded. The member `font' has been set to
2468 the frame's default font in this case. */
2469 unsigned font_not_found_p : 1;
2470
2471 /* 1 means that the face in which this glyph string is drawn has a
2472 stipple pattern. */
2473 unsigned stippled_p : 1;
2474
66ac4b0e
GM
2475 /* 1 means only the foreground of this glyph string must be drawn,
2476 and we should use the physical height of the line this glyph
2477 string appears in as clip rect. */
2478 unsigned for_overlaps_p : 1;
2479
06a2c219
GM
2480 /* The GC to use for drawing this glyph string. */
2481 GC gc;
2482
2483 /* A pointer to the first glyph in the string. This glyph
2484 corresponds to char2b[0]. Needed to draw rectangles if
2485 font_not_found_p is 1. */
2486 struct glyph *first_glyph;
2487
2488 /* Image, if any. */
2489 struct image *img;
2490
2491 struct glyph_string *next, *prev;
2492};
2493
2494
61869b99 2495#if GLYPH_DEBUG
06a2c219
GM
2496
2497static void
2498x_dump_glyph_string (s)
2499 struct glyph_string *s;
2500{
2501 fprintf (stderr, "glyph string\n");
2502 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2503 s->x, s->y, s->width, s->height);
2504 fprintf (stderr, " ybase = %d\n", s->ybase);
2505 fprintf (stderr, " hl = %d\n", s->hl);
2506 fprintf (stderr, " left overhang = %d, right = %d\n",
2507 s->left_overhang, s->right_overhang);
2508 fprintf (stderr, " nchars = %d\n", s->nchars);
2509 fprintf (stderr, " extends to end of line = %d\n",
2510 s->extends_to_end_of_line_p);
2511 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2512 fprintf (stderr, " bg width = %d\n", s->background_width);
2513}
2514
2515#endif /* GLYPH_DEBUG */
2516
2517
2518
2519static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2520 struct glyph_string **,
2521 struct glyph_string *,
2522 struct glyph_string *));
2523static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2524 struct glyph_string **,
2525 struct glyph_string *,
2526 struct glyph_string *));
2527static void x_append_glyph_string P_ ((struct glyph_string **,
2528 struct glyph_string **,
2529 struct glyph_string *));
2530static int x_left_overwritten P_ ((struct glyph_string *));
2531static int x_left_overwriting P_ ((struct glyph_string *));
2532static int x_right_overwritten P_ ((struct glyph_string *));
2533static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2534static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2535 int));
06a2c219
GM
2536static void x_init_glyph_string P_ ((struct glyph_string *,
2537 XChar2b *, struct window *,
2538 struct glyph_row *,
2539 enum glyph_row_area, int,
2540 enum draw_glyphs_face));
2541static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2542 enum glyph_row_area, int, int,
f0a48a01 2543 enum draw_glyphs_face, int));
06a2c219
GM
2544static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2545static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2546static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2547 int));
2548static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2549static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2550static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2551static void x_draw_glyph_string P_ ((struct glyph_string *));
2552static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2553static void x_set_cursor_gc P_ ((struct glyph_string *));
2554static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2555static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2556static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2557 int *, int *));
2558static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2559static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2560 unsigned long *, double, int));
06a2c219 2561static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2562 double, int, unsigned long));
06a2c219
GM
2563static void x_setup_relief_colors P_ ((struct glyph_string *));
2564static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2565static void x_draw_image_relief P_ ((struct glyph_string *));
2566static void x_draw_image_foreground P_ ((struct glyph_string *));
2567static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2568static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2569static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2570 int, int, int));
2571static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2572 int, int, int, int, XRectangle *));
2573static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2574 int, int, int, XRectangle *));
66ac4b0e
GM
2575static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2576 enum glyph_row_area));
209f68d9
GM
2577static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2578 struct glyph_row *,
2579 enum glyph_row_area, int, int));
06a2c219 2580
163dcff3
GM
2581#if GLYPH_DEBUG
2582static void x_check_font P_ ((struct frame *, XFontStruct *));
2583#endif
2584
06a2c219 2585
06a2c219
GM
2586/* Append the list of glyph strings with head H and tail T to the list
2587 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2588
2589static INLINE void
2590x_append_glyph_string_lists (head, tail, h, t)
2591 struct glyph_string **head, **tail;
2592 struct glyph_string *h, *t;
2593{
2594 if (h)
2595 {
2596 if (*head)
2597 (*tail)->next = h;
2598 else
2599 *head = h;
2600 h->prev = *tail;
2601 *tail = t;
2602 }
2603}
2604
2605
2606/* Prepend the list of glyph strings with head H and tail T to the
2607 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2608 result. */
2609
2610static INLINE void
2611x_prepend_glyph_string_lists (head, tail, h, t)
2612 struct glyph_string **head, **tail;
2613 struct glyph_string *h, *t;
2614{
2615 if (h)
2616 {
2617 if (*head)
2618 (*head)->prev = t;
2619 else
2620 *tail = t;
2621 t->next = *head;
2622 *head = h;
2623 }
2624}
2625
2626
2627/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2628 Set *HEAD and *TAIL to the resulting list. */
2629
2630static INLINE void
2631x_append_glyph_string (head, tail, s)
2632 struct glyph_string **head, **tail;
2633 struct glyph_string *s;
2634{
2635 s->next = s->prev = NULL;
2636 x_append_glyph_string_lists (head, tail, s, s);
2637}
2638
2639
2640/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2641 face. */
2642
2643static void
2644x_set_cursor_gc (s)
2645 struct glyph_string *s;
2646{
2647 if (s->font == FRAME_FONT (s->f)
2648 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2649 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2650 && !s->cmp)
06a2c219
GM
2651 s->gc = s->f->output_data.x->cursor_gc;
2652 else
2653 {
2654 /* Cursor on non-default face: must merge. */
2655 XGCValues xgcv;
2656 unsigned long mask;
2657
2658 xgcv.background = s->f->output_data.x->cursor_pixel;
2659 xgcv.foreground = s->face->background;
2660
2661 /* If the glyph would be invisible, try a different foreground. */
2662 if (xgcv.foreground == xgcv.background)
2663 xgcv.foreground = s->face->foreground;
2664 if (xgcv.foreground == xgcv.background)
2665 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2666 if (xgcv.foreground == xgcv.background)
2667 xgcv.foreground = s->face->foreground;
2668
2669 /* Make sure the cursor is distinct from text in this face. */
2670 if (xgcv.background == s->face->background
2671 && xgcv.foreground == s->face->foreground)
2672 {
2673 xgcv.background = s->face->foreground;
2674 xgcv.foreground = s->face->background;
2675 }
2676
2677 IF_DEBUG (x_check_font (s->f, s->font));
2678 xgcv.font = s->font->fid;
2679 xgcv.graphics_exposures = False;
2680 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2681
2682 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2683 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2684 mask, &xgcv);
2685 else
2686 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2687 = XCreateGC (s->display, s->window, mask, &xgcv);
2688
2689 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2690 }
2691}
2692
2693
2694/* Set up S->gc of glyph string S for drawing text in mouse face. */
2695
2696static void
2697x_set_mouse_face_gc (s)
2698 struct glyph_string *s;
2699{
2700 int face_id;
ee569018 2701 struct face *face;
06a2c219 2702
e4ded23c 2703 /* What face has to be used last for the mouse face? */
06a2c219 2704 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2705 face = FACE_FROM_ID (s->f, face_id);
e4ded23c
GM
2706 if (face == NULL)
2707 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2708
033e3e18
GM
2709 if (s->first_glyph->type == CHAR_GLYPH)
2710 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2711 else
2712 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2713 s->face = FACE_FROM_ID (s->f, face_id);
2714 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2715
2716 /* If font in this face is same as S->font, use it. */
2717 if (s->font == s->face->font)
2718 s->gc = s->face->gc;
2719 else
2720 {
2721 /* Otherwise construct scratch_cursor_gc with values from FACE
2722 but font FONT. */
2723 XGCValues xgcv;
2724 unsigned long mask;
2725
2726 xgcv.background = s->face->background;
2727 xgcv.foreground = s->face->foreground;
2728 IF_DEBUG (x_check_font (s->f, s->font));
2729 xgcv.font = s->font->fid;
2730 xgcv.graphics_exposures = False;
2731 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2732
2733 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2734 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2735 mask, &xgcv);
2736 else
2737 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2738 = XCreateGC (s->display, s->window, mask, &xgcv);
2739
2740 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2741 }
2742
2743 xassert (s->gc != 0);
2744}
2745
2746
2747/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2748 Faces to use in the mode line have already been computed when the
2749 matrix was built, so there isn't much to do, here. */
2750
2751static INLINE void
2752x_set_mode_line_face_gc (s)
2753 struct glyph_string *s;
2754{
2755 s->gc = s->face->gc;
06a2c219
GM
2756}
2757
2758
2759/* Set S->gc of glyph string S for drawing that glyph string. Set
2760 S->stippled_p to a non-zero value if the face of S has a stipple
2761 pattern. */
2762
2763static INLINE void
2764x_set_glyph_string_gc (s)
2765 struct glyph_string *s;
2766{
209f68d9
GM
2767 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2768
06a2c219
GM
2769 if (s->hl == DRAW_NORMAL_TEXT)
2770 {
2771 s->gc = s->face->gc;
2772 s->stippled_p = s->face->stipple != 0;
2773 }
2774 else if (s->hl == DRAW_INVERSE_VIDEO)
2775 {
2776 x_set_mode_line_face_gc (s);
2777 s->stippled_p = s->face->stipple != 0;
2778 }
2779 else if (s->hl == DRAW_CURSOR)
2780 {
2781 x_set_cursor_gc (s);
2782 s->stippled_p = 0;
2783 }
2784 else if (s->hl == DRAW_MOUSE_FACE)
2785 {
2786 x_set_mouse_face_gc (s);
2787 s->stippled_p = s->face->stipple != 0;
2788 }
2789 else if (s->hl == DRAW_IMAGE_RAISED
2790 || s->hl == DRAW_IMAGE_SUNKEN)
2791 {
2792 s->gc = s->face->gc;
2793 s->stippled_p = s->face->stipple != 0;
2794 }
2795 else
2796 {
2797 s->gc = s->face->gc;
2798 s->stippled_p = s->face->stipple != 0;
2799 }
2800
2801 /* GC must have been set. */
2802 xassert (s->gc != 0);
2803}
2804
2805
2806/* Return in *R the clipping rectangle for glyph string S. */
2807
2808static void
2809x_get_glyph_string_clip_rect (s, r)
2810 struct glyph_string *s;
2811 XRectangle *r;
2812{
2813 if (s->row->full_width_p)
2814 {
2815 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2816 int canon_x = CANON_X_UNIT (s->f);
2817
2818 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2819 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2820
2821 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2822 {
1da3fd71 2823 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2824 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2825 r->x -= width;
2826 }
2827
b9432a85 2828 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2829
06a2c219
GM
2830 /* Unless displaying a mode or menu bar line, which are always
2831 fully visible, clip to the visible part of the row. */
2832 if (s->w->pseudo_window_p)
2833 r->height = s->row->visible_height;
2834 else
2835 r->height = s->height;
2836 }
2837 else
2838 {
2839 /* This is a text line that may be partially visible. */
2840 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2841 r->width = window_box_width (s->w, s->area);
2842 r->height = s->row->visible_height;
2843 }
2844
66ac4b0e
GM
2845 /* If S draws overlapping rows, it's sufficient to use the top and
2846 bottom of the window for clipping because this glyph string
2847 intentionally draws over other lines. */
2848 if (s->for_overlaps_p)
2849 {
045dee35 2850 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2851 r->height = window_text_bottom_y (s->w) - r->y;
2852 }
98b8a90f
GM
2853 else
2854 {
2855 /* Don't use S->y for clipping because it doesn't take partially
2856 visible lines into account. For example, it can be negative for
2857 partially visible lines at the top of a window. */
2858 if (!s->row->full_width_p
2859 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
2860 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
2861 else
2862 r->y = max (0, s->row->y);
2863
2864 /* If drawing a tool-bar window, draw it over the internal border
2865 at the top of the window. */
2866 if (s->w == XWINDOW (s->f->tool_bar_window))
2867 r->y -= s->f->output_data.x->internal_border_width;
2868 }
2869
66ac4b0e 2870 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2871}
2872
2873
2874/* Set clipping for output of glyph string S. S may be part of a mode
2875 line or menu if we don't have X toolkit support. */
2876
2877static INLINE void
2878x_set_glyph_string_clipping (s)
2879 struct glyph_string *s;
2880{
2881 XRectangle r;
2882 x_get_glyph_string_clip_rect (s, &r);
2883 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2884}
2885
2886
2887/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2888 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2889
2890static INLINE void
2891x_compute_glyph_string_overhangs (s)
2892 struct glyph_string *s;
2893{
b4192550 2894 if (s->cmp == NULL
06a2c219
GM
2895 && s->first_glyph->type == CHAR_GLYPH)
2896 {
2897 XCharStruct cs;
2898 int direction, font_ascent, font_descent;
2899 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2900 &font_ascent, &font_descent, &cs);
2901 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2902 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2903 }
2904}
2905
2906
2907/* Compute overhangs and x-positions for glyph string S and its
2908 predecessors, or successors. X is the starting x-position for S.
2909 BACKWARD_P non-zero means process predecessors. */
2910
2911static void
2912x_compute_overhangs_and_x (s, x, backward_p)
2913 struct glyph_string *s;
2914 int x;
2915 int backward_p;
2916{
2917 if (backward_p)
2918 {
2919 while (s)
2920 {
2921 x_compute_glyph_string_overhangs (s);
2922 x -= s->width;
2923 s->x = x;
2924 s = s->prev;
2925 }
2926 }
2927 else
2928 {
2929 while (s)
2930 {
2931 x_compute_glyph_string_overhangs (s);
2932 s->x = x;
2933 x += s->width;
2934 s = s->next;
2935 }
2936 }
2937}
2938
2939
2940/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2941 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2942 assumed to be zero. */
06a2c219
GM
2943
2944static void
2945x_get_glyph_overhangs (glyph, f, left, right)
2946 struct glyph *glyph;
2947 struct frame *f;
2948 int *left, *right;
2949{
06a2c219
GM
2950 *left = *right = 0;
2951
b4192550 2952 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2953 {
2954 XFontStruct *font;
2955 struct face *face;
2956 struct font_info *font_info;
2957 XChar2b char2b;
ee569018
KH
2958 XCharStruct *pcm;
2959
2960 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2961 font = face->font;
2962 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2963 if (font
2964 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2965 {
06a2c219
GM
2966 if (pcm->rbearing > pcm->width)
2967 *right = pcm->rbearing - pcm->width;
2968 if (pcm->lbearing < 0)
2969 *left = -pcm->lbearing;
2970 }
2971 }
2972}
2973
2974
2975/* Return the index of the first glyph preceding glyph string S that
2976 is overwritten by S because of S's left overhang. Value is -1
2977 if no glyphs are overwritten. */
2978
2979static int
2980x_left_overwritten (s)
2981 struct glyph_string *s;
2982{
2983 int k;
2984
2985 if (s->left_overhang)
2986 {
2987 int x = 0, i;
2988 struct glyph *glyphs = s->row->glyphs[s->area];
2989 int first = s->first_glyph - glyphs;
2990
2991 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2992 x -= glyphs[i].pixel_width;
2993
2994 k = i + 1;
2995 }
2996 else
2997 k = -1;
2998
2999 return k;
3000}
3001
3002
3003/* Return the index of the first glyph preceding glyph string S that
3004 is overwriting S because of its right overhang. Value is -1 if no
3005 glyph in front of S overwrites S. */
3006
3007static int
3008x_left_overwriting (s)
3009 struct glyph_string *s;
3010{
3011 int i, k, x;
3012 struct glyph *glyphs = s->row->glyphs[s->area];
3013 int first = s->first_glyph - glyphs;
3014
3015 k = -1;
3016 x = 0;
3017 for (i = first - 1; i >= 0; --i)
3018 {
3019 int left, right;
3020 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3021 if (x + right > 0)
3022 k = i;
3023 x -= glyphs[i].pixel_width;
3024 }
3025
3026 return k;
3027}
3028
3029
3030/* Return the index of the last glyph following glyph string S that is
3031 not overwritten by S because of S's right overhang. Value is -1 if
3032 no such glyph is found. */
3033
3034static int
3035x_right_overwritten (s)
3036 struct glyph_string *s;
3037{
3038 int k = -1;
3039
3040 if (s->right_overhang)
3041 {
3042 int x = 0, i;
3043 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3044 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3045 int end = s->row->used[s->area];
3046
3047 for (i = first; i < end && s->right_overhang > x; ++i)
3048 x += glyphs[i].pixel_width;
3049
3050 k = i;
3051 }
3052
3053 return k;
3054}
3055
3056
3057/* Return the index of the last glyph following glyph string S that
3058 overwrites S because of its left overhang. Value is negative
3059 if no such glyph is found. */
3060
3061static int
3062x_right_overwriting (s)
3063 struct glyph_string *s;
3064{
3065 int i, k, x;
3066 int end = s->row->used[s->area];
3067 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3068 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3069
3070 k = -1;
3071 x = 0;
3072 for (i = first; i < end; ++i)
3073 {
3074 int left, right;
3075 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3076 if (x - left < 0)
3077 k = i;
3078 x += glyphs[i].pixel_width;
3079 }
3080
3081 return k;
3082}
3083
3084
3085/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3086
3087static INLINE void
3088x_clear_glyph_string_rect (s, x, y, w, h)
3089 struct glyph_string *s;
3090 int x, y, w, h;
3091{
3092 XGCValues xgcv;
3093 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3094 XSetForeground (s->display, s->gc, xgcv.background);
3095 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3096 XSetForeground (s->display, s->gc, xgcv.foreground);
3097}
3098
3099
3100/* Draw the background of glyph_string S. If S->background_filled_p
3101 is non-zero don't draw it. FORCE_P non-zero means draw the
3102 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3103 when a string preceding S draws into the background of S, or S
3104 contains the first component of a composition. */
06a2c219
GM
3105
3106static void
3107x_draw_glyph_string_background (s, force_p)
3108 struct glyph_string *s;
3109 int force_p;
3110{
3111 /* Nothing to do if background has already been drawn or if it
3112 shouldn't be drawn in the first place. */
3113 if (!s->background_filled_p)
3114 {
ea2ba0d4
KH
3115 int box_line_width = max (s->face->box_line_width, 0);
3116
b4192550 3117 if (s->stippled_p)
06a2c219
GM
3118 {
3119 /* Fill background with a stipple pattern. */
3120 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3121 XFillRectangle (s->display, s->window, s->gc, s->x,
ea2ba0d4 3122 s->y + box_line_width,
06a2c219 3123 s->background_width,
ea2ba0d4 3124 s->height - 2 * box_line_width);
06a2c219
GM
3125 XSetFillStyle (s->display, s->gc, FillSolid);
3126 s->background_filled_p = 1;
3127 }
ea2ba0d4 3128 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
06a2c219
GM
3129 || s->font_not_found_p
3130 || s->extends_to_end_of_line_p
06a2c219
GM
3131 || force_p)
3132 {
ea2ba0d4 3133 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
06a2c219 3134 s->background_width,
ea2ba0d4 3135 s->height - 2 * box_line_width);
06a2c219
GM
3136 s->background_filled_p = 1;
3137 }
3138 }
3139}
3140
3141
3142/* Draw the foreground of glyph string S. */
3143
3144static void
3145x_draw_glyph_string_foreground (s)
3146 struct glyph_string *s;
3147{
3148 int i, x;
3149
3150 /* If first glyph of S has a left box line, start drawing the text
3151 of S to the right of that box line. */
3152 if (s->face->box != FACE_NO_BOX
3153 && s->first_glyph->left_box_line_p)
ea2ba0d4 3154 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
3155 else
3156 x = s->x;
3157
b4192550
KH
3158 /* Draw characters of S as rectangles if S's font could not be
3159 loaded. */
3160 if (s->font_not_found_p)
06a2c219 3161 {
b4192550 3162 for (i = 0; i < s->nchars; ++i)
06a2c219 3163 {
b4192550
KH
3164 struct glyph *g = s->first_glyph + i;
3165 XDrawRectangle (s->display, s->window,
3166 s->gc, x, s->y, g->pixel_width - 1,
3167 s->height - 1);
3168 x += g->pixel_width;
06a2c219
GM
3169 }
3170 }
3171 else
3172 {
b4192550
KH
3173 char *char1b = (char *) s->char2b;
3174 int boff = s->font_info->baseline_offset;
06a2c219 3175
b4192550
KH
3176 if (s->font_info->vertical_centering)
3177 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3178
3179 /* If we can use 8-bit functions, condense S->char2b. */
3180 if (!s->two_byte_p)
3181 for (i = 0; i < s->nchars; ++i)
3182 char1b[i] = s->char2b[i].byte2;
3183
3184 /* Draw text with XDrawString if background has already been
3185 filled. Otherwise, use XDrawImageString. (Note that
3186 XDrawImageString is usually faster than XDrawString.) Always
3187 use XDrawImageString when drawing the cursor so that there is
3188 no chance that characters under a box cursor are invisible. */
3189 if (s->for_overlaps_p
3190 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3191 {
3192 /* Draw characters with 16-bit or 8-bit functions. */
3193 if (s->two_byte_p)
3194 XDrawString16 (s->display, s->window, s->gc, x,
3195 s->ybase - boff, s->char2b, s->nchars);
3196 else
3197 XDrawString (s->display, s->window, s->gc, x,
3198 s->ybase - boff, char1b, s->nchars);
3199 }
06a2c219
GM
3200 else
3201 {
b4192550
KH
3202 if (s->two_byte_p)
3203 XDrawImageString16 (s->display, s->window, s->gc, x,
3204 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3205 else
b4192550
KH
3206 XDrawImageString (s->display, s->window, s->gc, x,
3207 s->ybase - boff, char1b, s->nchars);
3208 }
3209 }
3210}
06a2c219 3211
b4192550 3212/* Draw the foreground of composite glyph string S. */
06a2c219 3213
b4192550
KH
3214static void
3215x_draw_composite_glyph_string_foreground (s)
3216 struct glyph_string *s;
3217{
3218 int i, x;
06a2c219 3219
b4192550
KH
3220 /* If first glyph of S has a left box line, start drawing the text
3221 of S to the right of that box line. */
3222 if (s->face->box != FACE_NO_BOX
3223 && s->first_glyph->left_box_line_p)
ea2ba0d4 3224 x = s->x + abs (s->face->box_line_width);
b4192550
KH
3225 else
3226 x = s->x;
06a2c219 3227
b4192550
KH
3228 /* S is a glyph string for a composition. S->gidx is the index of
3229 the first character drawn for glyphs of this composition.
3230 S->gidx == 0 means we are drawing the very first character of
3231 this composition. */
06a2c219 3232
b4192550
KH
3233 /* Draw a rectangle for the composition if the font for the very
3234 first character of the composition could not be loaded. */
3235 if (s->font_not_found_p)
3236 {
3237 if (s->gidx == 0)
3238 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3239 s->width - 1, s->height - 1);
3240 }
3241 else
3242 {
3243 for (i = 0; i < s->nchars; i++, ++s->gidx)
3244 XDrawString16 (s->display, s->window, s->gc,
3245 x + s->cmp->offsets[s->gidx * 2],
3246 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3247 s->char2b + i, 1);
06a2c219
GM
3248 }
3249}
3250
3251
80c32bcc
GM
3252#ifdef USE_X_TOOLKIT
3253
3e71d8f2 3254static struct frame *x_frame_of_widget P_ ((Widget));
651f03b6
GM
3255static Boolean cvt_string_to_pixel P_ ((Display *, XrmValue *, Cardinal *,
3256 XrmValue *, XrmValue *, XtPointer *));
3257static void cvt_pixel_dtor P_ ((XtAppContext, XrmValue *, XtPointer,
3258 XrmValue *, Cardinal *));
80c32bcc 3259
3e71d8f2
GM
3260
3261/* Return the frame on which widget WIDGET is used.. Abort if frame
3262 cannot be determined. */
3263
e851c833 3264static struct frame *
3e71d8f2 3265x_frame_of_widget (widget)
80c32bcc 3266 Widget widget;
80c32bcc 3267{
80c32bcc 3268 struct x_display_info *dpyinfo;
5c187dee 3269 Lisp_Object tail;
3e71d8f2
GM
3270 struct frame *f;
3271
80c32bcc
GM
3272 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3273
3274 /* Find the top-level shell of the widget. Note that this function
3275 can be called when the widget is not yet realized, so XtWindow
3276 (widget) == 0. That's the reason we can't simply use
3277 x_any_window_to_frame. */
3278 while (!XtIsTopLevelShell (widget))
3279 widget = XtParent (widget);
3280
3281 /* Look for a frame with that top-level widget. Allocate the color
3282 on that frame to get the right gamma correction value. */
3283 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3284 if (GC_FRAMEP (XCAR (tail))
3285 && (f = XFRAME (XCAR (tail)),
3286 (f->output_data.nothing != 1
3287 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3288 && f->output_data.x->widget == widget)
3e71d8f2 3289 return f;
80c32bcc
GM
3290
3291 abort ();
3292}
3293
3e71d8f2
GM
3294
3295/* Allocate the color COLOR->pixel on the screen and display of
3296 widget WIDGET in colormap CMAP. If an exact match cannot be
3297 allocated, try the nearest color available. Value is non-zero
3298 if successful. This is called from lwlib. */
3299
3300int
3301x_alloc_nearest_color_for_widget (widget, cmap, color)
3302 Widget widget;
3303 Colormap cmap;
3304 XColor *color;
3305{
3306 struct frame *f = x_frame_of_widget (widget);
3307 return x_alloc_nearest_color (f, cmap, color);
3308}
3309
3310
46d516e5
MB
3311/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3312 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3313 If this produces the same color as PIXEL, try a color where all RGB
3314 values have DELTA added. Return the allocated color in *PIXEL.
3315 DISPLAY is the X display, CMAP is the colormap to operate on.
3316 Value is non-zero if successful. */
3317
3318int
3319x_alloc_lighter_color_for_widget (widget, display, cmap, pixel, factor, delta)
3320 Widget widget;
3321 Display *display;
3322 Colormap cmap;
3323 unsigned long *pixel;
3324 double factor;
3325 int delta;
3326{
3327 struct frame *f = x_frame_of_widget (widget);
3328 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
3329}
3330
3331
651f03b6
GM
3332/* Structure specifying which arguments should be passed by Xt to
3333 cvt_string_to_pixel. We want the widget's screen and colormap. */
3334
3335static XtConvertArgRec cvt_string_to_pixel_args[] =
3336 {
3337 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.screen),
3338 sizeof (Screen *)},
3339 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.colormap),
3340 sizeof (Colormap)}
3341 };
3342
3343
3344/* The address of this variable is returned by
3345 cvt_string_to_pixel. */
3346
3347static Pixel cvt_string_to_pixel_value;
3348
3349
3350/* Convert a color name to a pixel color.
3351
3352 DPY is the display we are working on.
3353
3354 ARGS is an array of *NARGS XrmValue structures holding additional
3355 information about the widget for which the conversion takes place.
3356 The contents of this array are determined by the specification
3357 in cvt_string_to_pixel_args.
3358
3359 FROM is a pointer to an XrmValue which points to the color name to
3360 convert. TO is an XrmValue in which to return the pixel color.
3361
3362 CLOSURE_RET is a pointer to user-data, in which we record if
3363 we allocated the color or not.
3364
3365 Value is True if successful, False otherwise. */
3366
3367static Boolean
3368cvt_string_to_pixel (dpy, args, nargs, from, to, closure_ret)
3369 Display *dpy;
3370 XrmValue *args;
3371 Cardinal *nargs;
3372 XrmValue *from, *to;
3373 XtPointer *closure_ret;
3374{
3375 Screen *screen;
3376 Colormap cmap;
3377 Pixel pixel;
3378 String color_name;
3379 XColor color;
3380
3381 if (*nargs != 2)
3382 {
3383 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3384 "wrongParameters", "cvt_string_to_pixel",
3385 "XtToolkitError",
3386 "Screen and colormap args required", NULL, NULL);
3387 return False;
3388 }
3389
3390 screen = *(Screen **) args[0].addr;
3391 cmap = *(Colormap *) args[1].addr;
3392 color_name = (String) from->addr;
3393
3394 if (strcmp (color_name, XtDefaultBackground) == 0)
3395 {
3396 *closure_ret = (XtPointer) False;
3397 pixel = WhitePixelOfScreen (screen);
3398 }
3399 else if (strcmp (color_name, XtDefaultForeground) == 0)
3400 {
3401 *closure_ret = (XtPointer) False;
3402 pixel = BlackPixelOfScreen (screen);
3403 }
3404 else if (XParseColor (dpy, cmap, color_name, &color)
3405 && x_alloc_nearest_color_1 (dpy, cmap, &color))
3406 {
3407 pixel = color.pixel;
3408 *closure_ret = (XtPointer) True;
3409 }
3410 else
3411 {
3412 String params[1];
3413 Cardinal nparams = 1;
3414
3415 params[0] = color_name;
3416 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3417 "badValue", "cvt_string_to_pixel",
3418 "XtToolkitError", "Invalid color `%s'",
3419 params, &nparams);
3420 return False;
3421 }
3422
3423 if (to->addr != NULL)
3424 {
3425 if (to->size < sizeof (Pixel))
3426 {
3427 to->size = sizeof (Pixel);
3428 return False;
3429 }
3430
3431 *(Pixel *) to->addr = pixel;
3432 }
3433 else
3434 {
3435 cvt_string_to_pixel_value = pixel;
3436 to->addr = (XtPointer) &cvt_string_to_pixel_value;
3437 }
3438
3439 to->size = sizeof (Pixel);
3440 return True;
3441}
3442
3443
3444/* Free a pixel color which was previously allocated via
3445 cvt_string_to_pixel. This is registered as the destructor
3446 for this type of resource via XtSetTypeConverter.
3447
3448 APP is the application context in which we work.
3449
3450 TO is a pointer to an XrmValue holding the color to free.
3451 CLOSURE is the value we stored in CLOSURE_RET for this color
3452 in cvt_string_to_pixel.
3453
3454 ARGS and NARGS are like for cvt_string_to_pixel. */
3455
3456static void
3457cvt_pixel_dtor (app, to, closure, args, nargs)
3458 XtAppContext app;
3459 XrmValuePtr to;
3460 XtPointer closure;
3461 XrmValuePtr args;
3462 Cardinal *nargs;
3463{
3464 if (*nargs != 2)
3465 {
3466 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
3467 "XtToolkitError",
3468 "Screen and colormap arguments required",
3469 NULL, NULL);
3470 }
3471 else if (closure != NULL)
3472 {
3473 /* We did allocate the pixel, so free it. */
3474 Screen *screen = *(Screen **) args[0].addr;
3475 Colormap cmap = *(Colormap *) args[1].addr;
3476 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
97762eb7 3477 (Pixel *) to->addr, 1);
651f03b6
GM
3478 }
3479}
3480
3481
80c32bcc
GM
3482#endif /* USE_X_TOOLKIT */
3483
3484
f04e1297 3485/* Value is an array of XColor structures for the contents of the
651f03b6 3486 color map of display DPY. Set *NCELLS to the size of the array.
f04e1297
GM
3487 Note that this probably shouldn't be called for large color maps,
3488 say a 24-bit TrueColor map. */
3489
3490static const XColor *
651f03b6
GM
3491x_color_cells (dpy, ncells)
3492 Display *dpy;
f04e1297
GM
3493 int *ncells;
3494{
651f03b6 3495 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
f04e1297
GM
3496
3497 if (dpyinfo->color_cells == NULL)
3498 {
651f03b6 3499 Screen *screen = dpyinfo->screen;
f04e1297
GM
3500 int i;
3501
3502 dpyinfo->ncolor_cells
651f03b6 3503 = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
f04e1297
GM
3504 dpyinfo->color_cells
3505 = (XColor *) xmalloc (dpyinfo->ncolor_cells
3506 * sizeof *dpyinfo->color_cells);
3507
3508 for (i = 0; i < dpyinfo->ncolor_cells; ++i)
3509 dpyinfo->color_cells[i].pixel = i;
3510
651f03b6 3511 XQueryColors (dpy, dpyinfo->cmap,
f04e1297
GM
3512 dpyinfo->color_cells, dpyinfo->ncolor_cells);
3513 }
3514
3515 *ncells = dpyinfo->ncolor_cells;
3516 return dpyinfo->color_cells;
3517}
3518
3519
3520/* On frame F, translate pixel colors to RGB values for the NCOLORS
3521 colors in COLORS. Use cached information, if available. */
3522
3523void
3524x_query_colors (f, colors, ncolors)
3525 struct frame *f;
3526 XColor *colors;
3527 int ncolors;
3528{
3529 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3530
3531 if (dpyinfo->color_cells)
3532 {
3533 int i;
3534 for (i = 0; i < ncolors; ++i)
3535 {
3536 unsigned long pixel = colors[i].pixel;
3537 xassert (pixel < dpyinfo->ncolor_cells);
3538 xassert (dpyinfo->color_cells[pixel].pixel == pixel);
3539 colors[i] = dpyinfo->color_cells[pixel];
3540 }
3541 }
3542 else
3543 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
3544}
3545
3546
3547/* On frame F, translate pixel color to RGB values for the color in
3548 COLOR. Use cached information, if available. */
3549
3550void
3551x_query_color (f, color)
3552 struct frame *f;
3553 XColor *color;
3554{
3555 x_query_colors (f, color, 1);
3556}
3557
3558
651f03b6
GM
3559/* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
3560 exact match can't be allocated, try the nearest color available.
3561 Value is non-zero if successful. Set *COLOR to the color
3562 allocated. */
06a2c219 3563
651f03b6
GM
3564static int
3565x_alloc_nearest_color_1 (dpy, cmap, color)
3566 Display *dpy;
06a2c219
GM
3567 Colormap cmap;
3568 XColor *color;
3569{
80c32bcc
GM
3570 int rc;
3571
651f03b6 3572 rc = XAllocColor (dpy, cmap, color);
06a2c219
GM
3573 if (rc == 0)
3574 {
3575 /* If we got to this point, the colormap is full, so we're going
3576 to try to get the next closest color. The algorithm used is
3577 a least-squares matching, which is what X uses for closest
3578 color matching with StaticColor visuals. */
3579 int nearest, i;
3580 unsigned long nearest_delta = ~0;
f04e1297 3581 int ncells;
651f03b6 3582 const XColor *cells = x_color_cells (dpy, &ncells);
06a2c219
GM
3583
3584 for (nearest = i = 0; i < ncells; ++i)
3585 {
3586 long dred = (color->red >> 8) - (cells[i].red >> 8);
3587 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3588 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3589 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3590
3591 if (delta < nearest_delta)
3592 {
3593 nearest = i;
3594 nearest_delta = delta;
3595 }
3596 }
3597
3598 color->red = cells[nearest].red;
3599 color->green = cells[nearest].green;
3600 color->blue = cells[nearest].blue;
651f03b6 3601 rc = XAllocColor (dpy, cmap, color);
06a2c219 3602 }
35efe0a1
GM
3603 else
3604 {
3605 /* If allocation succeeded, and the allocated pixel color is not
3606 equal to a cached pixel color recorded earlier, there was a
3607 change in the colormap, so clear the color cache. */
651f03b6 3608 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
35efe0a1
GM
3609 XColor *cached_color;
3610
3611 if (dpyinfo->color_cells
3612 && (cached_color = &dpyinfo->color_cells[color->pixel],
cae71efe
GM
3613 (cached_color->red != color->red
3614 || cached_color->blue != color->blue
3615 || cached_color->green != color->green)))
35efe0a1
GM
3616 {
3617 xfree (dpyinfo->color_cells);
3618 dpyinfo->color_cells = NULL;
3619 dpyinfo->ncolor_cells = 0;
3620 }
3621 }
06a2c219 3622
d9c545da
GM
3623#ifdef DEBUG_X_COLORS
3624 if (rc)
3625 register_color (color->pixel);
3626#endif /* DEBUG_X_COLORS */
3627
06a2c219
GM
3628 return rc;
3629}
3630
3631
651f03b6
GM
3632/* Allocate the color COLOR->pixel on frame F, colormap CMAP. If an
3633 exact match can't be allocated, try the nearest color available.
3634 Value is non-zero if successful. Set *COLOR to the color
3635 allocated. */
3636
3637int
3638x_alloc_nearest_color (f, cmap, color)
3639 struct frame *f;
3640 Colormap cmap;
3641 XColor *color;
3642{
3643 gamma_correct (f, color);
3644 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
3645}
3646
3647
d9c545da
GM
3648/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3649 It's necessary to do this instead of just using PIXEL directly to
3650 get color reference counts right. */
3651
3652unsigned long
3653x_copy_color (f, pixel)
3654 struct frame *f;
3655 unsigned long pixel;
3656{
3657 XColor color;
3658
3659 color.pixel = pixel;
3660 BLOCK_INPUT;
f04e1297 3661 x_query_color (f, &color);
d9c545da
GM
3662 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3663 UNBLOCK_INPUT;
3664#ifdef DEBUG_X_COLORS
3665 register_color (pixel);
3666#endif
3667 return color.pixel;
3668}
3669
3670
3e71d8f2
GM
3671/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3672 It's necessary to do this instead of just using PIXEL directly to
3673 get color reference counts right. */
3674
3675unsigned long
3676x_copy_dpy_color (dpy, cmap, pixel)
3677 Display *dpy;
3678 Colormap cmap;
3679 unsigned long pixel;
3680{
3681 XColor color;
3682
3683 color.pixel = pixel;
3684 BLOCK_INPUT;
3685 XQueryColor (dpy, cmap, &color);
3686 XAllocColor (dpy, cmap, &color);
3687 UNBLOCK_INPUT;
3688#ifdef DEBUG_X_COLORS
3689 register_color (pixel);
3690#endif
3691 return color.pixel;
3692}
3693
3694
6d8b0acd 3695/* Brightness beyond which a color won't have its highlight brightness
d7361edf 3696 boosted.
6d8b0acd 3697
d7361edf
MB
3698 Nominally, highlight colors for `3d' faces are calculated by
3699 brightening an object's color by a constant scale factor, but this
3700 doesn't yield good results for dark colors, so for colors who's
3701 brightness is less than this value (on a scale of 0-65535) have an
3702 use an additional additive factor.
6d8b0acd
MB
3703
3704 The value here is set so that the default menu-bar/mode-line color
3705 (grey75) will not have its highlights changed at all. */
3706#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
3707
3708
06a2c219
GM
3709/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3710 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3711 If this produces the same color as PIXEL, try a color where all RGB
3712 values have DELTA added. Return the allocated color in *PIXEL.
3713 DISPLAY is the X display, CMAP is the colormap to operate on.
3714 Value is non-zero if successful. */
3715
3716static int
3717x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3718 struct frame *f;
3719 Display *display;
3720 Colormap cmap;
3721 unsigned long *pixel;
68c45bf0 3722 double factor;
06a2c219
GM
3723 int delta;
3724{
3725 XColor color, new;
6d8b0acd 3726 long bright;
06a2c219
GM
3727 int success_p;
3728
3729 /* Get RGB color values. */
3730 color.pixel = *pixel;
f04e1297 3731 x_query_color (f, &color);
06a2c219
GM
3732
3733 /* Change RGB values by specified FACTOR. Avoid overflow! */
3734 xassert (factor >= 0);
3735 new.red = min (0xffff, factor * color.red);
3736 new.green = min (0xffff, factor * color.green);
3737 new.blue = min (0xffff, factor * color.blue);
3738
d7361edf
MB
3739 /* Calculate brightness of COLOR. */
3740 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
6d8b0acd
MB
3741
3742 /* We only boost colors that are darker than
3743 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3744 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3745 /* Make an additive adjustment to NEW, because it's dark enough so
3746 that scaling by FACTOR alone isn't enough. */
3747 {
3748 /* How far below the limit this color is (0 - 1, 1 being darker). */
3749 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3750 /* The additive adjustment. */
d7361edf 3751 int min_delta = delta * dimness * factor / 2;
6d8b0acd
MB
3752
3753 if (factor < 1)
3754 {
6d8b0acd
MB
3755 new.red = max (0, new.red - min_delta);
3756 new.green = max (0, new.green - min_delta);
3757 new.blue = max (0, new.blue - min_delta);
3758 }
3759 else
3760 {
3761 new.red = min (0xffff, min_delta + new.red);
3762 new.green = min (0xffff, min_delta + new.green);
3763 new.blue = min (0xffff, min_delta + new.blue);
3764 }
3765 }
3766
06a2c219 3767 /* Try to allocate the color. */
80c32bcc 3768 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3769 if (success_p)
3770 {
3771 if (new.pixel == *pixel)
3772 {
3773 /* If we end up with the same color as before, try adding
3774 delta to the RGB values. */
0d605c67 3775 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3776
3777 new.red = min (0xffff, delta + color.red);
3778 new.green = min (0xffff, delta + color.green);
3779 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3780 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3781 }
3782 else
3783 success_p = 1;
3784 *pixel = new.pixel;
3785 }
3786
3787 return success_p;
3788}
3789
3790
3791/* Set up the foreground color for drawing relief lines of glyph
3792 string S. RELIEF is a pointer to a struct relief containing the GC
3793 with which lines will be drawn. Use a color that is FACTOR or
3794 DELTA lighter or darker than the relief's background which is found
3795 in S->f->output_data.x->relief_background. If such a color cannot
3796 be allocated, use DEFAULT_PIXEL, instead. */
3797
3798static void
3799x_setup_relief_color (f, relief, factor, delta, default_pixel)
3800 struct frame *f;
3801 struct relief *relief;
68c45bf0 3802 double factor;
06a2c219
GM
3803 int delta;
3804 unsigned long default_pixel;
3805{
3806 XGCValues xgcv;
3807 struct x_output *di = f->output_data.x;
3808 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3809 unsigned long pixel;
3810 unsigned long background = di->relief_background;
43bd1b2b 3811 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3812 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3813 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3814
3815 xgcv.graphics_exposures = False;
3816 xgcv.line_width = 1;
3817
3818 /* Free previously allocated color. The color cell will be reused
3819 when it has been freed as many times as it was allocated, so this
3820 doesn't affect faces using the same colors. */
3821 if (relief->gc
3822 && relief->allocated_p)
3823 {
0d605c67 3824 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3825 relief->allocated_p = 0;
3826 }
3827
3828 /* Allocate new color. */
3829 xgcv.foreground = default_pixel;
3830 pixel = background;
dcd08bfb
GM
3831 if (dpyinfo->n_planes != 1
3832 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3833 {
3834 relief->allocated_p = 1;
3835 xgcv.foreground = relief->pixel = pixel;
3836 }
3837
3838 if (relief->gc == 0)
3839 {
dcd08bfb 3840 xgcv.stipple = dpyinfo->gray;
06a2c219 3841 mask |= GCStipple;
dcd08bfb 3842 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3843 }
3844 else
dcd08bfb 3845 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3846}
3847
3848
3849/* Set up colors for the relief lines around glyph string S. */
3850
3851static void
3852x_setup_relief_colors (s)
3853 struct glyph_string *s;
3854{
3855 struct x_output *di = s->f->output_data.x;
3856 unsigned long color;
3857
3858 if (s->face->use_box_color_for_shadows_p)
3859 color = s->face->box_color;
e2a57b34 3860 else if (s->first_glyph->type == IMAGE_GLYPH
0cb8bb48 3861 && s->img->pixmap
e2a57b34
MB
3862 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3863 color = IMAGE_BACKGROUND (s->img, s->f, 0);
06a2c219
GM
3864 else
3865 {
3866 XGCValues xgcv;
3867
3868 /* Get the background color of the face. */
3869 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3870 color = xgcv.background;
3871 }
3872
3873 if (di->white_relief.gc == 0
3874 || color != di->relief_background)
3875 {
3876 di->relief_background = color;
3877 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3878 WHITE_PIX_DEFAULT (s->f));
3879 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3880 BLACK_PIX_DEFAULT (s->f));
3881 }
3882}
3883
3884
3885/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3886 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3887 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3888 relief. LEFT_P non-zero means draw a relief on the left side of
3889 the rectangle. RIGHT_P non-zero means draw a relief on the right
3890 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3891 when drawing. */
3892
3893static void
3894x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3895 raised_p, left_p, right_p, clip_rect)
3896 struct frame *f;
3897 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3898 XRectangle *clip_rect;
3899{
de507556
GM
3900 Display *dpy = FRAME_X_DISPLAY (f);
3901 Window window = FRAME_X_WINDOW (f);
06a2c219
GM
3902 int i;
3903 GC gc;
3904
3905 if (raised_p)
3906 gc = f->output_data.x->white_relief.gc;
3907 else
3908 gc = f->output_data.x->black_relief.gc;
de507556 3909 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3910
3911 /* Top. */
3912 for (i = 0; i < width; ++i)
de507556 3913 XDrawLine (dpy, window, gc,
06a2c219
GM
3914 left_x + i * left_p, top_y + i,
3915 right_x + 1 - i * right_p, top_y + i);
3916
3917 /* Left. */
3918 if (left_p)
3919 for (i = 0; i < width; ++i)
de507556 3920 XDrawLine (dpy, window, gc,
44655e77 3921 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
06a2c219 3922
de507556 3923 XSetClipMask (dpy, gc, None);
06a2c219
GM
3924 if (raised_p)
3925 gc = f->output_data.x->black_relief.gc;
3926 else
3927 gc = f->output_data.x->white_relief.gc;
de507556 3928 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3929
3930 /* Bottom. */
3931 for (i = 0; i < width; ++i)
de507556
GM
3932 XDrawLine (dpy, window, gc,
3933 left_x + i * left_p, bottom_y - i,
327f42ee 3934 right_x + 1 - i * right_p, bottom_y - i);
06a2c219
GM
3935
3936 /* Right. */
3937 if (right_p)
3938 for (i = 0; i < width; ++i)
de507556 3939 XDrawLine (dpy, window, gc,
06a2c219
GM
3940 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3941
de507556 3942 XSetClipMask (dpy, gc, None);
06a2c219
GM
3943}
3944
3945
3946/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3947 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3948 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3949 left side of the rectangle. RIGHT_P non-zero means draw a line
3950 on the right side of the rectangle. CLIP_RECT is the clipping
3951 rectangle to use when drawing. */
3952
3953static void
3954x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3955 left_p, right_p, clip_rect)
3956 struct glyph_string *s;
3957 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3958 XRectangle *clip_rect;
3959{
3960 XGCValues xgcv;
3961
3962 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3963 XSetForeground (s->display, s->gc, s->face->box_color);
3964 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3965
3966 /* Top. */
3967 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3968 left_x, top_y, right_x - left_x + 1, width);
06a2c219
GM
3969
3970 /* Left. */
3971 if (left_p)
3972 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3973 left_x, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3974
3975 /* Bottom. */
3976 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3977 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
06a2c219
GM
3978
3979 /* Right. */
3980 if (right_p)
3981 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3982 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3983
3984 XSetForeground (s->display, s->gc, xgcv.foreground);
3985 XSetClipMask (s->display, s->gc, None);
3986}
3987
3988
3989/* Draw a box around glyph string S. */
3990
3991static void
3992x_draw_glyph_string_box (s)
3993 struct glyph_string *s;
3994{
3995 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3996 int left_p, right_p;
3997 struct glyph *last_glyph;
3998 XRectangle clip_rect;
3999
4000 last_x = window_box_right (s->w, s->area);
4001 if (s->row->full_width_p
4002 && !s->w->pseudo_window_p)
4003 {
3f332ef3 4004 last_x += FRAME_X_RIGHT_FRINGE_WIDTH (s->f);
06a2c219
GM
4005 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
4006 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
4007 }
4008
4009 /* The glyph that may have a right box line. */
b4192550 4010 last_glyph = (s->cmp || s->img
06a2c219
GM
4011 ? s->first_glyph
4012 : s->first_glyph + s->nchars - 1);
4013
ea2ba0d4 4014 width = abs (s->face->box_line_width);
06a2c219
GM
4015 raised_p = s->face->box == FACE_RAISED_BOX;
4016 left_x = s->x;
57ac7c81
GM
4017 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
4018 ? last_x - 1
4019 : min (last_x, s->x + s->background_width) - 1);
06a2c219
GM
4020 top_y = s->y;
4021 bottom_y = top_y + s->height - 1;
4022
4023 left_p = (s->first_glyph->left_box_line_p
4024 || (s->hl == DRAW_MOUSE_FACE
4025 && (s->prev == NULL
4026 || s->prev->hl != s->hl)));
4027 right_p = (last_glyph->right_box_line_p
4028 || (s->hl == DRAW_MOUSE_FACE
4029 && (s->next == NULL
4030 || s->next->hl != s->hl)));
327f42ee 4031
06a2c219
GM
4032 x_get_glyph_string_clip_rect (s, &clip_rect);
4033
4034 if (s->face->box == FACE_SIMPLE_BOX)
4035 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4036 left_p, right_p, &clip_rect);
4037 else
4038 {
4039 x_setup_relief_colors (s);
4040 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
4041 width, raised_p, left_p, right_p, &clip_rect);
4042 }
4043}
4044
4045
4046/* Draw foreground of image glyph string S. */
4047
4048static void
4049x_draw_image_foreground (s)
4050 struct glyph_string *s;
4051{
4052 int x;
95af8492 4053 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4054
4055 /* If first glyph of S has a left box line, start drawing it to the
4056 right of that line. */
4057 if (s->face->box != FACE_NO_BOX
4058 && s->first_glyph->left_box_line_p)
ea2ba0d4 4059 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4060 else
4061 x = s->x;
4062
4063 /* If there is a margin around the image, adjust x- and y-position
4064 by that margin. */
22d650b8
GM
4065 x += s->img->hmargin;
4066 y += s->img->vmargin;
06a2c219
GM
4067
4068 if (s->img->pixmap)
4069 {
4070 if (s->img->mask)
4071 {
4072 /* We can't set both a clip mask and use XSetClipRectangles
4073 because the latter also sets a clip mask. We also can't
4074 trust on the shape extension to be available
4075 (XShapeCombineRegion). So, compute the rectangle to draw
4076 manually. */
4077 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4078 | GCFunction);
4079 XGCValues xgcv;
4080 XRectangle clip_rect, image_rect, r;
4081
4082 xgcv.clip_mask = s->img->mask;
4083 xgcv.clip_x_origin = x;
4084 xgcv.clip_y_origin = y;
4085 xgcv.function = GXcopy;
4086 XChangeGC (s->display, s->gc, mask, &xgcv);
4087
4088 x_get_glyph_string_clip_rect (s, &clip_rect);
4089 image_rect.x = x;
4090 image_rect.y = y;
4091 image_rect.width = s->img->width;
4092 image_rect.height = s->img->height;
4093 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4094 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4095 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
4096 }
4097 else
4098 {
49ad1d99
GM
4099 XRectangle clip_rect, image_rect, r;
4100
4101 x_get_glyph_string_clip_rect (s, &clip_rect);
4102 image_rect.x = x;
4103 image_rect.y = y;
4104 image_rect.width = s->img->width;
4105 image_rect.height = s->img->height;
4106 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4107 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4108 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
06a2c219
GM
4109
4110 /* When the image has a mask, we can expect that at
4111 least part of a mouse highlight or a block cursor will
4112 be visible. If the image doesn't have a mask, make
4113 a block cursor visible by drawing a rectangle around
4114 the image. I believe it's looking better if we do
4115 nothing here for mouse-face. */
4116 if (s->hl == DRAW_CURSOR)
4117 XDrawRectangle (s->display, s->window, s->gc, x, y,
4118 s->img->width - 1, s->img->height - 1);
4119 }
4120 }
4121 else
4122 /* Draw a rectangle if image could not be loaded. */
4123 XDrawRectangle (s->display, s->window, s->gc, x, y,
4124 s->img->width - 1, s->img->height - 1);
4125}
4126
4127
4128/* Draw a relief around the image glyph string S. */
4129
4130static void
4131x_draw_image_relief (s)
4132 struct glyph_string *s;
4133{
4134 int x0, y0, x1, y1, thick, raised_p;
4135 XRectangle r;
4136 int x;
95af8492 4137 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4138
4139 /* If first glyph of S has a left box line, start drawing it to the
4140 right of that line. */
4141 if (s->face->box != FACE_NO_BOX
4142 && s->first_glyph->left_box_line_p)
ea2ba0d4 4143 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4144 else
4145 x = s->x;
4146
4147 /* If there is a margin around the image, adjust x- and y-position
4148 by that margin. */
22d650b8
GM
4149 x += s->img->hmargin;
4150 y += s->img->vmargin;
06a2c219
GM
4151
4152 if (s->hl == DRAW_IMAGE_SUNKEN
4153 || s->hl == DRAW_IMAGE_RAISED)
4154 {
62854fe2 4155 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
06a2c219
GM
4156 raised_p = s->hl == DRAW_IMAGE_RAISED;
4157 }
4158 else
4159 {
4160 thick = abs (s->img->relief);
4161 raised_p = s->img->relief > 0;
4162 }
4163
4164 x0 = x - thick;
4165 y0 = y - thick;
4166 x1 = x + s->img->width + thick - 1;
4167 y1 = y + s->img->height + thick - 1;
4168
4169 x_setup_relief_colors (s);
4170 x_get_glyph_string_clip_rect (s, &r);
4171 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
4172}
4173
4174
4175/* Draw the foreground of image glyph string S to PIXMAP. */
4176
4177static void
4178x_draw_image_foreground_1 (s, pixmap)
4179 struct glyph_string *s;
4180 Pixmap pixmap;
4181{
4182 int x;
95af8492 4183 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
4184
4185 /* If first glyph of S has a left box line, start drawing it to the
4186 right of that line. */
4187 if (s->face->box != FACE_NO_BOX
4188 && s->first_glyph->left_box_line_p)
ea2ba0d4 4189 x = abs (s->face->box_line_width);
06a2c219
GM
4190 else
4191 x = 0;
4192
4193 /* If there is a margin around the image, adjust x- and y-position
4194 by that margin. */
22d650b8
GM
4195 x += s->img->hmargin;
4196 y += s->img->vmargin;
dc43ef94 4197
06a2c219
GM
4198 if (s->img->pixmap)
4199 {
4200 if (s->img->mask)
4201 {
4202 /* We can't set both a clip mask and use XSetClipRectangles
4203 because the latter also sets a clip mask. We also can't
4204 trust on the shape extension to be available
4205 (XShapeCombineRegion). So, compute the rectangle to draw
4206 manually. */
4207 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4208 | GCFunction);
4209 XGCValues xgcv;
4210
4211 xgcv.clip_mask = s->img->mask;
4212 xgcv.clip_x_origin = x;
4213 xgcv.clip_y_origin = y;
4214 xgcv.function = GXcopy;
4215 XChangeGC (s->display, s->gc, mask, &xgcv);
4216
4217 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4218 0, 0, s->img->width, s->img->height, x, y);
4219 XSetClipMask (s->display, s->gc, None);
4220 }
4221 else
4222 {
4223 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4224 0, 0, s->img->width, s->img->height, x, y);
4225
4226 /* When the image has a mask, we can expect that at
4227 least part of a mouse highlight or a block cursor will
4228 be visible. If the image doesn't have a mask, make
4229 a block cursor visible by drawing a rectangle around
4230 the image. I believe it's looking better if we do
4231 nothing here for mouse-face. */
4232 if (s->hl == DRAW_CURSOR)
4233 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4234 s->img->width - 1, s->img->height - 1);
4235 }
4236 }
4237 else
4238 /* Draw a rectangle if image could not be loaded. */
4239 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4240 s->img->width - 1, s->img->height - 1);
4241}
dc43ef94 4242
990ba854 4243
06a2c219
GM
4244/* Draw part of the background of glyph string S. X, Y, W, and H
4245 give the rectangle to draw. */
a9a5b0a5 4246
06a2c219
GM
4247static void
4248x_draw_glyph_string_bg_rect (s, x, y, w, h)
4249 struct glyph_string *s;
4250 int x, y, w, h;
4251{
4252 if (s->stippled_p)
4253 {
4254 /* Fill background with a stipple pattern. */
4255 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4256 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4257 XSetFillStyle (s->display, s->gc, FillSolid);
4258 }
4259 else
4260 x_clear_glyph_string_rect (s, x, y, w, h);
4261}
07e34cb0 4262
b5210ea7 4263
06a2c219 4264/* Draw image glyph string S.
dc43ef94 4265
06a2c219
GM
4266 s->y
4267 s->x +-------------------------
4268 | s->face->box
4269 |
4270 | +-------------------------
4271 | | s->img->margin
4272 | |
4273 | | +-------------------
4274 | | | the image
dc43ef94 4275
06a2c219 4276 */
dc43ef94 4277
06a2c219
GM
4278static void
4279x_draw_image_glyph_string (s)
4280 struct glyph_string *s;
4281{
4282 int x, y;
ea2ba0d4
KH
4283 int box_line_hwidth = abs (s->face->box_line_width);
4284 int box_line_vwidth = max (s->face->box_line_width, 0);
06a2c219
GM
4285 int height;
4286 Pixmap pixmap = None;
4287
ea2ba0d4 4288 height = s->height - 2 * box_line_vwidth;
06a2c219
GM
4289
4290 /* Fill background with face under the image. Do it only if row is
4291 taller than image or if image has a clip mask to reduce
4292 flickering. */
4293 s->stippled_p = s->face->stipple != 0;
4294 if (height > s->img->height
22d650b8
GM
4295 || s->img->hmargin
4296 || s->img->vmargin
06a2c219
GM
4297 || s->img->mask
4298 || s->img->pixmap == 0
4299 || s->width != s->background_width)
4300 {
ea2ba0d4
KH
4301 if (box_line_hwidth && s->first_glyph->left_box_line_p)
4302 x = s->x + box_line_hwidth;
06a2c219
GM
4303 else
4304 x = s->x;
4305
ea2ba0d4 4306 y = s->y + box_line_vwidth;
06a2c219
GM
4307
4308 if (s->img->mask)
4309 {
f9b5db02
GM
4310 /* Create a pixmap as large as the glyph string. Fill it
4311 with the background color. Copy the image to it, using
4312 its mask. Copy the temporary pixmap to the display. */
06a2c219
GM
4313 Screen *screen = FRAME_X_SCREEN (s->f);
4314 int depth = DefaultDepthOfScreen (screen);
4315
4316 /* Create a pixmap as large as the glyph string. */
4317 pixmap = XCreatePixmap (s->display, s->window,
4318 s->background_width,
4319 s->height, depth);
4320
4321 /* Don't clip in the following because we're working on the
4322 pixmap. */
4323 XSetClipMask (s->display, s->gc, None);
4324
4325 /* Fill the pixmap with the background color/stipple. */
4326 if (s->stippled_p)
4327 {
4328 /* Fill background with a stipple pattern. */
4329 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4330 XFillRectangle (s->display, pixmap, s->gc,
4331 0, 0, s->background_width, s->height);
4332 XSetFillStyle (s->display, s->gc, FillSolid);
4333 }
4334 else
4335 {
4336 XGCValues xgcv;
4337 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4338 &xgcv);
4339 XSetForeground (s->display, s->gc, xgcv.background);
4340 XFillRectangle (s->display, pixmap, s->gc,
4341 0, 0, s->background_width, s->height);
4342 XSetForeground (s->display, s->gc, xgcv.foreground);
4343 }
4344 }
4345 else
06a2c219
GM
4346 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
4347
4348 s->background_filled_p = 1;
4349 }
dc43ef94 4350
06a2c219
GM
4351 /* Draw the foreground. */
4352 if (pixmap != None)
4353 {
4354 x_draw_image_foreground_1 (s, pixmap);
4355 x_set_glyph_string_clipping (s);
4356 XCopyArea (s->display, pixmap, s->window, s->gc,
4357 0, 0, s->background_width, s->height, s->x, s->y);
4358 XFreePixmap (s->display, pixmap);
4359 }
4360 else
4361 x_draw_image_foreground (s);
b5210ea7 4362
06a2c219
GM
4363 /* If we must draw a relief around the image, do it. */
4364 if (s->img->relief
4365 || s->hl == DRAW_IMAGE_RAISED
4366 || s->hl == DRAW_IMAGE_SUNKEN)
4367 x_draw_image_relief (s);
4368}
8c1a6a84 4369
990ba854 4370
06a2c219 4371/* Draw stretch glyph string S. */
dc43ef94 4372
06a2c219
GM
4373static void
4374x_draw_stretch_glyph_string (s)
4375 struct glyph_string *s;
4376{
4377 xassert (s->first_glyph->type == STRETCH_GLYPH);
4378 s->stippled_p = s->face->stipple != 0;
990ba854 4379
06a2c219
GM
4380 if (s->hl == DRAW_CURSOR
4381 && !x_stretch_cursor_p)
4382 {
4383 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4384 as wide as the stretch glyph. */
4385 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4386
06a2c219
GM
4387 /* Draw cursor. */
4388 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4389
06a2c219
GM
4390 /* Clear rest using the GC of the original non-cursor face. */
4391 if (width < s->background_width)
4392 {
06a2c219
GM
4393 int x = s->x + width, y = s->y;
4394 int w = s->background_width - width, h = s->height;
4395 XRectangle r;
b7f83f9e 4396 GC gc;
dc43ef94 4397
b7f83f9e
GM
4398 if (s->row->mouse_face_p
4399 && cursor_in_mouse_face_p (s->w))
4400 {
4401 x_set_mouse_face_gc (s);
4402 gc = s->gc;
4403 }
4404 else
4405 gc = s->face->gc;
4406
06a2c219
GM
4407 x_get_glyph_string_clip_rect (s, &r);
4408 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
b7f83f9e 4409
06a2c219
GM
4410 if (s->face->stipple)
4411 {
4412 /* Fill background with a stipple pattern. */
4413 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4414 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4415 XSetFillStyle (s->display, gc, FillSolid);
4416 }
4417 else
4418 {
4419 XGCValues xgcv;
4420 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4421 XSetForeground (s->display, gc, xgcv.background);
4422 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4423 XSetForeground (s->display, gc, xgcv.foreground);
4424 }
4425 }
4426 }
61e9f9f3 4427 else if (!s->background_filled_p)
06a2c219
GM
4428 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4429 s->height);
4430
4431 s->background_filled_p = 1;
4432}
4433
4434
4435/* Draw glyph string S. */
4436
4437static void
4438x_draw_glyph_string (s)
4439 struct glyph_string *s;
4440{
4458cf11
KH
4441 int relief_drawn_p = 0;
4442
06a2c219
GM
4443 /* If S draws into the background of its successor, draw the
4444 background of the successor first so that S can draw into it.
4445 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4446 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4447 {
4448 xassert (s->next->img == NULL);
4449 x_set_glyph_string_gc (s->next);
4450 x_set_glyph_string_clipping (s->next);
4451 x_draw_glyph_string_background (s->next, 1);
4452 }
97210f4e 4453
06a2c219
GM
4454 /* Set up S->gc, set clipping and draw S. */
4455 x_set_glyph_string_gc (s);
06a2c219 4456
4458cf11
KH
4457 /* Draw relief (if any) in advance for char/composition so that the
4458 glyph string can be drawn over it. */
4459 if (!s->for_overlaps_p
4460 && s->face->box != FACE_NO_BOX
4461 && (s->first_glyph->type == CHAR_GLYPH
4462 || s->first_glyph->type == COMPOSITE_GLYPH))
4463
4464 {
e6269cbb 4465 x_set_glyph_string_clipping (s);
4458cf11
KH
4466 x_draw_glyph_string_background (s, 1);
4467 x_draw_glyph_string_box (s);
e6269cbb 4468 x_set_glyph_string_clipping (s);
4458cf11
KH
4469 relief_drawn_p = 1;
4470 }
e6269cbb
GM
4471 else
4472 x_set_glyph_string_clipping (s);
4458cf11 4473
06a2c219
GM
4474 switch (s->first_glyph->type)
4475 {
4476 case IMAGE_GLYPH:
4477 x_draw_image_glyph_string (s);
4478 break;
4479
4480 case STRETCH_GLYPH:
4481 x_draw_stretch_glyph_string (s);
4482 break;
4483
4484 case CHAR_GLYPH:
66ac4b0e
GM
4485 if (s->for_overlaps_p)
4486 s->background_filled_p = 1;
4487 else
4488 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4489 x_draw_glyph_string_foreground (s);
4490 break;
4491
b4192550
KH
4492 case COMPOSITE_GLYPH:
4493 if (s->for_overlaps_p || s->gidx > 0)
4494 s->background_filled_p = 1;
4495 else
4496 x_draw_glyph_string_background (s, 1);
4497 x_draw_composite_glyph_string_foreground (s);
4498 break;
4499
06a2c219
GM
4500 default:
4501 abort ();
4502 }
4503
66ac4b0e 4504 if (!s->for_overlaps_p)
06a2c219 4505 {
66ac4b0e
GM
4506 /* Draw underline. */
4507 if (s->face->underline_p)
4508 {
e24e84cc
GM
4509 unsigned long tem, h;
4510 int y;
06a2c219 4511
e24e84cc 4512 /* Get the underline thickness. Default is 1 pixel. */
66ac4b0e
GM
4513 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4514 h = 1;
e24e84cc
GM
4515
4516 /* Get the underline position. This is the recommended
4517 vertical offset in pixels from the baseline to the top of
4518 the underline. This is a signed value according to the
4519 specs, and its default is
4520
4521 ROUND ((maximum descent) / 2), with
4522 ROUND(x) = floor (x + 0.5) */
4523
a72d5ce5
GM
4524 if (x_use_underline_position_properties
4525 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
e24e84cc
GM
4526 y = s->ybase + (long) tem;
4527 else if (s->face->font)
4528 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4529 else
a02f1be0 4530 y = s->y + s->height - h;
06a2c219 4531
66ac4b0e 4532 if (s->face->underline_defaulted_p)
e24e84cc
GM
4533 XFillRectangle (s->display, s->window, s->gc,
4534 s->x, y, s->width, h);
66ac4b0e
GM
4535 else
4536 {
4537 XGCValues xgcv;
4538 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4539 XSetForeground (s->display, s->gc, s->face->underline_color);
e24e84cc
GM
4540 XFillRectangle (s->display, s->window, s->gc,
4541 s->x, y, s->width, h);
66ac4b0e
GM
4542 XSetForeground (s->display, s->gc, xgcv.foreground);
4543 }
dc6f92b8 4544 }
07e34cb0 4545
66ac4b0e
GM
4546 /* Draw overline. */
4547 if (s->face->overline_p)
06a2c219 4548 {
66ac4b0e
GM
4549 unsigned long dy = 0, h = 1;
4550
4551 if (s->face->overline_color_defaulted_p)
4552 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4553 s->width, h);
4554 else
4555 {
4556 XGCValues xgcv;
4557 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4558 XSetForeground (s->display, s->gc, s->face->overline_color);
4559 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4560 s->width, h);
4561 XSetForeground (s->display, s->gc, xgcv.foreground);
4562 }
06a2c219 4563 }
06a2c219 4564
66ac4b0e
GM
4565 /* Draw strike-through. */
4566 if (s->face->strike_through_p)
06a2c219 4567 {
66ac4b0e
GM
4568 unsigned long h = 1;
4569 unsigned long dy = (s->height - h) / 2;
4570
4571 if (s->face->strike_through_color_defaulted_p)
4572 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4573 s->width, h);
4574 else
4575 {
4576 XGCValues xgcv;
4577 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4578 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4579 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4580 s->width, h);
4581 XSetForeground (s->display, s->gc, xgcv.foreground);
4582 }
06a2c219 4583 }
06a2c219 4584
4458cf11
KH
4585 /* Draw relief if not yet drawn. */
4586 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
66ac4b0e
GM
4587 x_draw_glyph_string_box (s);
4588 }
06a2c219
GM
4589
4590 /* Reset clipping. */
4591 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4592}
07e34cb0 4593
06a2c219 4594
b4192550
KH
4595static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4596 struct face **, int));
06a2c219 4597
06a2c219 4598
209f68d9
GM
4599/* Fill glyph string S with composition components specified by S->cmp.
4600
b4192550
KH
4601 FACES is an array of faces for all components of this composition.
4602 S->gidx is the index of the first component for S.
4603 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4604 use its physical height for clipping.
06a2c219 4605
b4192550 4606 Value is the index of a component not in S. */
07e34cb0 4607
b4192550
KH
4608static int
4609x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4610 struct glyph_string *s;
b4192550 4611 struct face **faces;
66ac4b0e 4612 int overlaps_p;
07e34cb0 4613{
b4192550 4614 int i;
06a2c219 4615
b4192550 4616 xassert (s);
06a2c219 4617
b4192550 4618 s->for_overlaps_p = overlaps_p;
06a2c219 4619
b4192550
KH
4620 s->face = faces[s->gidx];
4621 s->font = s->face->font;
4622 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4623
b4192550
KH
4624 /* For all glyphs of this composition, starting at the offset
4625 S->gidx, until we reach the end of the definition or encounter a
4626 glyph that requires the different face, add it to S. */
4627 ++s->nchars;
4628 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4629 ++s->nchars;
06a2c219 4630
b4192550
KH
4631 /* All glyph strings for the same composition has the same width,
4632 i.e. the width set for the first component of the composition. */
06a2c219 4633
06a2c219
GM
4634 s->width = s->first_glyph->pixel_width;
4635
4636 /* If the specified font could not be loaded, use the frame's
4637 default font, but record the fact that we couldn't load it in
4638 the glyph string so that we can draw rectangles for the
4639 characters of the glyph string. */
4640 if (s->font == NULL)
4641 {
4642 s->font_not_found_p = 1;
4643 s->font = FRAME_FONT (s->f);
4644 }
4645
4646 /* Adjust base line for subscript/superscript text. */
4647 s->ybase += s->first_glyph->voffset;
4648
4649 xassert (s->face && s->face->gc);
4650
4651 /* This glyph string must always be drawn with 16-bit functions. */
4652 s->two_byte_p = 1;
b4192550
KH
4653
4654 return s->gidx + s->nchars;
06a2c219
GM
4655}
4656
4657
209f68d9
GM
4658/* Fill glyph string S from a sequence of character glyphs.
4659
06a2c219 4660 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4661 first glyph to consider, END is the index of the last + 1.
4662 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4663 use its physical height for clipping.
66ac4b0e
GM
4664
4665 Value is the index of the first glyph not in S. */
06a2c219
GM
4666
4667static int
66ac4b0e 4668x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4669 struct glyph_string *s;
4670 int face_id;
66ac4b0e 4671 int start, end, overlaps_p;
06a2c219
GM
4672{
4673 struct glyph *glyph, *last;
4674 int voffset;
ee569018 4675 int glyph_not_available_p;
06a2c219 4676
06a2c219
GM
4677 xassert (s->f == XFRAME (s->w->frame));
4678 xassert (s->nchars == 0);
4679 xassert (start >= 0 && end > start);
4680
66ac4b0e 4681 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4682 glyph = s->row->glyphs[s->area] + start;
4683 last = s->row->glyphs[s->area] + end;
4684 voffset = glyph->voffset;
4685
ee569018
KH
4686 glyph_not_available_p = glyph->glyph_not_available_p;
4687
06a2c219
GM
4688 while (glyph < last
4689 && glyph->type == CHAR_GLYPH
4690 && glyph->voffset == voffset
ee569018
KH
4691 /* Same face id implies same font, nowadays. */
4692 && glyph->face_id == face_id
4693 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4694 {
ee569018
KH
4695 int two_byte_p;
4696
06a2c219 4697 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4698 s->char2b + s->nchars,
4699 &two_byte_p);
4700 s->two_byte_p = two_byte_p;
06a2c219
GM
4701 ++s->nchars;
4702 xassert (s->nchars <= end - start);
4703 s->width += glyph->pixel_width;
4704 ++glyph;
4705 }
4706
4707 s->font = s->face->font;
4708 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4709
4710 /* If the specified font could not be loaded, use the frame's font,
4711 but record the fact that we couldn't load it in
4712 S->font_not_found_p so that we can draw rectangles for the
4713 characters of the glyph string. */
ee569018 4714 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4715 {
4716 s->font_not_found_p = 1;
4717 s->font = FRAME_FONT (s->f);
4718 }
4719
4720 /* Adjust base line for subscript/superscript text. */
4721 s->ybase += voffset;
66ac4b0e 4722
06a2c219
GM
4723 xassert (s->face && s->face->gc);
4724 return glyph - s->row->glyphs[s->area];
07e34cb0 4725}
dc6f92b8 4726
06a2c219
GM
4727
4728/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4729
dfcf069d 4730static void
06a2c219
GM
4731x_fill_image_glyph_string (s)
4732 struct glyph_string *s;
4733{
4734 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4735 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4736 xassert (s->img);
43d120d8 4737 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4738 s->font = s->face->font;
4739 s->width = s->first_glyph->pixel_width;
4740
4741 /* Adjust base line for subscript/superscript text. */
4742 s->ybase += s->first_glyph->voffset;
4743}
4744
4745
209f68d9 4746/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4747
209f68d9
GM
4748 ROW is the glyph row in which the glyphs are found, AREA is the
4749 area within the row. START is the index of the first glyph to
4750 consider, END is the index of the last + 1.
4751
4752 Value is the index of the first glyph not in S. */
4753
4754static int
4755x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4756 struct glyph_string *s;
209f68d9
GM
4757 struct glyph_row *row;
4758 enum glyph_row_area area;
4759 int start, end;
06a2c219 4760{
209f68d9
GM
4761 struct glyph *glyph, *last;
4762 int voffset, face_id;
4763
06a2c219 4764 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4765
4766 glyph = s->row->glyphs[s->area] + start;
4767 last = s->row->glyphs[s->area] + end;
4768 face_id = glyph->face_id;
4769 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4770 s->font = s->face->font;
209f68d9
GM
4771 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4772 s->width = glyph->pixel_width;
4773 voffset = glyph->voffset;
4774
4775 for (++glyph;
4776 (glyph < last
4777 && glyph->type == STRETCH_GLYPH
4778 && glyph->voffset == voffset
4779 && glyph->face_id == face_id);
4780 ++glyph)
4781 s->width += glyph->pixel_width;
06a2c219
GM
4782
4783 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4784 s->ybase += voffset;
4785
c296fc01
GM
4786 /* The case that face->gc == 0 is handled when drawing the glyph
4787 string by calling PREPARE_FACE_FOR_DISPLAY. */
4788 xassert (s->face);
209f68d9 4789 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4790}
4791
4792
4793/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4794 of XChar2b structures for S; it can't be allocated in
4795 x_init_glyph_string because it must be allocated via `alloca'. W
4796 is the window on which S is drawn. ROW and AREA are the glyph row
4797 and area within the row from which S is constructed. START is the
4798 index of the first glyph structure covered by S. HL is a
4799 face-override for drawing S. */
4800
4801static void
4802x_init_glyph_string (s, char2b, w, row, area, start, hl)
4803 struct glyph_string *s;
4804 XChar2b *char2b;
4805 struct window *w;
4806 struct glyph_row *row;
4807 enum glyph_row_area area;
4808 int start;
4809 enum draw_glyphs_face hl;
4810{
4811 bzero (s, sizeof *s);
4812 s->w = w;
4813 s->f = XFRAME (w->frame);
4814 s->display = FRAME_X_DISPLAY (s->f);
4815 s->window = FRAME_X_WINDOW (s->f);
4816 s->char2b = char2b;
4817 s->hl = hl;
4818 s->row = row;
4819 s->area = area;
4820 s->first_glyph = row->glyphs[area] + start;
4821 s->height = row->height;
4822 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4823
9ea173e8
GM
4824 /* Display the internal border below the tool-bar window. */
4825 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4826 s->y -= s->f->output_data.x->internal_border_width;
4827
4828 s->ybase = s->y + row->ascent;
4829}
4830
4831
4832/* Set background width of glyph string S. START is the index of the
4833 first glyph following S. LAST_X is the right-most x-position + 1
4834 in the drawing area. */
4835
4836static INLINE void
4837x_set_glyph_string_background_width (s, start, last_x)
4838 struct glyph_string *s;
4839 int start;
4840 int last_x;
4841{
4842 /* If the face of this glyph string has to be drawn to the end of
4843 the drawing area, set S->extends_to_end_of_line_p. */
4844 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4845
4846 if (start == s->row->used[s->area]
eb79f5cc 4847 && s->area == TEXT_AREA
7b0870b2
GM
4848 && ((s->hl == DRAW_NORMAL_TEXT
4849 && (s->row->fill_line_p
4850 || s->face->background != default_face->background
4851 || s->face->stipple != default_face->stipple
4852 || s->row->mouse_face_p))
327f42ee
GM
4853 || s->hl == DRAW_MOUSE_FACE
4854 || ((s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN)
4855 && s->row->fill_line_p)))
7b0870b2 4856 s->extends_to_end_of_line_p = 1;
06a2c219
GM
4857
4858 /* If S extends its face to the end of the line, set its
4859 background_width to the distance to the right edge of the drawing
4860 area. */
4861 if (s->extends_to_end_of_line_p)
1da3fd71 4862 s->background_width = last_x - s->x + 1;
06a2c219
GM
4863 else
4864 s->background_width = s->width;
4865}
4866
4867
4868/* Add a glyph string for a stretch glyph to the list of strings
4869 between HEAD and TAIL. START is the index of the stretch glyph in
4870 row area AREA of glyph row ROW. END is the index of the last glyph
4871 in that glyph row area. X is the current output position assigned
4872 to the new glyph string constructed. HL overrides that face of the
4873 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4874 is the right-most x-position of the drawing area. */
4875
8abee2e1
DL
4876/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4877 and below -- keep them on one line. */
4878#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4879 do \
4880 { \
4881 s = (struct glyph_string *) alloca (sizeof *s); \
4882 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4883 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4884 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4885 s->x = (X); \
4886 } \
4887 while (0)
4888
4889
4890/* Add a glyph string for an image glyph to the list of strings
4891 between HEAD and TAIL. START is the index of the image glyph in
4892 row area AREA of glyph row ROW. END is the index of the last glyph
4893 in that glyph row area. X is the current output position assigned
4894 to the new glyph string constructed. HL overrides that face of the
4895 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4896 is the right-most x-position of the drawing area. */
4897
8abee2e1 4898#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4899 do \
4900 { \
4901 s = (struct glyph_string *) alloca (sizeof *s); \
4902 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4903 x_fill_image_glyph_string (s); \
4904 x_append_glyph_string (&HEAD, &TAIL, s); \
4905 ++START; \
4906 s->x = (X); \
4907 } \
4908 while (0)
4909
4910
4911/* Add a glyph string for a sequence of character glyphs to the list
4912 of strings between HEAD and TAIL. START is the index of the first
4913 glyph in row area AREA of glyph row ROW that is part of the new
4914 glyph string. END is the index of the last glyph in that glyph row
4915 area. X is the current output position assigned to the new glyph
4916 string constructed. HL overrides that face of the glyph; e.g. it
4917 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4918 right-most x-position of the drawing area. */
4919
8abee2e1 4920#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4921 do \
4922 { \
3e71d8f2 4923 int c, face_id; \
06a2c219
GM
4924 XChar2b *char2b; \
4925 \
43d120d8 4926 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4927 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4928 \
b4192550
KH
4929 s = (struct glyph_string *) alloca (sizeof *s); \
4930 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4931 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4932 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4933 s->x = (X); \
4934 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4935 OVERLAPS_P); \
06a2c219
GM
4936 } \
4937 while (0)
4938
4939
b4192550
KH
4940/* Add a glyph string for a composite sequence to the list of strings
4941 between HEAD and TAIL. START is the index of the first glyph in
4942 row area AREA of glyph row ROW that is part of the new glyph
4943 string. END is the index of the last glyph in that glyph row area.
4944 X is the current output position assigned to the new glyph string
4945 constructed. HL overrides that face of the glyph; e.g. it is
4946 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4947 x-position of the drawing area. */
4948
6c27ec25 4949#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4950 do { \
43d120d8
KH
4951 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4952 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4953 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4954 struct composition *cmp = composition_table[cmp_id]; \
4955 int glyph_len = cmp->glyph_len; \
4956 XChar2b *char2b; \
4957 struct face **faces; \
4958 struct glyph_string *first_s = NULL; \
4959 int n; \
4960 \
ee569018 4961 base_face = base_face->ascii_face; \
b4192550
KH
4962 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4963 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4964 /* At first, fill in `char2b' and `faces'. */ \
4965 for (n = 0; n < glyph_len; n++) \
4966 { \
43d120d8 4967 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4968 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4969 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4970 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
abfb6b46 4971 this_face_id, char2b + n, 1, 1); \
b4192550
KH
4972 } \
4973 \
4974 /* Make glyph_strings for each glyph sequence that is drawable by \
4975 the same face, and append them to HEAD/TAIL. */ \
4976 for (n = 0; n < cmp->glyph_len;) \
4977 { \
4978 s = (struct glyph_string *) alloca (sizeof *s); \
4979 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4980 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4981 s->cmp = cmp; \
4982 s->gidx = n; \
b4192550
KH
4983 s->x = (X); \
4984 \
4985 if (n == 0) \
4986 first_s = s; \
4987 \
4988 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4989 } \
4990 \
4991 ++START; \
4992 s = first_s; \
4993 } while (0)
4994
4995
06a2c219
GM
4996/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4997 of AREA of glyph row ROW on window W between indices START and END.
4998 HL overrides the face for drawing glyph strings, e.g. it is
4999 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
5000 x-positions of the drawing area.
5001
5002 This is an ugly monster macro construct because we must use alloca
5003 to allocate glyph strings (because x_draw_glyphs can be called
5004 asynchronously). */
5005
8abee2e1 5006#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
5007 do \
5008 { \
5009 HEAD = TAIL = NULL; \
5010 while (START < END) \
5011 { \
5012 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
5013 switch (first_glyph->type) \
5014 { \
5015 case CHAR_GLYPH: \
5016 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
5017 TAIL, HL, X, LAST_X, \
5018 OVERLAPS_P); \
06a2c219
GM
5019 break; \
5020 \
b4192550
KH
5021 case COMPOSITE_GLYPH: \
5022 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
5023 HEAD, TAIL, HL, X, LAST_X,\
5024 OVERLAPS_P); \
5025 break; \
5026 \
06a2c219
GM
5027 case STRETCH_GLYPH: \
5028 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
5029 HEAD, TAIL, HL, X, LAST_X); \
5030 break; \
5031 \
5032 case IMAGE_GLYPH: \
5033 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
5034 TAIL, HL, X, LAST_X); \
5035 break; \
5036 \
5037 default: \
5038 abort (); \
5039 } \
5040 \
5041 x_set_glyph_string_background_width (s, START, LAST_X); \
5042 (X) += s->width; \
5043 } \
5044 } \
5045 while (0)
5046
5047
5048/* Draw glyphs between START and END in AREA of ROW on window W,
5049 starting at x-position X. X is relative to AREA in W. HL is a
5050 face-override with the following meaning:
5051
5052 DRAW_NORMAL_TEXT draw normally
5053 DRAW_CURSOR draw in cursor face
5054 DRAW_MOUSE_FACE draw in mouse face.
5055 DRAW_INVERSE_VIDEO draw in mode line face
5056 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
5057 DRAW_IMAGE_RAISED draw an image with a raised relief around it
5058
66ac4b0e
GM
5059 If OVERLAPS_P is non-zero, draw only the foreground of characters
5060 and clip to the physical height of ROW.
5061
06a2c219
GM
5062 Value is the x-position reached, relative to AREA of W. */
5063
5064static int
f0a48a01 5065x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
06a2c219
GM
5066 struct window *w;
5067 int x;
5068 struct glyph_row *row;
5069 enum glyph_row_area area;
5070 int start, end;
5071 enum draw_glyphs_face hl;
66ac4b0e 5072 int overlaps_p;
dc6f92b8 5073{
06a2c219
GM
5074 struct glyph_string *head, *tail;
5075 struct glyph_string *s;
5076 int last_x, area_width;
5077 int x_reached;
5078 int i, j;
5079
5080 /* Let's rather be paranoid than getting a SEGV. */
06a2c219 5081 end = min (end, row->used[area]);
a8710abf
GM
5082 start = max (0, start);
5083 start = min (end, start);
06a2c219
GM
5084
5085 /* Translate X to frame coordinates. Set last_x to the right
5086 end of the drawing area. */
5087 if (row->full_width_p)
5088 {
5089 /* X is relative to the left edge of W, without scroll bars
3f332ef3 5090 or fringes. */
06a2c219 5091 struct frame *f = XFRAME (w->frame);
06a2c219 5092 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 5093
06a2c219
GM
5094 x += window_left_x;
5095 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
5096 last_x = window_left_x + area_width;
5097
5098 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5099 {
110859fc 5100 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
5101 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
5102 last_x += width;
5103 else
5104 x -= width;
5105 }
dc6f92b8 5106
b9432a85 5107 x += FRAME_INTERNAL_BORDER_WIDTH (f);
98fedd97 5108 last_x += FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
5109 }
5110 else
dc6f92b8 5111 {
06a2c219
GM
5112 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
5113 area_width = window_box_width (w, area);
5114 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
5115 }
5116
06a2c219
GM
5117 /* Build a doubly-linked list of glyph_string structures between
5118 head and tail from what we have to draw. Note that the macro
5119 BUILD_GLYPH_STRINGS will modify its start parameter. That's
5120 the reason we use a separate variable `i'. */
5121 i = start;
66ac4b0e
GM
5122 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
5123 overlaps_p);
06a2c219
GM
5124 if (tail)
5125 x_reached = tail->x + tail->background_width;
5126 else
5127 x_reached = x;
90e65f07 5128
06a2c219
GM
5129 /* If there are any glyphs with lbearing < 0 or rbearing > width in
5130 the row, redraw some glyphs in front or following the glyph
5131 strings built above. */
a8710abf 5132 if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
5133 {
5134 int dummy_x = 0;
5135 struct glyph_string *h, *t;
5136
5137 /* Compute overhangs for all glyph strings. */
5138 for (s = head; s; s = s->next)
5139 x_compute_glyph_string_overhangs (s);
5140
5141 /* Prepend glyph strings for glyphs in front of the first glyph
5142 string that are overwritten because of the first glyph
5143 string's left overhang. The background of all strings
5144 prepended must be drawn because the first glyph string
5145 draws over it. */
5146 i = x_left_overwritten (head);
5147 if (i >= 0)
5148 {
5149 j = i;
5150 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
5151 DRAW_NORMAL_TEXT, dummy_x, last_x,
5152 overlaps_p);
06a2c219 5153 start = i;
06a2c219
GM
5154 x_compute_overhangs_and_x (t, head->x, 1);
5155 x_prepend_glyph_string_lists (&head, &tail, h, t);
5156 }
58769bee 5157
06a2c219
GM
5158 /* Prepend glyph strings for glyphs in front of the first glyph
5159 string that overwrite that glyph string because of their
5160 right overhang. For these strings, only the foreground must
5161 be drawn, because it draws over the glyph string at `head'.
5162 The background must not be drawn because this would overwrite
5163 right overhangs of preceding glyphs for which no glyph
5164 strings exist. */
5165 i = x_left_overwriting (head);
5166 if (i >= 0)
5167 {
5168 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
5169 DRAW_NORMAL_TEXT, dummy_x, last_x,
5170 overlaps_p);
06a2c219
GM
5171 for (s = h; s; s = s->next)
5172 s->background_filled_p = 1;
06a2c219
GM
5173 x_compute_overhangs_and_x (t, head->x, 1);
5174 x_prepend_glyph_string_lists (&head, &tail, h, t);
5175 }
dbcb258a 5176
06a2c219
GM
5177 /* Append glyphs strings for glyphs following the last glyph
5178 string tail that are overwritten by tail. The background of
5179 these strings has to be drawn because tail's foreground draws
5180 over it. */
5181 i = x_right_overwritten (tail);
5182 if (i >= 0)
5183 {
5184 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5185 DRAW_NORMAL_TEXT, x, last_x,
5186 overlaps_p);
06a2c219
GM
5187 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5188 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219 5189 }
dc6f92b8 5190
06a2c219
GM
5191 /* Append glyph strings for glyphs following the last glyph
5192 string tail that overwrite tail. The foreground of such
5193 glyphs has to be drawn because it writes into the background
5194 of tail. The background must not be drawn because it could
5195 paint over the foreground of following glyphs. */
5196 i = x_right_overwriting (tail);
5197 if (i >= 0)
5198 {
5199 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5200 DRAW_NORMAL_TEXT, x, last_x,
5201 overlaps_p);
06a2c219
GM
5202 for (s = h; s; s = s->next)
5203 s->background_filled_p = 1;
5204 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5205 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219
GM
5206 }
5207 }
58769bee 5208
06a2c219
GM
5209 /* Draw all strings. */
5210 for (s = head; s; s = s->next)
5211 x_draw_glyph_string (s);
dc6f92b8 5212
bb313871
GM
5213 if (area == TEXT_AREA
5214 && !row->full_width_p
5215 /* When drawing overlapping rows, only the glyph strings'
5216 foreground is drawn, which doesn't erase a cursor
5217 completely. */
5218 && !overlaps_p)
f0a48a01
GM
5219 {
5220 int x0 = head ? head->x : x;
5221 int x1 = tail ? tail->x + tail->background_width : x;
5222
5223 x0 = FRAME_TO_WINDOW_PIXEL_X (w, x0);
5224 x1 = FRAME_TO_WINDOW_PIXEL_X (w, x1);
5225
bb313871 5226 if (XFASTINT (w->left_margin_width) != 0)
f0a48a01
GM
5227 {
5228 int left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
5229 x0 -= left_area_width;
5230 x1 -= left_area_width;
5231 }
5232
60626bab
GM
5233 notice_overwritten_cursor (w, area, x0, x1,
5234 row->y, MATRIX_ROW_BOTTOM_Y (row));
f0a48a01
GM
5235 }
5236
06a2c219
GM
5237 /* Value is the x-position up to which drawn, relative to AREA of W.
5238 This doesn't include parts drawn because of overhangs. */
5239 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
5240 if (!row->full_width_p)
5241 {
f0a48a01 5242 if (area > LEFT_MARGIN_AREA && XFASTINT (w->left_margin_width) != 0)
06a2c219
GM
5243 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
5244 if (area > TEXT_AREA)
5245 x_reached -= window_box_width (w, TEXT_AREA);
5246 }
a8710abf 5247
06a2c219
GM
5248 return x_reached;
5249}
dc6f92b8 5250
dc6f92b8 5251
66ac4b0e
GM
5252/* Fix the display of area AREA of overlapping row ROW in window W. */
5253
5254static void
5255x_fix_overlapping_area (w, row, area)
5256 struct window *w;
5257 struct glyph_row *row;
5258 enum glyph_row_area area;
5259{
5260 int i, x;
5261
5262 BLOCK_INPUT;
5263
5264 if (area == LEFT_MARGIN_AREA)
5265 x = 0;
5266 else if (area == TEXT_AREA)
5267 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5268 else
5269 x = (window_box_width (w, LEFT_MARGIN_AREA)
5270 + window_box_width (w, TEXT_AREA));
5271
5272 for (i = 0; i < row->used[area];)
5273 {
5274 if (row->glyphs[area][i].overlaps_vertically_p)
5275 {
5276 int start = i, start_x = x;
5277
5278 do
5279 {
5280 x += row->glyphs[area][i].pixel_width;
5281 ++i;
5282 }
5283 while (i < row->used[area]
5284 && row->glyphs[area][i].overlaps_vertically_p);
5285
5286 x_draw_glyphs (w, start_x, row, area, start, i,
f0a48a01 5287 DRAW_NORMAL_TEXT, 1);
66ac4b0e
GM
5288 }
5289 else
5290 {
5291 x += row->glyphs[area][i].pixel_width;
5292 ++i;
5293 }
5294 }
5295
5296 UNBLOCK_INPUT;
5297}
5298
5299
06a2c219
GM
5300/* Output LEN glyphs starting at START at the nominal cursor position.
5301 Advance the nominal cursor over the text. The global variable
5302 updated_window contains the window being updated, updated_row is
5303 the glyph row being updated, and updated_area is the area of that
5304 row being updated. */
dc6f92b8 5305
06a2c219
GM
5306static void
5307x_write_glyphs (start, len)
5308 struct glyph *start;
5309 int len;
5310{
f0a48a01 5311 int x, hpos;
d9cdbb3d 5312
06a2c219 5313 xassert (updated_window && updated_row);
dc6f92b8 5314 BLOCK_INPUT;
06a2c219
GM
5315
5316 /* Write glyphs. */
dc6f92b8 5317
06a2c219
GM
5318 hpos = start - updated_row->glyphs[updated_area];
5319 x = x_draw_glyphs (updated_window, output_cursor.x,
5320 updated_row, updated_area,
5321 hpos, hpos + len,
f0a48a01 5322 DRAW_NORMAL_TEXT, 0);
dc6f92b8
JB
5323
5324 UNBLOCK_INPUT;
06a2c219
GM
5325
5326 /* Advance the output cursor. */
5327 output_cursor.hpos += len;
5328 output_cursor.x = x;
dc6f92b8
JB
5329}
5330
0cdd0c9f 5331
06a2c219 5332/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 5333
06a2c219
GM
5334static void
5335x_insert_glyphs (start, len)
5336 struct glyph *start;
5337 register int len;
5338{
5339 struct frame *f;
5340 struct window *w;
5341 int line_height, shift_by_width, shifted_region_width;
5342 struct glyph_row *row;
5343 struct glyph *glyph;
2beb36f9 5344 int frame_x, frame_y, hpos;
58769bee 5345
06a2c219 5346 xassert (updated_window && updated_row);
0cdd0c9f 5347 BLOCK_INPUT;
06a2c219
GM
5348 w = updated_window;
5349 f = XFRAME (WINDOW_FRAME (w));
5350
5351 /* Get the height of the line we are in. */
5352 row = updated_row;
5353 line_height = row->height;
5354
5355 /* Get the width of the glyphs to insert. */
5356 shift_by_width = 0;
5357 for (glyph = start; glyph < start + len; ++glyph)
5358 shift_by_width += glyph->pixel_width;
5359
5360 /* Get the width of the region to shift right. */
5361 shifted_region_width = (window_box_width (w, updated_area)
5362 - output_cursor.x
5363 - shift_by_width);
5364
5365 /* Shift right. */
bf0ab8a2 5366 frame_x = window_box_left (w, updated_area) + output_cursor.x;
06a2c219
GM
5367 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
5368 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5369 f->output_data.x->normal_gc,
5370 frame_x, frame_y,
5371 shifted_region_width, line_height,
5372 frame_x + shift_by_width, frame_y);
5373
5374 /* Write the glyphs. */
5375 hpos = start - row->glyphs[updated_area];
5376 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
f0a48a01 5377 DRAW_NORMAL_TEXT, 0);
06a2c219
GM
5378
5379 /* Advance the output cursor. */
5380 output_cursor.hpos += len;
5381 output_cursor.x += shift_by_width;
0cdd0c9f
RS
5382 UNBLOCK_INPUT;
5383}
0cdd0c9f 5384
0cdd0c9f 5385
06a2c219
GM
5386/* Delete N glyphs at the nominal cursor position. Not implemented
5387 for X frames. */
c83febd7
RS
5388
5389static void
06a2c219
GM
5390x_delete_glyphs (n)
5391 register int n;
c83febd7 5392{
06a2c219 5393 abort ();
c83febd7
RS
5394}
5395
0cdd0c9f 5396
c5e6e06b
GM
5397/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
5398 If they are <= 0, this is probably an error. */
5399
5400void
5401x_clear_area (dpy, window, x, y, width, height, exposures)
5402 Display *dpy;
5403 Window window;
5404 int x, y;
5405 int width, height;
5406 int exposures;
5407{
5408 xassert (width > 0 && height > 0);
5409 XClearArea (dpy, window, x, y, width, height, exposures);
5410}
5411
5412
06a2c219
GM
5413/* Erase the current text line from the nominal cursor position
5414 (inclusive) to pixel column TO_X (exclusive). The idea is that
5415 everything from TO_X onward is already erased.
5416
5417 TO_X is a pixel position relative to updated_area of
5418 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 5419
06a2c219
GM
5420static void
5421x_clear_end_of_line (to_x)
5422 int to_x;
5423{
5424 struct frame *f;
5425 struct window *w = updated_window;
5426 int max_x, min_y, max_y;
5427 int from_x, from_y, to_y;
5428
5429 xassert (updated_window && updated_row);
5430 f = XFRAME (w->frame);
5431
5432 if (updated_row->full_width_p)
5433 {
5434 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
5435 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5436 && !w->pseudo_window_p)
5437 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 5438 }
06a2c219
GM
5439 else
5440 max_x = window_box_width (w, updated_area);
5441 max_y = window_text_bottom_y (w);
dc6f92b8 5442
06a2c219
GM
5443 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5444 of window. For TO_X > 0, truncate to end of drawing area. */
5445 if (to_x == 0)
5446 return;
5447 else if (to_x < 0)
5448 to_x = max_x;
5449 else
5450 to_x = min (to_x, max_x);
dbc4e1c1 5451
06a2c219
GM
5452 to_y = min (max_y, output_cursor.y + updated_row->height);
5453
5454 /* Notice if the cursor will be cleared by this operation. */
5455 if (!updated_row->full_width_p)
60626bab
GM
5456 notice_overwritten_cursor (w, updated_area,
5457 output_cursor.x, -1,
5458 updated_row->y,
5459 MATRIX_ROW_BOTTOM_Y (updated_row));
dbc4e1c1 5460
06a2c219
GM
5461 from_x = output_cursor.x;
5462
5463 /* Translate to frame coordinates. */
5464 if (updated_row->full_width_p)
5465 {
5466 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5467 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5468 }
0cdd0c9f
RS
5469 else
5470 {
06a2c219
GM
5471 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5472 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5473 }
5474
045dee35 5475 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5476 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5477 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5478
5479 /* Prevent inadvertently clearing to end of the X window. */
5480 if (to_x > from_x && to_y > from_y)
5481 {
5482 BLOCK_INPUT;
c5e6e06b
GM
5483 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5484 from_x, from_y, to_x - from_x, to_y - from_y,
5485 False);
06a2c219 5486 UNBLOCK_INPUT;
0cdd0c9f 5487 }
0cdd0c9f 5488}
dbc4e1c1 5489
0cdd0c9f 5490
06a2c219 5491/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5492 frame. Otherwise clear the selected frame. */
06a2c219
GM
5493
5494static void
5495x_clear_frame ()
0cdd0c9f 5496{
06a2c219 5497 struct frame *f;
0cdd0c9f 5498
06a2c219
GM
5499 if (updating_frame)
5500 f = updating_frame;
0cdd0c9f 5501 else
b86bd3dd 5502 f = SELECTED_FRAME ();
58769bee 5503
06a2c219
GM
5504 /* Clearing the frame will erase any cursor, so mark them all as no
5505 longer visible. */
5506 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5507 output_cursor.hpos = output_cursor.vpos = 0;
5508 output_cursor.x = -1;
5509
5510 /* We don't set the output cursor here because there will always
5511 follow an explicit cursor_to. */
5512 BLOCK_INPUT;
5513 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5514
5515 /* We have to clear the scroll bars, too. If we have changed
5516 colors or something like that, then they should be notified. */
5517 x_scroll_bar_clear (f);
0cdd0c9f 5518
06a2c219
GM
5519 XFlush (FRAME_X_DISPLAY (f));
5520 UNBLOCK_INPUT;
dc6f92b8 5521}
06a2c219
GM
5522
5523
dc6f92b8 5524\f
dbc4e1c1
JB
5525/* Invert the middle quarter of the frame for .15 sec. */
5526
06a2c219
GM
5527/* We use the select system call to do the waiting, so we have to make
5528 sure it's available. If it isn't, we just won't do visual bells. */
5529
dbc4e1c1
JB
5530#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5531
06a2c219
GM
5532
5533/* Subtract the `struct timeval' values X and Y, storing the result in
5534 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5535
5536static int
5537timeval_subtract (result, x, y)
5538 struct timeval *result, x, y;
5539{
06a2c219
GM
5540 /* Perform the carry for the later subtraction by updating y. This
5541 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5542 if (x.tv_usec < y.tv_usec)
5543 {
5544 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5545 y.tv_usec -= 1000000 * nsec;
5546 y.tv_sec += nsec;
5547 }
06a2c219 5548
dbc4e1c1
JB
5549 if (x.tv_usec - y.tv_usec > 1000000)
5550 {
5551 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5552 y.tv_usec += 1000000 * nsec;
5553 y.tv_sec -= nsec;
5554 }
5555
06a2c219
GM
5556 /* Compute the time remaining to wait. tv_usec is certainly
5557 positive. */
dbc4e1c1
JB
5558 result->tv_sec = x.tv_sec - y.tv_sec;
5559 result->tv_usec = x.tv_usec - y.tv_usec;
5560
06a2c219
GM
5561 /* Return indication of whether the result should be considered
5562 negative. */
dbc4e1c1
JB
5563 return x.tv_sec < y.tv_sec;
5564}
dc6f92b8 5565
dfcf069d 5566void
f676886a
JB
5567XTflash (f)
5568 struct frame *f;
dc6f92b8 5569{
dbc4e1c1 5570 BLOCK_INPUT;
dc6f92b8 5571
dbc4e1c1
JB
5572 {
5573 GC gc;
dc6f92b8 5574
06a2c219
GM
5575 /* Create a GC that will use the GXxor function to flip foreground
5576 pixels into background pixels. */
dbc4e1c1
JB
5577 {
5578 XGCValues values;
dc6f92b8 5579
dbc4e1c1 5580 values.function = GXxor;
7556890b
RS
5581 values.foreground = (f->output_data.x->foreground_pixel
5582 ^ f->output_data.x->background_pixel);
58769bee 5583
334208b7 5584 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5585 GCFunction | GCForeground, &values);
5586 }
dc6f92b8 5587
dbc4e1c1 5588 {
e84e14c3
RS
5589 /* Get the height not including a menu bar widget. */
5590 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5591 /* Height of each line to flash. */
5592 int flash_height = FRAME_LINE_HEIGHT (f);
5593 /* These will be the left and right margins of the rectangles. */
5594 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5595 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5596
5597 int width;
5598
5599 /* Don't flash the area between a scroll bar and the frame
5600 edge it is next to. */
5601 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5602 {
5603 case vertical_scroll_bar_left:
5604 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5605 break;
5606
5607 case vertical_scroll_bar_right:
5608 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5609 break;
06a2c219
GM
5610
5611 default:
5612 break;
e84e14c3
RS
5613 }
5614
5615 width = flash_right - flash_left;
5616
5617 /* If window is tall, flash top and bottom line. */
5618 if (height > 3 * FRAME_LINE_HEIGHT (f))
5619 {
5620 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5621 flash_left,
5622 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5623 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5624 width, flash_height);
5625 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5626 flash_left,
5627 (height - flash_height
5628 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5629 width, flash_height);
5630 }
5631 else
5632 /* If it is short, flash it all. */
5633 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5634 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5635 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5636
06a2c219 5637 x_flush (f);
dc6f92b8 5638
dbc4e1c1 5639 {
06a2c219 5640 struct timeval wakeup;
dc6f92b8 5641
66c30ea1 5642 EMACS_GET_TIME (wakeup);
dc6f92b8 5643
dbc4e1c1
JB
5644 /* Compute time to wait until, propagating carry from usecs. */
5645 wakeup.tv_usec += 150000;
5646 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5647 wakeup.tv_usec %= 1000000;
5648
101922c3
GM
5649 /* Keep waiting until past the time wakeup or any input gets
5650 available. */
5651 while (! detect_input_pending ())
dbc4e1c1 5652 {
101922c3 5653 struct timeval current;
dbc4e1c1
JB
5654 struct timeval timeout;
5655
101922c3 5656 EMACS_GET_TIME (current);
dbc4e1c1 5657
101922c3
GM
5658 /* Break if result would be negative. */
5659 if (timeval_subtract (&current, wakeup, current))
dbc4e1c1
JB
5660 break;
5661
101922c3
GM
5662 /* How long `select' should wait. */
5663 timeout.tv_sec = 0;
5664 timeout.tv_usec = 10000;
5665
dbc4e1c1 5666 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5667 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5668 }
5669 }
58769bee 5670
e84e14c3
RS
5671 /* If window is tall, flash top and bottom line. */
5672 if (height > 3 * FRAME_LINE_HEIGHT (f))
5673 {
5674 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5675 flash_left,
5676 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5677 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5678 width, flash_height);
5679 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5680 flash_left,
5681 (height - flash_height
5682 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5683 width, flash_height);
5684 }
5685 else
5686 /* If it is short, flash it all. */
5687 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5688 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5689 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5690
334208b7 5691 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5692 x_flush (f);
dc6f92b8 5693 }
dbc4e1c1
JB
5694 }
5695
5696 UNBLOCK_INPUT;
dc6f92b8
JB
5697}
5698
06a2c219 5699#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5700
5701
dc6f92b8
JB
5702/* Make audible bell. */
5703
dfcf069d 5704void
dc6f92b8
JB
5705XTring_bell ()
5706{
b86bd3dd
GM
5707 struct frame *f = SELECTED_FRAME ();
5708
5709 if (FRAME_X_DISPLAY (f))
5710 {
dbc4e1c1 5711#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5712 if (visible_bell)
5713 XTflash (f);
5714 else
dbc4e1c1 5715#endif
b86bd3dd
GM
5716 {
5717 BLOCK_INPUT;
5718 XBell (FRAME_X_DISPLAY (f), 0);
5719 XFlush (FRAME_X_DISPLAY (f));
5720 UNBLOCK_INPUT;
5721 }
dc6f92b8
JB
5722 }
5723}
06a2c219 5724
dc6f92b8 5725\f
06a2c219
GM
5726/* Specify how many text lines, from the top of the window,
5727 should be affected by insert-lines and delete-lines operations.
5728 This, and those operations, are used only within an update
5729 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5730
dfcf069d 5731static void
06a2c219
GM
5732XTset_terminal_window (n)
5733 register int n;
dc6f92b8 5734{
06a2c219 5735 /* This function intentionally left blank. */
dc6f92b8
JB
5736}
5737
06a2c219
GM
5738
5739\f
5740/***********************************************************************
5741 Line Dance
5742 ***********************************************************************/
5743
5744/* Perform an insert-lines or delete-lines operation, inserting N
5745 lines or deleting -N lines at vertical position VPOS. */
5746
dfcf069d 5747static void
06a2c219
GM
5748x_ins_del_lines (vpos, n)
5749 int vpos, n;
dc6f92b8
JB
5750{
5751 abort ();
5752}
06a2c219
GM
5753
5754
5755/* Scroll part of the display as described by RUN. */
dc6f92b8 5756
dfcf069d 5757static void
06a2c219
GM
5758x_scroll_run (w, run)
5759 struct window *w;
5760 struct run *run;
dc6f92b8 5761{
06a2c219
GM
5762 struct frame *f = XFRAME (w->frame);
5763 int x, y, width, height, from_y, to_y, bottom_y;
5764
5765 /* Get frame-relative bounding box of the text display area of W,
3f332ef3
KS
5766 without mode lines. Include in this box the left and right
5767 fringe of W. */
06a2c219 5768 window_box (w, -1, &x, &y, &width, &height);
3f332ef3
KS
5769 width += FRAME_X_FRINGE_WIDTH (f);
5770 x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
06a2c219
GM
5771
5772 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5773 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5774 bottom_y = y + height;
dc6f92b8 5775
06a2c219
GM
5776 if (to_y < from_y)
5777 {
5778 /* Scrolling up. Make sure we don't copy part of the mode
5779 line at the bottom. */
5780 if (from_y + run->height > bottom_y)
5781 height = bottom_y - from_y;
5782 else
5783 height = run->height;
5784 }
dc6f92b8 5785 else
06a2c219
GM
5786 {
5787 /* Scolling down. Make sure we don't copy over the mode line.
5788 at the bottom. */
5789 if (to_y + run->height > bottom_y)
5790 height = bottom_y - to_y;
5791 else
5792 height = run->height;
5793 }
7a13e894 5794
06a2c219
GM
5795 BLOCK_INPUT;
5796
5797 /* Cursor off. Will be switched on again in x_update_window_end. */
5798 updated_window = w;
5799 x_clear_cursor (w);
5800
5801 XCopyArea (FRAME_X_DISPLAY (f),
5802 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5803 f->output_data.x->normal_gc,
5804 x, from_y,
5805 width, height,
5806 x, to_y);
5807
5808 UNBLOCK_INPUT;
5809}
dc6f92b8 5810
dc6f92b8 5811
06a2c219
GM
5812\f
5813/***********************************************************************
5814 Exposure Events
5815 ***********************************************************************/
5816
5817/* Redisplay an exposed area of frame F. X and Y are the upper-left
5818 corner of the exposed rectangle. W and H are width and height of
5819 the exposed area. All are pixel values. W or H zero means redraw
5820 the entire frame. */
dc6f92b8 5821
06a2c219
GM
5822static void
5823expose_frame (f, x, y, w, h)
5824 struct frame *f;
5825 int x, y, w, h;
dc6f92b8 5826{
06a2c219 5827 XRectangle r;
82f053ab 5828 int mouse_face_overwritten_p = 0;
dc6f92b8 5829
06a2c219 5830 TRACE ((stderr, "expose_frame "));
dc6f92b8 5831
06a2c219
GM
5832 /* No need to redraw if frame will be redrawn soon. */
5833 if (FRAME_GARBAGED_P (f))
dc6f92b8 5834 {
06a2c219
GM
5835 TRACE ((stderr, " garbaged\n"));
5836 return;
5837 }
5838
5839 /* If basic faces haven't been realized yet, there is no point in
5840 trying to redraw anything. This can happen when we get an expose
5841 event while Emacs is starting, e.g. by moving another window. */
5842 if (FRAME_FACE_CACHE (f) == NULL
5843 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5844 {
5845 TRACE ((stderr, " no faces\n"));
5846 return;
58769bee 5847 }
06a2c219
GM
5848
5849 if (w == 0 || h == 0)
58769bee 5850 {
06a2c219
GM
5851 r.x = r.y = 0;
5852 r.width = CANON_X_UNIT (f) * f->width;
5853 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5854 }
5855 else
5856 {
06a2c219
GM
5857 r.x = x;
5858 r.y = y;
5859 r.width = w;
5860 r.height = h;
5861 }
5862
5863 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
82f053ab 5864 mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
06a2c219 5865
9ea173e8 5866 if (WINDOWP (f->tool_bar_window))
82f053ab
GM
5867 mouse_face_overwritten_p
5868 |= expose_window (XWINDOW (f->tool_bar_window), &r);
06a2c219
GM
5869
5870#ifndef USE_X_TOOLKIT
5871 if (WINDOWP (f->menu_bar_window))
82f053ab
GM
5872 mouse_face_overwritten_p
5873 |= expose_window (XWINDOW (f->menu_bar_window), &r);
06a2c219 5874#endif /* not USE_X_TOOLKIT */
82f053ab
GM
5875
5876 /* Some window managers support a focus-follows-mouse style with
5877 delayed raising of frames. Imagine a partially obscured frame,
5878 and moving the mouse into partially obscured mouse-face on that
5879 frame. The visible part of the mouse-face will be highlighted,
5880 then the WM raises the obscured frame. With at least one WM, KDE
5881 2.1, Emacs is not getting any event for the raising of the frame
5882 (even tried with SubstructureRedirectMask), only Expose events.
5883 These expose events will draw text normally, i.e. not
5884 highlighted. Which means we must redo the highlight here.
5885 Subsume it under ``we love X''. --gerd 2001-08-15 */
5886 if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
5887 {
5888 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5889 if (f == dpyinfo->mouse_face_mouse_frame)
5890 {
5891 int x = dpyinfo->mouse_face_mouse_x;
5892 int y = dpyinfo->mouse_face_mouse_y;
5893 clear_mouse_face (dpyinfo);
5894 note_mouse_highlight (f, x, y);
5895 }
5896 }
dc6f92b8
JB
5897}
5898
06a2c219
GM
5899
5900/* Redraw (parts) of all windows in the window tree rooted at W that
82f053ab
GM
5901 intersect R. R contains frame pixel coordinates. Value is
5902 non-zero if the exposure overwrites mouse-face. */
06a2c219 5903
82f053ab 5904static int
06a2c219
GM
5905expose_window_tree (w, r)
5906 struct window *w;
5907 XRectangle *r;
dc6f92b8 5908{
82f053ab
GM
5909 struct frame *f = XFRAME (w->frame);
5910 int mouse_face_overwritten_p = 0;
5911
5912 while (w && !FRAME_GARBAGED_P (f))
06a2c219
GM
5913 {
5914 if (!NILP (w->hchild))
82f053ab
GM
5915 mouse_face_overwritten_p
5916 |= expose_window_tree (XWINDOW (w->hchild), r);
06a2c219 5917 else if (!NILP (w->vchild))
82f053ab
GM
5918 mouse_face_overwritten_p
5919 |= expose_window_tree (XWINDOW (w->vchild), r);
5920 else
5921 mouse_face_overwritten_p |= expose_window (w, r);
5922
a02f1be0 5923 w = NILP (w->next) ? NULL : XWINDOW (w->next);
06a2c219 5924 }
82f053ab
GM
5925
5926 return mouse_face_overwritten_p;
06a2c219 5927}
58769bee 5928
dc6f92b8 5929
06a2c219
GM
5930/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5931 which intersects rectangle R. R is in window-relative coordinates. */
5932
5933static void
5934expose_area (w, row, r, area)
5935 struct window *w;
5936 struct glyph_row *row;
5937 XRectangle *r;
5938 enum glyph_row_area area;
5939{
06a2c219
GM
5940 struct glyph *first = row->glyphs[area];
5941 struct glyph *end = row->glyphs[area] + row->used[area];
5942 struct glyph *last;
4bc6dcc7 5943 int first_x, start_x, x;
06a2c219 5944
6fb13182
GM
5945 if (area == TEXT_AREA && row->fill_line_p)
5946 /* If row extends face to end of line write the whole line. */
153f5ed7 5947 x_draw_glyphs (w, 0, row, area, 0, row->used[area],
f0a48a01 5948 DRAW_NORMAL_TEXT, 0);
6fb13182
GM
5949 else
5950 {
4bc6dcc7
GM
5951 /* Set START_X to the window-relative start position for drawing glyphs of
5952 AREA. The first glyph of the text area can be partially visible.
5953 The first glyphs of other areas cannot. */
5954 if (area == LEFT_MARGIN_AREA)
5955 start_x = 0;
5956 else if (area == TEXT_AREA)
5957 start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5958 else
5959 start_x = (window_box_width (w, LEFT_MARGIN_AREA)
5960 + window_box_width (w, TEXT_AREA));
5961 x = start_x;
5962
6fb13182
GM
5963 /* Find the first glyph that must be redrawn. */
5964 while (first < end
5965 && x + first->pixel_width < r->x)
5966 {
5967 x += first->pixel_width;
5968 ++first;
5969 }
5970
5971 /* Find the last one. */
5972 last = first;
5973 first_x = x;
5974 while (last < end
5975 && x < r->x + r->width)
5976 {
5977 x += last->pixel_width;
5978 ++last;
5979 }
5980
5981 /* Repaint. */
5982 if (last > first)
4bc6dcc7 5983 x_draw_glyphs (w, first_x - start_x, row, area,
6fb13182
GM
5984 first - row->glyphs[area],
5985 last - row->glyphs[area],
f0a48a01 5986 DRAW_NORMAL_TEXT, 0);
6fb13182 5987 }
06a2c219
GM
5988}
5989
58769bee 5990
06a2c219 5991/* Redraw the parts of the glyph row ROW on window W intersecting
82f053ab
GM
5992 rectangle R. R is in window-relative coordinates. Value is
5993 non-zero if mouse-face was overwritten. */
dc6f92b8 5994
82f053ab 5995static int
06a2c219
GM
5996expose_line (w, row, r)
5997 struct window *w;
5998 struct glyph_row *row;
5999 XRectangle *r;
6000{
6001 xassert (row->enabled_p);
6002
6003 if (row->mode_line_p || w->pseudo_window_p)
6004 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
f0a48a01 6005 DRAW_NORMAL_TEXT, 0);
06a2c219
GM
6006 else
6007 {
6008 if (row->used[LEFT_MARGIN_AREA])
6009 expose_area (w, row, r, LEFT_MARGIN_AREA);
6010 if (row->used[TEXT_AREA])
6011 expose_area (w, row, r, TEXT_AREA);
6012 if (row->used[RIGHT_MARGIN_AREA])
6013 expose_area (w, row, r, RIGHT_MARGIN_AREA);
3f332ef3 6014 x_draw_row_fringe_bitmaps (w, row);
06a2c219 6015 }
82f053ab
GM
6016
6017 return row->mouse_face_p;
06a2c219 6018}
dc6f92b8 6019
58769bee 6020
06a2c219
GM
6021/* Return non-zero if W's cursor intersects rectangle R. */
6022
6023static int
6024x_phys_cursor_in_rect_p (w, r)
6025 struct window *w;
6026 XRectangle *r;
6027{
6028 XRectangle cr, result;
6029 struct glyph *cursor_glyph;
6030
6031 cursor_glyph = get_phys_cursor_glyph (w);
6032 if (cursor_glyph)
6033 {
6034 cr.x = w->phys_cursor.x;
6035 cr.y = w->phys_cursor.y;
6036 cr.width = cursor_glyph->pixel_width;
6037 cr.height = w->phys_cursor_height;
6038 return x_intersect_rectangles (&cr, r, &result);
6039 }
6040 else
6041 return 0;
dc6f92b8 6042}
dc6f92b8 6043
06a2c219 6044
a02f1be0
GM
6045/* Redraw the part of window W intersection rectangle FR. Pixel
6046 coordinates in FR are frame-relative. Call this function with
82f053ab
GM
6047 input blocked. Value is non-zero if the exposure overwrites
6048 mouse-face. */
dc6f92b8 6049
a39202f6 6050static int
a02f1be0 6051expose_window (w, fr)
06a2c219 6052 struct window *w;
a02f1be0 6053 XRectangle *fr;
dc6f92b8 6054{
a02f1be0 6055 struct frame *f = XFRAME (w->frame);
a02f1be0 6056 XRectangle wr, r;
82f053ab 6057 int mouse_face_overwritten_p = 0;
dc6f92b8 6058
80c32bcc
GM
6059 /* If window is not yet fully initialized, do nothing. This can
6060 happen when toolkit scroll bars are used and a window is split.
6061 Reconfiguring the scroll bar will generate an expose for a newly
6062 created window. */
a39202f6 6063 if (w->current_matrix == NULL)
82f053ab 6064 return 0;
a39202f6
GM
6065
6066 /* When we're currently updating the window, display and current
6067 matrix usually don't agree. Arrange for a thorough display
6068 later. */
6069 if (w == updated_window)
6070 {
6071 SET_FRAME_GARBAGED (f);
6072 return 0;
6073 }
80c32bcc 6074
a39202f6 6075 /* Frame-relative pixel rectangle of W. */
a02f1be0
GM
6076 wr.x = XFASTINT (w->left) * CANON_X_UNIT (f);
6077 wr.y = XFASTINT (w->top) * CANON_Y_UNIT (f);
6078 wr.width = XFASTINT (w->width) * CANON_X_UNIT (f);
6079 wr.height = XFASTINT (w->height) * CANON_Y_UNIT (f);
6080
a39202f6
GM
6081 if (x_intersect_rectangles (fr, &wr, &r))
6082 {
6083 int yb = window_text_bottom_y (w);
6084 struct glyph_row *row;
6085 int cursor_cleared_p;
a02f1be0 6086
a39202f6
GM
6087 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
6088 r.x, r.y, r.width, r.height));
dc6f92b8 6089
a39202f6
GM
6090 /* Convert to window coordinates. */
6091 r.x = FRAME_TO_WINDOW_PIXEL_X (w, r.x);
6092 r.y = FRAME_TO_WINDOW_PIXEL_Y (w, r.y);
dc6f92b8 6093
a39202f6
GM
6094 /* Turn off the cursor. */
6095 if (!w->pseudo_window_p
6096 && x_phys_cursor_in_rect_p (w, &r))
6097 {
6098 x_clear_cursor (w);
6099 cursor_cleared_p = 1;
6100 }
6101 else
6102 cursor_cleared_p = 0;
06a2c219 6103
a39202f6
GM
6104 /* Find the first row intersecting the rectangle R. */
6105 for (row = w->current_matrix->rows;
6106 row->enabled_p;
6107 ++row)
6108 {
6109 int y0 = row->y;
6110 int y1 = MATRIX_ROW_BOTTOM_Y (row);
6111
6112 if ((y0 >= r.y && y0 < r.y + r.height)
6113 || (y1 > r.y && y1 < r.y + r.height)
6114 || (r.y >= y0 && r.y < y1)
6115 || (r.y + r.height > y0 && r.y + r.height < y1))
82f053ab
GM
6116 {
6117 if (expose_line (w, row, &r))
6118 mouse_face_overwritten_p = 1;
6119 }
6120
a39202f6
GM
6121 if (y1 >= yb)
6122 break;
6123 }
dc6f92b8 6124
a39202f6
GM
6125 /* Display the mode line if there is one. */
6126 if (WINDOW_WANTS_MODELINE_P (w)
6127 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
6128 row->enabled_p)
6129 && row->y < r.y + r.height)
82f053ab
GM
6130 {
6131 if (expose_line (w, row, &r))
6132 mouse_face_overwritten_p = 1;
6133 }
a39202f6
GM
6134
6135 if (!w->pseudo_window_p)
6136 {
6137 /* Draw border between windows. */
6138 x_draw_vertical_border (w);
06a2c219 6139
a39202f6
GM
6140 /* Turn the cursor on again. */
6141 if (cursor_cleared_p)
6142 x_update_window_cursor (w, 1);
6143 }
06a2c219 6144 }
82f053ab
GM
6145
6146 return mouse_face_overwritten_p;
06a2c219 6147}
dc6f92b8 6148
dc6f92b8 6149
06a2c219
GM
6150/* Determine the intersection of two rectangles R1 and R2. Return
6151 the intersection in *RESULT. Value is non-zero if RESULT is not
6152 empty. */
6153
6154static int
6155x_intersect_rectangles (r1, r2, result)
6156 XRectangle *r1, *r2, *result;
6157{
6158 XRectangle *left, *right;
6159 XRectangle *upper, *lower;
6160 int intersection_p = 0;
6161
6162 /* Rearrange so that R1 is the left-most rectangle. */
6163 if (r1->x < r2->x)
6164 left = r1, right = r2;
6165 else
6166 left = r2, right = r1;
6167
6168 /* X0 of the intersection is right.x0, if this is inside R1,
6169 otherwise there is no intersection. */
6170 if (right->x <= left->x + left->width)
6171 {
6172 result->x = right->x;
6173
6174 /* The right end of the intersection is the minimum of the
6175 the right ends of left and right. */
6176 result->width = (min (left->x + left->width, right->x + right->width)
6177 - result->x);
6178
6179 /* Same game for Y. */
6180 if (r1->y < r2->y)
6181 upper = r1, lower = r2;
6182 else
6183 upper = r2, lower = r1;
6184
6185 /* The upper end of the intersection is lower.y0, if this is inside
6186 of upper. Otherwise, there is no intersection. */
6187 if (lower->y <= upper->y + upper->height)
dc43ef94 6188 {
06a2c219
GM
6189 result->y = lower->y;
6190
6191 /* The lower end of the intersection is the minimum of the lower
6192 ends of upper and lower. */
6193 result->height = (min (lower->y + lower->height,
6194 upper->y + upper->height)
6195 - result->y);
6196 intersection_p = 1;
dc43ef94 6197 }
dc6f92b8
JB
6198 }
6199
06a2c219 6200 return intersection_p;
dc6f92b8 6201}
06a2c219
GM
6202
6203
6204
6205
dc6f92b8 6206\f
dc6f92b8 6207static void
334208b7
RS
6208frame_highlight (f)
6209 struct frame *f;
dc6f92b8 6210{
b3e1e05c
JB
6211 /* We used to only do this if Vx_no_window_manager was non-nil, but
6212 the ICCCM (section 4.1.6) says that the window's border pixmap
6213 and border pixel are window attributes which are "private to the
6214 client", so we can always change it to whatever we want. */
6215 BLOCK_INPUT;
334208b7 6216 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6217 f->output_data.x->border_pixel);
b3e1e05c 6218 UNBLOCK_INPUT;
5d46f928 6219 x_update_cursor (f, 1);
dc6f92b8
JB
6220}
6221
6222static void
334208b7
RS
6223frame_unhighlight (f)
6224 struct frame *f;
dc6f92b8 6225{
b3e1e05c
JB
6226 /* We used to only do this if Vx_no_window_manager was non-nil, but
6227 the ICCCM (section 4.1.6) says that the window's border pixmap
6228 and border pixel are window attributes which are "private to the
6229 client", so we can always change it to whatever we want. */
6230 BLOCK_INPUT;
334208b7 6231 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6232 f->output_data.x->border_tile);
b3e1e05c 6233 UNBLOCK_INPUT;
5d46f928 6234 x_update_cursor (f, 1);
dc6f92b8 6235}
dc6f92b8 6236
f676886a
JB
6237/* The focus has changed. Update the frames as necessary to reflect
6238 the new situation. Note that we can't change the selected frame
c5acd733 6239 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 6240 Each event gets marked with the frame in which it occurred, so the
c5acd733 6241 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 6242
6d4238f3 6243static void
0f941935
KH
6244x_new_focus_frame (dpyinfo, frame)
6245 struct x_display_info *dpyinfo;
f676886a 6246 struct frame *frame;
dc6f92b8 6247{
0f941935 6248 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 6249
0f941935 6250 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 6251 {
58769bee 6252 /* Set this before calling other routines, so that they see
f676886a 6253 the correct value of x_focus_frame. */
0f941935 6254 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
6255
6256 if (old_focus && old_focus->auto_lower)
f676886a 6257 x_lower_frame (old_focus);
dc6f92b8
JB
6258
6259#if 0
f676886a 6260 selected_frame = frame;
e0c1aef2
KH
6261 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6262 selected_frame);
f676886a
JB
6263 Fselect_window (selected_frame->selected_window);
6264 choose_minibuf_frame ();
c118dd06 6265#endif /* ! 0 */
dc6f92b8 6266
0f941935
KH
6267 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6268 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
6269 else
6270 pending_autoraise_frame = 0;
6d4238f3 6271 }
dc6f92b8 6272
0f941935 6273 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
6274}
6275
37c2c98b
RS
6276/* Handle an event saying the mouse has moved out of an Emacs frame. */
6277
6278void
0f941935
KH
6279x_mouse_leave (dpyinfo)
6280 struct x_display_info *dpyinfo;
37c2c98b 6281{
0f941935 6282 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 6283}
6d4238f3 6284
f451eb13
JB
6285/* The focus has changed, or we have redirected a frame's focus to
6286 another frame (this happens when a frame uses a surrogate
06a2c219 6287 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
6288
6289 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 6290 frame is being highlighted or un-highlighted; we only use it to find
0f941935 6291 the appropriate X display info. */
06a2c219 6292
6d4238f3 6293static void
0f941935
KH
6294XTframe_rehighlight (frame)
6295 struct frame *frame;
6d4238f3 6296{
0f941935
KH
6297 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6298}
6d4238f3 6299
0f941935
KH
6300static void
6301x_frame_rehighlight (dpyinfo)
6302 struct x_display_info *dpyinfo;
6303{
6304 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6305
6306 if (dpyinfo->x_focus_frame)
6d4238f3 6307 {
0f941935
KH
6308 dpyinfo->x_highlight_frame
6309 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6310 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6311 : dpyinfo->x_focus_frame);
6312 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 6313 {
0f941935
KH
6314 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6315 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 6316 }
dc6f92b8 6317 }
6d4238f3 6318 else
0f941935 6319 dpyinfo->x_highlight_frame = 0;
dc6f92b8 6320
0f941935 6321 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
6322 {
6323 if (old_highlight)
f676886a 6324 frame_unhighlight (old_highlight);
0f941935
KH
6325 if (dpyinfo->x_highlight_frame)
6326 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 6327 }
dc6f92b8 6328}
06a2c219
GM
6329
6330
dc6f92b8 6331\f
06a2c219 6332/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 6333
28430d3c
JB
6334/* Initialize mode_switch_bit and modifier_meaning. */
6335static void
334208b7
RS
6336x_find_modifier_meanings (dpyinfo)
6337 struct x_display_info *dpyinfo;
28430d3c 6338{
f689eb05 6339 int min_code, max_code;
28430d3c
JB
6340 KeySym *syms;
6341 int syms_per_code;
6342 XModifierKeymap *mods;
6343
334208b7
RS
6344 dpyinfo->meta_mod_mask = 0;
6345 dpyinfo->shift_lock_mask = 0;
6346 dpyinfo->alt_mod_mask = 0;
6347 dpyinfo->super_mod_mask = 0;
6348 dpyinfo->hyper_mod_mask = 0;
58769bee 6349
9658a521 6350#ifdef HAVE_X11R4
334208b7 6351 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 6352#else
4a60f8c5
RS
6353 min_code = dpyinfo->display->min_keycode;
6354 max_code = dpyinfo->display->max_keycode;
9658a521
JB
6355#endif
6356
334208b7 6357 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
6358 min_code, max_code - min_code + 1,
6359 &syms_per_code);
334208b7 6360 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 6361
58769bee 6362 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 6363 Alt keysyms are on. */
28430d3c 6364 {
06a2c219 6365 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
6366
6367 for (row = 3; row < 8; row++)
6368 for (col = 0; col < mods->max_keypermod; col++)
6369 {
0299d313
RS
6370 KeyCode code
6371 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 6372
af92970c
KH
6373 /* Zeroes are used for filler. Skip them. */
6374 if (code == 0)
6375 continue;
6376
28430d3c
JB
6377 /* Are any of this keycode's keysyms a meta key? */
6378 {
6379 int code_col;
6380
6381 for (code_col = 0; code_col < syms_per_code; code_col++)
6382 {
f689eb05 6383 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 6384
f689eb05 6385 switch (sym)
28430d3c 6386 {
f689eb05
JB
6387 case XK_Meta_L:
6388 case XK_Meta_R:
334208b7 6389 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 6390 break;
f689eb05
JB
6391
6392 case XK_Alt_L:
6393 case XK_Alt_R:
334208b7 6394 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
6395 break;
6396
6397 case XK_Hyper_L:
6398 case XK_Hyper_R:
334208b7 6399 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
6400 break;
6401
6402 case XK_Super_L:
6403 case XK_Super_R:
334208b7 6404 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 6405 break;
11edeb03
JB
6406
6407 case XK_Shift_Lock:
6408 /* Ignore this if it's not on the lock modifier. */
6409 if ((1 << row) == LockMask)
334208b7 6410 dpyinfo->shift_lock_mask = LockMask;
11edeb03 6411 break;
28430d3c
JB
6412 }
6413 }
6414 }
6415 }
6416 }
6417
f689eb05 6418 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 6419 if (! dpyinfo->meta_mod_mask)
a3c44b14 6420 {
334208b7
RS
6421 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6422 dpyinfo->alt_mod_mask = 0;
a3c44b14 6423 }
f689eb05 6424
148c4b70
RS
6425 /* If some keys are both alt and meta,
6426 make them just meta, not alt. */
334208b7 6427 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 6428 {
334208b7 6429 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 6430 }
58769bee 6431
28430d3c 6432 XFree ((char *) syms);
f689eb05 6433 XFreeModifiermap (mods);
28430d3c
JB
6434}
6435
dfeccd2d
JB
6436/* Convert between the modifier bits X uses and the modifier bits
6437 Emacs uses. */
06a2c219 6438
7c5283e4 6439static unsigned int
334208b7
RS
6440x_x_to_emacs_modifiers (dpyinfo, state)
6441 struct x_display_info *dpyinfo;
dc6f92b8
JB
6442 unsigned int state;
6443{
98659da6
KG
6444 EMACS_UINT mod_meta = meta_modifier;
6445 EMACS_UINT mod_alt = alt_modifier;
6446 EMACS_UINT mod_hyper = hyper_modifier;
6447 EMACS_UINT mod_super = super_modifier;
6448 Lisp_Object tem;
6449
6450 tem = Fget (Vx_alt_keysym, Qmodifier_value);
6451 if (! EQ (tem, Qnil)) mod_alt = XUINT (tem);
6452 tem = Fget (Vx_meta_keysym, Qmodifier_value);
6453 if (! EQ (tem, Qnil)) mod_meta = XUINT (tem);
6454 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
6455 if (! EQ (tem, Qnil)) mod_hyper = XUINT (tem);
6456 tem = Fget (Vx_super_keysym, Qmodifier_value);
6457 if (! EQ (tem, Qnil)) mod_super = XUINT (tem);
6458
6459
334208b7 6460 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
98659da6
KG
6461 | ((state & ControlMask) ? ctrl_modifier : 0)
6462 | ((state & dpyinfo->meta_mod_mask) ? mod_meta : 0)
6463 | ((state & dpyinfo->alt_mod_mask) ? mod_alt : 0)
6464 | ((state & dpyinfo->super_mod_mask) ? mod_super : 0)
6465 | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0));
dc6f92b8
JB
6466}
6467
dfeccd2d 6468static unsigned int
334208b7
RS
6469x_emacs_to_x_modifiers (dpyinfo, state)
6470 struct x_display_info *dpyinfo;
dfeccd2d
JB
6471 unsigned int state;
6472{
98659da6
KG
6473 EMACS_UINT mod_meta = meta_modifier;
6474 EMACS_UINT mod_alt = alt_modifier;
6475 EMACS_UINT mod_hyper = hyper_modifier;
6476 EMACS_UINT mod_super = super_modifier;
6477
6478 Lisp_Object tem;
6479
6480 tem = Fget (Vx_alt_keysym, Qmodifier_value);
6481 if (! EQ (tem, Qnil)) mod_alt = XUINT (tem);
6482 tem = Fget (Vx_meta_keysym, Qmodifier_value);
6483 if (! EQ (tem, Qnil)) mod_meta = XUINT (tem);
6484 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
6485 if (! EQ (tem, Qnil)) mod_hyper = XUINT (tem);
6486 tem = Fget (Vx_super_keysym, Qmodifier_value);
6487 if (! EQ (tem, Qnil)) mod_super = XUINT (tem);
6488
6489
6490 return ( ((state & mod_alt) ? dpyinfo->alt_mod_mask : 0)
6491 | ((state & mod_super) ? dpyinfo->super_mod_mask : 0)
6492 | ((state & mod_hyper) ? dpyinfo->hyper_mod_mask : 0)
6493 | ((state & shift_modifier) ? ShiftMask : 0)
6494 | ((state & ctrl_modifier) ? ControlMask : 0)
6495 | ((state & mod_meta) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6496}
d047c4eb
KH
6497
6498/* Convert a keysym to its name. */
6499
6500char *
6501x_get_keysym_name (keysym)
6502 KeySym keysym;
6503{
6504 char *value;
6505
6506 BLOCK_INPUT;
6507 value = XKeysymToString (keysym);
6508 UNBLOCK_INPUT;
6509
6510 return value;
6511}
06a2c219
GM
6512
6513
e4571a43
JB
6514\f
6515/* Mouse clicks and mouse movement. Rah. */
e4571a43 6516
06a2c219
GM
6517/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6518 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6519 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6520 not force the value into range. */
69388238 6521
c8dba240 6522void
69388238 6523pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6524 FRAME_PTR f;
69388238 6525 register int pix_x, pix_y;
e4571a43
JB
6526 register int *x, *y;
6527 XRectangle *bounds;
69388238 6528 int noclip;
e4571a43 6529{
06a2c219 6530 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6531 even for negative values. */
6532 if (pix_x < 0)
7556890b 6533 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6534 if (pix_y < 0)
7556890b 6535 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6536
e4571a43
JB
6537 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6538 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6539
6540 if (bounds)
6541 {
7556890b
RS
6542 bounds->width = FONT_WIDTH (f->output_data.x->font);
6543 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6544 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6545 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6546 }
6547
69388238
RS
6548 if (!noclip)
6549 {
6550 if (pix_x < 0)
6551 pix_x = 0;
3cbd2e0b
RS
6552 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6553 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6554
6555 if (pix_y < 0)
6556 pix_y = 0;
6557 else if (pix_y > f->height)
6558 pix_y = f->height;
6559 }
e4571a43
JB
6560
6561 *x = pix_x;
6562 *y = pix_y;
6563}
6564
06a2c219
GM
6565
6566/* Given HPOS/VPOS in the current matrix of W, return corresponding
6567 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6568 can't tell the positions because W's display is not up to date,
6569 return 0. */
6570
6571int
6572glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6573 struct window *w;
6574 int hpos, vpos;
6575 int *frame_x, *frame_y;
2b5c9e71 6576{
06a2c219
GM
6577 int success_p;
6578
6579 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6580 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6581
6582 if (display_completed)
6583 {
6584 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6585 struct glyph *glyph = row->glyphs[TEXT_AREA];
6586 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6587
6588 *frame_y = row->y;
6589 *frame_x = row->x;
6590 while (glyph < end)
6591 {
6592 *frame_x += glyph->pixel_width;
6593 ++glyph;
6594 }
6595
6596 success_p = 1;
6597 }
6598 else
6599 {
6600 *frame_y = *frame_x = 0;
6601 success_p = 0;
6602 }
6603
6604 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6605 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6606 return success_p;
2b5c9e71
RS
6607}
6608
06a2c219 6609
dc6f92b8
JB
6610/* Prepare a mouse-event in *RESULT for placement in the input queue.
6611
6612 If the event is a button press, then note that we have grabbed
f451eb13 6613 the mouse. */
dc6f92b8
JB
6614
6615static Lisp_Object
f451eb13 6616construct_mouse_click (result, event, f)
dc6f92b8
JB
6617 struct input_event *result;
6618 XButtonEvent *event;
f676886a 6619 struct frame *f;
dc6f92b8 6620{
f451eb13 6621 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6622 otherwise. */
f451eb13 6623 result->kind = mouse_click;
69388238 6624 result->code = event->button - Button1;
1113d9db 6625 result->timestamp = event->time;
334208b7
RS
6626 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6627 event->state)
f689eb05 6628 | (event->type == ButtonRelease
58769bee 6629 ? up_modifier
f689eb05 6630 : down_modifier));
dc6f92b8 6631
06a2c219
GM
6632 XSETINT (result->x, event->x);
6633 XSETINT (result->y, event->y);
6634 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6635 result->arg = Qnil;
06a2c219 6636 return Qnil;
dc6f92b8 6637}
b849c413 6638
69388238 6639\f
90e65f07
JB
6640/* Function to report a mouse movement to the mainstream Emacs code.
6641 The input handler calls this.
6642
6643 We have received a mouse movement event, which is given in *event.
6644 If the mouse is over a different glyph than it was last time, tell
6645 the mainstream emacs code by setting mouse_moved. If not, ask for
6646 another motion event, so we can check again the next time it moves. */
b8009dd1 6647
06a2c219
GM
6648static XMotionEvent last_mouse_motion_event;
6649static Lisp_Object last_mouse_motion_frame;
6650
90e65f07 6651static void
12ba150f 6652note_mouse_movement (frame, event)
f676886a 6653 FRAME_PTR frame;
90e65f07 6654 XMotionEvent *event;
90e65f07 6655{
e5d77022 6656 last_mouse_movement_time = event->time;
06a2c219
GM
6657 last_mouse_motion_event = *event;
6658 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6659
27f338af
RS
6660 if (event->window != FRAME_X_WINDOW (frame))
6661 {
39d8bb4d 6662 frame->mouse_moved = 1;
27f338af 6663 last_mouse_scroll_bar = Qnil;
27f338af 6664 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6665 }
6666
90e65f07 6667 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6668 else if (event->x < last_mouse_glyph.x
6669 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6670 || event->y < last_mouse_glyph.y
6671 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6672 {
39d8bb4d 6673 frame->mouse_moved = 1;
ab648270 6674 last_mouse_scroll_bar = Qnil;
b8009dd1 6675 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6676 }
6677}
6678
06a2c219
GM
6679\f
6680/************************************************************************
6681 Mouse Face
6682 ************************************************************************/
6683
6684/* Find the glyph under window-relative coordinates X/Y in window W.
6685 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6686 strings. Return in *HPOS and *VPOS the row and column number of
6687 the glyph found. Return in *AREA the glyph area containing X.
6688 Value is a pointer to the glyph found or null if X/Y is not on
6689 text, or we can't tell because W's current matrix is not up to
6690 date. */
6691
6692static struct glyph *
f9db2310 6693x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
06a2c219
GM
6694 struct window *w;
6695 int x, y;
6696 int *hpos, *vpos, *area;
f9db2310 6697 int buffer_only_p;
06a2c219
GM
6698{
6699 struct glyph *glyph, *end;
3e71d8f2 6700 struct glyph_row *row = NULL;
06a2c219
GM
6701 int x0, i, left_area_width;
6702
6703 /* Find row containing Y. Give up if some row is not enabled. */
6704 for (i = 0; i < w->current_matrix->nrows; ++i)
6705 {
6706 row = MATRIX_ROW (w->current_matrix, i);
6707 if (!row->enabled_p)
6708 return NULL;
6709 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6710 break;
6711 }
6712
6713 *vpos = i;
6714 *hpos = 0;
6715
6716 /* Give up if Y is not in the window. */
6717 if (i == w->current_matrix->nrows)
6718 return NULL;
6719
6720 /* Get the glyph area containing X. */
6721 if (w->pseudo_window_p)
6722 {
6723 *area = TEXT_AREA;
6724 x0 = 0;
6725 }
6726 else
6727 {
6728 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6729 if (x < left_area_width)
6730 {
6731 *area = LEFT_MARGIN_AREA;
6732 x0 = 0;
6733 }
6734 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6735 {
6736 *area = TEXT_AREA;
6737 x0 = row->x + left_area_width;
6738 }
6739 else
6740 {
6741 *area = RIGHT_MARGIN_AREA;
6742 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6743 }
6744 }
6745
6746 /* Find glyph containing X. */
6747 glyph = row->glyphs[*area];
6748 end = glyph + row->used[*area];
6749 while (glyph < end)
6750 {
6751 if (x < x0 + glyph->pixel_width)
6752 {
6753 if (w->pseudo_window_p)
6754 break;
f9db2310 6755 else if (!buffer_only_p || BUFFERP (glyph->object))
06a2c219
GM
6756 break;
6757 }
6758
6759 x0 += glyph->pixel_width;
6760 ++glyph;
6761 }
6762
6763 if (glyph == end)
6764 return NULL;
6765
6766 *hpos = glyph - row->glyphs[*area];
6767 return glyph;
6768}
6769
6770
6771/* Convert frame-relative x/y to coordinates relative to window W.
6772 Takes pseudo-windows into account. */
6773
6774static void
6775frame_to_window_pixel_xy (w, x, y)
6776 struct window *w;
6777 int *x, *y;
6778{
6779 if (w->pseudo_window_p)
6780 {
6781 /* A pseudo-window is always full-width, and starts at the
6782 left edge of the frame, plus a frame border. */
6783 struct frame *f = XFRAME (w->frame);
6784 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6785 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6786 }
6787 else
6788 {
6789 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6790 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6791 }
6792}
6793
6794
b436feb6
GM
6795/* Take proper action when mouse has moved to the mode or header line
6796 or marginal area of window W, x-position X and y-position Y. Area
6797 is 1, 3, 6 or 7 for the mode line, header line, left and right
6798 marginal area respectively. X is relative to the start of the text
6799 display area of W, so the width of bitmap areas and scroll bars
6800 must be subtracted to get a position relative to the start of the
6801 mode line. */
6802
06a2c219 6803static void
b436feb6 6804note_mode_line_or_margin_highlight (w, x, y, portion)
06a2c219 6805 struct window *w;
b436feb6 6806 int x, y, portion;
06a2c219
GM
6807{
6808 struct frame *f = XFRAME (w->frame);
6809 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6810 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6811 struct glyph_row *row;
b436feb6
GM
6812 int i, area, charpos;
6813 Lisp_Object string, help, map, pos;
06a2c219 6814
b436feb6
GM
6815 if (portion == 1 || portion == 3)
6816 string = mode_line_string (w, x, y, portion == 1, &charpos);
6817 else
6818 string = marginal_area_string (w, x, y, portion, &charpos);
e371a781 6819
b436feb6 6820 if (STRINGP (string))
06a2c219 6821 {
b436feb6 6822 pos = make_number (charpos);
e371a781 6823
b436feb6
GM
6824 /* If we're on a string with `help-echo' text property, arrange
6825 for the help to be displayed. This is done by setting the
6826 global variable help_echo to the help string. */
6827 help = Fget_text_property (pos, Qhelp_echo, string);
6828 if (!NILP (help))
06a2c219 6829 {
b436feb6
GM
6830 help_echo = help;
6831 XSETWINDOW (help_echo_window, w);
6832 help_echo_object = string;
6833 help_echo_pos = charpos;
06a2c219
GM
6834 }
6835
b436feb6
GM
6836 /* Change the mouse pointer according to what is under X/Y. */
6837 map = Fget_text_property (pos, Qlocal_map, string);
6838 if (!KEYMAPP (map))
6839 map = Fget_text_property (pos, Qkeymap, string);
6840 if (KEYMAPP (map))
6841 cursor = f->output_data.x->nontext_cursor;
06a2c219 6842 }
b436feb6 6843
06a2c219
GM
6844 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6845}
6846
6847
6848/* Take proper action when the mouse has moved to position X, Y on
6849 frame F as regards highlighting characters that have mouse-face
6850 properties. Also de-highlighting chars where the mouse was before.
27f338af 6851 X and Y can be negative or out of range. */
b8009dd1
RS
6852
6853static void
6854note_mouse_highlight (f, x, y)
06a2c219 6855 struct frame *f;
c32cdd9a 6856 int x, y;
b8009dd1 6857{
06a2c219
GM
6858 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6859 int portion;
b8009dd1
RS
6860 Lisp_Object window;
6861 struct window *w;
0d487c52
GM
6862 Cursor cursor = None;
6863 struct buffer *b;
b8009dd1 6864
06a2c219
GM
6865 /* When a menu is active, don't highlight because this looks odd. */
6866#ifdef USE_X_TOOLKIT
6867 if (popup_activated ())
6868 return;
6869#endif
6870
66301061 6871 if (NILP (Vmouse_highlight)
04fff9c0 6872 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6873 return;
6874
06a2c219
GM
6875 dpyinfo->mouse_face_mouse_x = x;
6876 dpyinfo->mouse_face_mouse_y = y;
6877 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6878
06a2c219 6879 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6880 return;
6881
514e4681
RS
6882 if (gc_in_progress)
6883 {
06a2c219 6884 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6885 return;
6886 }
6887
b8009dd1 6888 /* Which window is that in? */
06a2c219 6889 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6890
6891 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6892 if (! EQ (window, dpyinfo->mouse_face_window))
6893 clear_mouse_face (dpyinfo);
6894
6895 /* Not on a window -> return. */
6896 if (!WINDOWP (window))
6897 return;
6898
6899 /* Convert to window-relative pixel coordinates. */
6900 w = XWINDOW (window);
6901 frame_to_window_pixel_xy (w, &x, &y);
6902
9ea173e8 6903 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6904 buffer. */
9ea173e8 6905 if (EQ (window, f->tool_bar_window))
06a2c219 6906 {
9ea173e8 6907 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6908 return;
6909 }
6910
b436feb6
GM
6911 /* Mouse is on the mode, header line or margin? */
6912 if (portion == 1 || portion == 3 || portion == 6 || portion == 7)
06a2c219 6913 {
b436feb6 6914 note_mode_line_or_margin_highlight (w, x, y, portion);
06a2c219
GM
6915 return;
6916 }
0d487c52
GM
6917
6918 if (portion == 2)
6919 cursor = f->output_data.x->horizontal_drag_cursor;
06a2c219 6920 else
0d487c52 6921 cursor = f->output_data.x->text_cursor;
b8009dd1 6922
0cdd0c9f
RS
6923 /* Are we in a window whose display is up to date?
6924 And verify the buffer's text has not changed. */
0d487c52 6925 b = XBUFFER (w->buffer);
06a2c219
GM
6926 if (/* Within text portion of the window. */
6927 portion == 0
0cdd0c9f 6928 && EQ (w->window_end_valid, w->buffer)
0d487c52
GM
6929 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
6930 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
b8009dd1 6931 {
06a2c219
GM
6932 int hpos, vpos, pos, i, area;
6933 struct glyph *glyph;
f9db2310 6934 Lisp_Object object;
0d487c52
GM
6935 Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
6936 Lisp_Object *overlay_vec = NULL;
6937 int len, noverlays;
6938 struct buffer *obuf;
6939 int obegv, ozv, same_region;
b8009dd1 6940
06a2c219 6941 /* Find the glyph under X/Y. */
f9db2310 6942 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
06a2c219
GM
6943
6944 /* Clear mouse face if X/Y not over text. */
6945 if (glyph == NULL
6946 || area != TEXT_AREA
6947 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6948 {
fa262c07
GM
6949 if (clear_mouse_face (dpyinfo))
6950 cursor = None;
6951 goto set_cursor;
06a2c219
GM
6952 }
6953
6954 pos = glyph->charpos;
f9db2310
GM
6955 object = glyph->object;
6956 if (!STRINGP (object) && !BUFFERP (object))
fa262c07 6957 goto set_cursor;
06a2c219 6958
0d487c52
GM
6959 /* If we get an out-of-range value, return now; avoid an error. */
6960 if (BUFFERP (object) && pos > BUF_Z (b))
fa262c07 6961 goto set_cursor;
06a2c219 6962
0d487c52
GM
6963 /* Make the window's buffer temporarily current for
6964 overlays_at and compute_char_face. */
6965 obuf = current_buffer;
6966 current_buffer = b;
6967 obegv = BEGV;
6968 ozv = ZV;
6969 BEGV = BEG;
6970 ZV = Z;
06a2c219 6971
0d487c52
GM
6972 /* Is this char mouse-active or does it have help-echo? */
6973 position = make_number (pos);
f9db2310 6974
0d487c52
GM
6975 if (BUFFERP (object))
6976 {
6977 /* Put all the overlays we want in a vector in overlay_vec.
6978 Store the length in len. If there are more than 10, make
6979 enough space for all, and try again. */
6980 len = 10;
6981 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6982 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
6983 if (noverlays > len)
6984 {
6985 len = noverlays;
6986 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6987 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
6988 }
f8349001 6989
0d487c52
GM
6990 /* Sort overlays into increasing priority order. */
6991 noverlays = sort_overlays (overlay_vec, noverlays, w);
6992 }
6993 else
6994 noverlays = 0;
6995
6996 same_region = (EQ (window, dpyinfo->mouse_face_window)
6997 && vpos >= dpyinfo->mouse_face_beg_row
6998 && vpos <= dpyinfo->mouse_face_end_row
6999 && (vpos > dpyinfo->mouse_face_beg_row
7000 || hpos >= dpyinfo->mouse_face_beg_col)
7001 && (vpos < dpyinfo->mouse_face_end_row
7002 || hpos < dpyinfo->mouse_face_end_col
7003 || dpyinfo->mouse_face_past_end));
7004
7005 if (same_region)
7006 cursor = None;
7007
7008 /* Check mouse-face highlighting. */
7009 if (! same_region
7010 /* If there exists an overlay with mouse-face overlapping
7011 the one we are currently highlighting, we have to
7012 check if we enter the overlapping overlay, and then
7013 highlight only that. */
7014 || (OVERLAYP (dpyinfo->mouse_face_overlay)
7015 && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
7016 {
0d487c52
GM
7017 /* Find the highest priority overlay that has a mouse-face
7018 property. */
7019 overlay = Qnil;
7020 for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
7021 {
7022 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
7023 if (!NILP (mouse_face))
7024 overlay = overlay_vec[i];
7025 }
8bd189fb
GM
7026
7027 /* If we're actually highlighting the same overlay as
7028 before, there's no need to do that again. */
7029 if (!NILP (overlay)
7030 && EQ (overlay, dpyinfo->mouse_face_overlay))
7031 goto check_help_echo;
f9db2310 7032
8bd189fb
GM
7033 dpyinfo->mouse_face_overlay = overlay;
7034
7035 /* Clear the display of the old active region, if any. */
7036 if (clear_mouse_face (dpyinfo))
7037 cursor = None;
7038
0d487c52
GM
7039 /* If no overlay applies, get a text property. */
7040 if (NILP (overlay))
7041 mouse_face = Fget_text_property (position, Qmouse_face, object);
06a2c219 7042
0d487c52
GM
7043 /* Handle the overlay case. */
7044 if (!NILP (overlay))
7045 {
7046 /* Find the range of text around this char that
7047 should be active. */
7048 Lisp_Object before, after;
7049 int ignore;
7050
7051 before = Foverlay_start (overlay);
7052 after = Foverlay_end (overlay);
7053 /* Record this as the current active region. */
7054 fast_find_position (w, XFASTINT (before),
7055 &dpyinfo->mouse_face_beg_col,
7056 &dpyinfo->mouse_face_beg_row,
7057 &dpyinfo->mouse_face_beg_x,
7e376260
GM
7058 &dpyinfo->mouse_face_beg_y, Qnil);
7059
0d487c52
GM
7060 dpyinfo->mouse_face_past_end
7061 = !fast_find_position (w, XFASTINT (after),
7062 &dpyinfo->mouse_face_end_col,
7063 &dpyinfo->mouse_face_end_row,
7064 &dpyinfo->mouse_face_end_x,
7e376260 7065 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7066 dpyinfo->mouse_face_window = window;
7067 dpyinfo->mouse_face_face_id
7068 = face_at_buffer_position (w, pos, 0, 0,
7069 &ignore, pos + 1, 1);
7070
7071 /* Display it as active. */
7072 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7073 cursor = None;
0d487c52
GM
7074 }
7075 /* Handle the text property case. */
7076 else if (!NILP (mouse_face) && BUFFERP (object))
7077 {
7078 /* Find the range of text around this char that
7079 should be active. */
7080 Lisp_Object before, after, beginning, end;
7081 int ignore;
7082
7083 beginning = Fmarker_position (w->start);
7084 end = make_number (BUF_Z (XBUFFER (object))
7085 - XFASTINT (w->window_end_pos));
7086 before
7087 = Fprevious_single_property_change (make_number (pos + 1),
7088 Qmouse_face,
7089 object, beginning);
7090 after
7091 = Fnext_single_property_change (position, Qmouse_face,
7092 object, end);
7093
7094 /* Record this as the current active region. */
7095 fast_find_position (w, XFASTINT (before),
7096 &dpyinfo->mouse_face_beg_col,
7097 &dpyinfo->mouse_face_beg_row,
7098 &dpyinfo->mouse_face_beg_x,
7e376260 7099 &dpyinfo->mouse_face_beg_y, Qnil);
0d487c52
GM
7100 dpyinfo->mouse_face_past_end
7101 = !fast_find_position (w, XFASTINT (after),
7102 &dpyinfo->mouse_face_end_col,
7103 &dpyinfo->mouse_face_end_row,
7104 &dpyinfo->mouse_face_end_x,
7e376260 7105 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7106 dpyinfo->mouse_face_window = window;
7107
7108 if (BUFFERP (object))
06a2c219
GM
7109 dpyinfo->mouse_face_face_id
7110 = face_at_buffer_position (w, pos, 0, 0,
7111 &ignore, pos + 1, 1);
7112
0d487c52
GM
7113 /* Display it as active. */
7114 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7115 cursor = None;
0d487c52
GM
7116 }
7117 else if (!NILP (mouse_face) && STRINGP (object))
7118 {
7119 Lisp_Object b, e;
7120 int ignore;
f9db2310 7121
0d487c52
GM
7122 b = Fprevious_single_property_change (make_number (pos + 1),
7123 Qmouse_face,
7124 object, Qnil);
7125 e = Fnext_single_property_change (position, Qmouse_face,
7126 object, Qnil);
7127 if (NILP (b))
7128 b = make_number (0);
7129 if (NILP (e))
7130 e = make_number (XSTRING (object)->size - 1);
7131 fast_find_string_pos (w, XINT (b), object,
06a2c219
GM
7132 &dpyinfo->mouse_face_beg_col,
7133 &dpyinfo->mouse_face_beg_row,
7134 &dpyinfo->mouse_face_beg_x,
0d487c52
GM
7135 &dpyinfo->mouse_face_beg_y, 0);
7136 fast_find_string_pos (w, XINT (e), object,
7137 &dpyinfo->mouse_face_end_col,
7138 &dpyinfo->mouse_face_end_row,
7139 &dpyinfo->mouse_face_end_x,
7140 &dpyinfo->mouse_face_end_y, 1);
7141 dpyinfo->mouse_face_past_end = 0;
7142 dpyinfo->mouse_face_window = window;
7143 dpyinfo->mouse_face_face_id
7144 = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
7145 glyph->face_id, 1);
7146 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7147 cursor = None;
0d487c52 7148 }
7e376260
GM
7149 else if (STRINGP (object) && NILP (mouse_face))
7150 {
7151 /* A string which doesn't have mouse-face, but
7152 the text ``under'' it might have. */
7153 struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
7154 int start = MATRIX_ROW_START_CHARPOS (r);
7155
7156 pos = string_buffer_position (w, object, start);
7157 if (pos > 0)
7158 mouse_face = get_char_property_and_overlay (make_number (pos),
7159 Qmouse_face,
7160 w->buffer,
7161 &overlay);
7162 if (!NILP (mouse_face) && !NILP (overlay))
7163 {
7164 Lisp_Object before = Foverlay_start (overlay);
7165 Lisp_Object after = Foverlay_end (overlay);
91c153e2 7166 int ignore;
7e376260
GM
7167
7168 /* Note that we might not be able to find position
7169 BEFORE in the glyph matrix if the overlay is
7170 entirely covered by a `display' property. In
7171 this case, we overshoot. So let's stop in
7172 the glyph matrix before glyphs for OBJECT. */
7173 fast_find_position (w, XFASTINT (before),
7174 &dpyinfo->mouse_face_beg_col,
7175 &dpyinfo->mouse_face_beg_row,
7176 &dpyinfo->mouse_face_beg_x,
7177 &dpyinfo->mouse_face_beg_y,
7178 object);
7179
7180 dpyinfo->mouse_face_past_end
7181 = !fast_find_position (w, XFASTINT (after),
7182 &dpyinfo->mouse_face_end_col,
7183 &dpyinfo->mouse_face_end_row,
7184 &dpyinfo->mouse_face_end_x,
7185 &dpyinfo->mouse_face_end_y,
7186 Qnil);
7187 dpyinfo->mouse_face_window = window;
7188 dpyinfo->mouse_face_face_id
7189 = face_at_buffer_position (w, pos, 0, 0,
7190 &ignore, pos + 1, 1);
7191
7192 /* Display it as active. */
7193 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
7194 cursor = None;
7195 }
7196 }
0d487c52 7197 }
06a2c219 7198
8bd189fb
GM
7199 check_help_echo:
7200
0d487c52
GM
7201 /* Look for a `help-echo' property. */
7202 {
7203 Lisp_Object help, overlay;
06a2c219 7204
0d487c52
GM
7205 /* Check overlays first. */
7206 help = overlay = Qnil;
7207 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
7208 {
7209 overlay = overlay_vec[i];
7210 help = Foverlay_get (overlay, Qhelp_echo);
7211 }
be010514 7212
0d487c52
GM
7213 if (!NILP (help))
7214 {
7215 help_echo = help;
7216 help_echo_window = window;
7217 help_echo_object = overlay;
7218 help_echo_pos = pos;
7219 }
7220 else
7221 {
7222 Lisp_Object object = glyph->object;
7223 int charpos = glyph->charpos;
7177d86b 7224
0d487c52
GM
7225 /* Try text properties. */
7226 if (STRINGP (object)
7227 && charpos >= 0
7228 && charpos < XSTRING (object)->size)
7229 {
7230 help = Fget_text_property (make_number (charpos),
7231 Qhelp_echo, object);
7232 if (NILP (help))
7233 {
7234 /* If the string itself doesn't specify a help-echo,
7235 see if the buffer text ``under'' it does. */
7236 struct glyph_row *r
7237 = MATRIX_ROW (w->current_matrix, vpos);
7238 int start = MATRIX_ROW_START_CHARPOS (r);
7239 int pos = string_buffer_position (w, object, start);
7240 if (pos > 0)
7241 {
7e376260 7242 help = Fget_char_property (make_number (pos),
0d487c52
GM
7243 Qhelp_echo, w->buffer);
7244 if (!NILP (help))
7245 {
7246 charpos = pos;
7247 object = w->buffer;
7248 }
7249 }
7250 }
7251 }
7252 else if (BUFFERP (object)
7253 && charpos >= BEGV
7254 && charpos < ZV)
7255 help = Fget_text_property (make_number (charpos), Qhelp_echo,
7256 object);
06a2c219 7257
0d487c52
GM
7258 if (!NILP (help))
7259 {
7260 help_echo = help;
7261 help_echo_window = window;
7262 help_echo_object = object;
7263 help_echo_pos = charpos;
7264 }
7265 }
06a2c219 7266 }
0d487c52
GM
7267
7268 BEGV = obegv;
7269 ZV = ozv;
7270 current_buffer = obuf;
06a2c219 7271 }
0d487c52 7272
fa262c07
GM
7273 set_cursor:
7274
0d487c52
GM
7275 if (cursor != None)
7276 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
06a2c219
GM
7277}
7278
7279static void
7280redo_mouse_highlight ()
7281{
7282 if (!NILP (last_mouse_motion_frame)
7283 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
7284 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
7285 last_mouse_motion_event.x,
7286 last_mouse_motion_event.y);
7287}
7288
7289
7290\f
7291/***********************************************************************
9ea173e8 7292 Tool-bars
06a2c219
GM
7293 ***********************************************************************/
7294
9ea173e8
GM
7295static int x_tool_bar_item P_ ((struct frame *, int, int,
7296 struct glyph **, int *, int *, int *));
06a2c219 7297
9ea173e8 7298/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
7299 or -1. */
7300
9ea173e8 7301static int last_tool_bar_item;
06a2c219
GM
7302
7303
9ea173e8
GM
7304/* Get information about the tool-bar item at position X/Y on frame F.
7305 Return in *GLYPH a pointer to the glyph of the tool-bar item in
7306 the current matrix of the tool-bar window of F, or NULL if not
7307 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
8daf1204 7308 item in F->tool_bar_items. Value is
06a2c219 7309
9ea173e8 7310 -1 if X/Y is not on a tool-bar item
06a2c219
GM
7311 0 if X/Y is on the same item that was highlighted before.
7312 1 otherwise. */
7313
7314static int
9ea173e8 7315x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
7316 struct frame *f;
7317 int x, y;
7318 struct glyph **glyph;
7319 int *hpos, *vpos, *prop_idx;
7320{
7321 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7322 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7323 int area;
7324
7325 /* Find the glyph under X/Y. */
f9db2310 7326 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
06a2c219
GM
7327 if (*glyph == NULL)
7328 return -1;
7329
9ea173e8 7330 /* Get the start of this tool-bar item's properties in
8daf1204 7331 f->tool_bar_items. */
9ea173e8 7332 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
7333 return -1;
7334
7335 /* Is mouse on the highlighted item? */
9ea173e8 7336 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
7337 && *vpos >= dpyinfo->mouse_face_beg_row
7338 && *vpos <= dpyinfo->mouse_face_end_row
7339 && (*vpos > dpyinfo->mouse_face_beg_row
7340 || *hpos >= dpyinfo->mouse_face_beg_col)
7341 && (*vpos < dpyinfo->mouse_face_end_row
7342 || *hpos < dpyinfo->mouse_face_end_col
7343 || dpyinfo->mouse_face_past_end))
7344 return 0;
7345
7346 return 1;
7347}
7348
7349
9ea173e8 7350/* Handle mouse button event on the tool-bar of frame F, at
6c4a22e6 7351 frame-relative coordinates X/Y. EVENT_TYPE is either ButtonPress
06a2c219
GM
7352 or ButtonRelase. */
7353
7354static void
9ea173e8 7355x_handle_tool_bar_click (f, button_event)
06a2c219
GM
7356 struct frame *f;
7357 XButtonEvent *button_event;
7358{
7359 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7360 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7361 int hpos, vpos, prop_idx;
7362 struct glyph *glyph;
7363 Lisp_Object enabled_p;
7364 int x = button_event->x;
7365 int y = button_event->y;
7366
9ea173e8 7367 /* If not on the highlighted tool-bar item, return. */
06a2c219 7368 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 7369 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
7370 return;
7371
7372 /* If item is disabled, do nothing. */
8daf1204 7373 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7374 if (NILP (enabled_p))
7375 return;
7376
7377 if (button_event->type == ButtonPress)
7378 {
7379 /* Show item in pressed state. */
7380 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
7381 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 7382 last_tool_bar_item = prop_idx;
06a2c219
GM
7383 }
7384 else
7385 {
7386 Lisp_Object key, frame;
7387 struct input_event event;
7388
7389 /* Show item in released state. */
7390 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
7391 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
7392
8daf1204 7393 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
06a2c219
GM
7394
7395 XSETFRAME (frame, f);
9ea173e8 7396 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7397 event.frame_or_window = frame;
7398 event.arg = frame;
06a2c219
GM
7399 kbd_buffer_store_event (&event);
7400
9ea173e8 7401 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7402 event.frame_or_window = frame;
7403 event.arg = key;
06a2c219
GM
7404 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7405 button_event->state);
7406 kbd_buffer_store_event (&event);
9ea173e8 7407 last_tool_bar_item = -1;
06a2c219
GM
7408 }
7409}
7410
7411
9ea173e8
GM
7412/* Possibly highlight a tool-bar item on frame F when mouse moves to
7413 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
7414 note_mouse_highlight. */
7415
7416static void
9ea173e8 7417note_tool_bar_highlight (f, x, y)
06a2c219
GM
7418 struct frame *f;
7419 int x, y;
7420{
9ea173e8 7421 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
7422 struct window *w = XWINDOW (window);
7423 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7424 int hpos, vpos;
7425 struct glyph *glyph;
7426 struct glyph_row *row;
5c187dee 7427 int i;
06a2c219
GM
7428 Lisp_Object enabled_p;
7429 int prop_idx;
140330de 7430 enum draw_glyphs_face draw;
5c187dee 7431 int mouse_down_p, rc;
06a2c219
GM
7432
7433 /* Function note_mouse_highlight is called with negative x(y
7434 values when mouse moves outside of the frame. */
7435 if (x <= 0 || y <= 0)
7436 {
7437 clear_mouse_face (dpyinfo);
7438 return;
7439 }
7440
9ea173e8 7441 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
7442 if (rc < 0)
7443 {
9ea173e8 7444 /* Not on tool-bar item. */
06a2c219
GM
7445 clear_mouse_face (dpyinfo);
7446 return;
7447 }
7448 else if (rc == 0)
06a2c219 7449 goto set_help_echo;
b8009dd1 7450
06a2c219
GM
7451 clear_mouse_face (dpyinfo);
7452
9ea173e8 7453 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
7454 mouse_down_p = (dpyinfo->grabbed
7455 && f == last_mouse_frame
7456 && FRAME_LIVE_P (f));
7457 if (mouse_down_p
9ea173e8 7458 && last_tool_bar_item != prop_idx)
06a2c219
GM
7459 return;
7460
7461 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7462 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7463
9ea173e8 7464 /* If tool-bar item is not enabled, don't highlight it. */
8daf1204 7465 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7466 if (!NILP (enabled_p))
7467 {
7468 /* Compute the x-position of the glyph. In front and past the
7469 image is a space. We include this is the highlighted area. */
7470 row = MATRIX_ROW (w->current_matrix, vpos);
7471 for (i = x = 0; i < hpos; ++i)
7472 x += row->glyphs[TEXT_AREA][i].pixel_width;
7473
7474 /* Record this as the current active region. */
7475 dpyinfo->mouse_face_beg_col = hpos;
7476 dpyinfo->mouse_face_beg_row = vpos;
7477 dpyinfo->mouse_face_beg_x = x;
7478 dpyinfo->mouse_face_beg_y = row->y;
7479 dpyinfo->mouse_face_past_end = 0;
7480
7481 dpyinfo->mouse_face_end_col = hpos + 1;
7482 dpyinfo->mouse_face_end_row = vpos;
7483 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7484 dpyinfo->mouse_face_end_y = row->y;
7485 dpyinfo->mouse_face_window = window;
9ea173e8 7486 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
7487
7488 /* Display it as active. */
7489 show_mouse_face (dpyinfo, draw);
7490 dpyinfo->mouse_face_image_state = draw;
b8009dd1 7491 }
06a2c219
GM
7492
7493 set_help_echo:
7494
50590060 7495 /* Set help_echo to a help string to display for this tool-bar item.
06a2c219 7496 XTread_socket does the rest. */
7cea38bc 7497 help_echo_object = help_echo_window = Qnil;
be010514 7498 help_echo_pos = -1;
8daf1204 7499 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
b7e80413 7500 if (NILP (help_echo))
8daf1204 7501 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
b8009dd1 7502}
4d73d038 7503
06a2c219
GM
7504
7505\f
9f8531e5
GM
7506/* Find the glyph matrix position of buffer position CHARPOS in window
7507 *W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7508 current glyphs must be up to date. If CHARPOS is above window
7509 start return (0, 0, 0, 0). If CHARPOS is after end of W, return end
7510 of last line in W. In the row containing CHARPOS, stop before glyphs
7e376260 7511 having STOP as object. */
b8009dd1 7512
9f8531e5
GM
7513#if 0 /* This is a version of fast_find_position that's more correct
7514 in the presence of hscrolling, for example. I didn't install
7515 it right away because the problem fixed is minor, it failed
7516 in 20.x as well, and I think it's too risky to install
7517 so near the release of 21.1. 2001-09-25 gerd. */
7518
7519static int
7520fast_find_position (w, charpos, hpos, vpos, x, y, stop)
7521 struct window *w;
7522 int charpos;
7523 int *hpos, *vpos, *x, *y;
7524 Lisp_Object stop;
7525{
7526 struct glyph_row *row, *first;
7527 struct glyph *glyph, *end;
7528 int i, past_end = 0;
7529
7530 first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
62e33982 7531 row = row_containing_pos (w, charpos, first, NULL, 0);
9f8531e5
GM
7532 if (row == NULL)
7533 {
7534 if (charpos < MATRIX_ROW_START_CHARPOS (first))
7535 {
7536 *x = *y = *hpos = *vpos = 0;
7537 return 0;
7538 }
7539 else
7540 {
7541 row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
7542 past_end = 1;
7543 }
7544 }
7545
7546 *x = row->x;
7547 *y = row->y;
7548 *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7549
7550 glyph = row->glyphs[TEXT_AREA];
7551 end = glyph + row->used[TEXT_AREA];
7552
7553 /* Skip over glyphs not having an object at the start of the row.
7554 These are special glyphs like truncation marks on terminal
7555 frames. */
7556 if (row->displays_text_p)
7557 while (glyph < end
7558 && INTEGERP (glyph->object)
7559 && !EQ (stop, glyph->object)
7560 && glyph->charpos < 0)
7561 {
7562 *x += glyph->pixel_width;
7563 ++glyph;
7564 }
7565
7566 while (glyph < end
7567 && !INTEGERP (glyph->object)
7568 && !EQ (stop, glyph->object)
7569 && (!BUFFERP (glyph->object)
7570 || glyph->charpos < charpos))
7571 {
7572 *x += glyph->pixel_width;
7573 ++glyph;
7574 }
7575
7576 *hpos = glyph - row->glyphs[TEXT_AREA];
7577 return past_end;
7578}
7579
7580#else /* not 0 */
7581
b8009dd1 7582static int
7e376260 7583fast_find_position (w, pos, hpos, vpos, x, y, stop)
06a2c219 7584 struct window *w;
b8009dd1 7585 int pos;
06a2c219 7586 int *hpos, *vpos, *x, *y;
7e376260 7587 Lisp_Object stop;
b8009dd1 7588{
b8009dd1 7589 int i;
bf1c0ba1 7590 int lastcol;
06a2c219
GM
7591 int maybe_next_line_p = 0;
7592 int line_start_position;
7593 int yb = window_text_bottom_y (w);
03d1a189
GM
7594 struct glyph_row *row, *best_row;
7595 int row_vpos, best_row_vpos;
06a2c219
GM
7596 int current_x;
7597
03d1a189
GM
7598 row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7599 row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7600
06a2c219 7601 while (row->y < yb)
b8009dd1 7602 {
06a2c219
GM
7603 if (row->used[TEXT_AREA])
7604 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7605 else
7606 line_start_position = 0;
7607
7608 if (line_start_position > pos)
b8009dd1 7609 break;
77b68646
RS
7610 /* If the position sought is the end of the buffer,
7611 don't include the blank lines at the bottom of the window. */
06a2c219
GM
7612 else if (line_start_position == pos
7613 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 7614 {
06a2c219 7615 maybe_next_line_p = 1;
77b68646
RS
7616 break;
7617 }
06a2c219
GM
7618 else if (line_start_position > 0)
7619 {
7620 best_row = row;
7621 best_row_vpos = row_vpos;
7622 }
4b0bb6f3
GM
7623
7624 if (row->y + row->height >= yb)
7625 break;
06a2c219
GM
7626
7627 ++row;
7628 ++row_vpos;
b8009dd1 7629 }
06a2c219
GM
7630
7631 /* Find the right column within BEST_ROW. */
7632 lastcol = 0;
7633 current_x = best_row->x;
7634 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 7635 {
06a2c219 7636 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7e376260 7637 int charpos = glyph->charpos;
06a2c219 7638
7e376260 7639 if (BUFFERP (glyph->object))
bf1c0ba1 7640 {
7e376260
GM
7641 if (charpos == pos)
7642 {
7643 *hpos = i;
7644 *vpos = best_row_vpos;
7645 *x = current_x;
7646 *y = best_row->y;
7647 return 1;
7648 }
7649 else if (charpos > pos)
7650 break;
bf1c0ba1 7651 }
7e376260 7652 else if (EQ (glyph->object, stop))
4d73d038 7653 break;
06a2c219 7654
7e376260
GM
7655 if (charpos > 0)
7656 lastcol = i;
06a2c219 7657 current_x += glyph->pixel_width;
bf1c0ba1 7658 }
b8009dd1 7659
77b68646
RS
7660 /* If we're looking for the end of the buffer,
7661 and we didn't find it in the line we scanned,
7662 use the start of the following line. */
06a2c219 7663 if (maybe_next_line_p)
77b68646 7664 {
06a2c219
GM
7665 ++best_row;
7666 ++best_row_vpos;
7667 lastcol = 0;
7668 current_x = best_row->x;
77b68646
RS
7669 }
7670
06a2c219
GM
7671 *vpos = best_row_vpos;
7672 *hpos = lastcol + 1;
7673 *x = current_x;
7674 *y = best_row->y;
b8009dd1
RS
7675 return 0;
7676}
7677
9f8531e5
GM
7678#endif /* not 0 */
7679
06a2c219 7680
269b7745 7681/* Find the position of the glyph for position POS in OBJECT in
7a4bce14
PJ
7682 window W's current matrix, and return in *X, *Y the pixel
7683 coordinates, and return in *HPOS, *VPOS the column/row of the glyph.
f9db2310
GM
7684
7685 RIGHT_P non-zero means return the position of the right edge of the
7686 glyph, RIGHT_P zero means return the left edge position.
7687
7688 If no glyph for POS exists in the matrix, return the position of
7689 the glyph with the next smaller position that is in the matrix, if
7690 RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS
7691 exists in the matrix, return the position of the glyph with the
7692 next larger position in OBJECT.
7693
7694 Value is non-zero if a glyph was found. */
7695
7696static int
7697fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
7698 struct window *w;
7699 int pos;
7700 Lisp_Object object;
7701 int *hpos, *vpos, *x, *y;
7702 int right_p;
7703{
7704 int yb = window_text_bottom_y (w);
7705 struct glyph_row *r;
7706 struct glyph *best_glyph = NULL;
7707 struct glyph_row *best_row = NULL;
7708 int best_x = 0;
7709
7710 for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7711 r->enabled_p && r->y < yb;
7712 ++r)
7713 {
7714 struct glyph *g = r->glyphs[TEXT_AREA];
7715 struct glyph *e = g + r->used[TEXT_AREA];
7716 int gx;
7717
7718 for (gx = r->x; g < e; gx += g->pixel_width, ++g)
7719 if (EQ (g->object, object))
7720 {
7721 if (g->charpos == pos)
7722 {
7723 best_glyph = g;
7724 best_x = gx;
7725 best_row = r;
7726 goto found;
7727 }
7728 else if (best_glyph == NULL
7729 || ((abs (g->charpos - pos)
7730 < abs (best_glyph->charpos - pos))
7731 && (right_p
7732 ? g->charpos < pos
7733 : g->charpos > pos)))
7734 {
7735 best_glyph = g;
7736 best_x = gx;
7737 best_row = r;
7738 }
7739 }
7740 }
7741
7742 found:
7743
7744 if (best_glyph)
7745 {
7746 *x = best_x;
7747 *hpos = best_glyph - best_row->glyphs[TEXT_AREA];
7748
7749 if (right_p)
7750 {
7751 *x += best_glyph->pixel_width;
7752 ++*hpos;
7753 }
7754
7755 *y = best_row->y;
7756 *vpos = best_row - w->current_matrix->rows;
7757 }
7758
7759 return best_glyph != NULL;
7760}
7761
7762
b8009dd1
RS
7763/* Display the active region described by mouse_face_*
7764 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7765
7766static void
06a2c219 7767show_mouse_face (dpyinfo, draw)
7a13e894 7768 struct x_display_info *dpyinfo;
06a2c219 7769 enum draw_glyphs_face draw;
b8009dd1 7770{
7a13e894 7771 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7772 struct frame *f = XFRAME (WINDOW_FRAME (w));
06a2c219 7773
b2bbd509
GM
7774 if (/* If window is in the process of being destroyed, don't bother
7775 to do anything. */
7776 w->current_matrix != NULL
66301061
KS
7777 /* Don't update mouse highlight if hidden */
7778 && (draw != DRAW_MOUSE_FACE || !dpyinfo->mouse_face_hidden)
b2bbd509
GM
7779 /* Recognize when we are called to operate on rows that don't exist
7780 anymore. This can happen when a window is split. */
7781 && dpyinfo->mouse_face_end_row < w->current_matrix->nrows)
06a2c219 7782 {
b2bbd509
GM
7783 int phys_cursor_on_p = w->phys_cursor_on_p;
7784 struct glyph_row *row, *first, *last;
06a2c219 7785
b2bbd509
GM
7786 first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row);
7787 last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row);
7788
7789 for (row = first; row <= last && row->enabled_p; ++row)
06a2c219 7790 {
b2bbd509 7791 int start_hpos, end_hpos, start_x;
06a2c219 7792
b2bbd509
GM
7793 /* For all but the first row, the highlight starts at column 0. */
7794 if (row == first)
7795 {
7796 start_hpos = dpyinfo->mouse_face_beg_col;
7797 start_x = dpyinfo->mouse_face_beg_x;
7798 }
7799 else
7800 {
7801 start_hpos = 0;
7802 start_x = 0;
7803 }
06a2c219 7804
b2bbd509
GM
7805 if (row == last)
7806 end_hpos = dpyinfo->mouse_face_end_col;
7807 else
7808 end_hpos = row->used[TEXT_AREA];
b8009dd1 7809
b2bbd509
GM
7810 if (end_hpos > start_hpos)
7811 {
7812 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7813 start_hpos, end_hpos, draw, 0);
b8009dd1 7814
60626bab
GM
7815 row->mouse_face_p
7816 = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED;
b2bbd509
GM
7817 }
7818 }
2729a2b5 7819
b2bbd509
GM
7820 /* When we've written over the cursor, arrange for it to
7821 be displayed again. */
7822 if (phys_cursor_on_p && !w->phys_cursor_on_p)
7823 x_display_cursor (w, 1,
7824 w->phys_cursor.hpos, w->phys_cursor.vpos,
7825 w->phys_cursor.x, w->phys_cursor.y);
7826 }
fb3b7de5 7827
06a2c219
GM
7828 /* Change the mouse cursor. */
7829 if (draw == DRAW_NORMAL_TEXT)
7830 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7831 f->output_data.x->text_cursor);
7832 else if (draw == DRAW_MOUSE_FACE)
334208b7 7833 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7834 f->output_data.x->cross_cursor);
27ead1d5 7835 else
334208b7 7836 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7837 f->output_data.x->nontext_cursor);
b8009dd1
RS
7838}
7839
7840/* Clear out the mouse-highlighted active region.
fa262c07
GM
7841 Redraw it un-highlighted first. Value is non-zero if mouse
7842 face was actually drawn unhighlighted. */
b8009dd1 7843
fa262c07 7844static int
7a13e894
RS
7845clear_mouse_face (dpyinfo)
7846 struct x_display_info *dpyinfo;
b8009dd1 7847{
fa262c07 7848 int cleared = 0;
06a2c219 7849
fa262c07
GM
7850 if (!NILP (dpyinfo->mouse_face_window))
7851 {
7852 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
7853 cleared = 1;
7854 }
b8009dd1 7855
7a13e894
RS
7856 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7857 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7858 dpyinfo->mouse_face_window = Qnil;
1b85dc1c 7859 dpyinfo->mouse_face_overlay = Qnil;
fa262c07 7860 return cleared;
b8009dd1 7861}
e687d06e 7862
71b8321e
GM
7863
7864/* Clear any mouse-face on window W. This function is part of the
7865 redisplay interface, and is called from try_window_id and similar
7866 functions to ensure the mouse-highlight is off. */
7867
7868static void
7869x_clear_mouse_face (w)
7870 struct window *w;
7871{
7872 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7873 Lisp_Object window;
7874
2e636f9d 7875 BLOCK_INPUT;
71b8321e
GM
7876 XSETWINDOW (window, w);
7877 if (EQ (window, dpyinfo->mouse_face_window))
7878 clear_mouse_face (dpyinfo);
2e636f9d 7879 UNBLOCK_INPUT;
71b8321e
GM
7880}
7881
7882
e687d06e
RS
7883/* Just discard the mouse face information for frame F, if any.
7884 This is used when the size of F is changed. */
7885
dfcf069d 7886void
e687d06e
RS
7887cancel_mouse_face (f)
7888 FRAME_PTR f;
7889{
7890 Lisp_Object window;
7891 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7892
7893 window = dpyinfo->mouse_face_window;
7894 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7895 {
7896 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7897 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7898 dpyinfo->mouse_face_window = Qnil;
7899 }
7900}
b52b65bd 7901
b8009dd1 7902\f
b52b65bd
GM
7903static int glyph_rect P_ ((struct frame *f, int, int, XRectangle *));
7904
7905
7906/* Try to determine frame pixel position and size of the glyph under
7907 frame pixel coordinates X/Y on frame F . Return the position and
7908 size in *RECT. Value is non-zero if we could compute these
7909 values. */
7910
7911static int
7912glyph_rect (f, x, y, rect)
7913 struct frame *f;
7914 int x, y;
7915 XRectangle *rect;
7916{
7917 Lisp_Object window;
7918 int part, found = 0;
7919
7920 window = window_from_coordinates (f, x, y, &part, 0);
7921 if (!NILP (window))
7922 {
7923 struct window *w = XWINDOW (window);
7924 struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7925 struct glyph_row *end = r + w->current_matrix->nrows - 1;
b52b65bd
GM
7926
7927 frame_to_window_pixel_xy (w, &x, &y);
7928
7929 for (; !found && r < end && r->enabled_p; ++r)
7930 if (r->y >= y)
7931 {
7932 struct glyph *g = r->glyphs[TEXT_AREA];
7933 struct glyph *end = g + r->used[TEXT_AREA];
7934 int gx;
7935
7936 for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
7937 if (gx >= x)
7938 {
7939 rect->width = g->pixel_width;
7940 rect->height = r->height;
7941 rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
7942 rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
7943 found = 1;
7944 }
7945 }
7946 }
7947
7948 return found;
7949}
7950
12ba150f 7951
90e65f07 7952/* Return the current position of the mouse.
b52b65bd 7953 *FP should be a frame which indicates which display to ask about.
90e65f07 7954
b52b65bd
GM
7955 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
7956 and *PART to the frame, window, and scroll bar part that the mouse
7957 is over. Set *X and *Y to the portion and whole of the mouse's
ab648270 7958 position on the scroll bar.
12ba150f 7959
b52b65bd
GM
7960 If the mouse movement started elsewhere, set *FP to the frame the
7961 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
12ba150f
JB
7962 the mouse is over.
7963
b52b65bd 7964 Set *TIME to the server time-stamp for the time at which the mouse
12ba150f
JB
7965 was at this position.
7966
a135645a
RS
7967 Don't store anything if we don't have a valid set of values to report.
7968
90e65f07 7969 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7970 movement. */
90e65f07
JB
7971
7972static void
1cf412ec 7973XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7974 FRAME_PTR *fp;
1cf412ec 7975 int insist;
12ba150f 7976 Lisp_Object *bar_window;
ab648270 7977 enum scroll_bar_part *part;
90e65f07 7978 Lisp_Object *x, *y;
e5d77022 7979 unsigned long *time;
90e65f07 7980{
a135645a
RS
7981 FRAME_PTR f1;
7982
90e65f07
JB
7983 BLOCK_INPUT;
7984
8bcee03e 7985 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7986 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7987 else
7988 {
12ba150f
JB
7989 Window root;
7990 int root_x, root_y;
90e65f07 7991
12ba150f
JB
7992 Window dummy_window;
7993 int dummy;
7994
39d8bb4d
KH
7995 Lisp_Object frame, tail;
7996
7997 /* Clear the mouse-moved flag for every frame on this display. */
7998 FOR_EACH_FRAME (tail, frame)
7999 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
8000 XFRAME (frame)->mouse_moved = 0;
8001
ab648270 8002 last_mouse_scroll_bar = Qnil;
12ba150f
JB
8003
8004 /* Figure out which root window we're on. */
334208b7
RS
8005 XQueryPointer (FRAME_X_DISPLAY (*fp),
8006 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
8007
8008 /* The root window which contains the pointer. */
8009 &root,
8010
8011 /* Trash which we can't trust if the pointer is on
8012 a different screen. */
8013 &dummy_window,
8014
8015 /* The position on that root window. */
58769bee 8016 &root_x, &root_y,
12ba150f
JB
8017
8018 /* More trash we can't trust. */
8019 &dummy, &dummy,
8020
8021 /* Modifier keys and pointer buttons, about which
8022 we don't care. */
8023 (unsigned int *) &dummy);
8024
8025 /* Now we have a position on the root; find the innermost window
8026 containing the pointer. */
8027 {
8028 Window win, child;
8029 int win_x, win_y;
06a2c219 8030 int parent_x = 0, parent_y = 0;
e99db5a1 8031 int count;
12ba150f
JB
8032
8033 win = root;
69388238 8034
2d7fc7e8
RS
8035 /* XTranslateCoordinates can get errors if the window
8036 structure is changing at the same time this function
8037 is running. So at least we must not crash from them. */
8038
e99db5a1 8039 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 8040
334208b7 8041 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 8042 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 8043 {
69388238
RS
8044 /* If mouse was grabbed on a frame, give coords for that frame
8045 even if the mouse is now outside it. */
334208b7 8046 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 8047
12ba150f 8048 /* From-window, to-window. */
69388238 8049 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
8050
8051 /* From-position, to-position. */
8052 root_x, root_y, &win_x, &win_y,
8053
8054 /* Child of win. */
8055 &child);
69388238
RS
8056 f1 = last_mouse_frame;
8057 }
8058 else
8059 {
8060 while (1)
8061 {
334208b7 8062 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 8063
69388238
RS
8064 /* From-window, to-window. */
8065 root, win,
12ba150f 8066
69388238
RS
8067 /* From-position, to-position. */
8068 root_x, root_y, &win_x, &win_y,
8069
8070 /* Child of win. */
8071 &child);
8072
9af3143a 8073 if (child == None || child == win)
69388238
RS
8074 break;
8075
8076 win = child;
8077 parent_x = win_x;
8078 parent_y = win_y;
8079 }
12ba150f 8080
69388238
RS
8081 /* Now we know that:
8082 win is the innermost window containing the pointer
8083 (XTC says it has no child containing the pointer),
8084 win_x and win_y are the pointer's position in it
8085 (XTC did this the last time through), and
8086 parent_x and parent_y are the pointer's position in win's parent.
8087 (They are what win_x and win_y were when win was child.
8088 If win is the root window, it has no parent, and
8089 parent_{x,y} are invalid, but that's okay, because we'll
8090 never use them in that case.) */
8091
8092 /* Is win one of our frames? */
19126e11 8093 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
aad0f6ab
GM
8094
8095#ifdef USE_X_TOOLKIT
8096 /* If we end up with the menu bar window, say it's not
8097 on the frame. */
8098 if (f1 != NULL
8099 && f1->output_data.x->menubar_widget
8100 && win == XtWindow (f1->output_data.x->menubar_widget))
8101 f1 = NULL;
8102#endif /* USE_X_TOOLKIT */
69388238 8103 }
58769bee 8104
2d7fc7e8
RS
8105 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
8106 f1 = 0;
8107
e99db5a1 8108 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 8109
ab648270 8110 /* If not, is it one of our scroll bars? */
a135645a 8111 if (! f1)
12ba150f 8112 {
ab648270 8113 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
8114
8115 if (bar)
8116 {
a135645a 8117 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
8118 win_x = parent_x;
8119 win_y = parent_y;
8120 }
8121 }
90e65f07 8122
8bcee03e 8123 if (f1 == 0 && insist > 0)
b86bd3dd 8124 f1 = SELECTED_FRAME ();
1cf412ec 8125
a135645a 8126 if (f1)
12ba150f 8127 {
06a2c219
GM
8128 /* Ok, we found a frame. Store all the values.
8129 last_mouse_glyph is a rectangle used to reduce the
8130 generation of mouse events. To not miss any motion
8131 events, we must divide the frame into rectangles of the
8132 size of the smallest character that could be displayed
8133 on it, i.e. into the same rectangles that matrices on
8134 the frame are divided into. */
8135
b52b65bd
GM
8136 int width, height, gx, gy;
8137 XRectangle rect;
8138
8139 if (glyph_rect (f1, win_x, win_y, &rect))
8140 last_mouse_glyph = rect;
8141 else
8142 {
8143 width = FRAME_SMALLEST_CHAR_WIDTH (f1);
8144 height = FRAME_SMALLEST_FONT_HEIGHT (f1);
8145 gx = win_x;
8146 gy = win_y;
06a2c219 8147
b52b65bd
GM
8148 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
8149 round down even for negative values. */
8150 if (gx < 0)
8151 gx -= width - 1;
4f00e84d 8152 if (gy < 0)
b52b65bd
GM
8153 gy -= height - 1;
8154 gx = (gx + width - 1) / width * width;
8155 gy = (gy + height - 1) / height * height;
8156
8157 last_mouse_glyph.width = width;
8158 last_mouse_glyph.height = height;
8159 last_mouse_glyph.x = gx;
8160 last_mouse_glyph.y = gy;
8161 }
12ba150f
JB
8162
8163 *bar_window = Qnil;
8164 *part = 0;
334208b7 8165 *fp = f1;
e0c1aef2
KH
8166 XSETINT (*x, win_x);
8167 XSETINT (*y, win_y);
12ba150f
JB
8168 *time = last_mouse_movement_time;
8169 }
8170 }
8171 }
90e65f07
JB
8172
8173 UNBLOCK_INPUT;
8174}
f451eb13 8175
06a2c219 8176
06a2c219 8177#ifdef USE_X_TOOLKIT
bffcfca9
GM
8178
8179/* Atimer callback function for TIMER. Called every 0.1s to process
8180 Xt timeouts, if needed. We must avoid calling XtAppPending as
8181 much as possible because that function does an implicit XFlush
8182 that slows us down. */
8183
8184static void
8185x_process_timeouts (timer)
8186 struct atimer *timer;
8187{
8188 if (toolkit_scroll_bar_interaction || popup_activated_flag)
8189 {
8190 BLOCK_INPUT;
8191 while (XtAppPending (Xt_app_con) & XtIMTimer)
8192 XtAppProcessEvent (Xt_app_con, XtIMTimer);
8193 UNBLOCK_INPUT;
8194 }
06a2c219
GM
8195}
8196
bffcfca9 8197#endif /* USE_X_TOOLKIT */
06a2c219
GM
8198
8199\f
8200/* Scroll bar support. */
8201
8202/* Given an X window ID, find the struct scroll_bar which manages it.
8203 This can be called in GC, so we have to make sure to strip off mark
8204 bits. */
bffcfca9 8205
06a2c219
GM
8206static struct scroll_bar *
8207x_window_to_scroll_bar (window_id)
8208 Window window_id;
8209{
8210 Lisp_Object tail;
8211
8212 for (tail = Vframe_list;
8213 XGCTYPE (tail) == Lisp_Cons;
8e713be6 8214 tail = XCDR (tail))
06a2c219
GM
8215 {
8216 Lisp_Object frame, bar, condemned;
8217
8e713be6 8218 frame = XCAR (tail);
06a2c219
GM
8219 /* All elements of Vframe_list should be frames. */
8220 if (! GC_FRAMEP (frame))
8221 abort ();
8222
8223 /* Scan this frame's scroll bar list for a scroll bar with the
8224 right window ID. */
8225 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
8226 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
8227 /* This trick allows us to search both the ordinary and
8228 condemned scroll bar lists with one loop. */
8229 ! GC_NILP (bar) || (bar = condemned,
8230 condemned = Qnil,
8231 ! GC_NILP (bar));
8232 bar = XSCROLL_BAR (bar)->next)
8233 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
8234 return XSCROLL_BAR (bar);
8235 }
8236
8237 return 0;
8238}
8239
8240
01f67d2c 8241#if defined USE_LUCID
c95fc5f1
GM
8242
8243/* Return the Lucid menu bar WINDOW is part of. Return null
8244 if WINDOW is not part of a menu bar. */
8245
8246static Widget
8247x_window_to_menu_bar (window)
8248 Window window;
8249{
8250 Lisp_Object tail;
8251
8252 for (tail = Vframe_list;
8253 XGCTYPE (tail) == Lisp_Cons;
8254 tail = XCDR (tail))
8255 {
8256 Lisp_Object frame = XCAR (tail);
8257 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
8258
8259 if (menu_bar && xlwmenu_window_p (menu_bar, window))
8260 return menu_bar;
8261 }
8262
8263 return NULL;
8264}
8265
01f67d2c 8266#endif /* USE_LUCID */
c95fc5f1 8267
06a2c219
GM
8268\f
8269/************************************************************************
8270 Toolkit scroll bars
8271 ************************************************************************/
8272
eccc05db 8273#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8274
8275static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
8276static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
8277static void x_create_toolkit_scroll_bar P_ ((struct frame *,
8278 struct scroll_bar *));
8279static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
8280 int, int, int));
8281
8282
8283/* Id of action hook installed for scroll bars. */
8284
8285static XtActionHookId action_hook_id;
8286
8287/* Lisp window being scrolled. Set when starting to interact with
8288 a toolkit scroll bar, reset to nil when ending the interaction. */
8289
8290static Lisp_Object window_being_scrolled;
8291
8292/* Last scroll bar part sent in xm_scroll_callback. */
8293
8294static int last_scroll_bar_part;
8295
ec18280f
SM
8296/* Whether this is an Xaw with arrow-scrollbars. This should imply
8297 that movements of 1/20 of the screen size are mapped to up/down. */
8298
8299static Boolean xaw3d_arrow_scroll;
8300
8301/* Whether the drag scrolling maintains the mouse at the top of the
8302 thumb. If not, resizing the thumb needs to be done more carefully
8303 to avoid jerkyness. */
8304
8305static Boolean xaw3d_pick_top;
8306
06a2c219
GM
8307
8308/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 8309 bars are used.. The hook is responsible for detecting when
06a2c219
GM
8310 the user ends an interaction with the scroll bar, and generates
8311 a `end-scroll' scroll_bar_click' event if so. */
8312
8313static void
8314xt_action_hook (widget, client_data, action_name, event, params,
8315 num_params)
8316 Widget widget;
8317 XtPointer client_data;
8318 String action_name;
8319 XEvent *event;
8320 String *params;
8321 Cardinal *num_params;
8322{
8323 int scroll_bar_p;
8324 char *end_action;
8325
8326#ifdef USE_MOTIF
8327 scroll_bar_p = XmIsScrollBar (widget);
8328 end_action = "Release";
ec18280f 8329#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8330 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
8331 end_action = "EndScroll";
ec18280f 8332#endif /* USE_MOTIF */
06a2c219 8333
06a2c219
GM
8334 if (scroll_bar_p
8335 && strcmp (action_name, end_action) == 0
8336 && WINDOWP (window_being_scrolled))
8337 {
8338 struct window *w;
8339
8340 x_send_scroll_bar_event (window_being_scrolled,
8341 scroll_bar_end_scroll, 0, 0);
8342 w = XWINDOW (window_being_scrolled);
8343 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
8344 window_being_scrolled = Qnil;
8345 last_scroll_bar_part = -1;
bffcfca9
GM
8346
8347 /* Xt timeouts no longer needed. */
8348 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
8349 }
8350}
8351
07b3d16e
GM
8352/* A vector of windows used for communication between
8353 x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
8354
8355static struct window **scroll_bar_windows;
8356static int scroll_bar_windows_size;
8357
06a2c219
GM
8358
8359/* Send a client message with message type Xatom_Scrollbar for a
8360 scroll action to the frame of WINDOW. PART is a value identifying
8361 the part of the scroll bar that was clicked on. PORTION is the
8362 amount to scroll of a whole of WHOLE. */
8363
8364static void
8365x_send_scroll_bar_event (window, part, portion, whole)
8366 Lisp_Object window;
8367 int part, portion, whole;
8368{
8369 XEvent event;
8370 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
07b3d16e
GM
8371 struct window *w = XWINDOW (window);
8372 struct frame *f = XFRAME (w->frame);
8373 int i;
06a2c219 8374
07b3d16e
GM
8375 BLOCK_INPUT;
8376
06a2c219
GM
8377 /* Construct a ClientMessage event to send to the frame. */
8378 ev->type = ClientMessage;
8379 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
8380 ev->display = FRAME_X_DISPLAY (f);
8381 ev->window = FRAME_X_WINDOW (f);
8382 ev->format = 32;
07b3d16e
GM
8383
8384 /* We can only transfer 32 bits in the XClientMessageEvent, which is
8385 not enough to store a pointer or Lisp_Object on a 64 bit system.
8386 So, store the window in scroll_bar_windows and pass the index
8387 into that array in the event. */
8388 for (i = 0; i < scroll_bar_windows_size; ++i)
8389 if (scroll_bar_windows[i] == NULL)
8390 break;
8391
8392 if (i == scroll_bar_windows_size)
8393 {
8394 int new_size = max (10, 2 * scroll_bar_windows_size);
8395 size_t nbytes = new_size * sizeof *scroll_bar_windows;
8396 size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows;
8397
8398 scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
8399 nbytes);
8400 bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
8401 scroll_bar_windows_size = new_size;
8402 }
8403
8404 scroll_bar_windows[i] = w;
8405 ev->data.l[0] = (long) i;
06a2c219
GM
8406 ev->data.l[1] = (long) part;
8407 ev->data.l[2] = (long) 0;
8408 ev->data.l[3] = (long) portion;
8409 ev->data.l[4] = (long) whole;
8410
bffcfca9
GM
8411 /* Make Xt timeouts work while the scroll bar is active. */
8412 toolkit_scroll_bar_interaction = 1;
8413
06a2c219
GM
8414 /* Setting the event mask to zero means that the message will
8415 be sent to the client that created the window, and if that
8416 window no longer exists, no event will be sent. */
06a2c219
GM
8417 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
8418 UNBLOCK_INPUT;
8419}
8420
8421
8422/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
8423 in *IEVENT. */
8424
8425static void
8426x_scroll_bar_to_input_event (event, ievent)
8427 XEvent *event;
8428 struct input_event *ievent;
8429{
8430 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
8431 Lisp_Object window;
8432 struct frame *f;
07b3d16e
GM
8433 struct window *w;
8434
8435 w = scroll_bar_windows[ev->data.l[0]];
8436 scroll_bar_windows[ev->data.l[0]] = NULL;
52e386c2 8437
07b3d16e
GM
8438 XSETWINDOW (window, w);
8439 f = XFRAME (w->frame);
06a2c219
GM
8440
8441 ievent->kind = scroll_bar_click;
8442 ievent->frame_or_window = window;
0f8aabe9 8443 ievent->arg = Qnil;
06a2c219
GM
8444 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
8445 ievent->part = ev->data.l[1];
8446 ievent->code = ev->data.l[2];
8447 ievent->x = make_number ((int) ev->data.l[3]);
8448 ievent->y = make_number ((int) ev->data.l[4]);
8449 ievent->modifiers = 0;
8450}
8451
8452
8453#ifdef USE_MOTIF
8454
8455/* Minimum and maximum values used for Motif scroll bars. */
8456
8457#define XM_SB_MIN 1
8458#define XM_SB_MAX 10000000
8459#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
8460
8461
8462/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
8463 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
8464 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
8465
8466static void
8467xm_scroll_callback (widget, client_data, call_data)
8468 Widget widget;
8469 XtPointer client_data, call_data;
8470{
8471 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8472 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
06a2c219
GM
8473 int part = -1, whole = 0, portion = 0;
8474
8475 switch (cs->reason)
8476 {
8477 case XmCR_DECREMENT:
8478 bar->dragging = Qnil;
8479 part = scroll_bar_up_arrow;
8480 break;
8481
8482 case XmCR_INCREMENT:
8483 bar->dragging = Qnil;
8484 part = scroll_bar_down_arrow;
8485 break;
8486
8487 case XmCR_PAGE_DECREMENT:
8488 bar->dragging = Qnil;
8489 part = scroll_bar_above_handle;
8490 break;
8491
8492 case XmCR_PAGE_INCREMENT:
8493 bar->dragging = Qnil;
8494 part = scroll_bar_below_handle;
8495 break;
8496
8497 case XmCR_TO_TOP:
8498 bar->dragging = Qnil;
8499 part = scroll_bar_to_top;
8500 break;
8501
8502 case XmCR_TO_BOTTOM:
8503 bar->dragging = Qnil;
8504 part = scroll_bar_to_bottom;
8505 break;
8506
8507 case XmCR_DRAG:
8508 {
8509 int slider_size;
8510 int dragging_down_p = (INTEGERP (bar->dragging)
8511 && XINT (bar->dragging) <= cs->value);
8512
8513 /* Get the slider size. */
8514 BLOCK_INPUT;
8515 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
8516 UNBLOCK_INPUT;
8517
6f2a7a68
SM
8518 whole = XM_SB_RANGE - slider_size;
8519 portion = min (cs->value - XM_SB_MIN, whole);
8520 part = scroll_bar_handle;
8521 bar->dragging = make_number (cs->value);
06a2c219
GM
8522 }
8523 break;
8524
8525 case XmCR_VALUE_CHANGED:
8526 break;
8527 };
8528
8529 if (part >= 0)
8530 {
8531 window_being_scrolled = bar->window;
8532 last_scroll_bar_part = part;
8533 x_send_scroll_bar_event (bar->window, part, portion, whole);
8534 }
8535}
8536
8537
ec18280f 8538#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
8539
8540
ec18280f 8541/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
8542 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
8543 scroll bar struct. CALL_DATA is a pointer to a float saying where
8544 the thumb is. */
8545
8546static void
ec18280f 8547xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
8548 Widget widget;
8549 XtPointer client_data, call_data;
8550{
8551 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8552 float top = *(float *) call_data;
8553 float shown;
ec18280f
SM
8554 int whole, portion, height;
8555 int part;
06a2c219
GM
8556
8557 /* Get the size of the thumb, a value between 0 and 1. */
8558 BLOCK_INPUT;
ec18280f 8559 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
8560 UNBLOCK_INPUT;
8561
8562 whole = 10000000;
8563 portion = shown < 1 ? top * whole : 0;
06a2c219 8564
ec18280f
SM
8565 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
8566 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
8567 the bottom, so we force the scrolling whenever we see that we're
8568 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
8569 we try to ensure that we always stay two pixels away from the
8570 bottom). */
06a2c219
GM
8571 part = scroll_bar_down_arrow;
8572 else
8573 part = scroll_bar_handle;
8574
8575 window_being_scrolled = bar->window;
8576 bar->dragging = make_number (portion);
8577 last_scroll_bar_part = part;
8578 x_send_scroll_bar_event (bar->window, part, portion, whole);
8579}
8580
8581
ec18280f
SM
8582/* Xaw scroll bar callback. Invoked for incremental scrolling.,
8583 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
8584 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
8585 the scroll bar. CALL_DATA is an integer specifying the action that
8586 has taken place. It's magnitude is in the range 0..height of the
8587 scroll bar. Negative values mean scroll towards buffer start.
8588 Values < height of scroll bar mean line-wise movement. */
8589
8590static void
ec18280f 8591xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
8592 Widget widget;
8593 XtPointer client_data, call_data;
8594{
8595 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8596 int position = (int) call_data;
8597 Dimension height;
8598 int part;
8599
8600 /* Get the height of the scroll bar. */
8601 BLOCK_INPUT;
8602 XtVaGetValues (widget, XtNheight, &height, NULL);
8603 UNBLOCK_INPUT;
8604
ec18280f
SM
8605 if (abs (position) >= height)
8606 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
8607
8608 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
8609 it maps line-movement to call_data = max(5, height/20). */
8610 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
8611 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 8612 else
ec18280f 8613 part = scroll_bar_move_ratio;
06a2c219
GM
8614
8615 window_being_scrolled = bar->window;
8616 bar->dragging = Qnil;
8617 last_scroll_bar_part = part;
ec18280f 8618 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
8619}
8620
8621
8622#endif /* not USE_MOTIF */
8623
8624
8625/* Create the widget for scroll bar BAR on frame F. Record the widget
8626 and X window of the scroll bar in BAR. */
8627
8628static void
8629x_create_toolkit_scroll_bar (f, bar)
8630 struct frame *f;
8631 struct scroll_bar *bar;
8632{
8633 Window xwindow;
8634 Widget widget;
8635 Arg av[20];
8636 int ac = 0;
8637 char *scroll_bar_name = "verticalScrollBar";
8638 unsigned long pixel;
8639
8640 BLOCK_INPUT;
8641
8642#ifdef USE_MOTIF
06a2c219
GM
8643 /* Set resources. Create the widget. */
8644 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8645 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
8646 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
8647 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
8648 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
8649 XtSetArg (av[ac], XmNincrement, 1); ++ac;
8650 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
8651
8652 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8653 if (pixel != -1)
8654 {
8655 XtSetArg (av[ac], XmNforeground, pixel);
8656 ++ac;
8657 }
8658
8659 pixel = f->output_data.x->scroll_bar_background_pixel;
8660 if (pixel != -1)
8661 {
8662 XtSetArg (av[ac], XmNbackground, pixel);
8663 ++ac;
8664 }
8665
8666 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
8667 scroll_bar_name, av, ac);
8668
8669 /* Add one callback for everything that can happen. */
8670 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
8671 (XtPointer) bar);
8672 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
8673 (XtPointer) bar);
8674 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
8675 (XtPointer) bar);
8676 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
8677 (XtPointer) bar);
8678 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
8679 (XtPointer) bar);
8680 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
8681 (XtPointer) bar);
8682 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
8683 (XtPointer) bar);
8684
8685 /* Realize the widget. Only after that is the X window created. */
8686 XtRealizeWidget (widget);
8687
8688 /* Set the cursor to an arrow. I didn't find a resource to do that.
8689 And I'm wondering why it hasn't an arrow cursor by default. */
8690 XDefineCursor (XtDisplay (widget), XtWindow (widget),
8691 f->output_data.x->nontext_cursor);
8692
ec18280f 8693#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8694
8695 /* Set resources. Create the widget. The background of the
8696 Xaw3d scroll bar widget is a little bit light for my taste.
8697 We don't alter it here to let users change it according
8698 to their taste with `emacs*verticalScrollBar.background: xxx'. */
8699 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8700 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
8701 /* For smoother scrolling with Xaw3d -sm */
8702 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
06a2c219
GM
8703
8704 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8705 if (pixel != -1)
8706 {
8707 XtSetArg (av[ac], XtNforeground, pixel);
8708 ++ac;
8709 }
8710
8711 pixel = f->output_data.x->scroll_bar_background_pixel;
8712 if (pixel != -1)
8713 {
8714 XtSetArg (av[ac], XtNbackground, pixel);
8715 ++ac;
8716 }
7c1bef7a
MB
8717
8718 /* Top/bottom shadow colors. */
8719
8720 /* Allocate them, if necessary. */
8721 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
8722 {
8723 pixel = f->output_data.x->scroll_bar_background_pixel;
8724 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8725 &pixel, 1.2, 0x8000))
8726 pixel = -1;
8727 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
8728 }
8729 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8730 {
8731 pixel = f->output_data.x->scroll_bar_background_pixel;
8732 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8733 &pixel, 0.6, 0x4000))
8734 pixel = -1;
8735 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
8736 }
8737
8738 /* Tell the toolkit about them. */
8739 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
8740 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8741 /* We tried to allocate a color for the top/bottom shadow, and
8742 failed, so tell Xaw3d to use dithering instead. */
8743 {
8744 XtSetArg (av[ac], XtNbeNiceToColormap, True);
8745 ++ac;
8746 }
8747 else
8748 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
8749 be more consistent with other emacs 3d colors, and since Xaw3d is
8750 not good at dealing with allocation failure. */
8751 {
8752 /* This tells Xaw3d to use real colors instead of dithering for
8753 the shadows. */
8754 XtSetArg (av[ac], XtNbeNiceToColormap, False);
8755 ++ac;
8756
8757 /* Specify the colors. */
8758 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
8759 if (pixel != -1)
8760 {
8761 XtSetArg (av[ac], "topShadowPixel", pixel);
8762 ++ac;
8763 }
8764 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
8765 if (pixel != -1)
8766 {
8767 XtSetArg (av[ac], "bottomShadowPixel", pixel);
8768 ++ac;
8769 }
8770 }
8771
06a2c219
GM
8772 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
8773 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
8774
8775 {
8776 char *initial = "";
8777 char *val = initial;
8778 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
8779 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
8780 if (val == initial)
8781 { /* ARROW_SCROLL */
8782 xaw3d_arrow_scroll = True;
8783 /* Isn't that just a personal preference ? -sm */
8784 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
8785 }
8786 }
06a2c219
GM
8787
8788 /* Define callbacks. */
ec18280f
SM
8789 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
8790 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
8791 (XtPointer) bar);
8792
8793 /* Realize the widget. Only after that is the X window created. */
8794 XtRealizeWidget (widget);
8795
ec18280f 8796#endif /* !USE_MOTIF */
06a2c219
GM
8797
8798 /* Install an action hook that let's us detect when the user
8799 finishes interacting with a scroll bar. */
8800 if (action_hook_id == 0)
8801 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
8802
8803 /* Remember X window and widget in the scroll bar vector. */
8804 SET_SCROLL_BAR_X_WIDGET (bar, widget);
8805 xwindow = XtWindow (widget);
8806 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
8807
8808 UNBLOCK_INPUT;
8809}
8810
8811
8812/* Set the thumb size and position of scroll bar BAR. We are currently
8813 displaying PORTION out of a whole WHOLE, and our position POSITION. */
8814
8815static void
8816x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
8817 struct scroll_bar *bar;
8818 int portion, position, whole;
f451eb13 8819{
e83dc917
GM
8820 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8821 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
06a2c219 8822 float top, shown;
f451eb13 8823
6f2a7a68
SM
8824 BLOCK_INPUT;
8825
8826#ifdef USE_MOTIF
8827
8828 /* We use an estimate of 30 chars per line rather than the real
8829 `portion' value. This has the disadvantage that the thumb size
8830 is not very representative, but it makes our life a lot easier.
8831 Otherwise, we have to constantly adjust the thumb size, which
8832 we can't always do quickly enough: while dragging, the size of
8833 the thumb might prevent the user from dragging the thumb all the
8834 way to the end. but Motif and some versions of Xaw3d don't allow
8835 updating the thumb size while dragging. Also, even if we can update
8836 its size, the update will often happen too late.
8837 If you don't believe it, check out revision 1.650 of xterm.c to see
8838 what hoops we were going through and the still poor behavior we got. */
8839 portion = XFASTINT (XWINDOW (bar->window)->height) * 30;
8840 /* When the thumb is at the bottom, position == whole.
8841 So we need to increase `whole' to make space for the thumb. */
8842 whole += portion;
8843
8844 if (whole <= 0)
06a2c219
GM
8845 top = 0, shown = 1;
8846 else
f451eb13 8847 {
06a2c219
GM
8848 top = (float) position / whole;
8849 shown = (float) portion / whole;
8850 }
f451eb13 8851
6f2a7a68
SM
8852 if (NILP (bar->dragging))
8853 {
8854 int size, value;
06a2c219 8855
6f2a7a68
SM
8856 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
8857 is the scroll bar's maximum and MIN is the scroll bar's minimum
8858 value. */
8859 size = shown * XM_SB_RANGE;
8860 size = min (size, XM_SB_RANGE);
8861 size = max (size, 1);
06a2c219 8862
6f2a7a68
SM
8863 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
8864 value = top * XM_SB_RANGE;
8865 value = min (value, XM_SB_MAX - size);
8866 value = max (value, XM_SB_MIN);
8867
06a2c219 8868 XmScrollBarSetValues (widget, value, size, 0, 0, False);
6f2a7a68 8869 }
ec18280f 8870#else /* !USE_MOTIF i.e. use Xaw */
6f2a7a68
SM
8871
8872 if (whole == 0)
8873 top = 0, shown = 1;
8874 else
8875 {
8876 top = (float) position / whole;
8877 shown = (float) portion / whole;
8878 }
8879
06a2c219 8880 {
ec18280f
SM
8881 float old_top, old_shown;
8882 Dimension height;
8883 XtVaGetValues (widget,
8884 XtNtopOfThumb, &old_top,
8885 XtNshown, &old_shown,
8886 XtNheight, &height,
8887 NULL);
8888
8889 /* Massage the top+shown values. */
8890 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8891 top = max (0, min (1, top));
8892 else
8893 top = old_top;
8894 /* Keep two pixels available for moving the thumb down. */
8895 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8896
8897 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8898 check that your system's configuration file contains a define
8899 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8900 if (top != old_top || shown != old_shown)
eb393530 8901 {
ec18280f 8902 if (NILP (bar->dragging))
eb393530 8903 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8904 else
8905 {
ec18280f
SM
8906#ifdef HAVE_XAW3D
8907 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8908 int scroll_mode = 0;
ec18280f
SM
8909
8910 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8911 if (xaw3d_arrow_scroll)
8912 {
8913 /* Xaw3d stupidly ignores resize requests while dragging
8914 so we have to make it believe it's not in dragging mode. */
8915 scroll_mode = sb->scrollbar.scroll_mode;
8916 if (scroll_mode == 2)
8917 sb->scrollbar.scroll_mode = 0;
8918 }
8919#endif
8920 /* Try to make the scrolling a tad smoother. */
8921 if (!xaw3d_pick_top)
8922 shown = min (shown, old_shown);
8923
8924 XawScrollbarSetThumb (widget, top, shown);
8925
8926#ifdef HAVE_XAW3D
8927 if (xaw3d_arrow_scroll && scroll_mode == 2)
8928 sb->scrollbar.scroll_mode = scroll_mode;
8929#endif
06a2c219 8930 }
06a2c219
GM
8931 }
8932 }
ec18280f 8933#endif /* !USE_MOTIF */
06a2c219
GM
8934
8935 UNBLOCK_INPUT;
f451eb13
JB
8936}
8937
06a2c219
GM
8938#endif /* USE_TOOLKIT_SCROLL_BARS */
8939
8940
8941\f
8942/************************************************************************
8943 Scroll bars, general
8944 ************************************************************************/
8945
8946/* Create a scroll bar and return the scroll bar vector for it. W is
8947 the Emacs window on which to create the scroll bar. TOP, LEFT,
f7ccf929 8948 WIDTH and HEIGHT are the pixel coordinates and dimensions of the
06a2c219
GM
8949 scroll bar. */
8950
ab648270 8951static struct scroll_bar *
06a2c219
GM
8952x_scroll_bar_create (w, top, left, width, height)
8953 struct window *w;
f451eb13
JB
8954 int top, left, width, height;
8955{
06a2c219 8956 struct frame *f = XFRAME (w->frame);
334208b7
RS
8957 struct scroll_bar *bar
8958 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8959
8960 BLOCK_INPUT;
8961
eccc05db 8962#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8963 x_create_toolkit_scroll_bar (f, bar);
8964#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8965 {
8966 XSetWindowAttributes a;
8967 unsigned long mask;
5c187dee 8968 Window window;
06a2c219
GM
8969
8970 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8971 if (a.background_pixel == -1)
8972 a.background_pixel = f->output_data.x->background_pixel;
8973
12ba150f 8974 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 8975 | ButtonMotionMask | PointerMotionHintMask
12ba150f 8976 | ExposureMask);
7a13e894 8977 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 8978
dbc4e1c1 8979 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8980
06a2c219
GM
8981 /* Clear the area of W that will serve as a scroll bar. This is
8982 for the case that a window has been split horizontally. In
8983 this case, no clear_frame is generated to reduce flickering. */
7b49b9d2
GM
8984 if (width > 0 && height > 0)
8985 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8986 left, top, width,
8987 window_box_height (w), False);
06a2c219
GM
8988
8989 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8990 /* Position and size of scroll bar. */
8991 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8992 top,
8993 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8994 height,
8995 /* Border width, depth, class, and visual. */
8996 0,
8997 CopyFromParent,
8998 CopyFromParent,
8999 CopyFromParent,
9000 /* Attributes. */
9001 mask, &a);
9002 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 9003 }
06a2c219 9004#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9005
06a2c219 9006 XSETWINDOW (bar->window, w);
e0c1aef2
KH
9007 XSETINT (bar->top, top);
9008 XSETINT (bar->left, left);
9009 XSETINT (bar->width, width);
9010 XSETINT (bar->height, height);
9011 XSETINT (bar->start, 0);
9012 XSETINT (bar->end, 0);
12ba150f 9013 bar->dragging = Qnil;
f451eb13
JB
9014
9015 /* Add bar to its frame's list of scroll bars. */
334208b7 9016 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 9017 bar->prev = Qnil;
334208b7 9018 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 9019 if (!NILP (bar->next))
e0c1aef2 9020 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 9021
06a2c219 9022 /* Map the window/widget. */
eccc05db 9023#ifdef USE_TOOLKIT_SCROLL_BARS
f964b4d7
GM
9024 {
9025 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
9026 XtConfigureWidget (scroll_bar,
9027 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9028 top,
9029 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
9030 max (height, 1), 0);
9031 XtMapWidget (scroll_bar);
9032 }
06a2c219 9033#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 9034 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 9035#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9036
9037 UNBLOCK_INPUT;
12ba150f 9038 return bar;
f451eb13
JB
9039}
9040
06a2c219 9041
12ba150f 9042/* Draw BAR's handle in the proper position.
06a2c219 9043
12ba150f
JB
9044 If the handle is already drawn from START to END, don't bother
9045 redrawing it, unless REBUILD is non-zero; in that case, always
9046 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 9047 events.)
12ba150f
JB
9048
9049 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
9050 fit inside its rectangle, but if the user is dragging the scroll
9051 bar handle, we want to let them drag it down all the way, so that
9052 the bar's top is as far down as it goes; otherwise, there's no way
9053 to move to the very end of the buffer. */
9054
5c187dee
GM
9055#ifndef USE_TOOLKIT_SCROLL_BARS
9056
f451eb13 9057static void
ab648270
JB
9058x_scroll_bar_set_handle (bar, start, end, rebuild)
9059 struct scroll_bar *bar;
f451eb13 9060 int start, end;
12ba150f 9061 int rebuild;
f451eb13 9062{
12ba150f 9063 int dragging = ! NILP (bar->dragging);
ab648270 9064 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9065 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9066 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
9067
9068 /* If the display is already accurate, do nothing. */
9069 if (! rebuild
9070 && start == XINT (bar->start)
9071 && end == XINT (bar->end))
9072 return;
9073
f451eb13
JB
9074 BLOCK_INPUT;
9075
9076 {
d9cdbb3d
RS
9077 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
9078 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
9079 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
9080
9081 /* Make sure the values are reasonable, and try to preserve
9082 the distance between start and end. */
12ba150f
JB
9083 {
9084 int length = end - start;
9085
9086 if (start < 0)
9087 start = 0;
9088 else if (start > top_range)
9089 start = top_range;
9090 end = start + length;
9091
9092 if (end < start)
9093 end = start;
9094 else if (end > top_range && ! dragging)
9095 end = top_range;
9096 }
f451eb13 9097
ab648270 9098 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
9099 XSETINT (bar->start, start);
9100 XSETINT (bar->end, end);
f451eb13 9101
12ba150f
JB
9102 /* Clip the end position, just for display. */
9103 if (end > top_range)
9104 end = top_range;
f451eb13 9105
ab648270 9106 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
9107 below top positions, to make sure the handle is always at least
9108 that many pixels tall. */
ab648270 9109 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 9110
12ba150f
JB
9111 /* Draw the empty space above the handle. Note that we can't clear
9112 zero-height areas; that means "clear to end of window." */
9113 if (0 < start)
c5e6e06b
GM
9114 x_clear_area (FRAME_X_DISPLAY (f), w,
9115 /* x, y, width, height, and exposures. */
9116 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9117 VERTICAL_SCROLL_BAR_TOP_BORDER,
9118 inside_width, start,
9119 False);
f451eb13 9120
06a2c219
GM
9121 /* Change to proper foreground color if one is specified. */
9122 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9123 XSetForeground (FRAME_X_DISPLAY (f), gc,
9124 f->output_data.x->scroll_bar_foreground_pixel);
9125
12ba150f 9126 /* Draw the handle itself. */
334208b7 9127 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
12ba150f 9128 /* x, y, width, height */
ab648270
JB
9129 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9130 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 9131 inside_width, end - start);
f451eb13 9132
06a2c219
GM
9133 /* Restore the foreground color of the GC if we changed it above. */
9134 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9135 XSetForeground (FRAME_X_DISPLAY (f), gc,
9136 f->output_data.x->foreground_pixel);
f451eb13 9137
12ba150f
JB
9138 /* Draw the empty space below the handle. Note that we can't
9139 clear zero-height areas; that means "clear to end of window." */
9140 if (end < inside_height)
c5e6e06b
GM
9141 x_clear_area (FRAME_X_DISPLAY (f), w,
9142 /* x, y, width, height, and exposures. */
9143 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9144 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
9145 inside_width, inside_height - end,
9146 False);
f451eb13 9147
f451eb13
JB
9148 }
9149
f451eb13
JB
9150 UNBLOCK_INPUT;
9151}
9152
5c187dee 9153#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 9154
06a2c219
GM
9155/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
9156 nil. */
58769bee 9157
12ba150f 9158static void
ab648270
JB
9159x_scroll_bar_remove (bar)
9160 struct scroll_bar *bar;
12ba150f 9161{
e83dc917 9162 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
9163 BLOCK_INPUT;
9164
eccc05db 9165#ifdef USE_TOOLKIT_SCROLL_BARS
e83dc917
GM
9166 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
9167#else
9168 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
9169#endif
06a2c219 9170
ab648270
JB
9171 /* Disassociate this scroll bar from its window. */
9172 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
9173
9174 UNBLOCK_INPUT;
9175}
9176
06a2c219 9177
12ba150f
JB
9178/* Set the handle of the vertical scroll bar for WINDOW to indicate
9179 that we are displaying PORTION characters out of a total of WHOLE
ab648270 9180 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 9181 create one. */
06a2c219 9182
12ba150f 9183static void
06a2c219
GM
9184XTset_vertical_scroll_bar (w, portion, whole, position)
9185 struct window *w;
f451eb13
JB
9186 int portion, whole, position;
9187{
06a2c219 9188 struct frame *f = XFRAME (w->frame);
ab648270 9189 struct scroll_bar *bar;
3c6ede7b 9190 int top, height, left, sb_left, width, sb_width;
06a2c219 9191 int window_x, window_y, window_width, window_height;
06a2c219 9192
3c6ede7b 9193 /* Get window dimensions. */
06a2c219 9194 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
9195 top = window_y;
9196 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9197 height = window_height;
06a2c219 9198
3c6ede7b 9199 /* Compute the left edge of the scroll bar area. */
06a2c219 9200 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
9201 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
9202 else
9203 left = XFASTINT (w->left);
9204 left *= CANON_X_UNIT (f);
9205 left += FRAME_INTERNAL_BORDER_WIDTH (f);
9206
9207 /* Compute the width of the scroll bar which might be less than
9208 the width of the area reserved for the scroll bar. */
9209 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
9210 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 9211 else
3c6ede7b 9212 sb_width = width;
12ba150f 9213
3c6ede7b
GM
9214 /* Compute the left edge of the scroll bar. */
9215#ifdef USE_TOOLKIT_SCROLL_BARS
9216 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9217 sb_left = left + width - sb_width - (width - sb_width) / 2;
9218 else
9219 sb_left = left + (width - sb_width) / 2;
9220#else
9221 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9222 sb_left = left + width - sb_width;
9223 else
9224 sb_left = left;
9225#endif
9226
ab648270 9227 /* Does the scroll bar exist yet? */
06a2c219 9228 if (NILP (w->vertical_scroll_bar))
3c6ede7b 9229 {
7b49b9d2 9230 if (width > 0 && height > 0)
b547b6e8
GM
9231 {
9232 BLOCK_INPUT;
9233 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9234 left, top, width, height, False);
9235 UNBLOCK_INPUT;
9236 }
9237
3c6ede7b
GM
9238 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
9239 }
f451eb13 9240 else
12ba150f
JB
9241 {
9242 /* It may just need to be moved and resized. */
06a2c219
GM
9243 unsigned int mask = 0;
9244
9245 bar = XSCROLL_BAR (w->vertical_scroll_bar);
9246
9247 BLOCK_INPUT;
9248
3c6ede7b 9249 if (sb_left != XINT (bar->left))
06a2c219 9250 mask |= CWX;
3c6ede7b 9251 if (top != XINT (bar->top))
06a2c219 9252 mask |= CWY;
3c6ede7b 9253 if (sb_width != XINT (bar->width))
06a2c219 9254 mask |= CWWidth;
3c6ede7b 9255 if (height != XINT (bar->height))
06a2c219
GM
9256 mask |= CWHeight;
9257
9258#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
9259
9260 /* Since toolkit scroll bars are smaller than the space reserved
9261 for them on the frame, we have to clear "under" them. */
7b49b9d2 9262 if (width > 0 && height > 0)
f964b4d7
GM
9263 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9264 left, top, width, height, False);
06a2c219
GM
9265
9266 /* Move/size the scroll bar widget. */
9267 if (mask)
e83dc917 9268 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
3c6ede7b
GM
9269 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9270 top,
9271 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
f964b4d7 9272 max (height, 1), 0);
06a2c219
GM
9273
9274#else /* not USE_TOOLKIT_SCROLL_BARS */
9275
357e7376
GM
9276 /* Clear areas not covered by the scroll bar because of
9277 VERTICAL_SCROLL_BAR_WIDTH_TRIM. */
e1f6572f
RS
9278 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
9279 {
c5e6e06b
GM
9280 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9281 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9282 height, False);
9283 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9284 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9285 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9286 height, False);
e1f6572f 9287 }
357e7376
GM
9288
9289 /* Clear areas not covered by the scroll bar because it's not as
f7ccf929 9290 wide as the area reserved for it. This makes sure a
357e7376
GM
9291 previous mode line display is cleared after C-x 2 C-x 1, for
9292 example. */
9293 {
9294 int area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9295 int rest = area_width - sb_width;
38d2af0c
GM
9296 if (rest > 0 && height > 0)
9297 {
9298 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
9299 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9300 left + area_width - rest, top,
9301 rest, height, False);
9302 else
9303 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9304 left, top, rest, height, False);
9305 }
357e7376 9306 }
06a2c219
GM
9307
9308 /* Move/size the scroll bar window. */
9309 if (mask)
9310 {
9311 XWindowChanges wc;
9312
3c6ede7b
GM
9313 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
9314 wc.y = top;
9315 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
9316 wc.height = height;
06a2c219
GM
9317 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
9318 mask, &wc);
9319 }
9320
9321#endif /* not USE_TOOLKIT_SCROLL_BARS */
9322
9323 /* Remember new settings. */
3c6ede7b
GM
9324 XSETINT (bar->left, sb_left);
9325 XSETINT (bar->top, top);
9326 XSETINT (bar->width, sb_width);
9327 XSETINT (bar->height, height);
06a2c219
GM
9328
9329 UNBLOCK_INPUT;
12ba150f 9330 }
f451eb13 9331
eccc05db 9332#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
9333 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
9334#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 9335 /* Set the scroll bar's current state, unless we're currently being
f451eb13 9336 dragged. */
12ba150f 9337 if (NILP (bar->dragging))
f451eb13 9338 {
92857db0 9339 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 9340
12ba150f 9341 if (whole == 0)
ab648270 9342 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
9343 else
9344 {
43f868f5
JB
9345 int start = ((double) position * top_range) / whole;
9346 int end = ((double) (position + portion) * top_range) / whole;
ab648270 9347 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 9348 }
f451eb13 9349 }
06a2c219 9350#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9351
06a2c219 9352 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
9353}
9354
12ba150f 9355
f451eb13 9356/* The following three hooks are used when we're doing a thorough
ab648270 9357 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 9358 are going to be deleted, because keeping track of when windows go
12ba150f
JB
9359 away is a real pain - "Can you say set-window-configuration, boys
9360 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 9361 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 9362 from the fiery pit when we actually redisplay its window. */
f451eb13 9363
ab648270
JB
9364/* Arrange for all scroll bars on FRAME to be removed at the next call
9365 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
9366 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
9367
58769bee 9368static void
ab648270 9369XTcondemn_scroll_bars (frame)
f451eb13
JB
9370 FRAME_PTR frame;
9371{
f9e24cb9
RS
9372 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
9373 while (! NILP (FRAME_SCROLL_BARS (frame)))
9374 {
9375 Lisp_Object bar;
9376 bar = FRAME_SCROLL_BARS (frame);
9377 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
9378 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
9379 XSCROLL_BAR (bar)->prev = Qnil;
9380 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
9381 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
9382 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
9383 }
f451eb13
JB
9384}
9385
fa2dfc30 9386
06a2c219 9387/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 9388 Note that WINDOW isn't necessarily condemned at all. */
fa2dfc30 9389
f451eb13 9390static void
ab648270 9391XTredeem_scroll_bar (window)
12ba150f 9392 struct window *window;
f451eb13 9393{
ab648270 9394 struct scroll_bar *bar;
fa2dfc30 9395 struct frame *f;
12ba150f 9396
ab648270
JB
9397 /* We can't redeem this window's scroll bar if it doesn't have one. */
9398 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
9399 abort ();
9400
ab648270 9401 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
9402
9403 /* Unlink it from the condemned list. */
fa2dfc30
GM
9404 f = XFRAME (WINDOW_FRAME (window));
9405 if (NILP (bar->prev))
9406 {
9407 /* If the prev pointer is nil, it must be the first in one of
9408 the lists. */
9409 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
9410 /* It's not condemned. Everything's fine. */
9411 return;
9412 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
9413 window->vertical_scroll_bar))
9414 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
9415 else
9416 /* If its prev pointer is nil, it must be at the front of
9417 one or the other! */
9418 abort ();
9419 }
9420 else
9421 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f 9422
fa2dfc30
GM
9423 if (! NILP (bar->next))
9424 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 9425
fa2dfc30
GM
9426 bar->next = FRAME_SCROLL_BARS (f);
9427 bar->prev = Qnil;
9428 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
9429 if (! NILP (bar->next))
9430 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13
JB
9431}
9432
ab648270
JB
9433/* Remove all scroll bars on FRAME that haven't been saved since the
9434 last call to `*condemn_scroll_bars_hook'. */
06a2c219 9435
f451eb13 9436static void
ab648270 9437XTjudge_scroll_bars (f)
12ba150f 9438 FRAME_PTR f;
f451eb13 9439{
12ba150f 9440 Lisp_Object bar, next;
f451eb13 9441
ab648270 9442 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
9443
9444 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
9445 more events on the hapless scroll bars. */
9446 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
9447
9448 for (; ! NILP (bar); bar = next)
f451eb13 9449 {
ab648270 9450 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 9451
ab648270 9452 x_scroll_bar_remove (b);
12ba150f
JB
9453
9454 next = b->next;
9455 b->next = b->prev = Qnil;
f451eb13 9456 }
12ba150f 9457
ab648270 9458 /* Now there should be no references to the condemned scroll bars,
12ba150f 9459 and they should get garbage-collected. */
f451eb13
JB
9460}
9461
9462
06a2c219
GM
9463/* Handle an Expose or GraphicsExpose event on a scroll bar. This
9464 is a no-op when using toolkit scroll bars.
ab648270
JB
9465
9466 This may be called from a signal handler, so we have to ignore GC
9467 mark bits. */
06a2c219 9468
f451eb13 9469static void
ab648270
JB
9470x_scroll_bar_expose (bar, event)
9471 struct scroll_bar *bar;
f451eb13
JB
9472 XEvent *event;
9473{
06a2c219
GM
9474#ifndef USE_TOOLKIT_SCROLL_BARS
9475
ab648270 9476 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9477 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9478 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 9479 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 9480
f451eb13
JB
9481 BLOCK_INPUT;
9482
ab648270 9483 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 9484
06a2c219 9485 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 9486 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
9487
9488 /* x, y, width, height */
d9cdbb3d 9489 0, 0,
3cbd2e0b 9490 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
9491 XINT (bar->height) - 1);
9492
f451eb13 9493 UNBLOCK_INPUT;
06a2c219
GM
9494
9495#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9496}
9497
ab648270
JB
9498/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
9499 is set to something other than no_event, it is enqueued.
9500
9501 This may be called from a signal handler, so we have to ignore GC
9502 mark bits. */
06a2c219 9503
5c187dee
GM
9504#ifndef USE_TOOLKIT_SCROLL_BARS
9505
f451eb13 9506static void
ab648270
JB
9507x_scroll_bar_handle_click (bar, event, emacs_event)
9508 struct scroll_bar *bar;
f451eb13
JB
9509 XEvent *event;
9510 struct input_event *emacs_event;
9511{
0299d313 9512 if (! GC_WINDOWP (bar->window))
12ba150f
JB
9513 abort ();
9514
ab648270 9515 emacs_event->kind = scroll_bar_click;
69388238 9516 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
9517 emacs_event->modifiers
9518 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
9519 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
9520 event->xbutton.state)
9521 | (event->type == ButtonRelease
9522 ? up_modifier
9523 : down_modifier));
12ba150f 9524 emacs_event->frame_or_window = bar->window;
0f8aabe9 9525 emacs_event->arg = Qnil;
f451eb13 9526 emacs_event->timestamp = event->xbutton.time;
12ba150f 9527 {
06a2c219 9528#if 0
d9cdbb3d 9529 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 9530 int internal_height
d9cdbb3d 9531 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9532#endif
0299d313 9533 int top_range
d9cdbb3d 9534 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 9535 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
9536
9537 if (y < 0) y = 0;
9538 if (y > top_range) y = top_range;
9539
9540 if (y < XINT (bar->start))
ab648270
JB
9541 emacs_event->part = scroll_bar_above_handle;
9542 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9543 emacs_event->part = scroll_bar_handle;
12ba150f 9544 else
ab648270 9545 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
9546
9547 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
9548 they want to drag it. Lisp code needs to be able to decide
9549 whether or not we're dragging. */
929787e1 9550#if 0
12ba150f
JB
9551 /* If the user has just clicked on the handle, record where they're
9552 holding it. */
9553 if (event->type == ButtonPress
ab648270 9554 && emacs_event->part == scroll_bar_handle)
e0c1aef2 9555 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 9556#endif
12ba150f
JB
9557
9558 /* If the user has released the handle, set it to its final position. */
9559 if (event->type == ButtonRelease
9560 && ! NILP (bar->dragging))
9561 {
9562 int new_start = y - XINT (bar->dragging);
9563 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 9564
ab648270 9565 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
9566 bar->dragging = Qnil;
9567 }
f451eb13 9568
5116f055
JB
9569 /* Same deal here as the other #if 0. */
9570#if 0
58769bee 9571 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 9572 the handle. */
ab648270 9573 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
9574 emacs_event->x = bar->start;
9575 else
e0c1aef2 9576 XSETINT (emacs_event->x, y);
5116f055 9577#else
e0c1aef2 9578 XSETINT (emacs_event->x, y);
5116f055 9579#endif
f451eb13 9580
e0c1aef2 9581 XSETINT (emacs_event->y, top_range);
12ba150f
JB
9582 }
9583}
f451eb13 9584
ab648270
JB
9585/* Handle some mouse motion while someone is dragging the scroll bar.
9586
9587 This may be called from a signal handler, so we have to ignore GC
9588 mark bits. */
06a2c219 9589
f451eb13 9590static void
ab648270
JB
9591x_scroll_bar_note_movement (bar, event)
9592 struct scroll_bar *bar;
f451eb13
JB
9593 XEvent *event;
9594{
39d8bb4d
KH
9595 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
9596
f451eb13
JB
9597 last_mouse_movement_time = event->xmotion.time;
9598
39d8bb4d 9599 f->mouse_moved = 1;
e0c1aef2 9600 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
9601
9602 /* If we're dragging the bar, display it. */
ab648270 9603 if (! GC_NILP (bar->dragging))
f451eb13
JB
9604 {
9605 /* Where should the handle be now? */
12ba150f 9606 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 9607
12ba150f 9608 if (new_start != XINT (bar->start))
f451eb13 9609 {
12ba150f 9610 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 9611
ab648270 9612 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
9613 }
9614 }
f451eb13
JB
9615}
9616
5c187dee
GM
9617#endif /* !USE_TOOLKIT_SCROLL_BARS */
9618
12ba150f 9619/* Return information to the user about the current position of the mouse
ab648270 9620 on the scroll bar. */
06a2c219 9621
12ba150f 9622static void
334208b7
RS
9623x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
9624 FRAME_PTR *fp;
12ba150f 9625 Lisp_Object *bar_window;
ab648270 9626 enum scroll_bar_part *part;
12ba150f
JB
9627 Lisp_Object *x, *y;
9628 unsigned long *time;
9629{
ab648270 9630 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
9631 Window w = SCROLL_BAR_X_WINDOW (bar);
9632 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 9633 int win_x, win_y;
559cb2fb
JB
9634 Window dummy_window;
9635 int dummy_coord;
9636 unsigned int dummy_mask;
12ba150f 9637
cf7cb199
JB
9638 BLOCK_INPUT;
9639
ab648270 9640 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 9641 report that. */
334208b7 9642 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 9643
559cb2fb
JB
9644 /* Root, child, root x and root y. */
9645 &dummy_window, &dummy_window,
9646 &dummy_coord, &dummy_coord,
12ba150f 9647
559cb2fb
JB
9648 /* Position relative to scroll bar. */
9649 &win_x, &win_y,
12ba150f 9650
559cb2fb
JB
9651 /* Mouse buttons and modifier keys. */
9652 &dummy_mask))
7a13e894 9653 ;
559cb2fb
JB
9654 else
9655 {
06a2c219 9656#if 0
559cb2fb 9657 int inside_height
d9cdbb3d 9658 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9659#endif
559cb2fb 9660 int top_range
d9cdbb3d 9661 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
9662
9663 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
9664
9665 if (! NILP (bar->dragging))
9666 win_y -= XINT (bar->dragging);
9667
9668 if (win_y < 0)
9669 win_y = 0;
9670 if (win_y > top_range)
9671 win_y = top_range;
9672
334208b7 9673 *fp = f;
7a13e894 9674 *bar_window = bar->window;
559cb2fb
JB
9675
9676 if (! NILP (bar->dragging))
9677 *part = scroll_bar_handle;
9678 else if (win_y < XINT (bar->start))
9679 *part = scroll_bar_above_handle;
9680 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9681 *part = scroll_bar_handle;
9682 else
9683 *part = scroll_bar_below_handle;
12ba150f 9684
e0c1aef2
KH
9685 XSETINT (*x, win_y);
9686 XSETINT (*y, top_range);
12ba150f 9687
39d8bb4d 9688 f->mouse_moved = 0;
559cb2fb
JB
9689 last_mouse_scroll_bar = Qnil;
9690 }
12ba150f 9691
559cb2fb 9692 *time = last_mouse_movement_time;
cf7cb199 9693
cf7cb199 9694 UNBLOCK_INPUT;
12ba150f
JB
9695}
9696
f451eb13 9697
dbc4e1c1 9698/* The screen has been cleared so we may have changed foreground or
ab648270
JB
9699 background colors, and the scroll bars may need to be redrawn.
9700 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
9701 redraw them. */
9702
dfcf069d 9703void
ab648270 9704x_scroll_bar_clear (f)
dbc4e1c1
JB
9705 FRAME_PTR f;
9706{
06a2c219 9707#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
9708 Lisp_Object bar;
9709
b80c363e
RS
9710 /* We can have scroll bars even if this is 0,
9711 if we just turned off scroll bar mode.
9712 But in that case we should not clear them. */
9713 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
9714 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
9715 bar = XSCROLL_BAR (bar)->next)
c5e6e06b
GM
9716 XClearArea (FRAME_X_DISPLAY (f),
9717 SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
b80c363e 9718 0, 0, 0, 0, True);
06a2c219 9719#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
9720}
9721
06a2c219 9722/* This processes Expose events from the menu-bar specific X event
19126e11 9723 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 9724 when handling menu-bar or pop-up items. */
3afe33e7 9725
06a2c219 9726int
3afe33e7
RS
9727process_expose_from_menu (event)
9728 XEvent event;
9729{
9730 FRAME_PTR f;
19126e11 9731 struct x_display_info *dpyinfo;
06a2c219 9732 int frame_exposed_p = 0;
3afe33e7 9733
f94397b5
KH
9734 BLOCK_INPUT;
9735
19126e11
KH
9736 dpyinfo = x_display_info_for_display (event.xexpose.display);
9737 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
9738 if (f)
9739 {
9740 if (f->async_visible == 0)
9741 {
9742 f->async_visible = 1;
9743 f->async_iconified = 0;
06c488fd 9744 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
9745 SET_FRAME_GARBAGED (f);
9746 }
9747 else
9748 {
06a2c219
GM
9749 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
9750 event.xexpose.x, event.xexpose.y,
9751 event.xexpose.width, event.xexpose.height);
9752 frame_exposed_p = 1;
3afe33e7
RS
9753 }
9754 }
9755 else
9756 {
9757 struct scroll_bar *bar
9758 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9759
3afe33e7
RS
9760 if (bar)
9761 x_scroll_bar_expose (bar, &event);
9762 }
f94397b5
KH
9763
9764 UNBLOCK_INPUT;
06a2c219 9765 return frame_exposed_p;
3afe33e7 9766}
09756a85
RS
9767\f
9768/* Define a queue to save up SelectionRequest events for later handling. */
9769
9770struct selection_event_queue
9771 {
9772 XEvent event;
9773 struct selection_event_queue *next;
9774 };
9775
9776static struct selection_event_queue *queue;
9777
9778/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 9779
09756a85
RS
9780static int x_queue_selection_requests;
9781
9782/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 9783
09756a85 9784static void
334208b7
RS
9785x_queue_event (f, event)
9786 FRAME_PTR f;
09756a85
RS
9787 XEvent *event;
9788{
9789 struct selection_event_queue *queue_tmp
06a2c219 9790 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 9791
58769bee 9792 if (queue_tmp != NULL)
09756a85
RS
9793 {
9794 queue_tmp->event = *event;
9795 queue_tmp->next = queue;
9796 queue = queue_tmp;
9797 }
9798}
9799
9800/* Take all the queued events and put them back
9801 so that they get processed afresh. */
9802
9803static void
db3906fd
RS
9804x_unqueue_events (display)
9805 Display *display;
09756a85 9806{
58769bee 9807 while (queue != NULL)
09756a85
RS
9808 {
9809 struct selection_event_queue *queue_tmp = queue;
db3906fd 9810 XPutBackEvent (display, &queue_tmp->event);
09756a85 9811 queue = queue_tmp->next;
06a2c219 9812 xfree ((char *)queue_tmp);
09756a85
RS
9813 }
9814}
9815
9816/* Start queuing SelectionRequest events. */
9817
9818void
db3906fd
RS
9819x_start_queuing_selection_requests (display)
9820 Display *display;
09756a85
RS
9821{
9822 x_queue_selection_requests++;
9823}
9824
9825/* Stop queuing SelectionRequest events. */
9826
9827void
db3906fd
RS
9828x_stop_queuing_selection_requests (display)
9829 Display *display;
09756a85
RS
9830{
9831 x_queue_selection_requests--;
db3906fd 9832 x_unqueue_events (display);
09756a85 9833}
f451eb13
JB
9834\f
9835/* The main X event-reading loop - XTread_socket. */
dc6f92b8 9836
042c33d3 9837#if 0
06a2c219 9838/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
9839 but we have to put it out here, since static variables within functions
9840 sometimes don't work. */
06a2c219 9841
dc6f92b8 9842static Time enter_timestamp;
042c33d3 9843#endif
dc6f92b8 9844
11edeb03 9845/* This holds the state XLookupString needs to implement dead keys
58769bee 9846 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
9847 says that a portable program can't use this, but Stephen Gildea assures
9848 me that letting the compiler initialize it to zeros will work okay.
9849
9850 This must be defined outside of XTread_socket, for the same reasons
f7d40b3b 9851 given for enter_timestamp, above. */
06a2c219 9852
11edeb03
JB
9853static XComposeStatus compose_status;
9854
10e6549c
RS
9855/* Record the last 100 characters stored
9856 to help debug the loss-of-chars-during-GC problem. */
06a2c219 9857
2224b905
RS
9858static int temp_index;
9859static short temp_buffer[100];
10e6549c 9860
7a13e894
RS
9861/* Set this to nonzero to fake an "X I/O error"
9862 on a particular display. */
06a2c219 9863
7a13e894
RS
9864struct x_display_info *XTread_socket_fake_io_error;
9865
2224b905
RS
9866/* When we find no input here, we occasionally do a no-op command
9867 to verify that the X server is still running and we can still talk with it.
9868 We try all the open displays, one by one.
9869 This variable is used for cycling thru the displays. */
06a2c219 9870
2224b905
RS
9871static struct x_display_info *next_noop_dpyinfo;
9872
06a2c219
GM
9873#define SET_SAVED_MENU_EVENT(size) \
9874 do \
9875 { \
9876 if (f->output_data.x->saved_menu_event == 0) \
9877 f->output_data.x->saved_menu_event \
9878 = (XEvent *) xmalloc (sizeof (XEvent)); \
9879 bcopy (&event, f->output_data.x->saved_menu_event, size); \
9880 if (numchars >= 1) \
9881 { \
9882 bufp->kind = menu_bar_activate_event; \
9883 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 9884 bufp->arg = Qnil; \
06a2c219
GM
9885 bufp++; \
9886 count++; \
9887 numchars--; \
9888 } \
9889 } \
9890 while (0)
9891
8805890a 9892#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 9893#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 9894
dc6f92b8
JB
9895/* Read events coming from the X server.
9896 This routine is called by the SIGIO handler.
9897 We return as soon as there are no more events to be read.
9898
9899 Events representing keys are stored in buffer BUFP,
9900 which can hold up to NUMCHARS characters.
9901 We return the number of characters stored into the buffer,
9902 thus pretending to be `read'.
9903
dc6f92b8
JB
9904 EXPECTED is nonzero if the caller knows input is available. */
9905
6f2a7a68 9906static int
f66868ba 9907XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 9908 register int sd;
8805890a
KH
9909 /* register */ struct input_event *bufp;
9910 /* register */ int numchars;
dc6f92b8
JB
9911 int expected;
9912{
9913 int count = 0;
9914 int nbytes = 0;
dc6f92b8 9915 XEvent event;
f676886a 9916 struct frame *f;
66f55a9d 9917 int event_found = 0;
334208b7 9918 struct x_display_info *dpyinfo;
379b5ac0 9919 struct coding_system coding;
dc6f92b8 9920
9ac0d9e0 9921 if (interrupt_input_blocked)
dc6f92b8 9922 {
9ac0d9e0 9923 interrupt_input_pending = 1;
dc6f92b8
JB
9924 return -1;
9925 }
9926
9ac0d9e0 9927 interrupt_input_pending = 0;
dc6f92b8 9928 BLOCK_INPUT;
c0a04927
RS
9929
9930 /* So people can tell when we have read the available input. */
9931 input_signal_count++;
9932
dc6f92b8 9933 if (numchars <= 0)
06a2c219 9934 abort (); /* Don't think this happens. */
dc6f92b8 9935
bde5503b
GM
9936 ++handling_signal;
9937
379b5ac0
KH
9938 /* The input should be decoded if it is from XIM. Currently the
9939 locale of XIM is the same as that of the system. So, we can use
9940 Vlocale_coding_system which is initialized properly at Emacs
9941 startup time. */
9942 setup_coding_system (Vlocale_coding_system, &coding);
9943 coding.src_multibyte = 0;
9944 coding.dst_multibyte = 1;
9945 /* The input is converted to events, thus we can't handle
9946 composition. Anyway, there's no XIM that gives us composition
9947 information. */
9948 coding.composing = COMPOSITION_DISABLED;
9949
7a13e894
RS
9950 /* Find the display we are supposed to read input for.
9951 It's the one communicating on descriptor SD. */
9952 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9953 {
9954#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9955#ifdef FIOSNBIO
7a13e894
RS
9956 /* If available, Xlib uses FIOSNBIO to make the socket
9957 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9958 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9959 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9960 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9961#endif /* ! defined (FIOSNBIO) */
7a13e894 9962#endif
dc6f92b8 9963
7a13e894
RS
9964#if 0 /* This code can't be made to work, with multiple displays,
9965 and appears not to be used on any system any more.
9966 Also keyboard.c doesn't turn O_NDELAY on and off
9967 for X connections. */
dc6f92b8
JB
9968#ifndef SIGIO
9969#ifndef HAVE_SELECT
7a13e894
RS
9970 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9971 {
9972 extern int read_alarm_should_throw;
9973 read_alarm_should_throw = 1;
9974 XPeekEvent (dpyinfo->display, &event);
9975 read_alarm_should_throw = 0;
9976 }
c118dd06
JB
9977#endif /* HAVE_SELECT */
9978#endif /* SIGIO */
7a13e894 9979#endif
dc6f92b8 9980
7a13e894
RS
9981 /* For debugging, this gives a way to fake an I/O error. */
9982 if (dpyinfo == XTread_socket_fake_io_error)
9983 {
9984 XTread_socket_fake_io_error = 0;
9985 x_io_error_quitter (dpyinfo->display);
9986 }
dc6f92b8 9987
5f30b957
JD
9988#ifdef HAVE_X_SM
9989 BLOCK_INPUT;
9990 count += x_session_check_input (bufp, &numchars);
9991 UNBLOCK_INPUT;
9992#endif
9993
06a2c219 9994 while (XPending (dpyinfo->display))
dc6f92b8 9995 {
7a13e894 9996 XNextEvent (dpyinfo->display, &event);
06a2c219 9997
531483fb 9998#ifdef HAVE_X_I18N
d1bc4182 9999 {
f2be1146
GM
10000 /* Filter events for the current X input method.
10001 XFilterEvent returns non-zero if the input method has
10002 consumed the event. We pass the frame's X window to
10003 XFilterEvent because that's the one for which the IC
10004 was created. */
f5d11644
GM
10005 struct frame *f1 = x_any_window_to_frame (dpyinfo,
10006 event.xclient.window);
10007 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
10008 break;
10009 }
0cd6403b 10010#endif
7a13e894
RS
10011 event_found = 1;
10012
10013 switch (event.type)
10014 {
10015 case ClientMessage:
c047688c 10016 {
7a13e894
RS
10017 if (event.xclient.message_type
10018 == dpyinfo->Xatom_wm_protocols
10019 && event.xclient.format == 32)
c047688c 10020 {
7a13e894
RS
10021 if (event.xclient.data.l[0]
10022 == dpyinfo->Xatom_wm_take_focus)
c047688c 10023 {
8c1a6a84
RS
10024 /* Use x_any_window_to_frame because this
10025 could be the shell widget window
10026 if the frame has no title bar. */
10027 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
10028#ifdef HAVE_X_I18N
10029 /* Not quite sure this is needed -pd */
8c1a6a84 10030 if (f && FRAME_XIC (f))
6c183ba5
RS
10031 XSetICFocus (FRAME_XIC (f));
10032#endif
f1da8f06
GM
10033#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
10034 instructs the WM to set the input focus automatically for
10035 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
10036 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
10037 it has set the focus. So, XSetInputFocus below is not
10038 needed.
10039
10040 The call to XSetInputFocus below has also caused trouble. In
10041 cases where the XSetInputFocus done by the WM and the one
10042 below are temporally close (on a fast machine), the call
10043 below can generate additional FocusIn events which confuse
10044 Emacs. */
10045
bf7253f4
RS
10046 /* Since we set WM_TAKE_FOCUS, we must call
10047 XSetInputFocus explicitly. But not if f is null,
10048 since that might be an event for a deleted frame. */
7a13e894 10049 if (f)
bf7253f4
RS
10050 {
10051 Display *d = event.xclient.display;
10052 /* Catch and ignore errors, in case window has been
10053 iconified by a window manager such as GWM. */
10054 int count = x_catch_errors (d);
10055 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
10056 /* The ICCCM says this is
10057 the only valid choice. */
10058 RevertToParent,
bf7253f4
RS
10059 event.xclient.data.l[1]);
10060 /* This is needed to detect the error
10061 if there is an error. */
10062 XSync (d, False);
10063 x_uncatch_errors (d, count);
10064 }
7a13e894 10065 /* Not certain about handling scroll bars here */
f1da8f06 10066#endif /* 0 */
c047688c 10067 }
7a13e894
RS
10068 else if (event.xclient.data.l[0]
10069 == dpyinfo->Xatom_wm_save_yourself)
10070 {
10071 /* Save state modify the WM_COMMAND property to
06a2c219 10072 something which can reinstate us. This notifies
7a13e894
RS
10073 the session manager, who's looking for such a
10074 PropertyNotify. Can restart processing when
06a2c219 10075 a keyboard or mouse event arrives. */
5f30b957
JD
10076 /* If we have a session manager, don't set this.
10077 KDE will then start two Emacsen, one for the
10078 session manager and one for this. */
10079 if (numchars > 0
10080#ifdef HAVE_X_SM
10081 && ! x_session_have_connection ()
10082#endif
10083 )
7a13e894 10084 {
19126e11
KH
10085 f = x_top_window_to_frame (dpyinfo,
10086 event.xclient.window);
7a13e894
RS
10087 /* This is just so we only give real data once
10088 for a single Emacs process. */
b86bd3dd 10089 if (f == SELECTED_FRAME ())
7a13e894
RS
10090 XSetCommand (FRAME_X_DISPLAY (f),
10091 event.xclient.window,
10092 initial_argv, initial_argc);
f000f5c5 10093 else if (f)
7a13e894
RS
10094 XSetCommand (FRAME_X_DISPLAY (f),
10095 event.xclient.window,
10096 0, 0);
10097 }
10098 }
10099 else if (event.xclient.data.l[0]
10100 == dpyinfo->Xatom_wm_delete_window)
1fb20991 10101 {
19126e11
KH
10102 struct frame *f
10103 = x_any_window_to_frame (dpyinfo,
10104 event.xclient.window);
1fb20991 10105
7a13e894
RS
10106 if (f)
10107 {
10108 if (numchars == 0)
10109 abort ();
1fb20991 10110
7a13e894
RS
10111 bufp->kind = delete_window_event;
10112 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10113 bufp->arg = Qnil;
7a13e894
RS
10114 bufp++;
10115
10116 count += 1;
10117 numchars -= 1;
10118 }
1fb20991 10119 }
c047688c 10120 }
7a13e894
RS
10121 else if (event.xclient.message_type
10122 == dpyinfo->Xatom_wm_configure_denied)
10123 {
10124 }
10125 else if (event.xclient.message_type
10126 == dpyinfo->Xatom_wm_window_moved)
10127 {
10128 int new_x, new_y;
19126e11
KH
10129 struct frame *f
10130 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 10131
7a13e894
RS
10132 new_x = event.xclient.data.s[0];
10133 new_y = event.xclient.data.s[1];
1fb20991 10134
7a13e894
RS
10135 if (f)
10136 {
7556890b
RS
10137 f->output_data.x->left_pos = new_x;
10138 f->output_data.x->top_pos = new_y;
7a13e894 10139 }
1fb20991 10140 }
0fdff6bb 10141#ifdef HACK_EDITRES
7a13e894
RS
10142 else if (event.xclient.message_type
10143 == dpyinfo->Xatom_editres)
10144 {
19126e11
KH
10145 struct frame *f
10146 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 10147 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 10148 &event, NULL);
7a13e894 10149 }
0fdff6bb 10150#endif /* HACK_EDITRES */
06a2c219
GM
10151 else if ((event.xclient.message_type
10152 == dpyinfo->Xatom_DONE)
10153 || (event.xclient.message_type
10154 == dpyinfo->Xatom_PAGE))
10155 {
10156 /* Ghostview job completed. Kill it. We could
10157 reply with "Next" if we received "Page", but we
10158 currently never do because we are interested in
10159 images, only, which should have 1 page. */
06a2c219
GM
10160 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
10161 struct frame *f
10162 = x_window_to_frame (dpyinfo, event.xclient.window);
10163 x_kill_gs_process (pixmap, f);
10164 expose_frame (f, 0, 0, 0, 0);
10165 }
10166#ifdef USE_TOOLKIT_SCROLL_BARS
10167 /* Scroll bar callbacks send a ClientMessage from which
10168 we construct an input_event. */
10169 else if (event.xclient.message_type
10170 == dpyinfo->Xatom_Scrollbar)
10171 {
10172 x_scroll_bar_to_input_event (&event, bufp);
10173 ++bufp, ++count, --numchars;
10174 goto out;
10175 }
10176#endif /* USE_TOOLKIT_SCROLL_BARS */
10177 else
10178 goto OTHER;
7a13e894
RS
10179 }
10180 break;
dc6f92b8 10181
7a13e894 10182 case SelectionNotify:
3afe33e7 10183#ifdef USE_X_TOOLKIT
19126e11 10184 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 10185 goto OTHER;
3afe33e7 10186#endif /* not USE_X_TOOLKIT */
dfcf069d 10187 x_handle_selection_notify (&event.xselection);
7a13e894 10188 break;
d56a553a 10189
06a2c219 10190 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 10191#ifdef USE_X_TOOLKIT
19126e11 10192 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 10193 goto OTHER;
3afe33e7 10194#endif /* USE_X_TOOLKIT */
7a13e894
RS
10195 {
10196 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 10197
7a13e894
RS
10198 if (numchars == 0)
10199 abort ();
d56a553a 10200
7a13e894
RS
10201 bufp->kind = selection_clear_event;
10202 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10203 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10204 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10205 bufp->frame_or_window = Qnil;
0f8aabe9 10206 bufp->arg = Qnil;
7a13e894 10207 bufp++;
d56a553a 10208
7a13e894
RS
10209 count += 1;
10210 numchars -= 1;
10211 }
10212 break;
dc6f92b8 10213
06a2c219 10214 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 10215#ifdef USE_X_TOOLKIT
19126e11 10216 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 10217 goto OTHER;
3afe33e7 10218#endif /* USE_X_TOOLKIT */
7a13e894 10219 if (x_queue_selection_requests)
19126e11 10220 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
10221 &event);
10222 else
10223 {
1d2b2268
GM
10224 XSelectionRequestEvent *eventp
10225 = (XSelectionRequestEvent *) &event;
dc6f92b8 10226
7a13e894
RS
10227 if (numchars == 0)
10228 abort ();
10229
10230 bufp->kind = selection_request_event;
10231 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10232 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
10233 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10234 SELECTION_EVENT_TARGET (bufp) = eventp->target;
10235 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
10236 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10237 bufp->frame_or_window = Qnil;
0f8aabe9 10238 bufp->arg = Qnil;
7a13e894
RS
10239 bufp++;
10240
10241 count += 1;
10242 numchars -= 1;
10243 }
10244 break;
10245
10246 case PropertyNotify:
1d2b2268
GM
10247#if 0 /* This is plain wrong. In the case that we are waiting for a
10248 PropertyNotify used as an ACK in incremental selection
10249 transfer, the property will be on the receiver's window. */
10250#if defined USE_X_TOOLKIT
19126e11 10251 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 10252 goto OTHER;
1d2b2268
GM
10253#endif
10254#endif
dfcf069d 10255 x_handle_property_notify (&event.xproperty);
1d2b2268 10256 goto OTHER;
dc6f92b8 10257
7a13e894 10258 case ReparentNotify:
19126e11 10259 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
10260 if (f)
10261 {
10262 int x, y;
7556890b 10263 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 10264 x_real_positions (f, &x, &y);
7556890b
RS
10265 f->output_data.x->left_pos = x;
10266 f->output_data.x->top_pos = y;
7a13e894
RS
10267 }
10268 break;
3bd330d4 10269
7a13e894 10270 case Expose:
19126e11 10271 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 10272 if (f)
dc6f92b8 10273 {
d0fa3e56
EZ
10274 x_check_fullscreen (f);
10275
7a13e894
RS
10276 if (f->async_visible == 0)
10277 {
10278 f->async_visible = 1;
10279 f->async_iconified = 0;
06c488fd 10280 f->output_data.x->has_been_visible = 1;
7a13e894
RS
10281 SET_FRAME_GARBAGED (f);
10282 }
10283 else
06a2c219
GM
10284 expose_frame (x_window_to_frame (dpyinfo,
10285 event.xexpose.window),
10286 event.xexpose.x, event.xexpose.y,
10287 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
10288 }
10289 else
7a13e894 10290 {
12949a7f
EZ
10291#ifndef USE_TOOLKIT_SCROLL_BARS
10292 struct scroll_bar *bar;
10293#endif
01f67d2c 10294#if defined USE_LUCID
c95fc5f1
GM
10295 /* Submenus of the Lucid menu bar aren't widgets
10296 themselves, so there's no way to dispatch events
10297 to them. Recognize this case separately. */
10298 {
10299 Widget widget
10300 = x_window_to_menu_bar (event.xexpose.window);
10301 if (widget)
10302 xlwmenu_redisplay (widget);
10303 }
01f67d2c
PJ
10304#endif /* USE_LUCID */
10305
06a2c219
GM
10306#ifdef USE_TOOLKIT_SCROLL_BARS
10307 /* Dispatch event to the widget. */
10308 goto OTHER;
10309#else /* not USE_TOOLKIT_SCROLL_BARS */
12949a7f 10310 bar = x_window_to_scroll_bar (event.xexpose.window);
58769bee 10311
7a13e894
RS
10312 if (bar)
10313 x_scroll_bar_expose (bar, &event);
3afe33e7 10314#ifdef USE_X_TOOLKIT
7a13e894
RS
10315 else
10316 goto OTHER;
3afe33e7 10317#endif /* USE_X_TOOLKIT */
06a2c219 10318#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10319 }
10320 break;
dc6f92b8 10321
7a13e894 10322 case GraphicsExpose: /* This occurs when an XCopyArea's
d624284c
PJ
10323 source area was obscured or not
10324 available. */
19126e11 10325 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
10326 if (f)
10327 {
06a2c219
GM
10328 expose_frame (f,
10329 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
10330 event.xgraphicsexpose.width,
10331 event.xgraphicsexpose.height);
7a13e894 10332 }
3afe33e7 10333#ifdef USE_X_TOOLKIT
7a13e894
RS
10334 else
10335 goto OTHER;
3afe33e7 10336#endif /* USE_X_TOOLKIT */
7a13e894 10337 break;
dc6f92b8 10338
7a13e894 10339 case NoExpose: /* This occurs when an XCopyArea's
06a2c219 10340 source area was completely
d624284c 10341 available. */
7a13e894 10342 break;
dc6f92b8 10343
7a13e894 10344 case UnmapNotify:
06a2c219
GM
10345 /* Redo the mouse-highlight after the tooltip has gone. */
10346 if (event.xmap.window == tip_window)
10347 {
10348 tip_window = 0;
10349 redo_mouse_highlight ();
10350 }
10351
91ea2a7a 10352 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894 10353 if (f) /* F may no longer exist if
d624284c 10354 the frame was deleted. */
7a13e894
RS
10355 {
10356 /* While a frame is unmapped, display generation is
10357 disabled; you don't want to spend time updating a
10358 display that won't ever be seen. */
10359 f->async_visible = 0;
10360 /* We can't distinguish, from the event, whether the window
10361 has become iconified or invisible. So assume, if it
10362 was previously visible, than now it is iconified.
1aa6072f
RS
10363 But x_make_frame_invisible clears both
10364 the visible flag and the iconified flag;
10365 and that way, we know the window is not iconified now. */
7a13e894 10366 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
10367 {
10368 f->async_iconified = 1;
bddd097c 10369
1aa6072f
RS
10370 bufp->kind = iconify_event;
10371 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10372 bufp->arg = Qnil;
1aa6072f
RS
10373 bufp++;
10374 count++;
10375 numchars--;
10376 }
7a13e894 10377 }
7a13e894 10378 goto OTHER;
dc6f92b8 10379
7a13e894 10380 case MapNotify:
06a2c219
GM
10381 if (event.xmap.window == tip_window)
10382 /* The tooltip has been drawn already. Avoid
10383 the SET_FRAME_GARBAGED below. */
10384 goto OTHER;
10385
10386 /* We use x_top_window_to_frame because map events can
10387 come for sub-windows and they don't mean that the
10388 frame is visible. */
19126e11 10389 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
10390 if (f)
10391 {
10392 f->async_visible = 1;
10393 f->async_iconified = 0;
06c488fd 10394 f->output_data.x->has_been_visible = 1;
dc6f92b8 10395
7a13e894
RS
10396 /* wait_reading_process_input will notice this and update
10397 the frame's display structures. */
10398 SET_FRAME_GARBAGED (f);
bddd097c 10399
d806e720
RS
10400 if (f->iconified)
10401 {
10402 bufp->kind = deiconify_event;
10403 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10404 bufp->arg = Qnil;
d806e720
RS
10405 bufp++;
10406 count++;
10407 numchars--;
10408 }
e73ec6fa 10409 else if (! NILP (Vframe_list)
8e713be6 10410 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
10411 /* Force a redisplay sooner or later
10412 to update the frame titles
10413 in case this is the second frame. */
10414 record_asynch_buffer_change ();
7a13e894 10415 }
7a13e894 10416 goto OTHER;
dc6f92b8 10417
7a13e894 10418 case KeyPress:
19126e11 10419 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 10420
66301061
KS
10421 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
10422 {
10423 dpyinfo->mouse_face_hidden = 1;
10424 clear_mouse_face (dpyinfo);
10425 }
10426
eccc05db 10427#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
10428 if (f == 0)
10429 {
2564ea1b
GM
10430 /* Scroll bars consume key events, but we want
10431 the keys to go to the scroll bar's frame. */
06a2c219
GM
10432 Widget widget = XtWindowToWidget (dpyinfo->display,
10433 event.xkey.window);
10434 if (widget && XmIsScrollBar (widget))
10435 {
10436 widget = XtParent (widget);
10437 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
10438 }
10439 }
eccc05db 10440#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
06a2c219 10441
7a13e894
RS
10442 if (f != 0)
10443 {
10444 KeySym keysym, orig_keysym;
379b5ac0
KH
10445 /* al%imercury@uunet.uu.net says that making this 81
10446 instead of 80 fixed a bug whereby meta chars made
10447 his Emacs hang.
10448
10449 It seems that some version of XmbLookupString has
10450 a bug of not returning XBufferOverflow in
10451 status_return even if the input is too long to
10452 fit in 81 bytes. So, we must prepare sufficient
10453 bytes for copy_buffer. 513 bytes (256 chars for
6c4a22e6 10454 two-byte character set) seems to be a fairly good
379b5ac0
KH
10455 approximation. -- 2000.8.10 handa@etl.go.jp */
10456 unsigned char copy_buffer[513];
10457 unsigned char *copy_bufptr = copy_buffer;
10458 int copy_bufsiz = sizeof (copy_buffer);
7a13e894 10459 int modifiers;
64bb1782 10460
7a13e894
RS
10461 event.xkey.state
10462 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
10463 extra_keyboard_modifiers);
10464 modifiers = event.xkey.state;
3a2712f9 10465
7a13e894 10466 /* This will have to go some day... */
752a043f 10467
7a13e894
RS
10468 /* make_lispy_event turns chars into control chars.
10469 Don't do it here because XLookupString is too eager. */
10470 event.xkey.state &= ~ControlMask;
5d46f928
RS
10471 event.xkey.state &= ~(dpyinfo->meta_mod_mask
10472 | dpyinfo->super_mod_mask
10473 | dpyinfo->hyper_mod_mask
10474 | dpyinfo->alt_mod_mask);
10475
1cf4a0d1
RS
10476 /* In case Meta is ComposeCharacter,
10477 clear its status. According to Markus Ehrnsperger
10478 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
10479 this enables ComposeCharacter to work whether or
10480 not it is combined with Meta. */
10481 if (modifiers & dpyinfo->meta_mod_mask)
10482 bzero (&compose_status, sizeof (compose_status));
10483
6c183ba5
RS
10484#ifdef HAVE_X_I18N
10485 if (FRAME_XIC (f))
10486 {
f5d11644
GM
10487 Status status_return;
10488
6c183ba5 10489 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
10490 &event.xkey, copy_bufptr,
10491 copy_bufsiz, &keysym,
6c183ba5 10492 &status_return);
f5d11644
GM
10493 if (status_return == XBufferOverflow)
10494 {
10495 copy_bufsiz = nbytes + 1;
10496 copy_bufptr = (char *) alloca (copy_bufsiz);
10497 nbytes = XmbLookupString (FRAME_XIC (f),
10498 &event.xkey, copy_bufptr,
10499 copy_bufsiz, &keysym,
10500 &status_return);
10501 }
10502
1decb680
PE
10503 if (status_return == XLookupNone)
10504 break;
10505 else if (status_return == XLookupChars)
fdd9d55e
GM
10506 {
10507 keysym = NoSymbol;
10508 modifiers = 0;
10509 }
1decb680
PE
10510 else if (status_return != XLookupKeySym
10511 && status_return != XLookupBoth)
10512 abort ();
6c183ba5
RS
10513 }
10514 else
379b5ac0
KH
10515 nbytes = XLookupString (&event.xkey, copy_bufptr,
10516 copy_bufsiz, &keysym,
10517 &compose_status);
6c183ba5 10518#else
379b5ac0
KH
10519 nbytes = XLookupString (&event.xkey, copy_bufptr,
10520 copy_bufsiz, &keysym,
10521 &compose_status);
6c183ba5 10522#endif
dc6f92b8 10523
7a13e894 10524 orig_keysym = keysym;
55123275 10525
7a13e894
RS
10526 if (numchars > 1)
10527 {
10528 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
10529 || keysym == XK_Delete
1097aea0 10530#ifdef XK_ISO_Left_Tab
441affdb 10531 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 10532#endif
852bff8f 10533 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
10534 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
10535 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 10536#ifdef HPUX
7a13e894
RS
10537 /* This recognizes the "extended function keys".
10538 It seems there's no cleaner way.
10539 Test IsModifierKey to avoid handling mode_switch
10540 incorrectly. */
10541 || ((unsigned) (keysym) >= XK_Select
10542 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
10543#endif
10544#ifdef XK_dead_circumflex
7a13e894 10545 || orig_keysym == XK_dead_circumflex
69388238
RS
10546#endif
10547#ifdef XK_dead_grave
7a13e894 10548 || orig_keysym == XK_dead_grave
69388238
RS
10549#endif
10550#ifdef XK_dead_tilde
7a13e894 10551 || orig_keysym == XK_dead_tilde
69388238
RS
10552#endif
10553#ifdef XK_dead_diaeresis
7a13e894 10554 || orig_keysym == XK_dead_diaeresis
69388238
RS
10555#endif
10556#ifdef XK_dead_macron
7a13e894 10557 || orig_keysym == XK_dead_macron
69388238
RS
10558#endif
10559#ifdef XK_dead_degree
7a13e894 10560 || orig_keysym == XK_dead_degree
69388238
RS
10561#endif
10562#ifdef XK_dead_acute
7a13e894 10563 || orig_keysym == XK_dead_acute
69388238
RS
10564#endif
10565#ifdef XK_dead_cedilla
7a13e894 10566 || orig_keysym == XK_dead_cedilla
69388238
RS
10567#endif
10568#ifdef XK_dead_breve
7a13e894 10569 || orig_keysym == XK_dead_breve
69388238
RS
10570#endif
10571#ifdef XK_dead_ogonek
7a13e894 10572 || orig_keysym == XK_dead_ogonek
69388238
RS
10573#endif
10574#ifdef XK_dead_caron
7a13e894 10575 || orig_keysym == XK_dead_caron
69388238
RS
10576#endif
10577#ifdef XK_dead_doubleacute
7a13e894 10578 || orig_keysym == XK_dead_doubleacute
69388238
RS
10579#endif
10580#ifdef XK_dead_abovedot
7a13e894 10581 || orig_keysym == XK_dead_abovedot
c34790e0 10582#endif
7a13e894
RS
10583 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
10584 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
10585 /* Any "vendor-specific" key is ok. */
f0e299de
GM
10586 || (orig_keysym & (1 << 28))
10587 || (keysym != NoSymbol && nbytes == 0))
7a13e894 10588 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
10589#ifndef HAVE_X11R5
10590#ifdef XK_Mode_switch
7a13e894 10591 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
10592#endif
10593#ifdef XK_Num_Lock
7a13e894 10594 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
10595#endif
10596#endif /* not HAVE_X11R5 */
7ef18d79
EZ
10597 /* The symbols from XK_ISO_Lock to
10598 XK_ISO_Last_Group_Lock doesn't have real
10599 modifiers but should be treated similarly
10600 to Mode_switch by Emacs. */
10601#if defined XK_ISO_Lock && defined XK_ISO_Last_Group_Lock
10602 || ((unsigned)(orig_keysym) >= XK_ISO_Lock
10603 && (unsigned)(orig_keysym) <= XK_ISO_Last_Group_Lock)
10604#endif
7a13e894 10605 ))
dc6f92b8 10606 {
10e6549c
RS
10607 if (temp_index == sizeof temp_buffer / sizeof (short))
10608 temp_index = 0;
7a13e894
RS
10609 temp_buffer[temp_index++] = keysym;
10610 bufp->kind = non_ascii_keystroke;
10611 bufp->code = keysym;
e0c1aef2 10612 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10613 bufp->arg = Qnil;
334208b7
RS
10614 bufp->modifiers
10615 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10616 modifiers);
1113d9db 10617 bufp->timestamp = event.xkey.time;
dc6f92b8 10618 bufp++;
7a13e894
RS
10619 count++;
10620 numchars--;
dc6f92b8 10621 }
7a13e894
RS
10622 else if (numchars > nbytes)
10623 {
10624 register int i;
379b5ac0 10625 register int c;
379b5ac0 10626 int nchars, len;
7a13e894
RS
10627
10628 for (i = 0; i < nbytes; i++)
10629 {
379b5ac0
KH
10630 if (temp_index == (sizeof temp_buffer
10631 / sizeof (short)))
7a13e894 10632 temp_index = 0;
379b5ac0
KH
10633 temp_buffer[temp_index++] = copy_bufptr[i];
10634 }
10635
10636 if (/* If the event is not from XIM, */
10637 event.xkey.keycode != 0
10638 /* or the current locale doesn't request
10639 decoding of the intup data, ... */
10640 || coding.type == coding_type_raw_text
10641 || coding.type == coding_type_no_conversion)
10642 {
10643 /* ... we can use the input data as is. */
10644 nchars = nbytes;
10645 }
10646 else
10647 {
10648 /* We have to decode the input data. */
10649 int require;
10650 unsigned char *p;
10651
10652 require = decoding_buffer_size (&coding, nbytes);
10653 p = (unsigned char *) alloca (require);
10654 coding.mode |= CODING_MODE_LAST_BLOCK;
10655 decode_coding (&coding, copy_bufptr, p,
10656 nbytes, require);
10657 nbytes = coding.produced;
10658 nchars = coding.produced_char;
10659 copy_bufptr = p;
10660 }
10661
10662 /* Convert the input data to a sequence of
10663 character events. */
10664 for (i = 0; i < nbytes; i += len)
10665 {
fee2aedc
GM
10666 if (nchars == nbytes)
10667 c = copy_bufptr[i], len = 1;
10668 else
10669 c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
10670 nbytes - i, len);
10671
379b5ac0
KH
10672 bufp->kind = (SINGLE_BYTE_CHAR_P (c)
10673 ? ascii_keystroke
10674 : multibyte_char_keystroke);
10675 bufp->code = c;
7a13e894 10676 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10677 bufp->arg = Qnil;
7a13e894
RS
10678 bufp->modifiers
10679 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10680 modifiers);
10681 bufp->timestamp = event.xkey.time;
10682 bufp++;
10683 }
10684
379b5ac0
KH
10685 count += nchars;
10686 numchars -= nchars;
1decb680
PE
10687
10688 if (keysym == NoSymbol)
10689 break;
7a13e894
RS
10690 }
10691 else
10692 abort ();
dc6f92b8 10693 }
10e6549c
RS
10694 else
10695 abort ();
dc6f92b8 10696 }
59ddecde
GM
10697#ifdef HAVE_X_I18N
10698 /* Don't dispatch this event since XtDispatchEvent calls
10699 XFilterEvent, and two calls in a row may freeze the
10700 client. */
10701 break;
10702#else
717ca130 10703 goto OTHER;
59ddecde 10704#endif
f451eb13 10705
f5d11644 10706 case KeyRelease:
59ddecde
GM
10707#ifdef HAVE_X_I18N
10708 /* Don't dispatch this event since XtDispatchEvent calls
10709 XFilterEvent, and two calls in a row may freeze the
10710 client. */
10711 break;
10712#else
f5d11644 10713 goto OTHER;
59ddecde 10714#endif
f5d11644 10715
7a13e894 10716 /* Here's a possible interpretation of the whole
06a2c219
GM
10717 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
10718 you get a FocusIn event, you have to get a FocusOut
10719 event before you relinquish the focus. If you
10720 haven't received a FocusIn event, then a mere
10721 LeaveNotify is enough to free you. */
f451eb13 10722
7a13e894 10723 case EnterNotify:
06a2c219 10724 {
06a2c219
GM
10725 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
10726
2c850e26 10727#if 0
582c60f8 10728 if (event.xcrossing.focus)
06a2c219
GM
10729 {
10730 /* Avoid nasty pop/raise loops. */
10731 if (f && (!(f->auto_raise)
10732 || !(f->auto_lower)
10733 || (event.xcrossing.time - enter_timestamp) > 500))
10734 {
10735 x_new_focus_frame (dpyinfo, f);
10736 enter_timestamp = event.xcrossing.time;
10737 }
10738 }
10739 else if (f == dpyinfo->x_focus_frame)
10740 x_new_focus_frame (dpyinfo, 0);
2c850e26
RS
10741#endif
10742
06a2c219
GM
10743 /* EnterNotify counts as mouse movement,
10744 so update things that depend on mouse position. */
2533c408 10745 if (f && !f->output_data.x->hourglass_p)
06a2c219
GM
10746 note_mouse_movement (f, &event.xmotion);
10747 goto OTHER;
10748 }
dc6f92b8 10749
7a13e894 10750 case FocusIn:
19126e11 10751 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10752 if (event.xfocus.detail != NotifyPointer)
0f941935 10753 dpyinfo->x_focus_event_frame = f;
7a13e894 10754 if (f)
eb72635f
GM
10755 {
10756 x_new_focus_frame (dpyinfo, f);
10757
10758 /* Don't stop displaying the initial startup message
10759 for a switch-frame event we don't need. */
10760 if (GC_NILP (Vterminal_frame)
10761 && GC_CONSP (Vframe_list)
10762 && !GC_NILP (XCDR (Vframe_list)))
10763 {
10764 bufp->kind = FOCUS_IN_EVENT;
10765 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10766 bufp->arg = Qnil;
eb72635f
GM
10767 ++bufp, ++count, --numchars;
10768 }
10769 }
f9e24cb9 10770
6c183ba5
RS
10771#ifdef HAVE_X_I18N
10772 if (f && FRAME_XIC (f))
10773 XSetICFocus (FRAME_XIC (f));
10774#endif
10775
7a13e894 10776 goto OTHER;
10c5e63d 10777
7a13e894 10778 case LeaveNotify:
19126e11 10779 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 10780 if (f)
10c5e63d 10781 {
7a13e894 10782 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
10783 {
10784 /* If we move outside the frame, then we're
10785 certainly no longer on any text in the frame. */
10786 clear_mouse_face (dpyinfo);
10787 dpyinfo->mouse_face_mouse_frame = 0;
10788 }
10789
10790 /* Generate a nil HELP_EVENT to cancel a help-echo.
10791 Do it only if there's something to cancel.
10792 Otherwise, the startup message is cleared when
10793 the mouse leaves the frame. */
10794 if (any_help_event_p)
10795 {
be010514
GM
10796 Lisp_Object frame;
10797 int n;
10798
06a2c219 10799 XSETFRAME (frame, f);
82c5d67a 10800 help_echo = Qnil;
5ab2570d
GM
10801 n = gen_help_event (bufp, numchars,
10802 Qnil, frame, Qnil, Qnil, 0);
be010514 10803 bufp += n, count += n, numchars -= n;
06a2c219 10804 }
7a13e894 10805
2c850e26 10806#if 0
582c60f8 10807 if (event.xcrossing.focus)
0f941935 10808 x_mouse_leave (dpyinfo);
10c5e63d 10809 else
7a13e894 10810 {
0f941935
KH
10811 if (f == dpyinfo->x_focus_event_frame)
10812 dpyinfo->x_focus_event_frame = 0;
140d6643 10813 if (f == dpyinfo->x_focus_frame)
0f941935 10814 x_new_focus_frame (dpyinfo, 0);
7a13e894 10815 }
2c850e26 10816#endif
10c5e63d 10817 }
7a13e894 10818 goto OTHER;
dc6f92b8 10819
7a13e894 10820 case FocusOut:
19126e11 10821 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10822 if (event.xfocus.detail != NotifyPointer
0f941935
KH
10823 && f == dpyinfo->x_focus_event_frame)
10824 dpyinfo->x_focus_event_frame = 0;
10825 if (f && f == dpyinfo->x_focus_frame)
10826 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 10827
6c183ba5
RS
10828#ifdef HAVE_X_I18N
10829 if (f && FRAME_XIC (f))
10830 XUnsetICFocus (FRAME_XIC (f));
10831#endif
10832
7a13e894 10833 goto OTHER;
dc6f92b8 10834
7a13e894 10835 case MotionNotify:
dc6f92b8 10836 {
06a2c219 10837 previous_help_echo = help_echo;
7cea38bc 10838 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 10839 help_echo_pos = -1;
06a2c219 10840
7a13e894
RS
10841 if (dpyinfo->grabbed && last_mouse_frame
10842 && FRAME_LIVE_P (last_mouse_frame))
10843 f = last_mouse_frame;
10844 else
19126e11 10845 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 10846
66301061
KS
10847 if (dpyinfo->mouse_face_hidden)
10848 {
10849 dpyinfo->mouse_face_hidden = 0;
10850 clear_mouse_face (dpyinfo);
10851 }
10852
7a13e894 10853 if (f)
5bc62483
PJ
10854 {
10855
10856 /* Generate SELECT_WINDOW_EVENTs when needed. */
ee8ceff8 10857 if (mouse_autoselect_window)
5bc62483
PJ
10858 {
10859 Lisp_Object window;
10860 int area;
10861
10862 window = window_from_coordinates (f,
0fc8f792 10863 event.xmotion.x, event.xmotion.y,
5bc62483
PJ
10864 &area, 0);
10865
10866 /* Window will be selected only when it is not selected now and
10867 last mouse movement event was not in it. Minibuffer window
10868 will be selected iff it is active. */
ce1295bd
PJ
10869 if (WINDOWP(window)
10870 && !EQ (window, last_window)
5bc62483
PJ
10871 && !EQ (window, selected_window)
10872 && numchars > 0)
10873 {
10874 bufp->kind = SELECT_WINDOW_EVENT;
10875 bufp->frame_or_window = window;
10876 bufp->arg = Qnil;
10877 ++bufp, ++count, --numchars;
10878 }
10879
10880 last_window=window;
10881 }
10882 note_mouse_movement (f, &event.xmotion);
10883 }
7a13e894
RS
10884 else
10885 {
e88b3c50 10886#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10887 struct scroll_bar *bar
10888 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 10889
7a13e894
RS
10890 if (bar)
10891 x_scroll_bar_note_movement (bar, &event);
e88b3c50 10892#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 10893
06a2c219
GM
10894 /* If we move outside the frame, then we're
10895 certainly no longer on any text in the frame. */
7a13e894
RS
10896 clear_mouse_face (dpyinfo);
10897 }
06a2c219
GM
10898
10899 /* If the contents of the global variable help_echo
10900 has changed, generate a HELP_EVENT. */
b7e80413
SM
10901 if (!NILP (help_echo)
10902 || !NILP (previous_help_echo))
06a2c219
GM
10903 {
10904 Lisp_Object frame;
be010514 10905 int n;
06a2c219
GM
10906
10907 if (f)
10908 XSETFRAME (frame, f);
10909 else
10910 frame = Qnil;
10911
10912 any_help_event_p = 1;
5ab2570d 10913 n = gen_help_event (bufp, numchars, help_echo, frame,
7cea38bc
GM
10914 help_echo_window, help_echo_object,
10915 help_echo_pos);
be010514 10916 bufp += n, count += n, numchars -= n;
06a2c219
GM
10917 }
10918
10919 goto OTHER;
dc6f92b8 10920 }
dc6f92b8 10921
7a13e894 10922 case ConfigureNotify:
9829ddba
RS
10923 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
10924 if (f)
af395ec1 10925 {
7a4bce14 10926#ifndef USE_X_TOOLKIT
d0fa3e56
EZ
10927 /* If there is a pending resize for fullscreen, don't
10928 do this one, the right one will come later.
10929 The toolkit version doesn't seem to need this, but we
7a4bce14 10930 need to reset it below. */
d0fa3e56
EZ
10931 int dont_resize =
10932 ((f->output_data.x->want_fullscreen & FULLSCREEN_WAIT)
10933 && FRAME_NEW_WIDTH (f) != 0);
bf1b7b30
KH
10934 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
10935 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
d0fa3e56
EZ
10936 if (dont_resize)
10937 goto OTHER;
5c187dee 10938
2d7fc7e8
RS
10939 /* In the toolkit version, change_frame_size
10940 is called by the code that handles resizing
10941 of the EmacsFrame widget. */
7a13e894 10942
7a13e894
RS
10943 /* Even if the number of character rows and columns has
10944 not changed, the font size may have changed, so we need
10945 to check the pixel dimensions as well. */
10946 if (columns != f->width
10947 || rows != f->height
7556890b
RS
10948 || event.xconfigure.width != f->output_data.x->pixel_width
10949 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 10950 {
7d1e984f 10951 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 10952 SET_FRAME_GARBAGED (f);
e687d06e 10953 cancel_mouse_face (f);
7a13e894 10954 }
2d7fc7e8 10955#endif
af395ec1 10956
7556890b
RS
10957 f->output_data.x->pixel_width = event.xconfigure.width;
10958 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
10959
10960 /* What we have now is the position of Emacs's own window.
10961 Convert that to the position of the window manager window. */
dcb07ae9
RS
10962 x_real_positions (f, &f->output_data.x->left_pos,
10963 &f->output_data.x->top_pos);
10964
d0fa3e56
EZ
10965 x_check_fullscreen_move(f);
10966 if (f->output_data.x->want_fullscreen & FULLSCREEN_WAIT)
10967 f->output_data.x->want_fullscreen &=
10968 ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH);
f5d11644
GM
10969#ifdef HAVE_X_I18N
10970 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
10971 xic_set_statusarea (f);
10972#endif
10973
dcb07ae9
RS
10974 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
10975 {
10976 /* Since the WM decorations come below top_pos now,
10977 we must put them below top_pos in the future. */
10978 f->output_data.x->win_gravity = NorthWestGravity;
10979 x_wm_set_size_hint (f, (long) 0, 0);
10980 }
8f08dc93
KH
10981#ifdef USE_MOTIF
10982 /* Some window managers pass (0,0) as the location of
10983 the window, and the Motif event handler stores it
10984 in the emacs widget, which messes up Motif menus. */
10985 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
10986 {
10987 event.xconfigure.x = f->output_data.x->widget->core.x;
10988 event.xconfigure.y = f->output_data.x->widget->core.y;
10989 }
06a2c219 10990#endif /* USE_MOTIF */
7a13e894 10991 }
2d7fc7e8 10992 goto OTHER;
dc6f92b8 10993
7a13e894
RS
10994 case ButtonPress:
10995 case ButtonRelease:
10996 {
10997 /* If we decide we want to generate an event to be seen
10998 by the rest of Emacs, we put it here. */
10999 struct input_event emacs_event;
9ea173e8 11000 int tool_bar_p = 0;
06a2c219 11001
7a13e894 11002 emacs_event.kind = no_event;
7a13e894 11003 bzero (&compose_status, sizeof (compose_status));
9b07615b 11004
06a2c219
GM
11005 if (dpyinfo->grabbed
11006 && last_mouse_frame
9f67f20b
RS
11007 && FRAME_LIVE_P (last_mouse_frame))
11008 f = last_mouse_frame;
11009 else
2224b905 11010 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 11011
06a2c219
GM
11012 if (f)
11013 {
9ea173e8
GM
11014 /* Is this in the tool-bar? */
11015 if (WINDOWP (f->tool_bar_window)
11016 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
11017 {
11018 Lisp_Object window;
11019 int p, x, y;
11020
11021 x = event.xbutton.x;
11022 y = event.xbutton.y;
11023
11024 /* Set x and y. */
11025 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 11026 if (EQ (window, f->tool_bar_window))
06a2c219 11027 {
9ea173e8
GM
11028 x_handle_tool_bar_click (f, &event.xbutton);
11029 tool_bar_p = 1;
06a2c219
GM
11030 }
11031 }
11032
9ea173e8 11033 if (!tool_bar_p)
06a2c219
GM
11034 if (!dpyinfo->x_focus_frame
11035 || f == dpyinfo->x_focus_frame)
11036 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
11037 }
11038 else
11039 {
06a2c219 11040#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
11041 struct scroll_bar *bar
11042 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 11043
7a13e894
RS
11044 if (bar)
11045 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 11046#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
11047 }
11048
11049 if (event.type == ButtonPress)
11050 {
11051 dpyinfo->grabbed |= (1 << event.xbutton.button);
11052 last_mouse_frame = f;
edad46f6
KH
11053 /* Ignore any mouse motion that happened
11054 before this event; any subsequent mouse-movement
11055 Emacs events should reflect only motion after
11056 the ButtonPress. */
a00e91cd
KH
11057 if (f != 0)
11058 f->mouse_moved = 0;
06a2c219 11059
9ea173e8
GM
11060 if (!tool_bar_p)
11061 last_tool_bar_item = -1;
7a13e894 11062 }
3afe33e7
RS
11063 else
11064 {
7a13e894 11065 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 11066 }
23faf38f 11067
7a13e894
RS
11068 if (numchars >= 1 && emacs_event.kind != no_event)
11069 {
11070 bcopy (&emacs_event, bufp, sizeof (struct input_event));
11071 bufp++;
11072 count++;
11073 numchars--;
11074 }
3afe33e7
RS
11075
11076#ifdef USE_X_TOOLKIT
2224b905
RS
11077 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
11078 /* For a down-event in the menu bar,
11079 don't pass it to Xt right now.
11080 Instead, save it away
11081 and we will pass it to Xt from kbd_buffer_get_event.
11082 That way, we can run some Lisp code first. */
91375f8f
RS
11083 if (f && event.type == ButtonPress
11084 /* Verify the event is really within the menu bar
11085 and not just sent to it due to grabbing. */
11086 && event.xbutton.x >= 0
11087 && event.xbutton.x < f->output_data.x->pixel_width
11088 && event.xbutton.y >= 0
11089 && event.xbutton.y < f->output_data.x->menubar_height
11090 && event.xbutton.same_screen)
2224b905 11091 {
8805890a 11092 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
11093 XSETFRAME (last_mouse_press_frame, f);
11094 }
11095 else if (event.type == ButtonPress)
11096 {
11097 last_mouse_press_frame = Qnil;
30e671c3 11098 goto OTHER;
ce89ef46 11099 }
06a2c219 11100
2237cac9
RS
11101#ifdef USE_MOTIF /* This should do not harm for Lucid,
11102 but I am trying to be cautious. */
ce89ef46
RS
11103 else if (event.type == ButtonRelease)
11104 {
2237cac9 11105 if (!NILP (last_mouse_press_frame))
f10ded1c 11106 {
2237cac9
RS
11107 f = XFRAME (last_mouse_press_frame);
11108 if (f->output_data.x)
06a2c219 11109 SET_SAVED_BUTTON_EVENT;
f10ded1c 11110 }
06a2c219 11111 else
30e671c3 11112 goto OTHER;
2224b905 11113 }
2237cac9 11114#endif /* USE_MOTIF */
2224b905
RS
11115 else
11116 goto OTHER;
3afe33e7 11117#endif /* USE_X_TOOLKIT */
7a13e894
RS
11118 }
11119 break;
dc6f92b8 11120
7a13e894 11121 case CirculateNotify:
06a2c219
GM
11122 goto OTHER;
11123
7a13e894 11124 case CirculateRequest:
06a2c219
GM
11125 goto OTHER;
11126
11127 case VisibilityNotify:
11128 goto OTHER;
dc6f92b8 11129
7a13e894
RS
11130 case MappingNotify:
11131 /* Someone has changed the keyboard mapping - update the
11132 local cache. */
11133 switch (event.xmapping.request)
11134 {
11135 case MappingModifier:
11136 x_find_modifier_meanings (dpyinfo);
11137 /* This is meant to fall through. */
11138 case MappingKeyboard:
11139 XRefreshKeyboardMapping (&event.xmapping);
11140 }
7a13e894 11141 goto OTHER;
dc6f92b8 11142
7a13e894 11143 default:
7a13e894 11144 OTHER:
717ca130 11145#ifdef USE_X_TOOLKIT
7a13e894
RS
11146 BLOCK_INPUT;
11147 XtDispatchEvent (&event);
11148 UNBLOCK_INPUT;
3afe33e7 11149#endif /* USE_X_TOOLKIT */
7a13e894
RS
11150 break;
11151 }
dc6f92b8
JB
11152 }
11153 }
11154
06a2c219
GM
11155 out:;
11156
9a5196d0
RS
11157 /* On some systems, an X bug causes Emacs to get no more events
11158 when the window is destroyed. Detect that. (1994.) */
58769bee 11159 if (! event_found)
ef2a22d0 11160 {
ef2a22d0
RS
11161 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
11162 One XNOOP in 100 loops will make Emacs terminate.
11163 B. Bretthauer, 1994 */
11164 x_noop_count++;
58769bee 11165 if (x_noop_count >= 100)
ef2a22d0
RS
11166 {
11167 x_noop_count=0;
2224b905
RS
11168
11169 if (next_noop_dpyinfo == 0)
11170 next_noop_dpyinfo = x_display_list;
11171
11172 XNoOp (next_noop_dpyinfo->display);
11173
11174 /* Each time we get here, cycle through the displays now open. */
11175 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
11176 }
11177 }
502add23 11178
06a2c219 11179 /* If the focus was just given to an auto-raising frame,
0134a210 11180 raise it now. */
7a13e894 11181 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
11182 if (pending_autoraise_frame)
11183 {
11184 x_raise_frame (pending_autoraise_frame);
11185 pending_autoraise_frame = 0;
11186 }
0134a210 11187
dc6f92b8 11188 UNBLOCK_INPUT;
bde5503b 11189 --handling_signal;
dc6f92b8
JB
11190 return count;
11191}
06a2c219
GM
11192
11193
11194
dc6f92b8 11195\f
06a2c219
GM
11196/***********************************************************************
11197 Text Cursor
11198 ***********************************************************************/
11199
60626bab
GM
11200/* Notice when the text cursor of window W has been completely
11201 overwritten by a drawing operation that outputs glyphs in AREA
11202 starting at X0 and ending at X1 in the line starting at Y0 and
11203 ending at Y1. X coordinates are area-relative. X1 < 0 means all
11204 the rest of the line after X0 has been written. Y coordinates
11205 are window-relative. */
06a2c219
GM
11206
11207static void
60626bab 11208notice_overwritten_cursor (w, area, x0, x1, y0, y1)
06a2c219 11209 struct window *w;
60626bab
GM
11210 enum glyph_row_area area;
11211 int x0, y0, x1, y1;
06a2c219 11212{
60626bab 11213 if (area == TEXT_AREA
f0a48a01 11214 && w->phys_cursor_on_p
60626bab
GM
11215 && y0 <= w->phys_cursor.y
11216 && y1 >= w->phys_cursor.y + w->phys_cursor_height
11217 && x0 <= w->phys_cursor.x
11218 && (x1 < 0 || x1 > w->phys_cursor.x))
f0a48a01 11219 w->phys_cursor_on_p = 0;
06a2c219 11220}
f451eb13
JB
11221
11222
06a2c219
GM
11223/* Set clipping for output in glyph row ROW. W is the window in which
11224 we operate. GC is the graphics context to set clipping in.
11225 WHOLE_LINE_P non-zero means include the areas used for truncation
11226 mark display and alike in the clipping rectangle.
11227
11228 ROW may be a text row or, e.g., a mode line. Text rows must be
11229 clipped to the interior of the window dedicated to text display,
11230 mode lines must be clipped to the whole window. */
dc6f92b8
JB
11231
11232static void
06a2c219
GM
11233x_clip_to_row (w, row, gc, whole_line_p)
11234 struct window *w;
11235 struct glyph_row *row;
11236 GC gc;
11237 int whole_line_p;
dc6f92b8 11238{
06a2c219
GM
11239 struct frame *f = XFRAME (WINDOW_FRAME (w));
11240 XRectangle clip_rect;
11241 int window_x, window_y, window_width, window_height;
dc6f92b8 11242
06a2c219 11243 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 11244
06a2c219
GM
11245 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
11246 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
11247 clip_rect.y = max (clip_rect.y, window_y);
11248 clip_rect.width = window_width;
11249 clip_rect.height = row->visible_height;
5c1aae96 11250
06a2c219
GM
11251 /* If clipping to the whole line, including trunc marks, extend
11252 the rectangle to the left and increase its width. */
11253 if (whole_line_p)
11254 {
3f332ef3
KS
11255 clip_rect.x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
11256 clip_rect.width += FRAME_X_FRINGE_WIDTH (f);
06a2c219 11257 }
5c1aae96 11258
06a2c219 11259 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
11260}
11261
06a2c219
GM
11262
11263/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
11264
11265static void
06a2c219
GM
11266x_draw_hollow_cursor (w, row)
11267 struct window *w;
11268 struct glyph_row *row;
dc6f92b8 11269{
06a2c219
GM
11270 struct frame *f = XFRAME (WINDOW_FRAME (w));
11271 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11272 Display *dpy = FRAME_X_DISPLAY (f);
11273 int x, y, wd, h;
11274 XGCValues xgcv;
11275 struct glyph *cursor_glyph;
11276 GC gc;
11277
11278 /* Compute frame-relative coordinates from window-relative
11279 coordinates. */
11280 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11281 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
11282 + row->ascent - w->phys_cursor_ascent);
11283 h = row->height - 1;
11284
11285 /* Get the glyph the cursor is on. If we can't tell because
11286 the current matrix is invalid or such, give up. */
11287 cursor_glyph = get_phys_cursor_glyph (w);
11288 if (cursor_glyph == NULL)
dc6f92b8
JB
11289 return;
11290
06a2c219
GM
11291 /* Compute the width of the rectangle to draw. If on a stretch
11292 glyph, and `x-stretch-block-cursor' is nil, don't draw a
11293 rectangle as wide as the glyph, but use a canonical character
11294 width instead. */
11295 wd = cursor_glyph->pixel_width - 1;
11296 if (cursor_glyph->type == STRETCH_GLYPH
11297 && !x_stretch_cursor_p)
11298 wd = min (CANON_X_UNIT (f), wd);
11299
11300 /* The foreground of cursor_gc is typically the same as the normal
11301 background color, which can cause the cursor box to be invisible. */
11302 xgcv.foreground = f->output_data.x->cursor_pixel;
11303 if (dpyinfo->scratch_cursor_gc)
11304 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
11305 else
11306 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
11307 GCForeground, &xgcv);
11308 gc = dpyinfo->scratch_cursor_gc;
11309
11310 /* Set clipping, draw the rectangle, and reset clipping again. */
11311 x_clip_to_row (w, row, gc, 0);
11312 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
11313 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
11314}
11315
06a2c219
GM
11316
11317/* Draw a bar cursor on window W in glyph row ROW.
11318
11319 Implementation note: One would like to draw a bar cursor with an
11320 angle equal to the one given by the font property XA_ITALIC_ANGLE.
11321 Unfortunately, I didn't find a font yet that has this property set.
11322 --gerd. */
dc6f92b8
JB
11323
11324static void
f02d8aa0 11325x_draw_bar_cursor (w, row, width)
06a2c219
GM
11326 struct window *w;
11327 struct glyph_row *row;
f02d8aa0 11328 int width;
dc6f92b8 11329{
92f424df
GM
11330 struct frame *f = XFRAME (w->frame);
11331 struct glyph *cursor_glyph;
06a2c219 11332
92f424df
GM
11333 /* If cursor is out of bounds, don't draw garbage. This can happen
11334 in mini-buffer windows when switching between echo area glyphs
11335 and mini-buffer. */
11336 cursor_glyph = get_phys_cursor_glyph (w);
11337 if (cursor_glyph == NULL)
11338 return;
06a2c219 11339
92f424df
GM
11340 /* If on an image, draw like a normal cursor. That's usually better
11341 visible than drawing a bar, esp. if the image is large so that
11342 the bar might not be in the window. */
11343 if (cursor_glyph->type == IMAGE_GLYPH)
11344 {
11345 struct glyph_row *row;
11346 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
11347 x_draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
11348 }
11349 else
11350 {
34e5d0af
GM
11351 Display *dpy = FRAME_X_DISPLAY (f);
11352 Window window = FRAME_X_WINDOW (f);
11353 GC gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
11354 unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures;
11355 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
11356 XGCValues xgcv;
11357
11358 /* If the glyph's background equals the color we normally draw
11359 the bar cursor in, the bar cursor in its normal color is
11360 invisible. Use the glyph's foreground color instead in this
11361 case, on the assumption that the glyph's colors are chosen so
11362 that the glyph is legible. */
11363 if (face->background == f->output_data.x->cursor_pixel)
11364 xgcv.background = xgcv.foreground = face->foreground;
11365 else
11366 xgcv.background = xgcv.foreground = f->output_data.x->cursor_pixel;
06a2c219 11367 xgcv.graphics_exposures = 0;
92f424df 11368
06a2c219
GM
11369 if (gc)
11370 XChangeGC (dpy, gc, mask, &xgcv);
11371 else
11372 {
11373 gc = XCreateGC (dpy, window, mask, &xgcv);
11374 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
11375 }
92f424df 11376
f02d8aa0
GM
11377 if (width < 0)
11378 width = f->output_data.x->cursor_width;
34e5d0af 11379 width = min (cursor_glyph->pixel_width, width);
92f424df 11380
06a2c219
GM
11381 x_clip_to_row (w, row, gc, 0);
11382 XFillRectangle (dpy, window, gc,
34e5d0af 11383 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
06a2c219 11384 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
34e5d0af 11385 width, row->height);
06a2c219
GM
11386 XSetClipMask (dpy, gc, None);
11387 }
dc6f92b8
JB
11388}
11389
06a2c219
GM
11390
11391/* Clear the cursor of window W to background color, and mark the
11392 cursor as not shown. This is used when the text where the cursor
11393 is is about to be rewritten. */
11394
dc6f92b8 11395static void
06a2c219
GM
11396x_clear_cursor (w)
11397 struct window *w;
dc6f92b8 11398{
06a2c219
GM
11399 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
11400 x_update_window_cursor (w, 0);
11401}
90e65f07 11402
dbc4e1c1 11403
06a2c219
GM
11404/* Draw the cursor glyph of window W in glyph row ROW. See the
11405 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 11406
06a2c219
GM
11407static void
11408x_draw_phys_cursor_glyph (w, row, hl)
11409 struct window *w;
11410 struct glyph_row *row;
11411 enum draw_glyphs_face hl;
11412{
11413 /* If cursor hpos is out of bounds, don't draw garbage. This can
11414 happen in mini-buffer windows when switching between echo area
11415 glyphs and mini-buffer. */
11416 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e 11417 {
f0a48a01
GM
11418 int on_p = w->phys_cursor_on_p;
11419
66ac4b0e
GM
11420 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
11421 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
f0a48a01
GM
11422 hl, 0);
11423 w->phys_cursor_on_p = on_p;
66ac4b0e
GM
11424
11425 /* When we erase the cursor, and ROW is overlapped by other
11426 rows, make sure that these overlapping parts of other rows
11427 are redrawn. */
11428 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
11429 {
11430 if (row > w->current_matrix->rows
11431 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
11432 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
11433
11434 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
11435 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
11436 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
11437 }
11438 }
06a2c219 11439}
dbc4e1c1 11440
eea6af04 11441
06a2c219 11442/* Erase the image of a cursor of window W from the screen. */
eea6af04 11443
06a2c219
GM
11444static void
11445x_erase_phys_cursor (w)
11446 struct window *w;
11447{
11448 struct frame *f = XFRAME (w->frame);
11449 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11450 int hpos = w->phys_cursor.hpos;
11451 int vpos = w->phys_cursor.vpos;
11452 int mouse_face_here_p = 0;
11453 struct glyph_matrix *active_glyphs = w->current_matrix;
11454 struct glyph_row *cursor_row;
11455 struct glyph *cursor_glyph;
11456 enum draw_glyphs_face hl;
11457
11458 /* No cursor displayed or row invalidated => nothing to do on the
11459 screen. */
11460 if (w->phys_cursor_type == NO_CURSOR)
11461 goto mark_cursor_off;
11462
11463 /* VPOS >= active_glyphs->nrows means that window has been resized.
11464 Don't bother to erase the cursor. */
11465 if (vpos >= active_glyphs->nrows)
11466 goto mark_cursor_off;
11467
11468 /* If row containing cursor is marked invalid, there is nothing we
11469 can do. */
11470 cursor_row = MATRIX_ROW (active_glyphs, vpos);
11471 if (!cursor_row->enabled_p)
11472 goto mark_cursor_off;
11473
a2c6de8e
KS
11474 /* If row is completely invisible, don't attempt to delete a cursor which
11475 isn't there. This can happen if cursor is at top of a window, and
11476 we switch to a buffer with a header line in that window. */
11477 if (cursor_row->visible_height <= 0)
11478 goto mark_cursor_off;
11479
06a2c219
GM
11480 /* This can happen when the new row is shorter than the old one.
11481 In this case, either x_draw_glyphs or clear_end_of_line
11482 should have cleared the cursor. Note that we wouldn't be
11483 able to erase the cursor in this case because we don't have a
11484 cursor glyph at hand. */
11485 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
11486 goto mark_cursor_off;
11487
11488 /* If the cursor is in the mouse face area, redisplay that when
11489 we clear the cursor. */
8801a864
KR
11490 if (! NILP (dpyinfo->mouse_face_window)
11491 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
11492 && (vpos > dpyinfo->mouse_face_beg_row
11493 || (vpos == dpyinfo->mouse_face_beg_row
11494 && hpos >= dpyinfo->mouse_face_beg_col))
11495 && (vpos < dpyinfo->mouse_face_end_row
11496 || (vpos == dpyinfo->mouse_face_end_row
11497 && hpos < dpyinfo->mouse_face_end_col))
11498 /* Don't redraw the cursor's spot in mouse face if it is at the
11499 end of a line (on a newline). The cursor appears there, but
11500 mouse highlighting does not. */
11501 && cursor_row->used[TEXT_AREA] > hpos)
11502 mouse_face_here_p = 1;
11503
11504 /* Maybe clear the display under the cursor. */
11505 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
11506 {
11507 int x;
045dee35 11508 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 11509
06a2c219
GM
11510 cursor_glyph = get_phys_cursor_glyph (w);
11511 if (cursor_glyph == NULL)
11512 goto mark_cursor_off;
dbc4e1c1 11513
e0300d33 11514 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
06a2c219 11515
c5e6e06b
GM
11516 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11517 x,
11518 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
11519 cursor_row->y)),
11520 cursor_glyph->pixel_width,
11521 cursor_row->visible_height,
11522 False);
dbc4e1c1 11523 }
06a2c219
GM
11524
11525 /* Erase the cursor by redrawing the character underneath it. */
11526 if (mouse_face_here_p)
11527 hl = DRAW_MOUSE_FACE;
06a2c219
GM
11528 else
11529 hl = DRAW_NORMAL_TEXT;
11530 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 11531
06a2c219
GM
11532 mark_cursor_off:
11533 w->phys_cursor_on_p = 0;
11534 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
11535}
11536
11537
b7f83f9e
GM
11538/* Non-zero if physical cursor of window W is within mouse face. */
11539
11540static int
11541cursor_in_mouse_face_p (w)
11542 struct window *w;
11543{
11544 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
11545 int in_mouse_face = 0;
11546
11547 if (WINDOWP (dpyinfo->mouse_face_window)
11548 && XWINDOW (dpyinfo->mouse_face_window) == w)
11549 {
11550 int hpos = w->phys_cursor.hpos;
11551 int vpos = w->phys_cursor.vpos;
11552
11553 if (vpos >= dpyinfo->mouse_face_beg_row
11554 && vpos <= dpyinfo->mouse_face_end_row
11555 && (vpos > dpyinfo->mouse_face_beg_row
11556 || hpos >= dpyinfo->mouse_face_beg_col)
11557 && (vpos < dpyinfo->mouse_face_end_row
11558 || hpos < dpyinfo->mouse_face_end_col
11559 || dpyinfo->mouse_face_past_end))
11560 in_mouse_face = 1;
11561 }
11562
11563 return in_mouse_face;
11564}
11565
11566
06a2c219
GM
11567/* Display or clear cursor of window W. If ON is zero, clear the
11568 cursor. If it is non-zero, display the cursor. If ON is nonzero,
11569 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 11570
06a2c219
GM
11571void
11572x_display_and_set_cursor (w, on, hpos, vpos, x, y)
11573 struct window *w;
11574 int on, hpos, vpos, x, y;
dbc4e1c1 11575{
06a2c219
GM
11576 struct frame *f = XFRAME (w->frame);
11577 int new_cursor_type;
f02d8aa0 11578 int new_cursor_width;
06a2c219
GM
11579 struct glyph_matrix *current_glyphs;
11580 struct glyph_row *glyph_row;
11581 struct glyph *glyph;
34368a22 11582 int cursor_non_selected;
dbc4e1c1 11583
49d838ea 11584 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
11585 windows and frames; in the latter case, the frame or window may
11586 be in the midst of changing its size, and x and y may be off the
11587 window. */
11588 if (! FRAME_VISIBLE_P (f)
11589 || FRAME_GARBAGED_P (f)
11590 || vpos >= w->current_matrix->nrows
11591 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
11592 return;
11593
11594 /* If cursor is off and we want it off, return quickly. */
06a2c219 11595 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
11596 return;
11597
06a2c219
GM
11598 current_glyphs = w->current_matrix;
11599 glyph_row = MATRIX_ROW (current_glyphs, vpos);
11600 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
11601
11602 /* If cursor row is not enabled, we don't really know where to
11603 display the cursor. */
11604 if (!glyph_row->enabled_p)
11605 {
11606 w->phys_cursor_on_p = 0;
11607 return;
11608 }
11609
11610 xassert (interrupt_input_blocked);
11611
11612 /* Set new_cursor_type to the cursor we want to be displayed. In a
11613 mini-buffer window, we want the cursor only to appear if we are
11614 reading input from this window. For the selected window, we want
11615 the cursor type given by the frame parameter. If explicitly
11616 marked off, draw no cursor. In all other cases, we want a hollow
11617 box cursor. */
34368a22
RS
11618 cursor_non_selected
11619 = !NILP (Fbuffer_local_value (Qcursor_in_non_selected_windows,
11620 w->buffer));
f02d8aa0 11621 new_cursor_width = -1;
9b4a7047
GM
11622 if (cursor_in_echo_area
11623 && FRAME_HAS_MINIBUF_P (f)
11624 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 11625 {
9b4a7047
GM
11626 if (w == XWINDOW (echo_area_window))
11627 new_cursor_type = FRAME_DESIRED_CURSOR (f);
34368a22 11628 else if (cursor_non_selected)
06a2c219 11629 new_cursor_type = HOLLOW_BOX_CURSOR;
9a7bdceb
GM
11630 else
11631 new_cursor_type = NO_CURSOR;
06a2c219 11632 }
06a2c219 11633 else
9b4a7047 11634 {
7a58ab59
GM
11635 if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
11636 || w != XWINDOW (f->selected_window))
9b4a7047 11637 {
2c850e26 11638 if ((MINI_WINDOW_P (w) && minibuf_level == 0)
34368a22 11639 || !cursor_non_selected
5cefa566 11640 || NILP (XBUFFER (w->buffer)->cursor_type))
9b4a7047
GM
11641 new_cursor_type = NO_CURSOR;
11642 else
11643 new_cursor_type = HOLLOW_BOX_CURSOR;
11644 }
9b4a7047 11645 else
f02d8aa0
GM
11646 {
11647 struct buffer *b = XBUFFER (w->buffer);
11648
11649 if (EQ (b->cursor_type, Qt))
11650 new_cursor_type = FRAME_DESIRED_CURSOR (f);
11651 else
11652 new_cursor_type = x_specified_cursor_type (b->cursor_type,
11653 &new_cursor_width);
e1429afe
KS
11654 if (w->cursor_off_p)
11655 {
11656 if (new_cursor_type == FILLED_BOX_CURSOR)
11657 new_cursor_type = HOLLOW_BOX_CURSOR;
11658 else if (new_cursor_type == BAR_CURSOR && new_cursor_width > 1)
11659 new_cursor_width = 1;
11660 else
11661 new_cursor_type = NO_CURSOR;
11662 }
f02d8aa0 11663 }
9b4a7047 11664 }
06a2c219
GM
11665
11666 /* If cursor is currently being shown and we don't want it to be or
11667 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 11668 erase it. */
06a2c219 11669 if (w->phys_cursor_on_p
dc6f92b8 11670 && (!on
06a2c219
GM
11671 || w->phys_cursor.x != x
11672 || w->phys_cursor.y != y
e1429afe
KS
11673 || new_cursor_type != w->phys_cursor_type
11674 || (new_cursor_type == BAR_CURSOR
11675 && new_cursor_width != w->phys_cursor_width)))
06a2c219
GM
11676 x_erase_phys_cursor (w);
11677
11678 /* If the cursor is now invisible and we want it to be visible,
11679 display it. */
11680 if (on && !w->phys_cursor_on_p)
11681 {
11682 w->phys_cursor_ascent = glyph_row->ascent;
11683 w->phys_cursor_height = glyph_row->height;
11684
11685 /* Set phys_cursor_.* before x_draw_.* is called because some
11686 of them may need the information. */
11687 w->phys_cursor.x = x;
11688 w->phys_cursor.y = glyph_row->y;
11689 w->phys_cursor.hpos = hpos;
11690 w->phys_cursor.vpos = vpos;
11691 w->phys_cursor_type = new_cursor_type;
e1429afe 11692 w->phys_cursor_width = new_cursor_width;
06a2c219
GM
11693 w->phys_cursor_on_p = 1;
11694
11695 switch (new_cursor_type)
dc6f92b8 11696 {
06a2c219
GM
11697 case HOLLOW_BOX_CURSOR:
11698 x_draw_hollow_cursor (w, glyph_row);
11699 break;
11700
11701 case FILLED_BOX_CURSOR:
11702 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
11703 break;
11704
11705 case BAR_CURSOR:
f02d8aa0 11706 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
11707 break;
11708
11709 case NO_CURSOR:
11710 break;
dc6f92b8 11711
06a2c219
GM
11712 default:
11713 abort ();
11714 }
59ddecde
GM
11715
11716#ifdef HAVE_X_I18N
11717 if (w == XWINDOW (f->selected_window))
11718 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
11719 xic_set_preeditarea (w, x, y);
11720#endif
dc6f92b8
JB
11721 }
11722
06a2c219 11723#ifndef XFlush
f676886a 11724 if (updating_frame != f)
334208b7 11725 XFlush (FRAME_X_DISPLAY (f));
06a2c219 11726#endif
dc6f92b8
JB
11727}
11728
06a2c219
GM
11729
11730/* Display the cursor on window W, or clear it. X and Y are window
11731 relative pixel coordinates. HPOS and VPOS are glyph matrix
11732 positions. If W is not the selected window, display a hollow
11733 cursor. ON non-zero means display the cursor at X, Y which
11734 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 11735
dfcf069d 11736void
06a2c219
GM
11737x_display_cursor (w, on, hpos, vpos, x, y)
11738 struct window *w;
11739 int on, hpos, vpos, x, y;
dc6f92b8 11740{
f94397b5 11741 BLOCK_INPUT;
06a2c219 11742 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
11743 UNBLOCK_INPUT;
11744}
11745
06a2c219
GM
11746
11747/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
11748 Don't change the cursor's position. */
11749
dfcf069d 11750void
06a2c219 11751x_update_cursor (f, on_p)
5d46f928 11752 struct frame *f;
5d46f928 11753{
06a2c219
GM
11754 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
11755}
11756
11757
11758/* Call x_update_window_cursor with parameter ON_P on all leaf windows
11759 in the window tree rooted at W. */
11760
11761static void
11762x_update_cursor_in_window_tree (w, on_p)
11763 struct window *w;
11764 int on_p;
11765{
11766 while (w)
11767 {
11768 if (!NILP (w->hchild))
11769 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
11770 else if (!NILP (w->vchild))
11771 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
11772 else
11773 x_update_window_cursor (w, on_p);
11774
11775 w = NILP (w->next) ? 0 : XWINDOW (w->next);
11776 }
11777}
5d46f928 11778
f94397b5 11779
06a2c219
GM
11780/* Switch the display of W's cursor on or off, according to the value
11781 of ON. */
11782
11783static void
11784x_update_window_cursor (w, on)
11785 struct window *w;
11786 int on;
11787{
16b5d424
GM
11788 /* Don't update cursor in windows whose frame is in the process
11789 of being deleted. */
11790 if (w->current_matrix)
11791 {
11792 BLOCK_INPUT;
11793 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
11794 w->phys_cursor.x, w->phys_cursor.y);
11795 UNBLOCK_INPUT;
11796 }
dc6f92b8 11797}
06a2c219
GM
11798
11799
11800
dc6f92b8
JB
11801\f
11802/* Icons. */
11803
dbc4e1c1 11804/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
11805
11806int
990ba854 11807x_bitmap_icon (f, file)
f676886a 11808 struct frame *f;
990ba854 11809 Lisp_Object file;
dc6f92b8 11810{
06a2c219 11811 int bitmap_id;
dc6f92b8 11812
c118dd06 11813 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11814 return 1;
11815
990ba854 11816 /* Free up our existing icon bitmap if any. */
7556890b
RS
11817 if (f->output_data.x->icon_bitmap > 0)
11818 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11819 f->output_data.x->icon_bitmap = 0;
990ba854
RS
11820
11821 if (STRINGP (file))
7f2ae036
RS
11822 bitmap_id = x_create_bitmap_from_file (f, file);
11823 else
11824 {
990ba854 11825 /* Create the GNU bitmap if necessary. */
5bf01b68 11826 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
11827 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
11828 = x_create_bitmap_from_data (f, gnu_bits,
11829 gnu_width, gnu_height);
990ba854
RS
11830
11831 /* The first time we create the GNU bitmap,
06a2c219 11832 this increments the ref-count one extra time.
990ba854
RS
11833 As a result, the GNU bitmap is never freed.
11834 That way, we don't have to worry about allocating it again. */
334208b7 11835 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 11836
334208b7 11837 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
11838 }
11839
11840 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 11841 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
11842
11843 return 0;
11844}
11845
11846
1be2d067
KH
11847/* Make the x-window of frame F use a rectangle with text.
11848 Use ICON_NAME as the text. */
dc6f92b8
JB
11849
11850int
f676886a
JB
11851x_text_icon (f, icon_name)
11852 struct frame *f;
dc6f92b8
JB
11853 char *icon_name;
11854{
c118dd06 11855 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11856 return 1;
11857
1be2d067
KH
11858#ifdef HAVE_X11R4
11859 {
11860 XTextProperty text;
11861 text.value = (unsigned char *) icon_name;
11862 text.encoding = XA_STRING;
11863 text.format = 8;
11864 text.nitems = strlen (icon_name);
11865#ifdef USE_X_TOOLKIT
7556890b 11866 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
11867 &text);
11868#else /* not USE_X_TOOLKIT */
11869 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
11870#endif /* not USE_X_TOOLKIT */
11871 }
11872#else /* not HAVE_X11R4 */
11873 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
11874#endif /* not HAVE_X11R4 */
58769bee 11875
7556890b
RS
11876 if (f->output_data.x->icon_bitmap > 0)
11877 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11878 f->output_data.x->icon_bitmap = 0;
b1c884c3 11879 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
11880
11881 return 0;
11882}
11883\f
e99db5a1
RS
11884#define X_ERROR_MESSAGE_SIZE 200
11885
11886/* If non-nil, this should be a string.
11887 It means catch X errors and store the error message in this string. */
11888
11889static Lisp_Object x_error_message_string;
11890
11891/* An X error handler which stores the error message in
11892 x_error_message_string. This is called from x_error_handler if
11893 x_catch_errors is in effect. */
11894
06a2c219 11895static void
e99db5a1
RS
11896x_error_catcher (display, error)
11897 Display *display;
11898 XErrorEvent *error;
11899{
11900 XGetErrorText (display, error->error_code,
11901 XSTRING (x_error_message_string)->data,
11902 X_ERROR_MESSAGE_SIZE);
11903}
11904
11905/* Begin trapping X errors for display DPY. Actually we trap X errors
11906 for all displays, but DPY should be the display you are actually
11907 operating on.
11908
11909 After calling this function, X protocol errors no longer cause
11910 Emacs to exit; instead, they are recorded in the string
11911 stored in x_error_message_string.
11912
11913 Calling x_check_errors signals an Emacs error if an X error has
11914 occurred since the last call to x_catch_errors or x_check_errors.
11915
11916 Calling x_uncatch_errors resumes the normal error handling. */
11917
11918void x_check_errors ();
11919static Lisp_Object x_catch_errors_unwind ();
11920
11921int
11922x_catch_errors (dpy)
11923 Display *dpy;
11924{
11925 int count = specpdl_ptr - specpdl;
11926
11927 /* Make sure any errors from previous requests have been dealt with. */
11928 XSync (dpy, False);
11929
11930 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
11931
11932 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
11933 XSTRING (x_error_message_string)->data[0] = 0;
11934
11935 return count;
11936}
11937
11938/* Unbind the binding that we made to check for X errors. */
11939
11940static Lisp_Object
11941x_catch_errors_unwind (old_val)
11942 Lisp_Object old_val;
11943{
11944 x_error_message_string = old_val;
11945 return Qnil;
11946}
11947
11948/* If any X protocol errors have arrived since the last call to
11949 x_catch_errors or x_check_errors, signal an Emacs error using
11950 sprintf (a buffer, FORMAT, the x error message text) as the text. */
11951
11952void
11953x_check_errors (dpy, format)
11954 Display *dpy;
11955 char *format;
11956{
11957 /* Make sure to catch any errors incurred so far. */
11958 XSync (dpy, False);
11959
11960 if (XSTRING (x_error_message_string)->data[0])
11961 error (format, XSTRING (x_error_message_string)->data);
11962}
11963
9829ddba
RS
11964/* Nonzero if we had any X protocol errors
11965 since we did x_catch_errors on DPY. */
e99db5a1
RS
11966
11967int
11968x_had_errors_p (dpy)
11969 Display *dpy;
11970{
11971 /* Make sure to catch any errors incurred so far. */
11972 XSync (dpy, False);
11973
11974 return XSTRING (x_error_message_string)->data[0] != 0;
11975}
11976
9829ddba
RS
11977/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
11978
06a2c219 11979void
9829ddba
RS
11980x_clear_errors (dpy)
11981 Display *dpy;
11982{
11983 XSTRING (x_error_message_string)->data[0] = 0;
11984}
11985
e99db5a1
RS
11986/* Stop catching X protocol errors and let them make Emacs die.
11987 DPY should be the display that was passed to x_catch_errors.
11988 COUNT should be the value that was returned by
11989 the corresponding call to x_catch_errors. */
11990
11991void
11992x_uncatch_errors (dpy, count)
11993 Display *dpy;
11994 int count;
11995{
11996 unbind_to (count, Qnil);
11997}
11998
11999#if 0
12000static unsigned int x_wire_count;
12001x_trace_wire ()
12002{
12003 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
12004}
12005#endif /* ! 0 */
12006
12007\f
12008/* Handle SIGPIPE, which can happen when the connection to a server
12009 simply goes away. SIGPIPE is handled by x_connection_signal.
12010 Don't need to do anything, because the write which caused the
12011 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 12012 which will do the appropriate cleanup for us. */
e99db5a1
RS
12013
12014static SIGTYPE
12015x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 12016 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
12017{
12018#ifdef USG
12019 /* USG systems forget handlers when they are used;
12020 must reestablish each time */
12021 signal (signalnum, x_connection_signal);
12022#endif /* USG */
12023}
0da1ab50 12024
e99db5a1 12025\f
0da1ab50
GM
12026/************************************************************************
12027 Handling X errors
12028 ************************************************************************/
4746118a 12029
f0e299de
GM
12030/* Error message passed to x_connection_closed. */
12031
12032static char *error_msg;
12033
a7248e4f 12034/* Function installed as fatal_error_signal_hook in
f0e299de
GM
12035 x_connection_closed. Print the X error message, and exit normally,
12036 instead of dumping core when XtCloseDisplay fails. */
12037
12038static void
12039x_fatal_error_signal ()
12040{
12041 fprintf (stderr, "%s\n", error_msg);
12042 exit (70);
12043}
12044
0da1ab50
GM
12045/* Handle the loss of connection to display DPY. ERROR_MESSAGE is
12046 the text of an error message that lead to the connection loss. */
16bd92ea 12047
4746118a 12048static SIGTYPE
5978125e
GM
12049x_connection_closed (dpy, error_message)
12050 Display *dpy;
7a13e894 12051 char *error_message;
4746118a 12052{
5978125e 12053 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
7a13e894 12054 Lisp_Object frame, tail;
0da1ab50 12055 int count;
0da1ab50 12056
f0e299de
GM
12057 error_msg = (char *) alloca (strlen (error_message) + 1);
12058 strcpy (error_msg, error_message);
1a532e54
GM
12059 handling_signal = 0;
12060
0da1ab50
GM
12061 /* Prevent being called recursively because of an error condition
12062 below. Otherwise, we might end up with printing ``can't find per
12063 display information'' in the recursive call instead of printing
12064 the original message here. */
12065 count = x_catch_errors (dpy);
12066
8a4f36cc
GM
12067 /* We have to close the display to inform Xt that it doesn't
12068 exist anymore. If we don't, Xt will continue to wait for
12069 events from the display. As a consequence, a sequence of
12070
12071 M-x make-frame-on-display RET :1 RET
12072 ...kill the new frame, so that we get an IO error...
12073 M-x make-frame-on-display RET :1 RET
12074
12075 will indefinitely wait in Xt for events for display `:1', opened
12076 in the first class to make-frame-on-display.
6186a4a0 12077
8a4f36cc
GM
12078 Closing the display is reported to lead to a bus error on
12079 OpenWindows in certain situations. I suspect that is a bug
12080 in OpenWindows. I don't know how to cicumvent it here. */
12081
f613a4c8 12082#ifdef USE_X_TOOLKIT
ae24cb3b
GM
12083 /* If DPYINFO is null, this means we didn't open the display
12084 in the first place, so don't try to close it. */
12085 if (dpyinfo)
f0e299de
GM
12086 {
12087 extern void (*fatal_error_signal_hook) P_ ((void));
12088 fatal_error_signal_hook = x_fatal_error_signal;
12089 XtCloseDisplay (dpy);
12090 fatal_error_signal_hook = NULL;
12091 }
f613a4c8 12092#endif
adabc3a9 12093
8a4f36cc 12094 /* Indicate that this display is dead. */
9e80b57d
KR
12095 if (dpyinfo)
12096 dpyinfo->display = 0;
6186a4a0 12097
06a2c219 12098 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
12099 that are on the dead display. */
12100 FOR_EACH_FRAME (tail, frame)
12101 {
12102 Lisp_Object minibuf_frame;
12103 minibuf_frame
12104 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
12105 if (FRAME_X_P (XFRAME (frame))
12106 && FRAME_X_P (XFRAME (minibuf_frame))
12107 && ! EQ (frame, minibuf_frame)
12108 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
12109 Fdelete_frame (frame, Qt);
12110 }
12111
12112 /* Now delete all remaining frames on the dead display.
06a2c219 12113 We are now sure none of these is used as the mini-buffer
7a13e894
RS
12114 for another frame that we need to delete. */
12115 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
12116 if (FRAME_X_P (XFRAME (frame))
12117 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
12118 {
12119 /* Set this to t so that Fdelete_frame won't get confused
12120 trying to find a replacement. */
12121 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
12122 Fdelete_frame (frame, Qt);
12123 }
7a13e894 12124
482a1bd2
KH
12125 if (dpyinfo)
12126 x_delete_display (dpyinfo);
7a13e894 12127
0da1ab50
GM
12128 x_uncatch_errors (dpy, count);
12129
7a13e894
RS
12130 if (x_display_list == 0)
12131 {
f0e299de 12132 fprintf (stderr, "%s\n", error_msg);
7a13e894
RS
12133 shut_down_emacs (0, 0, Qnil);
12134 exit (70);
12135 }
12ba150f 12136
7a13e894
RS
12137 /* Ordinary stack unwind doesn't deal with these. */
12138#ifdef SIGIO
12139 sigunblock (sigmask (SIGIO));
12140#endif
12141 sigunblock (sigmask (SIGALRM));
12142 TOTALLY_UNBLOCK_INPUT;
12143
aa4d9a9e 12144 clear_waiting_for_input ();
f0e299de 12145 error ("%s", error_msg);
4746118a
JB
12146}
12147
0da1ab50 12148
7a13e894
RS
12149/* This is the usual handler for X protocol errors.
12150 It kills all frames on the display that we got the error for.
12151 If that was the only one, it prints an error message and kills Emacs. */
12152
06a2c219 12153static void
c118dd06
JB
12154x_error_quitter (display, error)
12155 Display *display;
12156 XErrorEvent *error;
12157{
7a13e894 12158 char buf[256], buf1[356];
dc6f92b8 12159
58769bee 12160 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 12161 original error handler. */
dc6f92b8 12162
c118dd06 12163 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 12164 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 12165 buf, error->request_code);
7a13e894 12166 x_connection_closed (display, buf1);
dc6f92b8
JB
12167}
12168
0da1ab50 12169
e99db5a1
RS
12170/* This is the first-level handler for X protocol errors.
12171 It calls x_error_quitter or x_error_catcher. */
7a13e894 12172
8922af5f 12173static int
e99db5a1 12174x_error_handler (display, error)
8922af5f 12175 Display *display;
e99db5a1 12176 XErrorEvent *error;
8922af5f 12177{
e99db5a1
RS
12178 if (! NILP (x_error_message_string))
12179 x_error_catcher (display, error);
12180 else
12181 x_error_quitter (display, error);
06a2c219 12182 return 0;
f9e24cb9 12183}
c118dd06 12184
e99db5a1
RS
12185/* This is the handler for X IO errors, always.
12186 It kills all frames on the display that we lost touch with.
12187 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 12188
c118dd06 12189static int
e99db5a1 12190x_io_error_quitter (display)
c118dd06 12191 Display *display;
c118dd06 12192{
e99db5a1 12193 char buf[256];
dc6f92b8 12194
e99db5a1
RS
12195 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
12196 x_connection_closed (display, buf);
06a2c219 12197 return 0;
dc6f92b8 12198}
dc6f92b8 12199\f
f451eb13
JB
12200/* Changing the font of the frame. */
12201
76bcdf39
RS
12202/* Give frame F the font named FONTNAME as its default font, and
12203 return the full name of that font. FONTNAME may be a wildcard
12204 pattern; in that case, we choose some font that fits the pattern.
12205 The return value shows which font we chose. */
12206
b5cf7a0e 12207Lisp_Object
f676886a
JB
12208x_new_font (f, fontname)
12209 struct frame *f;
dc6f92b8
JB
12210 register char *fontname;
12211{
dc43ef94 12212 struct font_info *fontp
ee569018 12213 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 12214
dc43ef94
KH
12215 if (!fontp)
12216 return Qnil;
2224a5fc 12217
dc43ef94 12218 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 12219 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94 12220 f->output_data.x->fontset = -1;
976b73d7
KS
12221
12222 x_compute_fringe_widths (f, 1);
12223
b2cad826
KH
12224 /* Compute the scroll bar width in character columns. */
12225 if (f->scroll_bar_pixel_width > 0)
12226 {
7556890b 12227 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
12228 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
12229 }
12230 else
4e61bddf
RS
12231 {
12232 int wid = FONT_WIDTH (f->output_data.x->font);
12233 f->scroll_bar_cols = (14 + wid - 1) / wid;
12234 }
b2cad826 12235
f676886a 12236 /* Now make the frame display the given font. */
c118dd06 12237 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 12238 {
7556890b
RS
12239 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
12240 f->output_data.x->font->fid);
12241 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
12242 f->output_data.x->font->fid);
12243 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
12244 f->output_data.x->font->fid);
f676886a 12245
a27f9f86 12246 frame_update_line_height (f);
3497f73e
GM
12247
12248 /* Don't change the size of a tip frame; there's no point in
12249 doing it because it's done in Fx_show_tip, and it leads to
12250 problems because the tip frame has no widget. */
12251 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
12252 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 12253 }
a27f9f86
RS
12254 else
12255 /* If we are setting a new frame's font for the first time,
12256 there are no faces yet, so this font's height is the line height. */
7556890b 12257 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 12258
dc43ef94
KH
12259 return build_string (fontp->full_name);
12260}
12261
12262/* Give frame F the fontset named FONTSETNAME as its default font, and
12263 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
12264 pattern; in that case, we choose some fontset that fits the pattern.
12265 The return value shows which fontset we chose. */
b5cf7a0e 12266
dc43ef94
KH
12267Lisp_Object
12268x_new_fontset (f, fontsetname)
12269 struct frame *f;
12270 char *fontsetname;
12271{
ee569018 12272 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 12273 Lisp_Object result;
b5cf7a0e 12274
dc43ef94
KH
12275 if (fontset < 0)
12276 return Qnil;
b5cf7a0e 12277
2da424f1
KH
12278 if (f->output_data.x->fontset == fontset)
12279 /* This fontset is already set in frame F. There's nothing more
12280 to do. */
ee569018 12281 return fontset_name (fontset);
dc43ef94 12282
ee569018 12283 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
12284
12285 if (!STRINGP (result))
12286 /* Can't load ASCII font. */
12287 return Qnil;
12288
12289 /* Since x_new_font doesn't update any fontset information, do it now. */
12290 f->output_data.x->fontset = fontset;
dc43ef94 12291
f5d11644
GM
12292#ifdef HAVE_X_I18N
12293 if (FRAME_XIC (f)
12294 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 12295 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
12296#endif
12297
dc43ef94 12298 return build_string (fontsetname);
dc6f92b8 12299}
f5d11644 12300
976b73d7
KS
12301/* Compute actual fringe widths */
12302
12303void
12304x_compute_fringe_widths (f, redraw)
12305 struct frame *f;
12306 int redraw;
12307{
12308 int o_left = f->output_data.x->left_fringe_width;
12309 int o_right = f->output_data.x->right_fringe_width;
12310 int o_cols = f->output_data.x->fringe_cols;
12311
12312 Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist);
12313 Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist);
12314 int left_fringe_width, right_fringe_width;
12315
12316 if (!NILP (left_fringe))
12317 left_fringe = Fcdr (left_fringe);
12318 if (!NILP (right_fringe))
12319 right_fringe = Fcdr (right_fringe);
12320
12321 left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 :
12322 XINT (left_fringe));
12323 right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 :
12324 XINT (right_fringe));
12325
12326 if (left_fringe_width || right_fringe_width)
12327 {
12328 int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width;
12329 int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width;
12330 int conf_wid = left_wid + right_wid;
12331 int font_wid = FONT_WIDTH (f->output_data.x->font);
12332 int cols = (left_wid + right_wid + font_wid-1) / font_wid;
12333 int real_wid = cols * font_wid;
12334 if (left_wid && right_wid)
12335 {
12336 if (left_fringe_width < 0)
12337 {
12338 /* Left fringe width is fixed, adjust right fringe if necessary */
12339 f->output_data.x->left_fringe_width = left_wid;
12340 f->output_data.x->right_fringe_width = real_wid - left_wid;
12341 }
12342 else if (right_fringe_width < 0)
12343 {
12344 /* Right fringe width is fixed, adjust left fringe if necessary */
12345 f->output_data.x->left_fringe_width = real_wid - right_wid;
12346 f->output_data.x->right_fringe_width = right_wid;
12347 }
12348 else
12349 {
12350 /* Adjust both fringes with an equal amount.
12351 Note that we are doing integer arithmetic here, so don't
12352 lose a pixel if the total width is an odd number. */
12353 int fill = real_wid - conf_wid;
12354 f->output_data.x->left_fringe_width = left_wid + fill/2;
12355 f->output_data.x->right_fringe_width = right_wid + fill - fill/2;
12356 }
12357 }
12358 else if (left_fringe_width)
12359 {
12360 f->output_data.x->left_fringe_width = real_wid;
12361 f->output_data.x->right_fringe_width = 0;
12362 }
12363 else
12364 {
12365 f->output_data.x->left_fringe_width = 0;
12366 f->output_data.x->right_fringe_width = real_wid;
12367 }
12368 f->output_data.x->fringe_cols = cols;
12369 f->output_data.x->fringes_extra = real_wid;
12370 }
12371 else
12372 {
12373 f->output_data.x->left_fringe_width = 0;
12374 f->output_data.x->right_fringe_width = 0;
12375 f->output_data.x->fringe_cols = 0;
12376 f->output_data.x->fringes_extra = 0;
12377 }
12378
12379 if (redraw && FRAME_VISIBLE_P (f))
12380 if (o_left != f->output_data.x->left_fringe_width ||
12381 o_right != f->output_data.x->right_fringe_width ||
12382 o_cols != f->output_data.x->fringe_cols)
12383 redraw_frame (f);
12384}
f5d11644
GM
12385\f
12386/***********************************************************************
12387 X Input Methods
12388 ***********************************************************************/
12389
12390#ifdef HAVE_X_I18N
12391
12392#ifdef HAVE_X11R6
12393
12394/* XIM destroy callback function, which is called whenever the
12395 connection to input method XIM dies. CLIENT_DATA contains a
12396 pointer to the x_display_info structure corresponding to XIM. */
12397
12398static void
12399xim_destroy_callback (xim, client_data, call_data)
12400 XIM xim;
12401 XPointer client_data;
12402 XPointer call_data;
12403{
12404 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
12405 Lisp_Object frame, tail;
12406
12407 BLOCK_INPUT;
12408
12409 /* No need to call XDestroyIC.. */
12410 FOR_EACH_FRAME (tail, frame)
12411 {
12412 struct frame *f = XFRAME (frame);
12413 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
12414 {
12415 FRAME_XIC (f) = NULL;
12416 if (FRAME_XIC_FONTSET (f))
12417 {
12418 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
12419 FRAME_XIC_FONTSET (f) = NULL;
12420 }
12421 }
12422 }
12423
12424 /* No need to call XCloseIM. */
12425 dpyinfo->xim = NULL;
12426 XFree (dpyinfo->xim_styles);
12427 UNBLOCK_INPUT;
12428}
12429
12430#endif /* HAVE_X11R6 */
12431
12432/* Open the connection to the XIM server on display DPYINFO.
12433 RESOURCE_NAME is the resource name Emacs uses. */
12434
12435static void
12436xim_open_dpy (dpyinfo, resource_name)
12437 struct x_display_info *dpyinfo;
12438 char *resource_name;
12439{
287f7dd6 12440#ifdef USE_XIM
f5d11644
GM
12441 XIM xim;
12442
12443 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
12444 dpyinfo->xim = xim;
12445
12446 if (xim)
12447 {
f5d11644
GM
12448#ifdef HAVE_X11R6
12449 XIMCallback destroy;
12450#endif
12451
12452 /* Get supported styles and XIM values. */
12453 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
12454
12455#ifdef HAVE_X11R6
12456 destroy.callback = xim_destroy_callback;
12457 destroy.client_data = (XPointer)dpyinfo;
cea2ad76 12458 /* This isn't prototyped in OSF 5.0. */
f5d11644
GM
12459 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
12460#endif
12461 }
287f7dd6
GM
12462
12463#else /* not USE_XIM */
12464 dpyinfo->xim = NULL;
12465#endif /* not USE_XIM */
f5d11644
GM
12466}
12467
12468
b9de836c 12469#ifdef HAVE_X11R6_XIM
f5d11644
GM
12470
12471struct xim_inst_t
12472{
12473 struct x_display_info *dpyinfo;
12474 char *resource_name;
12475};
12476
12477/* XIM instantiate callback function, which is called whenever an XIM
12478 server is available. DISPLAY is teh display of the XIM.
12479 CLIENT_DATA contains a pointer to an xim_inst_t structure created
12480 when the callback was registered. */
12481
12482static void
12483xim_instantiate_callback (display, client_data, call_data)
12484 Display *display;
12485 XPointer client_data;
12486 XPointer call_data;
12487{
12488 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
12489 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
12490
12491 /* We don't support multiple XIM connections. */
12492 if (dpyinfo->xim)
12493 return;
12494
12495 xim_open_dpy (dpyinfo, xim_inst->resource_name);
12496
12497 /* Create XIC for the existing frames on the same display, as long
12498 as they have no XIC. */
12499 if (dpyinfo->xim && dpyinfo->reference_count > 0)
12500 {
12501 Lisp_Object tail, frame;
12502
12503 BLOCK_INPUT;
12504 FOR_EACH_FRAME (tail, frame)
12505 {
12506 struct frame *f = XFRAME (frame);
12507
12508 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
12509 if (FRAME_XIC (f) == NULL)
12510 {
12511 create_frame_xic (f);
12512 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
12513 xic_set_statusarea (f);
12514 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
12515 {
12516 struct window *w = XWINDOW (f->selected_window);
12517 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
12518 }
12519 }
12520 }
12521
12522 UNBLOCK_INPUT;
12523 }
12524}
12525
b9de836c 12526#endif /* HAVE_X11R6_XIM */
f5d11644
GM
12527
12528
12529/* Open a connection to the XIM server on display DPYINFO.
12530 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
12531 connection only at the first time. On X11R6, open the connection
12532 in the XIM instantiate callback function. */
12533
12534static void
12535xim_initialize (dpyinfo, resource_name)
12536 struct x_display_info *dpyinfo;
12537 char *resource_name;
12538{
287f7dd6 12539#ifdef USE_XIM
b9de836c 12540#ifdef HAVE_X11R6_XIM
f5d11644
GM
12541 struct xim_inst_t *xim_inst;
12542 int len;
12543
12544 dpyinfo->xim = NULL;
12545 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
12546 xim_inst->dpyinfo = dpyinfo;
12547 len = strlen (resource_name);
12548 xim_inst->resource_name = (char *) xmalloc (len + 1);
12549 bcopy (resource_name, xim_inst->resource_name, len + 1);
12550 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12551 resource_name, EMACS_CLASS,
12552 xim_instantiate_callback,
2ebb2f8b
DL
12553 /* Fixme: This is XPointer in
12554 XFree86 but (XPointer *) on
12555 Tru64, at least. */
12556 (XPointer) xim_inst);
b9de836c 12557#else /* not HAVE_X11R6_XIM */
f5d11644
GM
12558 dpyinfo->xim = NULL;
12559 xim_open_dpy (dpyinfo, resource_name);
b9de836c 12560#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
12561
12562#else /* not USE_XIM */
12563 dpyinfo->xim = NULL;
12564#endif /* not USE_XIM */
f5d11644
GM
12565}
12566
12567
12568/* Close the connection to the XIM server on display DPYINFO. */
12569
12570static void
12571xim_close_dpy (dpyinfo)
12572 struct x_display_info *dpyinfo;
12573{
287f7dd6 12574#ifdef USE_XIM
b9de836c 12575#ifdef HAVE_X11R6_XIM
8a4f36cc
GM
12576 if (dpyinfo->display)
12577 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12578 NULL, EMACS_CLASS,
12579 xim_instantiate_callback, NULL);
b9de836c 12580#endif /* not HAVE_X11R6_XIM */
8a4f36cc
GM
12581 if (dpyinfo->display)
12582 XCloseIM (dpyinfo->xim);
f5d11644
GM
12583 dpyinfo->xim = NULL;
12584 XFree (dpyinfo->xim_styles);
287f7dd6 12585#endif /* USE_XIM */
f5d11644
GM
12586}
12587
b9de836c 12588#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
12589
12590
dc6f92b8 12591\f
2e365682
RS
12592/* Calculate the absolute position in frame F
12593 from its current recorded position values and gravity. */
12594
dfcf069d 12595void
43bca5d5 12596x_calc_absolute_position (f)
f676886a 12597 struct frame *f;
dc6f92b8 12598{
06a2c219 12599 Window child;
6dba1858 12600 int win_x = 0, win_y = 0;
7556890b 12601 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
12602 int this_window;
12603
9829ddba
RS
12604 /* We have nothing to do if the current position
12605 is already for the top-left corner. */
12606 if (! ((flags & XNegative) || (flags & YNegative)))
12607 return;
12608
c81412a0 12609#ifdef USE_X_TOOLKIT
7556890b 12610 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
12611#else
12612 this_window = FRAME_X_WINDOW (f);
12613#endif
6dba1858
RS
12614
12615 /* Find the position of the outside upper-left corner of
9829ddba
RS
12616 the inner window, with respect to the outer window.
12617 But do this only if we will need the results. */
7556890b 12618 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 12619 {
9829ddba
RS
12620 int count;
12621
6dba1858 12622 BLOCK_INPUT;
9829ddba
RS
12623 count = x_catch_errors (FRAME_X_DISPLAY (f));
12624 while (1)
12625 {
12626 x_clear_errors (FRAME_X_DISPLAY (f));
12627 XTranslateCoordinates (FRAME_X_DISPLAY (f),
12628
12629 /* From-window, to-window. */
12630 this_window,
12631 f->output_data.x->parent_desc,
12632
12633 /* From-position, to-position. */
12634 0, 0, &win_x, &win_y,
12635
12636 /* Child of win. */
12637 &child);
12638 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12639 {
12640 Window newroot, newparent = 0xdeadbeef;
12641 Window *newchildren;
2ebb2f8b 12642 unsigned int nchildren;
9829ddba
RS
12643
12644 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
12645 &newparent, &newchildren, &nchildren))
12646 break;
58769bee 12647
7c3c78a3 12648 XFree ((char *) newchildren);
6dba1858 12649
9829ddba
RS
12650 f->output_data.x->parent_desc = newparent;
12651 }
12652 else
12653 break;
12654 }
6dba1858 12655
9829ddba 12656 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
12657 UNBLOCK_INPUT;
12658 }
12659
12660 /* Treat negative positions as relative to the leftmost bottommost
12661 position that fits on the screen. */
20f55f9a 12662 if (flags & XNegative)
7556890b 12663 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
12664 - 2 * f->output_data.x->border_width - win_x
12665 - PIXEL_WIDTH (f)
12666 + f->output_data.x->left_pos);
dc6f92b8 12667
7708ced0
GM
12668 {
12669 int height = PIXEL_HEIGHT (f);
06a2c219 12670
7708ced0
GM
12671#if defined USE_X_TOOLKIT && defined USE_MOTIF
12672 /* Something is fishy here. When using Motif, starting Emacs with
12673 `-g -0-0', the frame appears too low by a few pixels.
12674
12675 This seems to be so because initially, while Emacs is starting,
12676 the column widget's height and the frame's pixel height are
12677 different. The column widget's height is the right one. In
12678 later invocations, when Emacs is up, the frame's pixel height
12679 is right, though.
12680
12681 It's not obvious where the initial small difference comes from.
12682 2000-12-01, gerd. */
12683
12684 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
06a2c219 12685#endif
2e365682 12686
7708ced0
GM
12687 if (flags & YNegative)
12688 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
12689 - 2 * f->output_data.x->border_width
12690 - win_y
12691 - height
12692 + f->output_data.x->top_pos);
12693 }
12694
3a35ab44
RS
12695 /* The left_pos and top_pos
12696 are now relative to the top and left screen edges,
12697 so the flags should correspond. */
7556890b 12698 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
12699}
12700
3a35ab44
RS
12701/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
12702 to really change the position, and 0 when calling from
12703 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
12704 position values). It is -1 when calling from x_set_frame_parameters,
12705 which means, do adjust for borders but don't change the gravity. */
3a35ab44 12706
dfcf069d 12707void
dc05a16b 12708x_set_offset (f, xoff, yoff, change_gravity)
f676886a 12709 struct frame *f;
dc6f92b8 12710 register int xoff, yoff;
dc05a16b 12711 int change_gravity;
dc6f92b8 12712{
4a4cbdd5
KH
12713 int modified_top, modified_left;
12714
aa3ff7c9 12715 if (change_gravity > 0)
3a35ab44 12716 {
7556890b
RS
12717 f->output_data.x->top_pos = yoff;
12718 f->output_data.x->left_pos = xoff;
12719 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 12720 if (xoff < 0)
7556890b 12721 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 12722 if (yoff < 0)
7556890b
RS
12723 f->output_data.x->size_hint_flags |= YNegative;
12724 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 12725 }
43bca5d5 12726 x_calc_absolute_position (f);
dc6f92b8
JB
12727
12728 BLOCK_INPUT;
c32cdd9a 12729 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 12730
7556890b
RS
12731 modified_left = f->output_data.x->left_pos;
12732 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
12733#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
12734 this seems to be unnecessary and incorrect. rms, 4/17/97. */
12735 /* It is a mystery why we need to add the border_width here
12736 when the frame is already visible, but experiment says we do. */
aa3ff7c9 12737 if (change_gravity != 0)
4a4cbdd5 12738 {
7556890b
RS
12739 modified_left += f->output_data.x->border_width;
12740 modified_top += f->output_data.x->border_width;
4a4cbdd5 12741 }
e73ec6fa 12742#endif
4a4cbdd5 12743
3afe33e7 12744#ifdef USE_X_TOOLKIT
7556890b 12745 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 12746 modified_left, modified_top);
3afe33e7 12747#else /* not USE_X_TOOLKIT */
334208b7 12748 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 12749 modified_left, modified_top);
3afe33e7 12750#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12751 UNBLOCK_INPUT;
12752}
12753
d0fa3e56
EZ
12754/* Check if we need to resize the frame due to a fullscreen request.
12755 If so needed, resize the frame. */
12756static void
12757x_check_fullscreen (f)
12758 struct frame *f;
12759{
12760 if (f->output_data.x->want_fullscreen & FULLSCREEN_BOTH)
12761 {
12762 int width, height, ign;
12763
12764 x_real_positions (f, &f->output_data.x->left_pos,
12765 &f->output_data.x->top_pos);
12766
12767 x_fullscreen_adjust (f, &width, &height, &ign, &ign);
12768
12769 /* We do not need to move the window, it shall be taken care of
12770 when setting WM manager hints.
12771 If the frame is visible already, the position is checked by
12772 x_check_fullscreen_move. */
12773 if (f->width != width || f->height != height)
12774 {
12775 change_frame_size (f, height, width, 0, 1, 0);
12776 SET_FRAME_GARBAGED (f);
12777 cancel_mouse_face (f);
12778
12779 /* Wait for the change of frame size to occur */
12780 f->output_data.x->want_fullscreen |= FULLSCREEN_WAIT;
12781
12782 }
12783 }
12784}
12785
12786/* If frame parameters are set after the frame is mapped, we need to move
12787 the window. This is done in xfns.c.
12788 Some window managers moves the window to the right position, some
12789 moves the outer window manager window to the specified position.
12790 Here we check that we are in the right spot. If not, make a second
12791 move, assuming we are dealing with the second kind of window manager. */
12792static void
12793x_check_fullscreen_move (f)
12794 struct frame *f;
12795{
12796 if (f->output_data.x->want_fullscreen & FULLSCREEN_MOVE_WAIT)
12797 {
12798 int expect_top = f->output_data.x->top_pos;
12799 int expect_left = f->output_data.x->left_pos;
12800
12801 if (f->output_data.x->want_fullscreen & FULLSCREEN_HEIGHT)
12802 expect_top = 0;
12803 if (f->output_data.x->want_fullscreen & FULLSCREEN_WIDTH)
12804 expect_left = 0;
12805
12806 if (expect_top != f->output_data.x->top_pos
12807 || expect_left != f->output_data.x->left_pos)
12808 x_set_offset (f, expect_left, expect_top, 1);
12809
12810 /* Just do this once */
12811 f->output_data.x->want_fullscreen &= ~FULLSCREEN_MOVE_WAIT;
12812 }
12813}
12814
12815
12816/* Calculate fullscreen size. Return in *TOP_POS and *LEFT_POS the
12817 wanted positions of the WM window (not emacs window).
12818 Return in *WIDTH and *HEIGHT the wanted width and height of Emacs
12819 window (FRAME_X_WINDOW).
12820 */
12821void
12822x_fullscreen_adjust (f, width, height, top_pos, left_pos)
12823 struct frame *f;
12824 int *width;
12825 int *height;
12826 int *top_pos;
12827 int *left_pos;
12828{
12829 int newwidth = f->width, newheight = f->height;
12830
12831 *top_pos = f->output_data.x->top_pos;
12832 *left_pos = f->output_data.x->left_pos;
12833
12834 if (f->output_data.x->want_fullscreen & FULLSCREEN_HEIGHT)
12835 {
12836 int ph;
12837
12838 ph = FRAME_X_DISPLAY_INFO (f)->height;
12839 newheight = PIXEL_TO_CHAR_HEIGHT (f, ph);
12840 ph = CHAR_TO_PIXEL_HEIGHT (f, newheight)
12841 - f->output_data.x->y_pixels_diff;
12842 newheight = PIXEL_TO_CHAR_HEIGHT (f, ph);
12843 *top_pos = 0;
12844 }
12845
12846 if (f->output_data.x->want_fullscreen & FULLSCREEN_WIDTH)
12847 {
12848 int pw;
12849
12850 pw = FRAME_X_DISPLAY_INFO (f)->width;
12851 newwidth = PIXEL_TO_CHAR_WIDTH (f, pw);
12852 pw = CHAR_TO_PIXEL_WIDTH (f, newwidth)
12853 - f->output_data.x->x_pixels_diff;
12854 newwidth = PIXEL_TO_CHAR_WIDTH (f, pw);
12855 *left_pos = 0;
12856 }
12857
12858 *width = newwidth;
12859 *height = newheight;
12860}
12861
dc6f92b8 12862
499b1844
GM
12863/* Change the size of frame F's X window to COLS/ROWS in the case F
12864 doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
12865 top-left-corner window gravity for this size change and subsequent
12866 size changes. Otherwise we leave the window gravity unchanged. */
12867
12868static void
12869x_set_window_size_1 (f, change_gravity, cols, rows)
f676886a 12870 struct frame *f;
bc20ebbf 12871 int change_gravity;
b1c884c3 12872 int cols, rows;
dc6f92b8
JB
12873{
12874 int pixelwidth, pixelheight;
80fd1fe2 12875
b1c884c3 12876 check_frame_size (f, &rows, &cols);
7556890b 12877 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
12878 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
12879 ? 0
12880 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 12881 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 12882 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
976b73d7
KS
12883
12884 x_compute_fringe_widths (f, 0);
12885
f451eb13
JB
12886 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
12887 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 12888
7556890b 12889 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 12890 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 12891
334208b7
RS
12892 XSync (FRAME_X_DISPLAY (f), False);
12893 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12894 pixelwidth, pixelheight);
b1c884c3
JB
12895
12896 /* Now, strictly speaking, we can't be sure that this is accurate,
12897 but the window manager will get around to dealing with the size
12898 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
12899 ConfigureNotify event gets here.
12900
12901 We could just not bother storing any of this information here,
12902 and let the ConfigureNotify event set everything up, but that
fddd5ceb 12903 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 12904 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
12905 point in the future when the ConfigureNotify event arrives.
12906
12907 We pass 1 for DELAY since we can't run Lisp code inside of
12908 a BLOCK_INPUT. */
7d1e984f 12909 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
12910 PIXEL_WIDTH (f) = pixelwidth;
12911 PIXEL_HEIGHT (f) = pixelheight;
12912
aee9a898
RS
12913 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
12914 receive in the ConfigureNotify event; if we get what we asked
12915 for, then the event won't cause the screen to become garbaged, so
12916 we have to make sure to do it here. */
12917 SET_FRAME_GARBAGED (f);
12918
12919 XFlush (FRAME_X_DISPLAY (f));
499b1844
GM
12920}
12921
12922
12923/* Call this to change the size of frame F's x-window.
12924 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
12925 for this size change and subsequent size changes.
12926 Otherwise we leave the window gravity unchanged. */
aee9a898 12927
499b1844
GM
12928void
12929x_set_window_size (f, change_gravity, cols, rows)
12930 struct frame *f;
12931 int change_gravity;
12932 int cols, rows;
12933{
12934 BLOCK_INPUT;
12935
12936#ifdef USE_X_TOOLKIT
12937
f1f4d345 12938 if (f->output_data.x->widget != NULL)
499b1844
GM
12939 {
12940 /* The x and y position of the widget is clobbered by the
12941 call to XtSetValues within EmacsFrameSetCharSize.
12942 This is a real kludge, but I don't understand Xt so I can't
12943 figure out a correct fix. Can anyone else tell me? -- rms. */
12944 int xpos = f->output_data.x->widget->core.x;
12945 int ypos = f->output_data.x->widget->core.y;
12946 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
12947 f->output_data.x->widget->core.x = xpos;
12948 f->output_data.x->widget->core.y = ypos;
12949 }
12950 else
12951 x_set_window_size_1 (f, change_gravity, cols, rows);
12952
12953#else /* not USE_X_TOOLKIT */
12954
12955 x_set_window_size_1 (f, change_gravity, cols, rows);
12956
aee9a898
RS
12957#endif /* not USE_X_TOOLKIT */
12958
4d73d038 12959 /* If cursor was outside the new size, mark it as off. */
06a2c219 12960 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 12961
aee9a898
RS
12962 /* Clear out any recollection of where the mouse highlighting was,
12963 since it might be in a place that's outside the new frame size.
12964 Actually checking whether it is outside is a pain in the neck,
12965 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 12966 cancel_mouse_face (f);
dbc4e1c1 12967
dc6f92b8
JB
12968 UNBLOCK_INPUT;
12969}
dc6f92b8 12970\f
d047c4eb 12971/* Mouse warping. */
dc6f92b8 12972
9b378208 12973void
f676886a
JB
12974x_set_mouse_position (f, x, y)
12975 struct frame *f;
dc6f92b8
JB
12976 int x, y;
12977{
12978 int pix_x, pix_y;
12979
7556890b
RS
12980 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
12981 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
12982
12983 if (pix_x < 0) pix_x = 0;
12984 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
12985
12986 if (pix_y < 0) pix_y = 0;
12987 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
12988
12989 BLOCK_INPUT;
dc6f92b8 12990
334208b7
RS
12991 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12992 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
12993 UNBLOCK_INPUT;
12994}
12995
9b378208
RS
12996/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
12997
12998void
12999x_set_mouse_pixel_position (f, pix_x, pix_y)
13000 struct frame *f;
13001 int pix_x, pix_y;
13002{
13003 BLOCK_INPUT;
13004
334208b7
RS
13005 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
13006 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
13007 UNBLOCK_INPUT;
13008}
d047c4eb
KH
13009\f
13010/* focus shifting, raising and lowering. */
9b378208 13011
dfcf069d 13012void
f676886a
JB
13013x_focus_on_frame (f)
13014 struct frame *f;
dc6f92b8 13015{
1fb20991 13016#if 0 /* This proves to be unpleasant. */
f676886a 13017 x_raise_frame (f);
1fb20991 13018#endif
6d4238f3
JB
13019#if 0
13020 /* I don't think that the ICCCM allows programs to do things like this
13021 without the interaction of the window manager. Whatever you end up
f676886a 13022 doing with this code, do it to x_unfocus_frame too. */
334208b7 13023 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 13024 RevertToPointerRoot, CurrentTime);
c118dd06 13025#endif /* ! 0 */
dc6f92b8
JB
13026}
13027
dfcf069d 13028void
f676886a
JB
13029x_unfocus_frame (f)
13030 struct frame *f;
dc6f92b8 13031{
6d4238f3 13032#if 0
f676886a 13033 /* Look at the remarks in x_focus_on_frame. */
0f941935 13034 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 13035 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 13036 RevertToPointerRoot, CurrentTime);
c118dd06 13037#endif /* ! 0 */
dc6f92b8
JB
13038}
13039
f676886a 13040/* Raise frame F. */
dc6f92b8 13041
dfcf069d 13042void
f676886a
JB
13043x_raise_frame (f)
13044 struct frame *f;
dc6f92b8 13045{
3a88c238 13046 if (f->async_visible)
dc6f92b8
JB
13047 {
13048 BLOCK_INPUT;
3afe33e7 13049#ifdef USE_X_TOOLKIT
7556890b 13050 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 13051#else /* not USE_X_TOOLKIT */
334208b7 13052 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 13053#endif /* not USE_X_TOOLKIT */
334208b7 13054 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
13055 UNBLOCK_INPUT;
13056 }
13057}
13058
f676886a 13059/* Lower frame F. */
dc6f92b8 13060
dfcf069d 13061void
f676886a
JB
13062x_lower_frame (f)
13063 struct frame *f;
dc6f92b8 13064{
3a88c238 13065 if (f->async_visible)
dc6f92b8
JB
13066 {
13067 BLOCK_INPUT;
3afe33e7 13068#ifdef USE_X_TOOLKIT
7556890b 13069 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 13070#else /* not USE_X_TOOLKIT */
334208b7 13071 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 13072#endif /* not USE_X_TOOLKIT */
334208b7 13073 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
13074 UNBLOCK_INPUT;
13075 }
13076}
13077
dbc4e1c1 13078static void
6b0442dc 13079XTframe_raise_lower (f, raise_flag)
dbc4e1c1 13080 FRAME_PTR f;
6b0442dc 13081 int raise_flag;
dbc4e1c1 13082{
6b0442dc 13083 if (raise_flag)
dbc4e1c1
JB
13084 x_raise_frame (f);
13085 else
13086 x_lower_frame (f);
13087}
d047c4eb
KH
13088\f
13089/* Change of visibility. */
dc6f92b8 13090
9382638d
KH
13091/* This tries to wait until the frame is really visible.
13092 However, if the window manager asks the user where to position
13093 the frame, this will return before the user finishes doing that.
13094 The frame will not actually be visible at that time,
13095 but it will become visible later when the window manager
13096 finishes with it. */
13097
dfcf069d 13098void
f676886a
JB
13099x_make_frame_visible (f)
13100 struct frame *f;
dc6f92b8 13101{
990ba854 13102 Lisp_Object type;
1aa6072f 13103 int original_top, original_left;
31be9251
GM
13104 int retry_count = 2;
13105
13106 retry:
dc6f92b8 13107
dc6f92b8 13108 BLOCK_INPUT;
dc6f92b8 13109
990ba854
RS
13110 type = x_icon_type (f);
13111 if (!NILP (type))
13112 x_bitmap_icon (f, type);
bdcd49ba 13113
f676886a 13114 if (! FRAME_VISIBLE_P (f))
90e65f07 13115 {
1aa6072f
RS
13116 /* We test FRAME_GARBAGED_P here to make sure we don't
13117 call x_set_offset a second time
13118 if we get to x_make_frame_visible a second time
13119 before the window gets really visible. */
13120 if (! FRAME_ICONIFIED_P (f)
13121 && ! f->output_data.x->asked_for_visible)
13122 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
13123
13124 f->output_data.x->asked_for_visible = 1;
13125
90e65f07 13126 if (! EQ (Vx_no_window_manager, Qt))
f676886a 13127 x_wm_set_window_state (f, NormalState);
3afe33e7 13128#ifdef USE_X_TOOLKIT
d7a38a2e 13129 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 13130 XtMapWidget (f->output_data.x->widget);
3afe33e7 13131#else /* not USE_X_TOOLKIT */
7f9c7f94 13132 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 13133#endif /* not USE_X_TOOLKIT */
0134a210
RS
13134#if 0 /* This seems to bring back scroll bars in the wrong places
13135 if the window configuration has changed. They seem
13136 to come back ok without this. */
ab648270 13137 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 13138 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 13139#endif
90e65f07 13140 }
dc6f92b8 13141
334208b7 13142 XFlush (FRAME_X_DISPLAY (f));
90e65f07 13143
0dacf791
RS
13144 /* Synchronize to ensure Emacs knows the frame is visible
13145 before we do anything else. We do this loop with input not blocked
13146 so that incoming events are handled. */
13147 {
13148 Lisp_Object frame;
12ce2351 13149 int count;
28c01ffe
RS
13150 /* This must be before UNBLOCK_INPUT
13151 since events that arrive in response to the actions above
13152 will set it when they are handled. */
13153 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
13154
13155 original_left = f->output_data.x->left_pos;
13156 original_top = f->output_data.x->top_pos;
c0a04927
RS
13157
13158 /* This must come after we set COUNT. */
13159 UNBLOCK_INPUT;
13160
2745e6c4 13161 /* We unblock here so that arriving X events are processed. */
1aa6072f 13162
dcb07ae9
RS
13163 /* Now move the window back to where it was "supposed to be".
13164 But don't do it if the gravity is negative.
13165 When the gravity is negative, this uses a position
28c01ffe
RS
13166 that is 3 pixels too low. Perhaps that's really the border width.
13167
13168 Don't do this if the window has never been visible before,
13169 because the window manager may choose the position
13170 and we don't want to override it. */
1aa6072f 13171
4d3f5d9a 13172 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 13173 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 13174 && previously_visible)
1aa6072f 13175 {
2745e6c4
RS
13176 Drawable rootw;
13177 int x, y;
13178 unsigned int width, height, border, depth;
06a2c219 13179
1aa6072f 13180 BLOCK_INPUT;
9829ddba 13181
06a2c219
GM
13182 /* On some window managers (such as FVWM) moving an existing
13183 window, even to the same place, causes the window manager
13184 to introduce an offset. This can cause the window to move
13185 to an unexpected location. Check the geometry (a little
13186 slow here) and then verify that the window is in the right
13187 place. If the window is not in the right place, move it
13188 there, and take the potential window manager hit. */
2745e6c4
RS
13189 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
13190 &rootw, &x, &y, &width, &height, &border, &depth);
13191
13192 if (original_left != x || original_top != y)
13193 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
13194 original_left, original_top);
13195
1aa6072f
RS
13196 UNBLOCK_INPUT;
13197 }
9829ddba 13198
e0c1aef2 13199 XSETFRAME (frame, f);
c0a04927 13200
12ce2351
GM
13201 /* Wait until the frame is visible. Process X events until a
13202 MapNotify event has been seen, or until we think we won't get a
13203 MapNotify at all.. */
13204 for (count = input_signal_count + 10;
13205 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 13206 {
12ce2351 13207 /* Force processing of queued events. */
334208b7 13208 x_sync (f);
12ce2351
GM
13209
13210 /* Machines that do polling rather than SIGIO have been
13211 observed to go into a busy-wait here. So we'll fake an
13212 alarm signal to let the handler know that there's something
13213 to be read. We used to raise a real alarm, but it seems
13214 that the handler isn't always enabled here. This is
13215 probably a bug. */
8b2f8d4e 13216 if (input_polling_used ())
3b2fa4e6 13217 {
12ce2351
GM
13218 /* It could be confusing if a real alarm arrives while
13219 processing the fake one. Turn it off and let the
13220 handler reset it. */
3e71d8f2 13221 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
13222 int old_poll_suppress_count = poll_suppress_count;
13223 poll_suppress_count = 1;
13224 poll_for_input_1 ();
13225 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 13226 }
12ce2351
GM
13227
13228 /* See if a MapNotify event has been processed. */
13229 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 13230 }
31be9251
GM
13231
13232 /* 2000-09-28: In
13233
13234 (let ((f (selected-frame)))
13235 (iconify-frame f)
13236 (raise-frame f))
13237
13238 the frame is not raised with various window managers on
13239 FreeBSD, Linux and Solaris. It turns out that, for some
13240 unknown reason, the call to XtMapWidget is completely ignored.
13241 Mapping the widget a second time works. */
13242
13243 if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
13244 goto retry;
0dacf791 13245 }
dc6f92b8
JB
13246}
13247
06a2c219 13248/* Change from mapped state to withdrawn state. */
dc6f92b8 13249
d047c4eb
KH
13250/* Make the frame visible (mapped and not iconified). */
13251
dfcf069d 13252void
f676886a
JB
13253x_make_frame_invisible (f)
13254 struct frame *f;
dc6f92b8 13255{
546e6d5b
RS
13256 Window window;
13257
13258#ifdef USE_X_TOOLKIT
13259 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 13260 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
13261#else /* not USE_X_TOOLKIT */
13262 window = FRAME_X_WINDOW (f);
13263#endif /* not USE_X_TOOLKIT */
dc6f92b8 13264
9319ae23 13265 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
13266 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
13267 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 13268
5627c40e 13269#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 13270 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 13271 return;
5627c40e 13272#endif
dc6f92b8
JB
13273
13274 BLOCK_INPUT;
c118dd06 13275
af31d76f
RS
13276 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
13277 that the current position of the window is user-specified, rather than
13278 program-specified, so that when the window is mapped again, it will be
13279 placed at the same location, without forcing the user to position it
13280 by hand again (they have already done that once for this window.) */
c32cdd9a 13281 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 13282
c118dd06
JB
13283#ifdef HAVE_X11R4
13284
334208b7
RS
13285 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
13286 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
13287 {
13288 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13289 error ("Can't notify window manager of window withdrawal");
c118dd06 13290 }
c118dd06 13291#else /* ! defined (HAVE_X11R4) */
16bd92ea 13292
c118dd06 13293 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
13294 if (! EQ (Vx_no_window_manager, Qt))
13295 {
16bd92ea 13296 XEvent unmap;
dc6f92b8 13297
16bd92ea 13298 unmap.xunmap.type = UnmapNotify;
546e6d5b 13299 unmap.xunmap.window = window;
334208b7 13300 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 13301 unmap.xunmap.from_configure = False;
334208b7
RS
13302 if (! XSendEvent (FRAME_X_DISPLAY (f),
13303 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 13304 False,
06a2c219 13305 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
13306 &unmap))
13307 {
13308 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13309 error ("Can't notify window manager of withdrawal");
16bd92ea 13310 }
dc6f92b8
JB
13311 }
13312
16bd92ea 13313 /* Unmap the window ourselves. Cheeky! */
334208b7 13314 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 13315#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 13316
5627c40e
RS
13317 /* We can't distinguish this from iconification
13318 just by the event that we get from the server.
13319 So we can't win using the usual strategy of letting
13320 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
13321 and synchronize with the server to make sure we agree. */
13322 f->visible = 0;
13323 FRAME_ICONIFIED_P (f) = 0;
13324 f->async_visible = 0;
13325 f->async_iconified = 0;
13326
334208b7 13327 x_sync (f);
5627c40e 13328
dc6f92b8
JB
13329 UNBLOCK_INPUT;
13330}
13331
06a2c219 13332/* Change window state from mapped to iconified. */
dc6f92b8 13333
dfcf069d 13334void
f676886a
JB
13335x_iconify_frame (f)
13336 struct frame *f;
dc6f92b8 13337{
3afe33e7 13338 int result;
990ba854 13339 Lisp_Object type;
dc6f92b8 13340
9319ae23 13341 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
13342 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
13343 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 13344
3a88c238 13345 if (f->async_iconified)
dc6f92b8
JB
13346 return;
13347
3afe33e7 13348 BLOCK_INPUT;
546e6d5b 13349
9af3143a
RS
13350 FRAME_SAMPLE_VISIBILITY (f);
13351
990ba854
RS
13352 type = x_icon_type (f);
13353 if (!NILP (type))
13354 x_bitmap_icon (f, type);
bdcd49ba
RS
13355
13356#ifdef USE_X_TOOLKIT
13357
546e6d5b
RS
13358 if (! FRAME_VISIBLE_P (f))
13359 {
13360 if (! EQ (Vx_no_window_manager, Qt))
13361 x_wm_set_window_state (f, IconicState);
13362 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 13363 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
13364 /* The server won't give us any event to indicate
13365 that an invisible frame was changed to an icon,
13366 so we have to record it here. */
13367 f->iconified = 1;
1e6bc770 13368 f->visible = 1;
9cf30a30 13369 f->async_iconified = 1;
1e6bc770 13370 f->async_visible = 0;
546e6d5b
RS
13371 UNBLOCK_INPUT;
13372 return;
13373 }
13374
334208b7 13375 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 13376 XtWindow (f->output_data.x->widget),
334208b7 13377 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
13378 UNBLOCK_INPUT;
13379
13380 if (!result)
546e6d5b 13381 error ("Can't notify window manager of iconification");
3afe33e7
RS
13382
13383 f->async_iconified = 1;
1e6bc770
RS
13384 f->async_visible = 0;
13385
8c002a25
KH
13386
13387 BLOCK_INPUT;
334208b7 13388 XFlush (FRAME_X_DISPLAY (f));
8c002a25 13389 UNBLOCK_INPUT;
3afe33e7
RS
13390#else /* not USE_X_TOOLKIT */
13391
fd13dbb2
RS
13392 /* Make sure the X server knows where the window should be positioned,
13393 in case the user deiconifies with the window manager. */
13394 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 13395 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 13396
16bd92ea
JB
13397 /* Since we don't know which revision of X we're running, we'll use both
13398 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
13399
13400 /* X11R4: send a ClientMessage to the window manager using the
13401 WM_CHANGE_STATE type. */
13402 {
13403 XEvent message;
58769bee 13404
c118dd06 13405 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 13406 message.xclient.type = ClientMessage;
334208b7 13407 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
13408 message.xclient.format = 32;
13409 message.xclient.data.l[0] = IconicState;
13410
334208b7
RS
13411 if (! XSendEvent (FRAME_X_DISPLAY (f),
13412 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
13413 False,
13414 SubstructureRedirectMask | SubstructureNotifyMask,
13415 &message))
dc6f92b8
JB
13416 {
13417 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13418 error ("Can't notify window manager of iconification");
dc6f92b8 13419 }
16bd92ea 13420 }
dc6f92b8 13421
58769bee 13422 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
13423 IconicState. */
13424 x_wm_set_window_state (f, IconicState);
dc6f92b8 13425
a9c00105
RS
13426 if (!FRAME_VISIBLE_P (f))
13427 {
13428 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 13429 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
13430 }
13431
3a88c238 13432 f->async_iconified = 1;
1e6bc770 13433 f->async_visible = 0;
dc6f92b8 13434
334208b7 13435 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 13436 UNBLOCK_INPUT;
8c002a25 13437#endif /* not USE_X_TOOLKIT */
dc6f92b8 13438}
19f71add 13439
d047c4eb 13440\f
19f71add 13441/* Free X resources of frame F. */
dc6f92b8 13442
dfcf069d 13443void
19f71add 13444x_free_frame_resources (f)
f676886a 13445 struct frame *f;
dc6f92b8 13446{
7f9c7f94 13447 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
c6ea2775
EZ
13448 Lisp_Object bar;
13449 struct scroll_bar *b;
7f9c7f94 13450
dc6f92b8 13451 BLOCK_INPUT;
c0ff3fab 13452
6186a4a0
RS
13453 /* If a display connection is dead, don't try sending more
13454 commands to the X server. */
19f71add 13455 if (dpyinfo->display)
6186a4a0 13456 {
19f71add 13457 if (f->output_data.x->icon_desc)
6186a4a0 13458 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
c6ea2775
EZ
13459
13460#ifdef USE_X_TOOLKIT
13461 /* Explicitly destroy the scroll bars of the frame. Without
13462 this, we get "BadDrawable" errors from the toolkit later on,
13463 presumably from expose events generated for the disappearing
13464 toolkit scroll bars. */
13465 for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next)
13466 {
13467 b = XSCROLL_BAR (bar);
13468 x_scroll_bar_remove (b);
13469 }
13470#endif
13471
31f41daf 13472#ifdef HAVE_X_I18N
f5d11644
GM
13473 if (FRAME_XIC (f))
13474 free_frame_xic (f);
31f41daf 13475#endif
c6ea2775 13476
3afe33e7 13477#ifdef USE_X_TOOLKIT
06a2c219 13478 if (f->output_data.x->widget)
30ca89f5
GM
13479 {
13480 XtDestroyWidget (f->output_data.x->widget);
13481 f->output_data.x->widget = NULL;
13482 }
c6ea2775
EZ
13483 /* Tooltips don't have widgets, only a simple X window, even if
13484 we are using a toolkit. */
13485 else if (FRAME_X_WINDOW (f))
13486 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13487
6186a4a0 13488 free_frame_menubar (f);
c6ea2775
EZ
13489#else /* !USE_X_TOOLKIT */
13490 if (FRAME_X_WINDOW (f))
13491 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13492#endif /* !USE_X_TOOLKIT */
3afe33e7 13493
3e71d8f2
GM
13494 unload_color (f, f->output_data.x->foreground_pixel);
13495 unload_color (f, f->output_data.x->background_pixel);
13496 unload_color (f, f->output_data.x->cursor_pixel);
13497 unload_color (f, f->output_data.x->cursor_foreground_pixel);
13498 unload_color (f, f->output_data.x->border_pixel);
13499 unload_color (f, f->output_data.x->mouse_pixel);
c6ea2775 13500
3e71d8f2
GM
13501 if (f->output_data.x->scroll_bar_background_pixel != -1)
13502 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
13503 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
13504 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
7c1bef7a
MB
13505#ifdef USE_TOOLKIT_SCROLL_BARS
13506 /* Scrollbar shadow colors. */
13507 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
13508 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
13509 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
13510 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
13511#endif /* USE_TOOLKIT_SCROLL_BARS */
3e71d8f2
GM
13512 if (f->output_data.x->white_relief.allocated_p)
13513 unload_color (f, f->output_data.x->white_relief.pixel);
13514 if (f->output_data.x->black_relief.allocated_p)
13515 unload_color (f, f->output_data.x->black_relief.pixel);
4ca78676 13516
19f71add
GM
13517 if (FRAME_FACE_CACHE (f))
13518 free_frame_faces (f);
13519
4ca78676 13520 x_free_gcs (f);
6186a4a0
RS
13521 XFlush (FRAME_X_DISPLAY (f));
13522 }
dc6f92b8 13523
df89d8a4 13524 if (f->output_data.x->saved_menu_event)
06a2c219 13525 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 13526
7556890b 13527 xfree (f->output_data.x);
19f71add
GM
13528 f->output_data.x = NULL;
13529
0f941935
KH
13530 if (f == dpyinfo->x_focus_frame)
13531 dpyinfo->x_focus_frame = 0;
13532 if (f == dpyinfo->x_focus_event_frame)
13533 dpyinfo->x_focus_event_frame = 0;
13534 if (f == dpyinfo->x_highlight_frame)
13535 dpyinfo->x_highlight_frame = 0;
c0ff3fab 13536
7f9c7f94 13537 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 13538 {
7f9c7f94
RS
13539 dpyinfo->mouse_face_beg_row
13540 = dpyinfo->mouse_face_beg_col = -1;
13541 dpyinfo->mouse_face_end_row
13542 = dpyinfo->mouse_face_end_col = -1;
13543 dpyinfo->mouse_face_window = Qnil;
21323706
RS
13544 dpyinfo->mouse_face_deferred_gc = 0;
13545 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 13546 }
0134a210 13547
c0ff3fab 13548 UNBLOCK_INPUT;
dc6f92b8 13549}
19f71add
GM
13550
13551
13552/* Destroy the X window of frame F. */
13553
13554void
13555x_destroy_window (f)
13556 struct frame *f;
13557{
13558 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13559
13560 /* If a display connection is dead, don't try sending more
13561 commands to the X server. */
13562 if (dpyinfo->display != 0)
13563 x_free_frame_resources (f);
13564
13565 dpyinfo->reference_count--;
13566}
13567
dc6f92b8 13568\f
f451eb13
JB
13569/* Setting window manager hints. */
13570
af31d76f
RS
13571/* Set the normal size hints for the window manager, for frame F.
13572 FLAGS is the flags word to use--or 0 meaning preserve the flags
13573 that the window now has.
13574 If USER_POSITION is nonzero, we set the USPosition
13575 flag (this is useful when FLAGS is 0). */
6dba1858 13576
dfcf069d 13577void
af31d76f 13578x_wm_set_size_hint (f, flags, user_position)
f676886a 13579 struct frame *f;
af31d76f
RS
13580 long flags;
13581 int user_position;
dc6f92b8
JB
13582{
13583 XSizeHints size_hints;
3afe33e7
RS
13584
13585#ifdef USE_X_TOOLKIT
7e4f2521
FP
13586 Arg al[2];
13587 int ac = 0;
13588 Dimension widget_width, widget_height;
7556890b 13589 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 13590#else /* not USE_X_TOOLKIT */
c118dd06 13591 Window window = FRAME_X_WINDOW (f);
3afe33e7 13592#endif /* not USE_X_TOOLKIT */
dc6f92b8 13593
b72a58fd
RS
13594 /* Setting PMaxSize caused various problems. */
13595 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 13596
7556890b
RS
13597 size_hints.x = f->output_data.x->left_pos;
13598 size_hints.y = f->output_data.x->top_pos;
7553a6b7 13599
7e4f2521
FP
13600#ifdef USE_X_TOOLKIT
13601 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
13602 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 13603 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
13604 size_hints.height = widget_height;
13605 size_hints.width = widget_width;
13606#else /* not USE_X_TOOLKIT */
f676886a
JB
13607 size_hints.height = PIXEL_HEIGHT (f);
13608 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 13609#endif /* not USE_X_TOOLKIT */
7553a6b7 13610
7556890b
RS
13611 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
13612 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
13613 size_hints.max_width
13614 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
13615 size_hints.max_height
13616 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 13617
d067ea8b
KH
13618 /* Calculate the base and minimum sizes.
13619
13620 (When we use the X toolkit, we don't do it here.
13621 Instead we copy the values that the widgets are using, below.) */
13622#ifndef USE_X_TOOLKIT
b1c884c3 13623 {
b0342f17 13624 int base_width, base_height;
0134a210 13625 int min_rows = 0, min_cols = 0;
b0342f17 13626
f451eb13
JB
13627 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
13628 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 13629
0134a210 13630 check_frame_size (f, &min_rows, &min_cols);
b0342f17 13631
0134a210
RS
13632 /* The window manager uses the base width hints to calculate the
13633 current number of rows and columns in the frame while
13634 resizing; min_width and min_height aren't useful for this
13635 purpose, since they might not give the dimensions for a
13636 zero-row, zero-column frame.
58769bee 13637
0134a210
RS
13638 We use the base_width and base_height members if we have
13639 them; otherwise, we set the min_width and min_height members
13640 to the size for a zero x zero frame. */
b0342f17
JB
13641
13642#ifdef HAVE_X11R4
0134a210
RS
13643 size_hints.flags |= PBaseSize;
13644 size_hints.base_width = base_width;
13645 size_hints.base_height = base_height;
13646 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
13647 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 13648#else
0134a210
RS
13649 size_hints.min_width = base_width;
13650 size_hints.min_height = base_height;
b0342f17 13651#endif
b1c884c3 13652 }
dc6f92b8 13653
d067ea8b 13654 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 13655 if (flags)
dc6f92b8 13656 {
d067ea8b
KH
13657 size_hints.flags |= flags;
13658 goto no_read;
13659 }
13660#endif /* not USE_X_TOOLKIT */
13661
13662 {
13663 XSizeHints hints; /* Sometimes I hate X Windows... */
13664 long supplied_return;
13665 int value;
af31d76f
RS
13666
13667#ifdef HAVE_X11R4
d067ea8b
KH
13668 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
13669 &supplied_return);
af31d76f 13670#else
d067ea8b 13671 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 13672#endif
58769bee 13673
d067ea8b
KH
13674#ifdef USE_X_TOOLKIT
13675 size_hints.base_height = hints.base_height;
13676 size_hints.base_width = hints.base_width;
13677 size_hints.min_height = hints.min_height;
13678 size_hints.min_width = hints.min_width;
13679#endif
13680
13681 if (flags)
13682 size_hints.flags |= flags;
13683 else
13684 {
13685 if (value == 0)
13686 hints.flags = 0;
13687 if (hints.flags & PSize)
13688 size_hints.flags |= PSize;
13689 if (hints.flags & PPosition)
13690 size_hints.flags |= PPosition;
13691 if (hints.flags & USPosition)
13692 size_hints.flags |= USPosition;
13693 if (hints.flags & USSize)
13694 size_hints.flags |= USSize;
13695 }
13696 }
13697
06a2c219 13698#ifndef USE_X_TOOLKIT
d067ea8b 13699 no_read:
06a2c219 13700#endif
0134a210 13701
af31d76f 13702#ifdef PWinGravity
7556890b 13703 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 13704 size_hints.flags |= PWinGravity;
dc05a16b 13705
af31d76f 13706 if (user_position)
6dba1858 13707 {
af31d76f
RS
13708 size_hints.flags &= ~ PPosition;
13709 size_hints.flags |= USPosition;
6dba1858 13710 }
2554751d 13711#endif /* PWinGravity */
6dba1858 13712
b0342f17 13713#ifdef HAVE_X11R4
334208b7 13714 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13715#else
334208b7 13716 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13717#endif
dc6f92b8
JB
13718}
13719
13720/* Used for IconicState or NormalState */
06a2c219 13721
dfcf069d 13722void
f676886a
JB
13723x_wm_set_window_state (f, state)
13724 struct frame *f;
dc6f92b8
JB
13725 int state;
13726{
3afe33e7 13727#ifdef USE_X_TOOLKIT
546e6d5b
RS
13728 Arg al[1];
13729
13730 XtSetArg (al[0], XtNinitialState, state);
7556890b 13731 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 13732#else /* not USE_X_TOOLKIT */
c118dd06 13733 Window window = FRAME_X_WINDOW (f);
dc6f92b8 13734
7556890b
RS
13735 f->output_data.x->wm_hints.flags |= StateHint;
13736 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 13737
7556890b 13738 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 13739#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13740}
13741
dfcf069d 13742void
7f2ae036 13743x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 13744 struct frame *f;
7f2ae036 13745 int pixmap_id;
dc6f92b8 13746{
d2bd6bc4
RS
13747 Pixmap icon_pixmap;
13748
06a2c219 13749#ifndef USE_X_TOOLKIT
c118dd06 13750 Window window = FRAME_X_WINDOW (f);
75231bad 13751#endif
dc6f92b8 13752
7f2ae036 13753 if (pixmap_id > 0)
dbc4e1c1 13754 {
d2bd6bc4 13755 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 13756 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
13757 }
13758 else
68568555
RS
13759 {
13760 /* It seems there is no way to turn off use of an icon pixmap.
13761 The following line does it, only if no icon has yet been created,
13762 for some window managers. But with mwm it crashes.
13763 Some people say it should clear the IconPixmapHint bit in this case,
13764 but that doesn't work, and the X consortium said it isn't the
13765 right thing at all. Since there is no way to win,
13766 best to explicitly give up. */
13767#if 0
13768 f->output_data.x->wm_hints.icon_pixmap = None;
13769#else
13770 return;
13771#endif
13772 }
b1c884c3 13773
d2bd6bc4
RS
13774#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
13775
13776 {
13777 Arg al[1];
13778 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
13779 XtSetValues (f->output_data.x->widget, al, 1);
13780 }
13781
13782#else /* not USE_X_TOOLKIT */
13783
7556890b
RS
13784 f->output_data.x->wm_hints.flags |= IconPixmapHint;
13785 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
13786
13787#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13788}
13789
dfcf069d 13790void
f676886a
JB
13791x_wm_set_icon_position (f, icon_x, icon_y)
13792 struct frame *f;
dc6f92b8
JB
13793 int icon_x, icon_y;
13794{
75231bad 13795#ifdef USE_X_TOOLKIT
7556890b 13796 Window window = XtWindow (f->output_data.x->widget);
75231bad 13797#else
c118dd06 13798 Window window = FRAME_X_WINDOW (f);
75231bad 13799#endif
dc6f92b8 13800
7556890b
RS
13801 f->output_data.x->wm_hints.flags |= IconPositionHint;
13802 f->output_data.x->wm_hints.icon_x = icon_x;
13803 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 13804
7556890b 13805 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
13806}
13807
13808\f
06a2c219
GM
13809/***********************************************************************
13810 Fonts
13811 ***********************************************************************/
dc43ef94
KH
13812
13813/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 13814
dc43ef94
KH
13815struct font_info *
13816x_get_font_info (f, font_idx)
13817 FRAME_PTR f;
13818 int font_idx;
13819{
13820 return (FRAME_X_FONT_TABLE (f) + font_idx);
13821}
13822
13823
9c11f79e
GM
13824/* Return a list of names of available fonts matching PATTERN on frame F.
13825
13826 If SIZE is > 0, it is the size (maximum bounds width) of fonts
13827 to be listed.
13828
13829 SIZE < 0 means include scalable fonts.
13830
13831 Frame F null means we have not yet created any frame on X, and
13832 consult the first display in x_display_list. MAXNAMES sets a limit
13833 on how many fonts to match. */
dc43ef94
KH
13834
13835Lisp_Object
13836x_list_fonts (f, pattern, size, maxnames)
9c11f79e 13837 struct frame *f;
dc43ef94
KH
13838 Lisp_Object pattern;
13839 int size;
13840 int maxnames;
13841{
06a2c219
GM
13842 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
13843 Lisp_Object tem, second_best;
9c11f79e
GM
13844 struct x_display_info *dpyinfo
13845 = f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
13846 Display *dpy = dpyinfo->display;
09c6077f 13847 int try_XLoadQueryFont = 0;
53ca4657 13848 int count;
9c11f79e
GM
13849 int allow_scalable_fonts_p = 0;
13850
13851 if (size < 0)
13852 {
13853 allow_scalable_fonts_p = 1;
13854 size = 0;
13855 }
dc43ef94 13856
6b0efe73 13857 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
13858 if (NILP (patterns))
13859 patterns = Fcons (pattern, Qnil);
81ba44e5 13860
09c6077f
KH
13861 if (maxnames == 1 && !size)
13862 /* We can return any single font matching PATTERN. */
13863 try_XLoadQueryFont = 1;
9a32686f 13864
8e713be6 13865 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 13866 {
dc43ef94 13867 int num_fonts;
3e71d8f2 13868 char **names = NULL;
dc43ef94 13869
8e713be6 13870 pattern = XCAR (patterns);
536f4067
RS
13871 /* See if we cached the result for this particular query.
13872 The cache is an alist of the form:
9c11f79e
GM
13873 ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */
13874 tem = XCDR (dpyinfo->name_list_element);
13875 key = Fcons (Fcons (pattern, make_number (maxnames)),
13876 allow_scalable_fonts_p ? Qt : Qnil);
13877 list = Fassoc (key, tem);
13878 if (!NILP (list))
b5210ea7
KH
13879 {
13880 list = Fcdr_safe (list);
13881 /* We have a cashed list. Don't have to get the list again. */
13882 goto label_cached;
13883 }
13884
13885 /* At first, put PATTERN in the cache. */
09c6077f 13886
dc43ef94 13887 BLOCK_INPUT;
17d85edc
KH
13888 count = x_catch_errors (dpy);
13889
09c6077f
KH
13890 if (try_XLoadQueryFont)
13891 {
13892 XFontStruct *font;
13893 unsigned long value;
13894
13895 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
13896 if (x_had_errors_p (dpy))
13897 {
13898 /* This error is perhaps due to insufficient memory on X
13899 server. Let's just ignore it. */
13900 font = NULL;
13901 x_clear_errors (dpy);
13902 }
13903
09c6077f
KH
13904 if (font
13905 && XGetFontProperty (font, XA_FONT, &value))
13906 {
13907 char *name = (char *) XGetAtomName (dpy, (Atom) value);
13908 int len = strlen (name);
01c752b5 13909 char *tmp;
09c6077f 13910
6f6512e8
KH
13911 /* If DXPC (a Differential X Protocol Compressor)
13912 Ver.3.7 is running, XGetAtomName will return null
13913 string. We must avoid such a name. */
13914 if (len == 0)
13915 try_XLoadQueryFont = 0;
13916 else
13917 {
13918 num_fonts = 1;
13919 names = (char **) alloca (sizeof (char *));
13920 /* Some systems only allow alloca assigned to a
13921 simple var. */
13922 tmp = (char *) alloca (len + 1); names[0] = tmp;
13923 bcopy (name, names[0], len + 1);
13924 XFree (name);
13925 }
09c6077f
KH
13926 }
13927 else
13928 try_XLoadQueryFont = 0;
a083fd23
RS
13929
13930 if (font)
13931 XFreeFont (dpy, font);
09c6077f
KH
13932 }
13933
13934 if (!try_XLoadQueryFont)
17d85edc
KH
13935 {
13936 /* We try at least 10 fonts because XListFonts will return
13937 auto-scaled fonts at the head. */
13938 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
13939 &num_fonts);
13940 if (x_had_errors_p (dpy))
13941 {
13942 /* This error is perhaps due to insufficient memory on X
13943 server. Let's just ignore it. */
13944 names = NULL;
13945 x_clear_errors (dpy);
13946 }
13947 }
13948
13949 x_uncatch_errors (dpy, count);
dc43ef94
KH
13950 UNBLOCK_INPUT;
13951
13952 if (names)
13953 {
13954 int i;
dc43ef94
KH
13955
13956 /* Make a list of all the fonts we got back.
13957 Store that in the font cache for the display. */
13958 for (i = 0; i < num_fonts; i++)
13959 {
06a2c219 13960 int width = 0;
dc43ef94 13961 char *p = names[i];
06a2c219
GM
13962 int average_width = -1, dashes = 0;
13963
dc43ef94 13964 /* Count the number of dashes in NAMES[I]. If there are
9c11f79e
GM
13965 14 dashes, and the field value following 12th dash
13966 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
13967 is usually too ugly to be used for editing. Let's
13968 ignore it. */
dc43ef94
KH
13969 while (*p)
13970 if (*p++ == '-')
13971 {
13972 dashes++;
13973 if (dashes == 7) /* PIXEL_SIZE field */
13974 width = atoi (p);
13975 else if (dashes == 12) /* AVERAGE_WIDTH field */
13976 average_width = atoi (p);
13977 }
9c11f79e
GM
13978
13979 if (allow_scalable_fonts_p
13980 || dashes < 14 || average_width != 0)
dc43ef94
KH
13981 {
13982 tem = build_string (names[i]);
13983 if (NILP (Fassoc (tem, list)))
13984 {
13985 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
13986 && ((fast_c_string_match_ignore_case
13987 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
13988 >= 0))
13989 /* We can set the value of PIXEL_SIZE to the
b5210ea7 13990 width of this font. */
dc43ef94
KH
13991 list = Fcons (Fcons (tem, make_number (width)), list);
13992 else
13993 /* For the moment, width is not known. */
13994 list = Fcons (Fcons (tem, Qnil), list);
13995 }
13996 }
13997 }
e38f4136 13998
09c6077f 13999 if (!try_XLoadQueryFont)
e38f4136
GM
14000 {
14001 BLOCK_INPUT;
14002 XFreeFontNames (names);
14003 UNBLOCK_INPUT;
14004 }
dc43ef94
KH
14005 }
14006
b5210ea7 14007 /* Now store the result in the cache. */
f3fbd155
KR
14008 XSETCDR (dpyinfo->name_list_element,
14009 Fcons (Fcons (key, list), XCDR (dpyinfo->name_list_element)));
dc43ef94 14010
b5210ea7
KH
14011 label_cached:
14012 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 14013
b5210ea7
KH
14014 newlist = second_best = Qnil;
14015 /* Make a list of the fonts that have the right width. */
8e713be6 14016 for (; CONSP (list); list = XCDR (list))
b5210ea7 14017 {
536f4067
RS
14018 int found_size;
14019
8e713be6 14020 tem = XCAR (list);
dc43ef94 14021
8e713be6 14022 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
14023 continue;
14024 if (!size)
14025 {
8e713be6 14026 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
14027 continue;
14028 }
dc43ef94 14029
8e713be6 14030 if (!INTEGERP (XCDR (tem)))
dc43ef94 14031 {
b5210ea7 14032 /* Since we have not yet known the size of this font, we
9c11f79e 14033 must try slow function call XLoadQueryFont. */
dc43ef94
KH
14034 XFontStruct *thisinfo;
14035
14036 BLOCK_INPUT;
17d85edc 14037 count = x_catch_errors (dpy);
dc43ef94 14038 thisinfo = XLoadQueryFont (dpy,
8e713be6 14039 XSTRING (XCAR (tem))->data);
17d85edc
KH
14040 if (x_had_errors_p (dpy))
14041 {
14042 /* This error is perhaps due to insufficient memory on X
14043 server. Let's just ignore it. */
14044 thisinfo = NULL;
14045 x_clear_errors (dpy);
14046 }
14047 x_uncatch_errors (dpy, count);
dc43ef94
KH
14048 UNBLOCK_INPUT;
14049
14050 if (thisinfo)
14051 {
f3fbd155
KR
14052 XSETCDR (tem,
14053 (thisinfo->min_bounds.width == 0
14054 ? make_number (0)
14055 : make_number (thisinfo->max_bounds.width)));
e38f4136 14056 BLOCK_INPUT;
dc43ef94 14057 XFreeFont (dpy, thisinfo);
e38f4136 14058 UNBLOCK_INPUT;
dc43ef94
KH
14059 }
14060 else
b5210ea7 14061 /* For unknown reason, the previous call of XListFont had
06a2c219 14062 returned a font which can't be opened. Record the size
b5210ea7 14063 as 0 not to try to open it again. */
f3fbd155 14064 XSETCDR (tem, make_number (0));
dc43ef94 14065 }
536f4067 14066
8e713be6 14067 found_size = XINT (XCDR (tem));
536f4067 14068 if (found_size == size)
8e713be6 14069 newlist = Fcons (XCAR (tem), newlist);
536f4067 14070 else if (found_size > 0)
b5210ea7 14071 {
536f4067 14072 if (NILP (second_best))
b5210ea7 14073 second_best = tem;
536f4067
RS
14074 else if (found_size < size)
14075 {
8e713be6
KR
14076 if (XINT (XCDR (second_best)) > size
14077 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
14078 second_best = tem;
14079 }
14080 else
14081 {
8e713be6
KR
14082 if (XINT (XCDR (second_best)) > size
14083 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
14084 second_best = tem;
14085 }
b5210ea7
KH
14086 }
14087 }
14088 if (!NILP (newlist))
14089 break;
14090 else if (!NILP (second_best))
14091 {
8e713be6 14092 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 14093 break;
dc43ef94 14094 }
dc43ef94
KH
14095 }
14096
14097 return newlist;
14098}
14099
06a2c219
GM
14100
14101#if GLYPH_DEBUG
14102
14103/* Check that FONT is valid on frame F. It is if it can be found in F's
14104 font table. */
14105
14106static void
14107x_check_font (f, font)
14108 struct frame *f;
14109 XFontStruct *font;
14110{
14111 int i;
14112 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14113
14114 xassert (font != NULL);
14115
14116 for (i = 0; i < dpyinfo->n_fonts; i++)
14117 if (dpyinfo->font_table[i].name
14118 && font == dpyinfo->font_table[i].font)
14119 break;
14120
14121 xassert (i < dpyinfo->n_fonts);
14122}
14123
14124#endif /* GLYPH_DEBUG != 0 */
14125
14126/* Set *W to the minimum width, *H to the minimum font height of FONT.
14127 Note: There are (broken) X fonts out there with invalid XFontStruct
14128 min_bounds contents. For example, handa@etl.go.jp reports that
14129 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
14130 have font->min_bounds.width == 0. */
14131
14132static INLINE void
14133x_font_min_bounds (font, w, h)
14134 XFontStruct *font;
14135 int *w, *h;
14136{
14137 *h = FONT_HEIGHT (font);
14138 *w = font->min_bounds.width;
14139
14140 /* Try to handle the case where FONT->min_bounds has invalid
14141 contents. Since the only font known to have invalid min_bounds
14142 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
14143 if (*w <= 0)
14144 *w = font->max_bounds.width;
14145}
14146
14147
14148/* Compute the smallest character width and smallest font height over
14149 all fonts available on frame F. Set the members smallest_char_width
14150 and smallest_font_height in F's x_display_info structure to
14151 the values computed. Value is non-zero if smallest_font_height or
14152 smallest_char_width become smaller than they were before. */
14153
14154static int
14155x_compute_min_glyph_bounds (f)
14156 struct frame *f;
14157{
14158 int i;
14159 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14160 XFontStruct *font;
14161 int old_width = dpyinfo->smallest_char_width;
14162 int old_height = dpyinfo->smallest_font_height;
14163
14164 dpyinfo->smallest_font_height = 100000;
14165 dpyinfo->smallest_char_width = 100000;
14166
14167 for (i = 0; i < dpyinfo->n_fonts; ++i)
14168 if (dpyinfo->font_table[i].name)
14169 {
14170 struct font_info *fontp = dpyinfo->font_table + i;
14171 int w, h;
14172
14173 font = (XFontStruct *) fontp->font;
14174 xassert (font != (XFontStruct *) ~0);
14175 x_font_min_bounds (font, &w, &h);
14176
14177 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
14178 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
14179 }
14180
14181 xassert (dpyinfo->smallest_char_width > 0
14182 && dpyinfo->smallest_font_height > 0);
14183
14184 return (dpyinfo->n_fonts == 1
14185 || dpyinfo->smallest_char_width < old_width
14186 || dpyinfo->smallest_font_height < old_height);
14187}
14188
14189
dc43ef94
KH
14190/* Load font named FONTNAME of the size SIZE for frame F, and return a
14191 pointer to the structure font_info while allocating it dynamically.
14192 If SIZE is 0, load any size of font.
14193 If loading is failed, return NULL. */
14194
14195struct font_info *
14196x_load_font (f, fontname, size)
14197 struct frame *f;
14198 register char *fontname;
14199 int size;
14200{
14201 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14202 Lisp_Object font_names;
d645aaa4 14203 int count;
dc43ef94
KH
14204
14205 /* Get a list of all the fonts that match this name. Once we
14206 have a list of matching fonts, we compare them against the fonts
14207 we already have by comparing names. */
09c6077f 14208 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
14209
14210 if (!NILP (font_names))
14211 {
14212 Lisp_Object tail;
14213 int i;
14214
14215 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 14216 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
14217 if (dpyinfo->font_table[i].name
14218 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 14219 XSTRING (XCAR (tail))->data)
06a2c219 14220 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 14221 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
14222 return (dpyinfo->font_table + i);
14223 }
14224
14225 /* Load the font and add it to the table. */
14226 {
14227 char *full_name;
14228 XFontStruct *font;
14229 struct font_info *fontp;
14230 unsigned long value;
06a2c219 14231 int i;
dc43ef94 14232
2da424f1
KH
14233 /* If we have found fonts by x_list_font, load one of them. If
14234 not, we still try to load a font by the name given as FONTNAME
14235 because XListFonts (called in x_list_font) of some X server has
14236 a bug of not finding a font even if the font surely exists and
14237 is loadable by XLoadQueryFont. */
e1d6d5b9 14238 if (size > 0 && !NILP (font_names))
8e713be6 14239 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
14240
14241 BLOCK_INPUT;
d645aaa4 14242 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 14243 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
14244 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
14245 {
14246 /* This error is perhaps due to insufficient memory on X
14247 server. Let's just ignore it. */
14248 font = NULL;
14249 x_clear_errors (FRAME_X_DISPLAY (f));
14250 }
14251 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 14252 UNBLOCK_INPUT;
b5210ea7 14253 if (!font)
dc43ef94
KH
14254 return NULL;
14255
06a2c219
GM
14256 /* Find a free slot in the font table. */
14257 for (i = 0; i < dpyinfo->n_fonts; ++i)
14258 if (dpyinfo->font_table[i].name == NULL)
14259 break;
14260
14261 /* If no free slot found, maybe enlarge the font table. */
14262 if (i == dpyinfo->n_fonts
14263 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 14264 {
06a2c219
GM
14265 int sz;
14266 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
14267 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 14268 dpyinfo->font_table
06a2c219 14269 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
14270 }
14271
06a2c219
GM
14272 fontp = dpyinfo->font_table + i;
14273 if (i == dpyinfo->n_fonts)
14274 ++dpyinfo->n_fonts;
dc43ef94
KH
14275
14276 /* Now fill in the slots of *FONTP. */
14277 BLOCK_INPUT;
14278 fontp->font = font;
06a2c219 14279 fontp->font_idx = i;
dc43ef94
KH
14280 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
14281 bcopy (fontname, fontp->name, strlen (fontname) + 1);
14282
14283 /* Try to get the full name of FONT. Put it in FULL_NAME. */
14284 full_name = 0;
14285 if (XGetFontProperty (font, XA_FONT, &value))
14286 {
14287 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
14288 char *p = name;
14289 int dashes = 0;
14290
14291 /* Count the number of dashes in the "full name".
14292 If it is too few, this isn't really the font's full name,
14293 so don't use it.
14294 In X11R4, the fonts did not come with their canonical names
14295 stored in them. */
14296 while (*p)
14297 {
14298 if (*p == '-')
14299 dashes++;
14300 p++;
14301 }
14302
14303 if (dashes >= 13)
14304 {
14305 full_name = (char *) xmalloc (p - name + 1);
14306 bcopy (name, full_name, p - name + 1);
14307 }
14308
14309 XFree (name);
14310 }
14311
14312 if (full_name != 0)
14313 fontp->full_name = full_name;
14314 else
14315 fontp->full_name = fontp->name;
14316
14317 fontp->size = font->max_bounds.width;
d5749adb 14318 fontp->height = FONT_HEIGHT (font);
dc43ef94 14319
2da424f1
KH
14320 if (NILP (font_names))
14321 {
14322 /* We come here because of a bug of XListFonts mentioned at
14323 the head of this block. Let's store this information in
14324 the cache for x_list_fonts. */
14325 Lisp_Object lispy_name = build_string (fontname);
14326 Lisp_Object lispy_full_name = build_string (fontp->full_name);
9c11f79e
GM
14327 Lisp_Object key = Fcons (Fcons (lispy_name, make_number (256)),
14328 Qnil);
2da424f1 14329
f3fbd155
KR
14330 XSETCDR (dpyinfo->name_list_element,
14331 Fcons (Fcons (key,
14332 Fcons (Fcons (lispy_full_name,
14333 make_number (fontp->size)),
14334 Qnil)),
14335 XCDR (dpyinfo->name_list_element)));
2da424f1 14336 if (full_name)
9c11f79e
GM
14337 {
14338 key = Fcons (Fcons (lispy_full_name, make_number (256)),
14339 Qnil);
f3fbd155
KR
14340 XSETCDR (dpyinfo->name_list_element,
14341 Fcons (Fcons (key,
14342 Fcons (Fcons (lispy_full_name,
14343 make_number (fontp->size)),
14344 Qnil)),
14345 XCDR (dpyinfo->name_list_element)));
9c11f79e 14346 }
2da424f1
KH
14347 }
14348
dc43ef94
KH
14349 /* The slot `encoding' specifies how to map a character
14350 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
14351 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
14352 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 14353 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 14354 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
14355 which is never used by any charset. If mapping can't be
14356 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
14357 fontp->encoding[1]
14358 = (font->max_byte1 == 0
14359 /* 1-byte font */
14360 ? (font->min_char_or_byte2 < 0x80
14361 ? (font->max_char_or_byte2 < 0x80
14362 ? 0 /* 0x20..0x7F */
8ff102bd 14363 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
14364 : 1) /* 0xA0..0xFF */
14365 /* 2-byte font */
14366 : (font->min_byte1 < 0x80
14367 ? (font->max_byte1 < 0x80
14368 ? (font->min_char_or_byte2 < 0x80
14369 ? (font->max_char_or_byte2 < 0x80
14370 ? 0 /* 0x2020..0x7F7F */
8ff102bd 14371 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 14372 : 3) /* 0x20A0..0x7FFF */
8ff102bd 14373 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
14374 : (font->min_char_or_byte2 < 0x80
14375 ? (font->max_char_or_byte2 < 0x80
14376 ? 2 /* 0xA020..0xFF7F */
8ff102bd 14377 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
14378 : 1))); /* 0xA0A0..0xFFFF */
14379
14380 fontp->baseline_offset
14381 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
14382 ? (long) value : 0);
14383 fontp->relative_compose
14384 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
14385 ? (long) value : 0);
f78798df
KH
14386 fontp->default_ascent
14387 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
14388 ? (long) value : 0);
dc43ef94 14389
06a2c219
GM
14390 /* Set global flag fonts_changed_p to non-zero if the font loaded
14391 has a character with a smaller width than any other character
437dfb9f 14392 before, or if the font loaded has a smaller height than any
06a2c219
GM
14393 other font loaded before. If this happens, it will make a
14394 glyph matrix reallocation necessary. */
437dfb9f 14395 fonts_changed_p |= x_compute_min_glyph_bounds (f);
dc43ef94 14396 UNBLOCK_INPUT;
dc43ef94
KH
14397 return fontp;
14398 }
14399}
14400
06a2c219
GM
14401
14402/* Return a pointer to struct font_info of a font named FONTNAME for
14403 frame F. If no such font is loaded, return NULL. */
14404
dc43ef94
KH
14405struct font_info *
14406x_query_font (f, fontname)
14407 struct frame *f;
14408 register char *fontname;
14409{
14410 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14411 int i;
14412
14413 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
14414 if (dpyinfo->font_table[i].name
14415 && (!strcmp (dpyinfo->font_table[i].name, fontname)
14416 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
14417 return (dpyinfo->font_table + i);
14418 return NULL;
14419}
14420
06a2c219
GM
14421
14422/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
14423 `encoder' of the structure. */
14424
14425void
14426x_find_ccl_program (fontp)
14427 struct font_info *fontp;
14428{
a42f54e6 14429 Lisp_Object list, elt;
a6582676 14430
f9b5db02 14431 elt = Qnil;
8e713be6 14432 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 14433 {
8e713be6 14434 elt = XCAR (list);
a6582676 14435 if (CONSP (elt)
8e713be6 14436 && STRINGP (XCAR (elt))
9f2feff6
KH
14437 && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
14438 >= 0)
14439 || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
14440 >= 0)))
a42f54e6
KH
14441 break;
14442 }
f9b5db02 14443
a42f54e6
KH
14444 if (! NILP (list))
14445 {
d27f8ca7
KH
14446 struct ccl_program *ccl
14447 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 14448
8e713be6 14449 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
14450 xfree (ccl);
14451 else
14452 fontp->font_encoder = ccl;
a6582676
KH
14453 }
14454}
14455
06a2c219 14456
dc43ef94 14457\f
06a2c219
GM
14458/***********************************************************************
14459 Initialization
14460 ***********************************************************************/
f451eb13 14461
3afe33e7
RS
14462#ifdef USE_X_TOOLKIT
14463static XrmOptionDescRec emacs_options[] = {
14464 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
14465 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
14466
14467 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
14468 XrmoptionSepArg, NULL},
14469 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
14470
14471 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14472 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14473 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14474 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14475 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14476 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
14477 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
14478};
14479#endif /* USE_X_TOOLKIT */
14480
7a13e894
RS
14481static int x_initialized;
14482
29b38361
KH
14483#ifdef MULTI_KBOARD
14484/* Test whether two display-name strings agree up to the dot that separates
14485 the screen number from the server number. */
14486static int
14487same_x_server (name1, name2)
14488 char *name1, *name2;
14489{
14490 int seen_colon = 0;
cf591cc1
RS
14491 unsigned char *system_name = XSTRING (Vsystem_name)->data;
14492 int system_name_length = strlen (system_name);
14493 int length_until_period = 0;
14494
14495 while (system_name[length_until_period] != 0
14496 && system_name[length_until_period] != '.')
14497 length_until_period++;
14498
14499 /* Treat `unix' like an empty host name. */
14500 if (! strncmp (name1, "unix:", 5))
14501 name1 += 4;
14502 if (! strncmp (name2, "unix:", 5))
14503 name2 += 4;
14504 /* Treat this host's name like an empty host name. */
14505 if (! strncmp (name1, system_name, system_name_length)
14506 && name1[system_name_length] == ':')
14507 name1 += system_name_length;
14508 if (! strncmp (name2, system_name, system_name_length)
14509 && name2[system_name_length] == ':')
14510 name2 += system_name_length;
14511 /* Treat this host's domainless name like an empty host name. */
14512 if (! strncmp (name1, system_name, length_until_period)
14513 && name1[length_until_period] == ':')
14514 name1 += length_until_period;
14515 if (! strncmp (name2, system_name, length_until_period)
14516 && name2[length_until_period] == ':')
14517 name2 += length_until_period;
14518
29b38361
KH
14519 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
14520 {
14521 if (*name1 == ':')
14522 seen_colon++;
14523 if (seen_colon && *name1 == '.')
14524 return 1;
14525 }
14526 return (seen_colon
14527 && (*name1 == '.' || *name1 == '\0')
14528 && (*name2 == '.' || *name2 == '\0'));
14529}
14530#endif
14531
334208b7 14532struct x_display_info *
1f8255f2 14533x_term_init (display_name, xrm_option, resource_name)
334208b7 14534 Lisp_Object display_name;
1f8255f2
RS
14535 char *xrm_option;
14536 char *resource_name;
dc6f92b8 14537{
334208b7 14538 int connection;
7a13e894 14539 Display *dpy;
334208b7
RS
14540 struct x_display_info *dpyinfo;
14541 XrmDatabase xrdb;
14542
60439948
KH
14543 BLOCK_INPUT;
14544
7a13e894
RS
14545 if (!x_initialized)
14546 {
14547 x_initialize ();
14548 x_initialized = 1;
14549 }
dc6f92b8 14550
3afe33e7 14551#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
14552 /* weiner@footloose.sps.mot.com reports that this causes
14553 errors with X11R5:
14554 X protocol error: BadAtom (invalid Atom parameter)
14555 on protocol request 18skiloaf.
14556 So let's not use it until R6. */
14557#ifdef HAVE_X11XTR6
bdcd49ba
RS
14558 XtSetLanguageProc (NULL, NULL, NULL);
14559#endif
14560
7f9c7f94
RS
14561 {
14562 int argc = 0;
14563 char *argv[3];
14564
14565 argv[0] = "";
14566 argc = 1;
14567 if (xrm_option)
14568 {
14569 argv[argc++] = "-xrm";
14570 argv[argc++] = xrm_option;
14571 }
14572 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
14573 resource_name, EMACS_CLASS,
14574 emacs_options, XtNumber (emacs_options),
14575 &argc, argv);
39d8bb4d
KH
14576
14577#ifdef HAVE_X11XTR6
10537cb1 14578 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 14579 fixup_locale ();
39d8bb4d 14580#endif
7f9c7f94 14581 }
3afe33e7
RS
14582
14583#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
14584#ifdef HAVE_X11R5
14585 XSetLocaleModifiers ("");
14586#endif
7a13e894 14587 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 14588#endif /* not USE_X_TOOLKIT */
334208b7 14589
7a13e894
RS
14590 /* Detect failure. */
14591 if (dpy == 0)
60439948
KH
14592 {
14593 UNBLOCK_INPUT;
14594 return 0;
14595 }
7a13e894
RS
14596
14597 /* We have definitely succeeded. Record the new connection. */
14598
14599 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
f04e1297 14600 bzero (dpyinfo, sizeof *dpyinfo);
7a13e894 14601
29b38361
KH
14602#ifdef MULTI_KBOARD
14603 {
14604 struct x_display_info *share;
14605 Lisp_Object tail;
14606
14607 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
14608 share = share->next, tail = XCDR (tail))
14609 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
14610 XSTRING (display_name)->data))
14611 break;
14612 if (share)
14613 dpyinfo->kboard = share->kboard;
14614 else
14615 {
14616 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
14617 init_kboard (dpyinfo->kboard);
59e755be
KH
14618 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
14619 {
14620 char *vendor = ServerVendor (dpy);
9b6ed9f3 14621 UNBLOCK_INPUT;
59e755be
KH
14622 dpyinfo->kboard->Vsystem_key_alist
14623 = call1 (Qvendor_specific_keysyms,
14624 build_string (vendor ? vendor : ""));
9b6ed9f3 14625 BLOCK_INPUT;
59e755be
KH
14626 }
14627
29b38361
KH
14628 dpyinfo->kboard->next_kboard = all_kboards;
14629 all_kboards = dpyinfo->kboard;
0ad5446c
KH
14630 /* Don't let the initial kboard remain current longer than necessary.
14631 That would cause problems if a file loaded on startup tries to
06a2c219 14632 prompt in the mini-buffer. */
0ad5446c
KH
14633 if (current_kboard == initial_kboard)
14634 current_kboard = dpyinfo->kboard;
29b38361
KH
14635 }
14636 dpyinfo->kboard->reference_count++;
14637 }
b9737ad3
KH
14638#endif
14639
7a13e894
RS
14640 /* Put this display on the chain. */
14641 dpyinfo->next = x_display_list;
14642 x_display_list = dpyinfo;
14643
14644 /* Put it on x_display_name_list as well, to keep them parallel. */
14645 x_display_name_list = Fcons (Fcons (display_name, Qnil),
14646 x_display_name_list);
8e713be6 14647 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
14648
14649 dpyinfo->display = dpy;
dc6f92b8 14650
dc6f92b8 14651#if 0
7a13e894 14652 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 14653#endif /* ! 0 */
7a13e894
RS
14654
14655 dpyinfo->x_id_name
fc932ac6
RS
14656 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
14657 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
14658 + 2);
14659 sprintf (dpyinfo->x_id_name, "%s@%s",
14660 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
14661
14662 /* Figure out which modifier bits mean what. */
334208b7 14663 x_find_modifier_meanings (dpyinfo);
f451eb13 14664
ab648270 14665 /* Get the scroll bar cursor. */
7a13e894 14666 dpyinfo->vertical_scroll_bar_cursor
334208b7 14667 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 14668
334208b7
RS
14669 xrdb = x_load_resources (dpyinfo->display, xrm_option,
14670 resource_name, EMACS_CLASS);
14671#ifdef HAVE_XRMSETDATABASE
14672 XrmSetDatabase (dpyinfo->display, xrdb);
14673#else
14674 dpyinfo->display->db = xrdb;
14675#endif
547d9db8 14676 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
14677 all versions. */
14678 dpyinfo->xrdb = xrdb;
334208b7
RS
14679
14680 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
14681 DefaultScreen (dpyinfo->display));
5ff67d81 14682 select_visual (dpyinfo);
43bd1b2b 14683 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
14684 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
14685 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
14686 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
14687 dpyinfo->grabbed = 0;
14688 dpyinfo->reference_count = 0;
14689 dpyinfo->icon_bitmap_id = -1;
06a2c219 14690 dpyinfo->font_table = NULL;
7a13e894
RS
14691 dpyinfo->n_fonts = 0;
14692 dpyinfo->font_table_size = 0;
14693 dpyinfo->bitmaps = 0;
14694 dpyinfo->bitmaps_size = 0;
14695 dpyinfo->bitmaps_last = 0;
14696 dpyinfo->scratch_cursor_gc = 0;
14697 dpyinfo->mouse_face_mouse_frame = 0;
14698 dpyinfo->mouse_face_deferred_gc = 0;
14699 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
14700 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 14701 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894 14702 dpyinfo->mouse_face_window = Qnil;
0a61c667 14703 dpyinfo->mouse_face_overlay = Qnil;
7a13e894
RS
14704 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
14705 dpyinfo->mouse_face_defer = 0;
66301061 14706 dpyinfo->mouse_face_hidden = 0;
0f941935
KH
14707 dpyinfo->x_focus_frame = 0;
14708 dpyinfo->x_focus_event_frame = 0;
14709 dpyinfo->x_highlight_frame = 0;
06a2c219 14710 dpyinfo->image_cache = make_image_cache ();
334208b7 14711
43bd1b2b 14712 /* See if a private colormap is requested. */
5ff67d81
GM
14713 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
14714 {
14715 if (dpyinfo->visual->class == PseudoColor)
14716 {
14717 Lisp_Object value;
14718 value = display_x_get_resource (dpyinfo,
14719 build_string ("privateColormap"),
14720 build_string ("PrivateColormap"),
14721 Qnil, Qnil);
14722 if (STRINGP (value)
14723 && (!strcmp (XSTRING (value)->data, "true")
14724 || !strcmp (XSTRING (value)->data, "on")))
14725 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
14726 }
43bd1b2b 14727 }
5ff67d81
GM
14728 else
14729 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
14730 dpyinfo->visual, AllocNone);
43bd1b2b 14731
06a2c219
GM
14732 {
14733 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
14734 double pixels = DisplayHeight (dpyinfo->display, screen_number);
14735 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
14736 dpyinfo->resy = pixels * 25.4 / mm;
14737 pixels = DisplayWidth (dpyinfo->display, screen_number);
14738 mm = DisplayWidthMM (dpyinfo->display, screen_number);
14739 dpyinfo->resx = pixels * 25.4 / mm;
14740 }
14741
334208b7
RS
14742 dpyinfo->Xatom_wm_protocols
14743 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
14744 dpyinfo->Xatom_wm_take_focus
14745 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
14746 dpyinfo->Xatom_wm_save_yourself
14747 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
14748 dpyinfo->Xatom_wm_delete_window
14749 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
14750 dpyinfo->Xatom_wm_change_state
14751 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
14752 dpyinfo->Xatom_wm_configure_denied
14753 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
14754 dpyinfo->Xatom_wm_window_moved
14755 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
14756 dpyinfo->Xatom_editres
14757 = XInternAtom (dpyinfo->display, "Editres", False);
14758 dpyinfo->Xatom_CLIPBOARD
14759 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
14760 dpyinfo->Xatom_TIMESTAMP
14761 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
14762 dpyinfo->Xatom_TEXT
14763 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
14764 dpyinfo->Xatom_COMPOUND_TEXT
14765 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
14766 dpyinfo->Xatom_DELETE
14767 = XInternAtom (dpyinfo->display, "DELETE", False);
14768 dpyinfo->Xatom_MULTIPLE
14769 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
14770 dpyinfo->Xatom_INCR
14771 = XInternAtom (dpyinfo->display, "INCR", False);
14772 dpyinfo->Xatom_EMACS_TMP
14773 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
14774 dpyinfo->Xatom_TARGETS
14775 = XInternAtom (dpyinfo->display, "TARGETS", False);
14776 dpyinfo->Xatom_NULL
14777 = XInternAtom (dpyinfo->display, "NULL", False);
14778 dpyinfo->Xatom_ATOM_PAIR
14779 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
14780 /* For properties of font. */
14781 dpyinfo->Xatom_PIXEL_SIZE
14782 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
14783 dpyinfo->Xatom_MULE_BASELINE_OFFSET
14784 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
14785 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
14786 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
14787 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
14788 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 14789
06a2c219
GM
14790 /* Ghostscript support. */
14791 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
14792 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
14793
14794 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
14795 False);
14796
547d9db8
KH
14797 dpyinfo->cut_buffers_initialized = 0;
14798
334208b7
RS
14799 connection = ConnectionNumber (dpyinfo->display);
14800 dpyinfo->connection = connection;
14801
dc43ef94 14802 {
5d7cc324
RS
14803 char null_bits[1];
14804
14805 null_bits[0] = 0x00;
dc43ef94
KH
14806
14807 dpyinfo->null_pixel
14808 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14809 null_bits, 1, 1, (long) 0, (long) 0,
14810 1);
14811 }
14812
06a2c219
GM
14813 {
14814 extern int gray_bitmap_width, gray_bitmap_height;
10659c77 14815 extern char *gray_bitmap_bits;
06a2c219
GM
14816 dpyinfo->gray
14817 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14818 gray_bitmap_bits,
14819 gray_bitmap_width, gray_bitmap_height,
14820 (unsigned long) 1, (unsigned long) 0, 1);
14821 }
14822
f5d11644
GM
14823#ifdef HAVE_X_I18N
14824 xim_initialize (dpyinfo, resource_name);
14825#endif
14826
87485d6f
MW
14827#ifdef subprocesses
14828 /* This is only needed for distinguishing keyboard and process input. */
334208b7 14829 if (connection != 0)
7a13e894 14830 add_keyboard_wait_descriptor (connection);
87485d6f 14831#endif
6d4238f3 14832
041b69ac 14833#ifndef F_SETOWN_BUG
dc6f92b8 14834#ifdef F_SETOWN
dc6f92b8 14835#ifdef F_SETOWN_SOCK_NEG
61c3ce62 14836 /* stdin is a socket here */
334208b7 14837 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 14838#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 14839 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
14840#endif /* ! defined (F_SETOWN_SOCK_NEG) */
14841#endif /* ! defined (F_SETOWN) */
041b69ac 14842#endif /* F_SETOWN_BUG */
dc6f92b8
JB
14843
14844#ifdef SIGIO
eee20f6a
KH
14845 if (interrupt_input)
14846 init_sigio (connection);
c118dd06 14847#endif /* ! defined (SIGIO) */
dc6f92b8 14848
51b592fb 14849#ifdef USE_LUCID
f8c39f51 14850#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
14851 /* Make sure that we have a valid font for dialog boxes
14852 so that Xt does not crash. */
14853 {
14854 Display *dpy = dpyinfo->display;
14855 XrmValue d, fr, to;
14856 Font font;
e99db5a1 14857 int count;
51b592fb
RS
14858
14859 d.addr = (XPointer)&dpy;
14860 d.size = sizeof (Display *);
14861 fr.addr = XtDefaultFont;
14862 fr.size = sizeof (XtDefaultFont);
14863 to.size = sizeof (Font *);
14864 to.addr = (XPointer)&font;
e99db5a1 14865 count = x_catch_errors (dpy);
51b592fb
RS
14866 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
14867 abort ();
14868 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
14869 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 14870 x_uncatch_errors (dpy, count);
51b592fb
RS
14871 }
14872#endif
f8c39f51 14873#endif
51b592fb 14874
34e23e5a
GM
14875 /* See if we should run in synchronous mode. This is useful
14876 for debugging X code. */
14877 {
14878 Lisp_Object value;
14879 value = display_x_get_resource (dpyinfo,
14880 build_string ("synchronous"),
14881 build_string ("Synchronous"),
14882 Qnil, Qnil);
14883 if (STRINGP (value)
14884 && (!strcmp (XSTRING (value)->data, "true")
14885 || !strcmp (XSTRING (value)->data, "on")))
14886 XSynchronize (dpyinfo->display, True);
14887 }
14888
60439948
KH
14889 UNBLOCK_INPUT;
14890
7a13e894
RS
14891 return dpyinfo;
14892}
14893\f
14894/* Get rid of display DPYINFO, assuming all frames are already gone,
14895 and without sending any more commands to the X server. */
dc6f92b8 14896
7a13e894
RS
14897void
14898x_delete_display (dpyinfo)
14899 struct x_display_info *dpyinfo;
14900{
14901 delete_keyboard_wait_descriptor (dpyinfo->connection);
14902
14903 /* Discard this display from x_display_name_list and x_display_list.
14904 We can't use Fdelq because that can quit. */
14905 if (! NILP (x_display_name_list)
8e713be6
KR
14906 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
14907 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
14908 else
14909 {
14910 Lisp_Object tail;
14911
14912 tail = x_display_name_list;
8e713be6 14913 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 14914 {
bffcfca9 14915 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 14916 {
f3fbd155 14917 XSETCDR (tail, XCDR (XCDR (tail)));
7a13e894
RS
14918 break;
14919 }
8e713be6 14920 tail = XCDR (tail);
7a13e894
RS
14921 }
14922 }
14923
9bda743f
GM
14924 if (next_noop_dpyinfo == dpyinfo)
14925 next_noop_dpyinfo = dpyinfo->next;
14926
7a13e894
RS
14927 if (x_display_list == dpyinfo)
14928 x_display_list = dpyinfo->next;
7f9c7f94
RS
14929 else
14930 {
14931 struct x_display_info *tail;
7a13e894 14932
7f9c7f94
RS
14933 for (tail = x_display_list; tail; tail = tail->next)
14934 if (tail->next == dpyinfo)
14935 tail->next = tail->next->next;
14936 }
7a13e894 14937
0d777288
RS
14938#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
14939#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
14940 XrmDestroyDatabase (dpyinfo->xrdb);
14941#endif
0d777288 14942#endif
29b38361
KH
14943#ifdef MULTI_KBOARD
14944 if (--dpyinfo->kboard->reference_count == 0)
39f79001 14945 delete_kboard (dpyinfo->kboard);
b9737ad3 14946#endif
f5d11644
GM
14947#ifdef HAVE_X_I18N
14948 if (dpyinfo->xim)
14949 xim_close_dpy (dpyinfo);
14950#endif
14951
b9737ad3
KH
14952 xfree (dpyinfo->font_table);
14953 xfree (dpyinfo->x_id_name);
f04e1297 14954 xfree (dpyinfo->color_cells);
b9737ad3 14955 xfree (dpyinfo);
7a13e894 14956}
f04e1297 14957
7a13e894
RS
14958\f
14959/* Set up use of X before we make the first connection. */
14960
06a2c219
GM
14961static struct redisplay_interface x_redisplay_interface =
14962{
14963 x_produce_glyphs,
14964 x_write_glyphs,
14965 x_insert_glyphs,
14966 x_clear_end_of_line,
14967 x_scroll_run,
14968 x_after_update_window_line,
14969 x_update_window_begin,
14970 x_update_window_end,
14971 XTcursor_to,
14972 x_flush,
71b8321e 14973 x_clear_mouse_face,
66ac4b0e
GM
14974 x_get_glyph_overhangs,
14975 x_fix_overlapping_area
06a2c219
GM
14976};
14977
dfcf069d 14978void
7a13e894
RS
14979x_initialize ()
14980{
06a2c219
GM
14981 rif = &x_redisplay_interface;
14982
14983 clear_frame_hook = x_clear_frame;
14984 ins_del_lines_hook = x_ins_del_lines;
06a2c219 14985 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
14986 ring_bell_hook = XTring_bell;
14987 reset_terminal_modes_hook = XTreset_terminal_modes;
14988 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
14989 update_begin_hook = x_update_begin;
14990 update_end_hook = x_update_end;
dc6f92b8
JB
14991 set_terminal_window_hook = XTset_terminal_window;
14992 read_socket_hook = XTread_socket;
b8009dd1 14993 frame_up_to_date_hook = XTframe_up_to_date;
90e65f07 14994 mouse_position_hook = XTmouse_position;
f451eb13 14995 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 14996 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
14997 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
14998 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
14999 redeem_scroll_bar_hook = XTredeem_scroll_bar;
15000 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 15001 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 15002
f676886a 15003 scroll_region_ok = 1; /* we'll scroll partial frames */
9017309f 15004 char_ins_del_ok = 1;
dc6f92b8
JB
15005 line_ins_del_ok = 1; /* we'll just blt 'em */
15006 fast_clear_end_of_line = 1; /* X does this well */
58769bee 15007 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
15008 off the bottom */
15009 baud_rate = 19200;
15010
7a13e894 15011 x_noop_count = 0;
9ea173e8 15012 last_tool_bar_item = -1;
06a2c219
GM
15013 any_help_event_p = 0;
15014
b30b24cb
RS
15015 /* Try to use interrupt input; if we can't, then start polling. */
15016 Fset_input_mode (Qt, Qnil, Qt, Qnil);
15017
7f9c7f94
RS
15018#ifdef USE_X_TOOLKIT
15019 XtToolkitInitialize ();
651f03b6 15020
7f9c7f94 15021 Xt_app_con = XtCreateApplicationContext ();
651f03b6
GM
15022
15023 /* Register a converter from strings to pixels, which uses
15024 Emacs' color allocation infrastructure. */
15025 XtAppSetTypeConverter (Xt_app_con,
15026 XtRString, XtRPixel, cvt_string_to_pixel,
15027 cvt_string_to_pixel_args,
15028 XtNumber (cvt_string_to_pixel_args),
15029 XtCacheByDisplay, cvt_pixel_dtor);
15030
665881ad 15031 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
15032
15033 /* Install an asynchronous timer that processes Xt timeout events
15034 every 0.1s. This is necessary because some widget sets use
15035 timeouts internally, for example the LessTif menu bar, or the
15036 Xaw3d scroll bar. When Xt timouts aren't processed, these
15037 widgets don't behave normally. */
15038 {
15039 EMACS_TIME interval;
15040 EMACS_SET_SECS_USECS (interval, 0, 100000);
15041 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
15042 }
db74249b 15043#endif
bffcfca9 15044
eccc05db 15045#ifdef USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
15046 xaw3d_arrow_scroll = False;
15047 xaw3d_pick_top = True;
7f9c7f94
RS
15048#endif
15049
58769bee 15050 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 15051 original error handler. */
e99db5a1 15052 XSetErrorHandler (x_error_handler);
334208b7 15053 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 15054
06a2c219 15055 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
15056#ifdef SIGWINCH
15057 signal (SIGWINCH, SIG_DFL);
c118dd06 15058#endif /* ! defined (SIGWINCH) */
dc6f92b8 15059
92e2441b 15060 signal (SIGPIPE, x_connection_signal);
5f30b957
JD
15061
15062#ifdef HAVE_X_SM
15063 x_session_initialize ();
15064#endif
dc6f92b8 15065}
55123275 15066
06a2c219 15067
55123275
JB
15068void
15069syms_of_xterm ()
15070{
e99db5a1
RS
15071 staticpro (&x_error_message_string);
15072 x_error_message_string = Qnil;
15073
7a13e894
RS
15074 staticpro (&x_display_name_list);
15075 x_display_name_list = Qnil;
334208b7 15076
ab648270 15077 staticpro (&last_mouse_scroll_bar);
e53cb100 15078 last_mouse_scroll_bar = Qnil;
59e755be
KH
15079
15080 staticpro (&Qvendor_specific_keysyms);
15081 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
15082
15083 staticpro (&last_mouse_press_frame);
15084 last_mouse_press_frame = Qnil;
06a2c219 15085
06a2c219 15086 help_echo = Qnil;
be010514
GM
15087 staticpro (&help_echo);
15088 help_echo_object = Qnil;
15089 staticpro (&help_echo_object);
7cea38bc
GM
15090 help_echo_window = Qnil;
15091 staticpro (&help_echo_window);
06a2c219 15092 previous_help_echo = Qnil;
be010514
GM
15093 staticpro (&previous_help_echo);
15094 help_echo_pos = -1;
06a2c219 15095
ee8ceff8 15096 DEFVAR_BOOL ("mouse-autoselect-window", &mouse_autoselect_window,
503e457e 15097 doc: /* *Non-nil means autoselect window with mouse pointer. */);
ee8ceff8 15098 mouse_autoselect_window = 0;
503e457e 15099
7ee72033
MB
15100 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
15101 doc: /* *Non-nil means draw block cursor as wide as the glyph under it.
228299fa
GM
15102For example, if a block cursor is over a tab, it will be drawn as
15103wide as that tab on the display. */);
06a2c219
GM
15104 x_stretch_cursor_p = 0;
15105
a72d5ce5 15106 DEFVAR_BOOL ("x-use-underline-position-properties",
7ee72033
MB
15107 &x_use_underline_position_properties,
15108 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
f0529b5b 15109nil means ignore them. If you encounter fonts with bogus
228299fa
GM
15110UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
15111to 4.1, set this to nil. */);
a72d5ce5
GM
15112 x_use_underline_position_properties = 1;
15113
7ee72033
MB
15114 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
15115 doc: /* What X toolkit scroll bars Emacs uses.
228299fa
GM
15116A value of nil means Emacs doesn't use X toolkit scroll bars.
15117Otherwise, value is a symbol describing the X toolkit. */);
eccc05db 15118#ifdef USE_TOOLKIT_SCROLL_BARS
5bf04520
GM
15119#ifdef USE_MOTIF
15120 Vx_toolkit_scroll_bars = intern ("motif");
15121#elif defined HAVE_XAW3D
15122 Vx_toolkit_scroll_bars = intern ("xaw3d");
15123#else
15124 Vx_toolkit_scroll_bars = intern ("xaw");
15125#endif
06a2c219 15126#else
5bf04520 15127 Vx_toolkit_scroll_bars = Qnil;
06a2c219
GM
15128#endif
15129
06a2c219
GM
15130 staticpro (&last_mouse_motion_frame);
15131 last_mouse_motion_frame = Qnil;
98659da6
KG
15132
15133 Qmodifier_value = intern ("modifier-value");
15134 Qalt = intern ("alt");
15135 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
15136 Qhyper = intern ("hyper");
15137 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
15138 Qmeta = intern ("meta");
15139 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
15140 Qsuper = intern ("super");
15141 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
15142
15143 DEFVAR_LISP ("x-alt-keysym", &Vx_alt_keysym,
15144 doc: /* Which keys Emacs uses for the alt modifier.
15145This should be one of the symbols `alt', `hyper', `meta', `super'.
15146For example, `alt' means use the Alt_L and Alt_R keysyms. The default
15147is nil, which is the same as `alt'. */);
15148 Vx_alt_keysym = Qnil;
15149
15150 DEFVAR_LISP ("x-hyper-keysym", &Vx_hyper_keysym,
15151 doc: /* Which keys Emacs uses for the hyper modifier.
15152This should be one of the symbols `alt', `hyper', `meta', `super'.
15153For example, `hyper' means use the Hyper_L and Hyper_R keysyms. The
15154default is nil, which is the same as `hyper'. */);
15155 Vx_hyper_keysym = Qnil;
15156
15157 DEFVAR_LISP ("x-meta-keysym", &Vx_meta_keysym,
15158 doc: /* Which keys Emacs uses for the meta modifier.
15159This should be one of the symbols `alt', `hyper', `meta', `super'.
15160For example, `meta' means use the Meta_L and Meta_R keysyms. The
15161default is nil, which is the same as `meta'. */);
15162 Vx_meta_keysym = Qnil;
15163
15164 DEFVAR_LISP ("x-super-keysym", &Vx_super_keysym,
15165 doc: /* Which keys Emacs uses for the super modifier.
15166This should be one of the symbols `alt', `hyper', `meta', `super'.
15167For example, `super' means use the Super_L and Super_R keysyms. The
15168default is nil, which is the same as `super'. */);
15169 Vx_super_keysym = Qnil;
15170
55123275 15171}
6cf0ae86 15172
1d6c120a 15173#endif /* HAVE_X_WINDOWS */