(CHECK_FRAME, CHECK_LIVE_FRAME): Remove unused argument `i' in macros.
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
edf36fe6 2 Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001
06a2c219 3 Free Software Foundation, Inc.
dc6f92b8
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
4746118a 9the Free Software Foundation; either version 2, or (at your option)
dc6f92b8
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
dc6f92b8 21
06a2c219 22/* New display code by Gerd Moellmann <gerd@gnu.org>. */
3afe33e7
RS
23/* Xt features made by Fred Pierresteguy. */
24
68c45bf0
PE
25#include <config.h>
26
039440c4 27/* On 4.3 these lose if they come after xterm.h. */
039440c4 28/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
29#include <signal.h>
30
4846819e
RS
31#include <stdio.h>
32
dc6f92b8
JB
33#ifdef HAVE_X_WINDOWS
34
35#include "lisp.h"
9ac0d9e0 36#include "blockinput.h"
dc6f92b8 37
ae79c227
AS
38/* Need syssignal.h for various externs and definitions that may be required
39 by some configurations for calls to signal later in this source file. */
40#include "syssignal.h"
41
dc6f92b8
JB
42/* This may include sys/types.h, and that somehow loses
43 if this is not done before the other system files. */
44#include "xterm.h"
f451eb13 45#include <X11/cursorfont.h>
dc6f92b8
JB
46
47/* Load sys/types.h if not already loaded.
48 In some systems loading it twice is suicidal. */
49#ifndef makedev
50#include <sys/types.h>
c118dd06 51#endif /* makedev */
dc6f92b8 52
6df54671 53#ifdef BSD_SYSTEM
dc6f92b8 54#include <sys/ioctl.h>
6df54671 55#endif /* ! defined (BSD_SYSTEM) */
dc6f92b8 56
2d368234 57#include "systty.h"
3a2712f9 58#include "systime.h"
dc6f92b8 59
b8009dd1 60#ifndef INCLUDED_FCNTL
dc6f92b8 61#include <fcntl.h>
b8009dd1 62#endif
dc6f92b8
JB
63#include <ctype.h>
64#include <errno.h>
65#include <setjmp.h>
66#include <sys/stat.h>
a0a7635f
RS
67/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
68/* #include <sys/param.h> */
dc6f92b8 69
dc43ef94 70#include "charset.h"
379b5ac0 71#include "coding.h"
dc43ef94 72#include "ccl.h"
7a13e894 73#include "frame.h"
dc6f92b8 74#include "dispextern.h"
ee569018 75#include "fontset.h"
dc6f92b8
JB
76#include "termhooks.h"
77#include "termopts.h"
78#include "termchar.h"
dc6f92b8 79#include "gnu.h"
dc6f92b8 80#include "disptab.h"
dc6f92b8 81#include "buffer.h"
f451eb13 82#include "window.h"
3b2fa4e6 83#include "keyboard.h"
bde7c500 84#include "intervals.h"
dfcf069d 85#include "process.h"
bffcfca9 86#include "atimer.h"
8feddab4 87#include "keymap.h"
dc6f92b8 88
d2bd6bc4
RS
89#ifdef USE_X_TOOLKIT
90#include <X11/Shell.h>
91#endif
92
06a2c219
GM
93#ifdef HAVE_SYS_TIME_H
94#include <sys/time.h>
95#endif
96#ifdef HAVE_UNISTD_H
97#include <unistd.h>
98#endif
99
d624284c
PJ
100#ifdef USE_LUCID
101extern int xlwmenu_window_p (Widget w, Window window);
102extern void xlwmenu_redisplay P_ ((Widget));
103#endif
104
3afe33e7 105#ifdef USE_X_TOOLKIT
06a2c219 106
952291d9
GM
107extern void free_frame_menubar P_ ((struct frame *));
108extern struct frame *x_menubar_window_to_frame P_ ((struct x_display_info *,
109 int));
06a2c219 110
0fdff6bb
RS
111#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
112#define HACK_EDITRES
113extern void _XEditResCheckMessages ();
114#endif /* not NO_EDITRES */
06a2c219
GM
115
116/* Include toolkit specific headers for the scroll bar widget. */
117
118#ifdef USE_TOOLKIT_SCROLL_BARS
119#if defined USE_MOTIF
120#include <Xm/Xm.h> /* for LESSTIF_VERSION */
121#include <Xm/ScrollBar.h>
ec18280f
SM
122#else /* !USE_MOTIF i.e. use Xaw */
123
124#ifdef HAVE_XAW3D
06a2c219 125#include <X11/Xaw3d/Simple.h>
06a2c219
GM
126#include <X11/Xaw3d/Scrollbar.h>
127#define ARROW_SCROLLBAR
128#include <X11/Xaw3d/ScrollbarP.h>
ec18280f
SM
129#else /* !HAVE_XAW3D */
130#include <X11/Xaw/Simple.h>
131#include <X11/Xaw/Scrollbar.h>
132#endif /* !HAVE_XAW3D */
133#ifndef XtNpickTop
134#define XtNpickTop "pickTop"
135#endif /* !XtNpickTop */
136#endif /* !USE_MOTIF */
06a2c219
GM
137#endif /* USE_TOOLKIT_SCROLL_BARS */
138
3afe33e7
RS
139#endif /* USE_X_TOOLKIT */
140
b849c413
RS
141#ifndef USE_X_TOOLKIT
142#define x_any_window_to_frame x_window_to_frame
5627c40e 143#define x_top_window_to_frame x_window_to_frame
b849c413
RS
144#endif
145
546e6d5b 146#ifdef USE_X_TOOLKIT
d067ea8b 147#include "widget.h"
546e6d5b
RS
148#ifndef XtNinitialState
149#define XtNinitialState "initialState"
150#endif
151#endif
152
06a2c219
GM
153#define abs(x) ((x) < 0 ? -(x) : (x))
154
155#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
156
157\f
158/* Bitmaps for truncated lines. */
159
160enum bitmap_type
161{
162 NO_BITMAP,
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
175#define zv_height 8
176static unsigned char zv_bits[] = {
177 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00};
178
179/* An arrow like this: `<-'. */
180
181#define left_width 8
182#define left_height 8
183static unsigned char left_bits[] = {
184 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
185
110859fc
GM
186/* Right truncation arrow bitmap `->'. */
187
188#define right_width 8
189#define right_height 8
190static unsigned char right_bits[] = {
191 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
192
06a2c219
GM
193/* Marker for continued lines. */
194
195#define continued_width 8
196#define continued_height 8
197static unsigned char continued_bits[] = {
110859fc
GM
198 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
199
200/* Marker for continuation lines. */
06a2c219
GM
201
202#define continuation_width 8
203#define continuation_height 8
204static unsigned char continuation_bits[] = {
110859fc 205 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
06a2c219 206
110859fc 207/* Overlay arrow bitmap. */
06a2c219 208
110859fc
GM
209#if 0
210/* A bomb. */
06a2c219
GM
211#define ov_width 8
212#define ov_height 8
213static unsigned char ov_bits[] = {
214 0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
06a2c219 215#else
110859fc 216/* A triangular arrow. */
06a2c219
GM
217#define ov_width 8
218#define ov_height 8
219static unsigned char ov_bits[] = {
110859fc
GM
220 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
221
e4b68333 222#endif
06a2c219
GM
223
224extern Lisp_Object Qhelp_echo;
225
69388238 226\f
5bf04520 227/* Non-nil means Emacs uses toolkit scroll bars. */
06a2c219 228
5bf04520 229Lisp_Object Vx_toolkit_scroll_bars;
06a2c219
GM
230
231/* If a string, XTread_socket generates an event to display that string.
232 (The display is done in read_char.) */
233
234static Lisp_Object help_echo;
7cea38bc 235static Lisp_Object help_echo_window;
be010514
GM
236static Lisp_Object help_echo_object;
237static int help_echo_pos;
06a2c219
GM
238
239/* Temporary variable for XTread_socket. */
240
241static Lisp_Object previous_help_echo;
242
243/* Non-zero means that a HELP_EVENT has been generated since Emacs
244 start. */
245
246static int any_help_event_p;
247
248/* Non-zero means draw block and hollow cursor as wide as the glyph
249 under it. For example, if a block cursor is over a tab, it will be
250 drawn as wide as that tab on the display. */
251
252int x_stretch_cursor_p;
253
a72d5ce5
GM
254/* Non-zero means make use of UNDERLINE_POSITION font properties. */
255
256int x_use_underline_position_properties;
257
06a2c219
GM
258/* This is a chain of structures for all the X displays currently in
259 use. */
260
334208b7 261struct x_display_info *x_display_list;
dc6f92b8 262
06a2c219
GM
263/* This is a list of cons cells, each of the form (NAME
264 . FONT-LIST-CACHE), one for each element of x_display_list and in
265 the same order. NAME is the name of the frame. FONT-LIST-CACHE
266 records previous values returned by x-list-fonts. */
267
7a13e894 268Lisp_Object x_display_name_list;
f451eb13 269
987d2ad1 270/* Frame being updated by update_frame. This is declared in term.c.
06a2c219
GM
271 This is set by update_begin and looked at by all the XT functions.
272 It is zero while not inside an update. In that case, the XT
273 functions assume that `selected_frame' is the frame to apply to. */
274
d0386f2a 275extern struct frame *updating_frame;
dc6f92b8 276
dfcf069d 277extern int waiting_for_input;
0e81d8cd 278
06a2c219
GM
279/* This is a frame waiting to be auto-raised, within XTread_socket. */
280
0134a210
RS
281struct frame *pending_autoraise_frame;
282
7f9c7f94
RS
283#ifdef USE_X_TOOLKIT
284/* The application context for Xt use. */
285XtAppContext Xt_app_con;
06a2c219
GM
286static String Xt_default_resources[] = {0};
287#endif /* USE_X_TOOLKIT */
665881ad 288
06a2c219
GM
289/* Nominal cursor position -- where to draw output.
290 HPOS and VPOS are window relative glyph matrix coordinates.
291 X and Y are window relative pixel coordinates. */
dc6f92b8 292
06a2c219 293struct cursor_pos output_cursor;
dc6f92b8 294
bffcfca9
GM
295/* Non-zero means user is interacting with a toolkit scroll bar. */
296
297static int toolkit_scroll_bar_interaction;
dc6f92b8 298
69388238
RS
299/* Mouse movement.
300
06a2c219 301 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
302 so that we would have to call XQueryPointer after each MotionNotify
303 event to ask for another such event. However, this made mouse tracking
304 slow, and there was a bug that made it eventually stop.
305
306 Simply asking for MotionNotify all the time seems to work better.
307
69388238
RS
308 In order to avoid asking for motion events and then throwing most
309 of them away or busy-polling the server for mouse positions, we ask
310 the server for pointer motion hints. This means that we get only
311 one event per group of mouse movements. "Groups" are delimited by
312 other kinds of events (focus changes and button clicks, for
313 example), or by XQueryPointer calls; when one of these happens, we
314 get another MotionNotify event the next time the mouse moves. This
315 is at least as efficient as getting motion events when mouse
316 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 317 is off. */
69388238
RS
318
319/* Where the mouse was last time we reported a mouse event. */
69388238 320
06a2c219
GM
321FRAME_PTR last_mouse_frame;
322static XRectangle last_mouse_glyph;
2237cac9
RS
323static Lisp_Object last_mouse_press_frame;
324
69388238
RS
325/* The scroll bar in which the last X motion event occurred.
326
06a2c219
GM
327 If the last X motion event occurred in a scroll bar, we set this so
328 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
329 an ordinary motion.
330
06a2c219
GM
331 If the last X motion event didn't occur in a scroll bar, we set
332 this to Qnil, to tell XTmouse_position to return an ordinary motion
333 event. */
334
69388238
RS
335static Lisp_Object last_mouse_scroll_bar;
336
69388238
RS
337/* This is a hack. We would really prefer that XTmouse_position would
338 return the time associated with the position it returns, but there
06a2c219 339 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
340 along with the position query. So, we just keep track of the time
341 of the last movement we received, and return that in hopes that
342 it's somewhat accurate. */
06a2c219 343
69388238
RS
344static Time last_mouse_movement_time;
345
06a2c219
GM
346/* Incremented by XTread_socket whenever it really tries to read
347 events. */
348
c0a04927
RS
349#ifdef __STDC__
350static int volatile input_signal_count;
351#else
352static int input_signal_count;
353#endif
354
7a13e894 355/* Used locally within XTread_socket. */
06a2c219 356
7a13e894 357static int x_noop_count;
dc6f92b8 358
7a13e894 359/* Initial values of argv and argc. */
06a2c219 360
7a13e894
RS
361extern char **initial_argv;
362extern int initial_argc;
dc6f92b8 363
7a13e894 364extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 365
06a2c219 366/* Tells if a window manager is present or not. */
7a13e894
RS
367
368extern Lisp_Object Vx_no_window_manager;
dc6f92b8 369
c2df547c 370extern Lisp_Object Qface, Qmouse_face;
b8009dd1 371
dc6f92b8
JB
372extern int errno;
373
dfeccd2d 374/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 375
64bb1782
RS
376extern int extra_keyboard_modifiers;
377
59e755be
KH
378static Lisp_Object Qvendor_specific_keysyms;
379
952291d9
GM
380extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
381extern Lisp_Object x_icon_type P_ ((struct frame *));
c32cdd9a 382
7a13e894 383
06a2c219
GM
384/* Enumeration for overriding/changing the face to use for drawing
385 glyphs in x_draw_glyphs. */
386
387enum draw_glyphs_face
388{
389 DRAW_NORMAL_TEXT,
390 DRAW_INVERSE_VIDEO,
391 DRAW_CURSOR,
392 DRAW_MOUSE_FACE,
393 DRAW_IMAGE_RAISED,
394 DRAW_IMAGE_SUNKEN
395};
396
b7f83f9e 397static int cursor_in_mouse_face_p P_ ((struct window *));
fa262c07 398static int clear_mouse_face P_ ((struct x_display_info *));
651f03b6 399static int x_alloc_nearest_color_1 P_ ((Display *, Colormap, XColor *));
499b1844 400static void x_set_window_size_1 P_ ((struct frame *, int, int, int));
651f03b6 401static const XColor *x_color_cells P_ ((Display *, int *));
71b8321e 402static void x_update_window_end P_ ((struct window *, int, int));
06a2c219
GM
403static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
404void x_delete_display P_ ((struct x_display_info *));
405static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
406 unsigned));
407static int fast_find_position P_ ((struct window *, int, int *, int *,
7e376260 408 int *, int *, Lisp_Object));
f9db2310
GM
409static int fast_find_string_pos P_ ((struct window *, int, Lisp_Object,
410 int *, int *, int *, int *, int));
06a2c219
GM
411static void set_output_cursor P_ ((struct cursor_pos *));
412static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
f9db2310 413 int *, int *, int *, int));
06a2c219 414static void note_mode_line_highlight P_ ((struct window *, int, int));
06a2c219 415static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
416static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
417static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
418static void show_mouse_face P_ ((struct x_display_info *,
419 enum draw_glyphs_face));
420static int x_io_error_quitter P_ ((Display *));
421int x_catch_errors P_ ((Display *));
422void x_uncatch_errors P_ ((Display *, int));
423void x_lower_frame P_ ((struct frame *));
424void x_scroll_bar_clear P_ ((struct frame *));
425int x_had_errors_p P_ ((Display *));
426void x_wm_set_size_hint P_ ((struct frame *, long, int));
427void x_raise_frame P_ ((struct frame *));
428void x_set_window_size P_ ((struct frame *, int, int, int));
429void x_wm_set_window_state P_ ((struct frame *, int));
430void x_wm_set_icon_pixmap P_ ((struct frame *, int));
431void x_initialize P_ ((void));
432static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
433static int x_compute_min_glyph_bounds P_ ((struct frame *));
434static void x_draw_phys_cursor_glyph P_ ((struct window *,
435 struct glyph_row *,
436 enum draw_glyphs_face));
437static void x_update_end P_ ((struct frame *));
438static void XTframe_up_to_date P_ ((struct frame *));
06a2c219
GM
439static void XTset_terminal_modes P_ ((void));
440static void XTreset_terminal_modes P_ ((void));
441static void XTcursor_to P_ ((int, int, int, int));
442static void x_write_glyphs P_ ((struct glyph *, int));
443static void x_clear_end_of_line P_ ((int));
444static void x_clear_frame P_ ((void));
445static void x_clear_cursor P_ ((struct window *));
446static void frame_highlight P_ ((struct frame *));
447static void frame_unhighlight P_ ((struct frame *));
448static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
449static void XTframe_rehighlight P_ ((struct frame *));
450static void x_frame_rehighlight P_ ((struct x_display_info *));
451static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
f02d8aa0 452static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
06a2c219
GM
453static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
454 XRectangle *));
455static void expose_frame P_ ((struct frame *, int, int, int, int));
82f053ab 456static int expose_window_tree P_ ((struct window *, XRectangle *));
a39202f6 457static int expose_window P_ ((struct window *, XRectangle *));
06a2c219
GM
458static void expose_area P_ ((struct window *, struct glyph_row *,
459 XRectangle *, enum glyph_row_area));
82f053ab 460static int expose_line P_ ((struct window *, struct glyph_row *,
06a2c219
GM
461 XRectangle *));
462static void x_update_cursor_in_window_tree P_ ((struct window *, int));
463static void x_update_window_cursor P_ ((struct window *, int));
464static void x_erase_phys_cursor P_ ((struct window *));
465void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
466static void x_draw_bitmap P_ ((struct window *, struct glyph_row *,
467 enum bitmap_type));
468
469static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
470 GC, int));
471static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
472static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
78a9a4c5 473static void notice_overwritten_cursor P_ ((struct window *, int, int));
06a2c219 474static void x_flush P_ ((struct frame *f));
952291d9
GM
475static void x_update_begin P_ ((struct frame *));
476static void x_update_window_begin P_ ((struct window *));
477static void x_draw_vertical_border P_ ((struct window *));
478static void x_after_update_window_line P_ ((struct glyph_row *));
479static INLINE void take_vertical_position_into_account P_ ((struct it *));
480static void x_produce_stretch_glyph P_ ((struct it *));
b52b65bd
GM
481static struct scroll_bar *x_window_to_scroll_bar P_ ((Window));
482static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
483 enum scroll_bar_part *,
484 Lisp_Object *, Lisp_Object *,
485 unsigned long *));
06a2c219
GM
486
487/* Flush display of frame F, or of all frames if F is null. */
488
489static void
490x_flush (f)
491 struct frame *f;
492{
493 BLOCK_INPUT;
494 if (f == NULL)
495 {
496 Lisp_Object rest, frame;
497 FOR_EACH_FRAME (rest, frame)
498 x_flush (XFRAME (frame));
499 }
500 else if (FRAME_X_P (f))
501 XFlush (FRAME_X_DISPLAY (f));
502 UNBLOCK_INPUT;
503}
504
dc6f92b8 505
06a2c219
GM
506/* Remove calls to XFlush by defining XFlush to an empty replacement.
507 Calls to XFlush should be unnecessary because the X output buffer
508 is flushed automatically as needed by calls to XPending,
509 XNextEvent, or XWindowEvent according to the XFlush man page.
510 XTread_socket calls XPending. Removing XFlush improves
511 performance. */
512
513#define XFlush(DISPLAY) (void) 0
b8009dd1 514
334208b7 515\f
06a2c219
GM
516/***********************************************************************
517 Debugging
518 ***********************************************************************/
519
9382638d 520#if 0
06a2c219
GM
521
522/* This is a function useful for recording debugging information about
523 the sequence of occurrences in this file. */
9382638d
KH
524
525struct record
526{
527 char *locus;
528 int type;
529};
530
531struct record event_record[100];
532
533int event_record_index;
534
535record_event (locus, type)
536 char *locus;
537 int type;
538{
539 if (event_record_index == sizeof (event_record) / sizeof (struct record))
540 event_record_index = 0;
541
542 event_record[event_record_index].locus = locus;
543 event_record[event_record_index].type = type;
544 event_record_index++;
545}
546
547#endif /* 0 */
06a2c219
GM
548
549
9382638d 550\f
334208b7
RS
551/* Return the struct x_display_info corresponding to DPY. */
552
553struct x_display_info *
554x_display_info_for_display (dpy)
555 Display *dpy;
556{
557 struct x_display_info *dpyinfo;
558
559 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
560 if (dpyinfo->display == dpy)
561 return dpyinfo;
16bd92ea 562
334208b7
RS
563 return 0;
564}
f451eb13 565
06a2c219
GM
566
567\f
568/***********************************************************************
569 Starting and ending an update
570 ***********************************************************************/
571
572/* Start an update of frame F. This function is installed as a hook
573 for update_begin, i.e. it is called when update_begin is called.
574 This function is called prior to calls to x_update_window_begin for
575 each window being updated. Currently, there is nothing to do here
576 because all interesting stuff is done on a window basis. */
dc6f92b8 577
dfcf069d 578static void
06a2c219 579x_update_begin (f)
f676886a 580 struct frame *f;
58769bee 581{
06a2c219
GM
582 /* Nothing to do. */
583}
dc6f92b8 584
dc6f92b8 585
06a2c219
GM
586/* Start update of window W. Set the global variable updated_window
587 to the window being updated and set output_cursor to the cursor
588 position of W. */
dc6f92b8 589
06a2c219
GM
590static void
591x_update_window_begin (w)
592 struct window *w;
593{
594 struct frame *f = XFRAME (WINDOW_FRAME (w));
595 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
596
597 updated_window = w;
598 set_output_cursor (&w->cursor);
b8009dd1 599
06a2c219 600 BLOCK_INPUT;
d1bc4182 601
06a2c219 602 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 603 {
514e4681 604 /* Don't do highlighting for mouse motion during the update. */
06a2c219 605 display_info->mouse_face_defer = 1;
37c2c98b 606
06a2c219
GM
607 /* If F needs to be redrawn, simply forget about any prior mouse
608 highlighting. */
9f67f20b 609 if (FRAME_GARBAGED_P (f))
06a2c219
GM
610 display_info->mouse_face_window = Qnil;
611
64f26cf5
GM
612#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
613 their mouse_face_p flag set, which means that they are always
614 unequal to rows in a desired matrix which never have that
615 flag set. So, rows containing mouse-face glyphs are never
616 scrolled, and we don't have to switch the mouse highlight off
617 here to prevent it from being scrolled. */
618
06a2c219
GM
619 /* Can we tell that this update does not affect the window
620 where the mouse highlight is? If so, no need to turn off.
621 Likewise, don't do anything if the frame is garbaged;
622 in that case, the frame's current matrix that we would use
623 is all wrong, and we will redisplay that line anyway. */
624 if (!NILP (display_info->mouse_face_window)
625 && w == XWINDOW (display_info->mouse_face_window))
514e4681 626 {
06a2c219 627 int i;
514e4681 628
06a2c219
GM
629 for (i = 0; i < w->desired_matrix->nrows; ++i)
630 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
631 break;
632
06a2c219
GM
633 if (i < w->desired_matrix->nrows)
634 clear_mouse_face (display_info);
514e4681 635 }
64f26cf5 636#endif /* 0 */
b8009dd1 637 }
6ccf47d1 638
dc6f92b8
JB
639 UNBLOCK_INPUT;
640}
641
06a2c219
GM
642
643/* Draw a vertical window border to the right of window W if W doesn't
644 have vertical scroll bars. */
645
dfcf069d 646static void
06a2c219
GM
647x_draw_vertical_border (w)
648 struct window *w;
58769bee 649{
06a2c219
GM
650 struct frame *f = XFRAME (WINDOW_FRAME (w));
651
652 /* Redraw borders between horizontally adjacent windows. Don't
653 do it for frames with vertical scroll bars because either the
654 right scroll bar of a window, or the left scroll bar of its
655 neighbor will suffice as a border. */
656 if (!WINDOW_RIGHTMOST_P (w)
657 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
658 {
659 int x0, x1, y0, y1;
dc6f92b8 660
06a2c219 661 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
110859fc 662 x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
663 y1 -= 1;
664
665 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
666 f->output_data.x->normal_gc, x1, y0, x1, y1);
667 }
668}
669
670
71b8321e
GM
671/* End update of window W (which is equal to updated_window).
672
673 Draw vertical borders between horizontally adjacent windows, and
674 display W's cursor if CURSOR_ON_P is non-zero.
675
676 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
677 glyphs in mouse-face were overwritten. In that case we have to
678 make sure that the mouse-highlight is properly redrawn.
679
680 W may be a menu bar pseudo-window in case we don't have X toolkit
681 support. Such windows don't have a cursor, so don't display it
682 here. */
06a2c219
GM
683
684static void
71b8321e 685x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 686 struct window *w;
71b8321e 687 int cursor_on_p, mouse_face_overwritten_p;
06a2c219 688{
140330de
GM
689 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
690
06a2c219
GM
691 if (!w->pseudo_window_p)
692 {
693 BLOCK_INPUT;
71b8321e 694
06a2c219
GM
695 if (cursor_on_p)
696 x_display_and_set_cursor (w, 1, output_cursor.hpos,
697 output_cursor.vpos,
698 output_cursor.x, output_cursor.y);
71b8321e 699
06a2c219
GM
700 x_draw_vertical_border (w);
701 UNBLOCK_INPUT;
702 }
703
140330de
GM
704 /* If a row with mouse-face was overwritten, arrange for
705 XTframe_up_to_date to redisplay the mouse highlight. */
706 if (mouse_face_overwritten_p)
707 {
708 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
709 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
710 dpyinfo->mouse_face_window = Qnil;
711 }
712
06a2c219
GM
713 updated_window = NULL;
714}
dc6f92b8 715
dc6f92b8 716
06a2c219
GM
717/* End update of frame F. This function is installed as a hook in
718 update_end. */
719
720static void
721x_update_end (f)
722 struct frame *f;
723{
724 /* Mouse highlight may be displayed again. */
aa8bff2e 725 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 726
06a2c219 727 BLOCK_INPUT;
334208b7 728 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
729 UNBLOCK_INPUT;
730}
b8009dd1 731
06a2c219
GM
732
733/* This function is called from various places in xdisp.c whenever a
734 complete update has been performed. The global variable
735 updated_window is not available here. */
b8009dd1 736
dfcf069d 737static void
b8009dd1 738XTframe_up_to_date (f)
06a2c219 739 struct frame *f;
b8009dd1 740{
06a2c219 741 if (FRAME_X_P (f))
514e4681 742 {
06a2c219 743 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 744
06a2c219
GM
745 if (dpyinfo->mouse_face_deferred_gc
746 || f == dpyinfo->mouse_face_mouse_frame)
747 {
748 BLOCK_INPUT;
749 if (dpyinfo->mouse_face_mouse_frame)
750 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
751 dpyinfo->mouse_face_mouse_x,
752 dpyinfo->mouse_face_mouse_y);
753 dpyinfo->mouse_face_deferred_gc = 0;
754 UNBLOCK_INPUT;
755 }
514e4681 756 }
b8009dd1 757}
06a2c219
GM
758
759
760/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
761 arrow bitmaps, or clear the areas where they would be displayed
762 before DESIRED_ROW is made current. The window being updated is
763 found in updated_window. This function It is called from
764 update_window_line only if it is known that there are differences
765 between bitmaps to be drawn between current row and DESIRED_ROW. */
766
767static void
768x_after_update_window_line (desired_row)
769 struct glyph_row *desired_row;
770{
771 struct window *w = updated_window;
ef253080 772 struct frame *f;
259cf6bc 773 int width, height;
06a2c219
GM
774
775 xassert (w);
776
777 if (!desired_row->mode_line_p && !w->pseudo_window_p)
778 {
779 BLOCK_INPUT;
780 x_draw_row_bitmaps (w, desired_row);
ef253080
GM
781 UNBLOCK_INPUT;
782 }
783
784 /* When a window has disappeared, make sure that no rest of
785 full-width rows stays visible in the internal border. Could
786 check here if updated_window is the leftmost/rightmost window,
787 but I guess it's not worth doing since vertically split windows
788 are almost never used, internal border is rarely set, and the
789 overhead is very small. */
790 if (windows_or_buffers_changed
791 && desired_row->full_width_p
792 && (f = XFRAME (w->frame),
793 width = FRAME_INTERNAL_BORDER_WIDTH (f),
259cf6bc
GM
794 width != 0)
795 && (height = desired_row->visible_height,
796 height > 0))
ef253080 797 {
ef253080 798 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
06a2c219 799
ef253080
GM
800 /* Internal border is drawn below the tool bar. */
801 if (WINDOWP (f->tool_bar_window)
802 && w == XWINDOW (f->tool_bar_window))
803 y -= width;
06a2c219 804
ef253080
GM
805 BLOCK_INPUT;
806 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
807 0, y, width, height, False);
808 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
809 f->output_data.x->pixel_width - width,
810 y, width, height, False);
06a2c219
GM
811 UNBLOCK_INPUT;
812 }
813}
814
815
816/* Draw the bitmap WHICH in one of the areas to the left or right of
817 window W. ROW is the glyph row for which to display the bitmap; it
818 determines the vertical position at which the bitmap has to be
819 drawn. */
820
821static void
822x_draw_bitmap (w, row, which)
823 struct window *w;
824 struct glyph_row *row;
825 enum bitmap_type which;
826{
827 struct frame *f = XFRAME (WINDOW_FRAME (w));
828 Display *display = FRAME_X_DISPLAY (f);
829 Window window = FRAME_X_WINDOW (f);
830 int x, y, wd, h, dy;
831 unsigned char *bits;
832 Pixmap pixmap;
833 GC gc = f->output_data.x->normal_gc;
834 struct face *face;
835 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
836
837 /* Must clip because of partially visible lines. */
838 x_clip_to_row (w, row, gc, 1);
839
840 switch (which)
841 {
842 case LEFT_TRUNCATION_BITMAP:
843 wd = left_width;
844 h = left_height;
845 bits = left_bits;
846 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
847 - wd
110859fc 848 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
849 break;
850
851 case OVERLAY_ARROW_BITMAP:
852 wd = left_width;
853 h = left_height;
854 bits = ov_bits;
855 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
856 - wd
110859fc 857 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
858 break;
859
860 case RIGHT_TRUNCATION_BITMAP:
861 wd = right_width;
862 h = right_height;
863 bits = right_bits;
864 x = window_box_right (w, -1);
110859fc 865 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
866 break;
867
868 case CONTINUED_LINE_BITMAP:
869 wd = right_width;
870 h = right_height;
871 bits = continued_bits;
872 x = window_box_right (w, -1);
110859fc 873 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
874 break;
875
876 case CONTINUATION_LINE_BITMAP:
877 wd = continuation_width;
878 h = continuation_height;
879 bits = continuation_bits;
880 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
881 - wd
110859fc 882 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
883 break;
884
885 case ZV_LINE_BITMAP:
886 wd = zv_width;
887 h = zv_height;
888 bits = zv_bits;
889 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
890 - wd
110859fc 891 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
892 break;
893
894 default:
895 abort ();
896 }
897
898 /* Convert to frame coordinates. Set dy to the offset in the row to
899 start drawing the bitmap. */
900 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
901 dy = (row->height - h) / 2;
902
903 /* Draw the bitmap. I believe these small pixmaps can be cached
904 by the server. */
905 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
906 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
907 face->foreground,
908 face->background, depth);
909 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
910 XFreePixmap (display, pixmap);
911 XSetClipMask (display, gc, None);
912}
913
914
915/* Draw flags bitmaps for glyph row ROW on window W. Call this
916 function with input blocked. */
917
918static void
919x_draw_row_bitmaps (w, row)
920 struct window *w;
921 struct glyph_row *row;
922{
923 struct frame *f = XFRAME (w->frame);
924 enum bitmap_type bitmap;
925 struct face *face;
045dee35 926 int header_line_height = -1;
06a2c219
GM
927
928 xassert (interrupt_input_blocked);
929
930 /* If row is completely invisible, because of vscrolling, we
931 don't have to draw anything. */
932 if (row->visible_height <= 0)
933 return;
934
935 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
936 PREPARE_FACE_FOR_DISPLAY (f, face);
937
938 /* Decide which bitmap to draw at the left side. */
939 if (row->overlay_arrow_p)
940 bitmap = OVERLAY_ARROW_BITMAP;
941 else if (row->truncated_on_left_p)
942 bitmap = LEFT_TRUNCATION_BITMAP;
943 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
944 bitmap = CONTINUATION_LINE_BITMAP;
945 else if (row->indicate_empty_line_p)
946 bitmap = ZV_LINE_BITMAP;
947 else
948 bitmap = NO_BITMAP;
949
950 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
951 the flags area. */
952 if (bitmap == NO_BITMAP
110859fc 953 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
954 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
955 {
956 /* If W has a vertical border to its left, don't draw over it. */
957 int border = ((XFASTINT (w->left) > 0
958 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
959 ? 1 : 0);
960 int left = window_box_left (w, -1);
961
045dee35
GM
962 if (header_line_height < 0)
963 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
964
965 /* In case the same realized face is used for bitmap areas 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 (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
971 else
972 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
973
06a2c219
GM
974 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
975 face->gc,
976 (left
110859fc 977 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219 978 + border),
045dee35 979 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 980 row->y)),
110859fc 981 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
06a2c219 982 row->visible_height);
dcd08bfb
GM
983 if (!face->stipple)
984 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
985 }
986
987 /* Draw the left bitmap. */
988 if (bitmap != NO_BITMAP)
989 x_draw_bitmap (w, row, bitmap);
990
991 /* Decide which bitmap to draw at the right side. */
992 if (row->truncated_on_right_p)
993 bitmap = RIGHT_TRUNCATION_BITMAP;
994 else if (row->continued_p)
995 bitmap = CONTINUED_LINE_BITMAP;
996 else
997 bitmap = NO_BITMAP;
998
999 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
1000 the flags area. */
1001 if (bitmap == NO_BITMAP
110859fc 1002 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
1003 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
1004 {
1005 int right = window_box_right (w, -1);
1006
045dee35
GM
1007 if (header_line_height < 0)
1008 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
1009
1010 /* In case the same realized face is used for bitmap areas and
1011 for something displayed in the text (e.g. face `region' on
1012 mono-displays, the fill style may have been changed to
1013 FillSolid in x_draw_glyph_string_background. */
1014 if (face->stipple)
1015 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
1016 else
1017 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
1018 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1019 face->gc,
1020 right,
045dee35 1021 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 1022 row->y)),
110859fc 1023 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
06a2c219 1024 row->visible_height);
dcd08bfb
GM
1025 if (!face->stipple)
1026 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
1027 }
1028
1029 /* Draw the right bitmap. */
1030 if (bitmap != NO_BITMAP)
1031 x_draw_bitmap (w, row, bitmap);
1032}
1033
dc6f92b8 1034\f
06a2c219
GM
1035
1036/* This is called when starting Emacs and when restarting after
1037 suspend. When starting Emacs, no X window is mapped. And nothing
1038 must be done to Emacs's own window if it is suspended (though that
1039 rarely happens). */
dc6f92b8 1040
dfcf069d 1041static void
dc6f92b8
JB
1042XTset_terminal_modes ()
1043{
1044}
1045
06a2c219
GM
1046/* This is called when exiting or suspending Emacs. Exiting will make
1047 the X-windows go away, and suspending requires no action. */
dc6f92b8 1048
dfcf069d 1049static void
dc6f92b8
JB
1050XTreset_terminal_modes ()
1051{
dc6f92b8 1052}
06a2c219
GM
1053
1054
dc6f92b8 1055\f
06a2c219
GM
1056/***********************************************************************
1057 Output Cursor
1058 ***********************************************************************/
1059
1060/* Set the global variable output_cursor to CURSOR. All cursor
1061 positions are relative to updated_window. */
dc6f92b8 1062
dfcf069d 1063static void
06a2c219
GM
1064set_output_cursor (cursor)
1065 struct cursor_pos *cursor;
dc6f92b8 1066{
06a2c219
GM
1067 output_cursor.hpos = cursor->hpos;
1068 output_cursor.vpos = cursor->vpos;
1069 output_cursor.x = cursor->x;
1070 output_cursor.y = cursor->y;
1071}
1072
1073
1074/* Set a nominal cursor position.
dc6f92b8 1075
06a2c219
GM
1076 HPOS and VPOS are column/row positions in a window glyph matrix. X
1077 and Y are window text area relative pixel positions.
1078
1079 If this is done during an update, updated_window will contain the
1080 window that is being updated and the position is the future output
1081 cursor position for that window. If updated_window is null, use
1082 selected_window and display the cursor at the given position. */
1083
1084static void
1085XTcursor_to (vpos, hpos, y, x)
1086 int vpos, hpos, y, x;
1087{
1088 struct window *w;
1089
1090 /* If updated_window is not set, work on selected_window. */
1091 if (updated_window)
1092 w = updated_window;
1093 else
1094 w = XWINDOW (selected_window);
dbcb258a 1095
06a2c219
GM
1096 /* Set the output cursor. */
1097 output_cursor.hpos = hpos;
1098 output_cursor.vpos = vpos;
1099 output_cursor.x = x;
1100 output_cursor.y = y;
dc6f92b8 1101
06a2c219
GM
1102 /* If not called as part of an update, really display the cursor.
1103 This will also set the cursor position of W. */
1104 if (updated_window == NULL)
dc6f92b8
JB
1105 {
1106 BLOCK_INPUT;
06a2c219 1107 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1108 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1109 UNBLOCK_INPUT;
1110 }
1111}
dc43ef94 1112
06a2c219
GM
1113
1114\f
1115/***********************************************************************
1116 Display Iterator
1117 ***********************************************************************/
1118
1119/* Function prototypes of this page. */
1120
1121static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1122 struct glyph *,
ee569018
KH
1123 XChar2b *,
1124 int *));
06a2c219
GM
1125static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1126 int, XChar2b *, int));
1127static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1128static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1129static void x_append_glyph P_ ((struct it *));
b4192550 1130static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1131static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1132 int, int, double));
1133static void x_produce_glyphs P_ ((struct it *));
06a2c219 1134static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1135
1136
e2ef8ee6
GM
1137/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1138 is not contained in the font. */
dc43ef94 1139
06a2c219 1140static INLINE XCharStruct *
ee569018 1141x_per_char_metric (font, char2b)
06a2c219
GM
1142 XFontStruct *font;
1143 XChar2b *char2b;
1144{
1145 /* The result metric information. */
1146 XCharStruct *pcm = NULL;
dc6f92b8 1147
06a2c219 1148 xassert (font && char2b);
dc6f92b8 1149
06a2c219 1150 if (font->per_char != NULL)
dc6f92b8 1151 {
06a2c219 1152 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1153 {
06a2c219
GM
1154 /* min_char_or_byte2 specifies the linear character index
1155 corresponding to the first element of the per_char array,
1156 max_char_or_byte2 is the index of the last character. A
1157 character with non-zero CHAR2B->byte1 is not in the font.
1158 A character with byte2 less than min_char_or_byte2 or
1159 greater max_char_or_byte2 is not in the font. */
1160 if (char2b->byte1 == 0
1161 && char2b->byte2 >= font->min_char_or_byte2
1162 && char2b->byte2 <= font->max_char_or_byte2)
1163 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1164 }
06a2c219 1165 else
dc6f92b8 1166 {
06a2c219
GM
1167 /* If either min_byte1 or max_byte1 are nonzero, both
1168 min_char_or_byte2 and max_char_or_byte2 are less than
1169 256, and the 2-byte character index values corresponding
1170 to the per_char array element N (counting from 0) are:
1171
1172 byte1 = N/D + min_byte1
1173 byte2 = N\D + min_char_or_byte2
1174
1175 where:
1176
1177 D = max_char_or_byte2 - min_char_or_byte2 + 1
1178 / = integer division
1179 \ = integer modulus */
1180 if (char2b->byte1 >= font->min_byte1
1181 && char2b->byte1 <= font->max_byte1
1182 && char2b->byte2 >= font->min_char_or_byte2
1183 && char2b->byte2 <= font->max_char_or_byte2)
1184 {
1185 pcm = (font->per_char
1186 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1187 * (char2b->byte1 - font->min_byte1))
1188 + (char2b->byte2 - font->min_char_or_byte2));
1189 }
dc6f92b8 1190 }
06a2c219
GM
1191 }
1192 else
1193 {
1194 /* If the per_char pointer is null, all glyphs between the first
1195 and last character indexes inclusive have the same
1196 information, as given by both min_bounds and max_bounds. */
1197 if (char2b->byte2 >= font->min_char_or_byte2
1198 && char2b->byte2 <= font->max_char_or_byte2)
1199 pcm = &font->max_bounds;
1200 }
dc6f92b8 1201
ee569018 1202 return ((pcm == NULL
3e71d8f2 1203 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1204 ? NULL : pcm);
06a2c219 1205}
b73b6aaf 1206
57b03282 1207
06a2c219
GM
1208/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1209 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1210
06a2c219
GM
1211static INLINE void
1212x_encode_char (c, char2b, font_info)
1213 int c;
1214 XChar2b *char2b;
1215 struct font_info *font_info;
1216{
1217 int charset = CHAR_CHARSET (c);
1218 XFontStruct *font = font_info->font;
1219
1220 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1221 This may be either a program in a special encoder language or a
1222 fixed encoding. */
1223 if (font_info->font_encoder)
1224 {
1225 /* It's a program. */
1226 struct ccl_program *ccl = font_info->font_encoder;
1227
1228 if (CHARSET_DIMENSION (charset) == 1)
1229 {
1230 ccl->reg[0] = charset;
1231 ccl->reg[1] = char2b->byte2;
1232 }
1233 else
1234 {
1235 ccl->reg[0] = charset;
1236 ccl->reg[1] = char2b->byte1;
1237 ccl->reg[2] = char2b->byte2;
1238 }
1239
1240 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1241
1242 /* We assume that MSBs are appropriately set/reset by CCL
1243 program. */
1244 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1245 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1246 else
1247 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1248 }
1249 else if (font_info->encoding[charset])
1250 {
1251 /* Fixed encoding scheme. See fontset.h for the meaning of the
1252 encoding numbers. */
1253 int enc = font_info->encoding[charset];
1254
1255 if ((enc == 1 || enc == 2)
1256 && CHARSET_DIMENSION (charset) == 2)
1257 char2b->byte1 |= 0x80;
1258
1259 if (enc == 1 || enc == 3)
1260 char2b->byte2 |= 0x80;
1261 }
1262}
1263
1264
1265/* Get face and two-byte form of character C in face FACE_ID on frame
1266 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1267 means we want to display multibyte text. Value is a pointer to a
1268 realized face that is ready for display. */
1269
1270static INLINE struct face *
1271x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1272 struct frame *f;
1273 int c, face_id;
1274 XChar2b *char2b;
1275 int multibyte_p;
1276{
1277 struct face *face = FACE_FROM_ID (f, face_id);
1278
1279 if (!multibyte_p)
1280 {
1281 /* Unibyte case. We don't have to encode, but we have to make
1282 sure to use a face suitable for unibyte. */
1283 char2b->byte1 = 0;
1284 char2b->byte2 = c;
ee569018
KH
1285 face_id = FACE_FOR_CHAR (f, face, c);
1286 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1287 }
1288 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1289 {
1290 /* Case of ASCII in a face known to fit ASCII. */
1291 char2b->byte1 = 0;
1292 char2b->byte2 = c;
1293 }
1294 else
1295 {
1296 int c1, c2, charset;
1297
1298 /* Split characters into bytes. If c2 is -1 afterwards, C is
1299 really a one-byte character so that byte1 is zero. */
1300 SPLIT_CHAR (c, charset, c1, c2);
1301 if (c2 > 0)
1302 char2b->byte1 = c1, char2b->byte2 = c2;
1303 else
1304 char2b->byte1 = 0, char2b->byte2 = c1;
1305
06a2c219 1306 /* Maybe encode the character in *CHAR2B. */
ee569018 1307 if (face->font != NULL)
06a2c219
GM
1308 {
1309 struct font_info *font_info
1310 = FONT_INFO_FROM_ID (f, face->font_info_id);
1311 if (font_info)
ee569018 1312 x_encode_char (c, char2b, font_info);
06a2c219
GM
1313 }
1314 }
1315
1316 /* Make sure X resources of the face are allocated. */
1317 xassert (face != NULL);
1318 PREPARE_FACE_FOR_DISPLAY (f, face);
1319
1320 return face;
1321}
1322
1323
1324/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1325 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1326 a pointer to a realized face that is ready for display. */
1327
1328static INLINE struct face *
ee569018 1329x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1330 struct frame *f;
1331 struct glyph *glyph;
1332 XChar2b *char2b;
ee569018 1333 int *two_byte_p;
06a2c219
GM
1334{
1335 struct face *face;
1336
1337 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1338 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1339
ee569018
KH
1340 if (two_byte_p)
1341 *two_byte_p = 0;
1342
06a2c219
GM
1343 if (!glyph->multibyte_p)
1344 {
1345 /* Unibyte case. We don't have to encode, but we have to make
1346 sure to use a face suitable for unibyte. */
1347 char2b->byte1 = 0;
43d120d8 1348 char2b->byte2 = glyph->u.ch;
06a2c219 1349 }
43d120d8
KH
1350 else if (glyph->u.ch < 128
1351 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1352 {
1353 /* Case of ASCII in a face known to fit ASCII. */
1354 char2b->byte1 = 0;
43d120d8 1355 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1356 }
1357 else
1358 {
1359 int c1, c2, charset;
1360
1361 /* Split characters into bytes. If c2 is -1 afterwards, C is
1362 really a one-byte character so that byte1 is zero. */
43d120d8 1363 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1364 if (c2 > 0)
1365 char2b->byte1 = c1, char2b->byte2 = c2;
1366 else
1367 char2b->byte1 = 0, char2b->byte2 = c1;
1368
1369 /* Maybe encode the character in *CHAR2B. */
1370 if (charset != CHARSET_ASCII)
1371 {
1372 struct font_info *font_info
1373 = FONT_INFO_FROM_ID (f, face->font_info_id);
1374 if (font_info)
1375 {
43d120d8 1376 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1377 if (two_byte_p)
1378 *two_byte_p
1379 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1380 }
1381 }
1382 }
1383
1384 /* Make sure X resources of the face are allocated. */
1385 xassert (face != NULL);
1386 PREPARE_FACE_FOR_DISPLAY (f, face);
1387 return face;
1388}
1389
1390
1391/* Store one glyph for IT->char_to_display in IT->glyph_row.
1392 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1393
1394static INLINE void
1395x_append_glyph (it)
1396 struct it *it;
1397{
1398 struct glyph *glyph;
1399 enum glyph_row_area area = it->area;
1400
1401 xassert (it->glyph_row);
1402 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1403
1404 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1405 if (glyph < it->glyph_row->glyphs[area + 1])
1406 {
06a2c219
GM
1407 glyph->charpos = CHARPOS (it->position);
1408 glyph->object = it->object;
88d75730 1409 glyph->pixel_width = it->pixel_width;
06a2c219 1410 glyph->voffset = it->voffset;
88d75730 1411 glyph->type = CHAR_GLYPH;
06a2c219 1412 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1413 glyph->left_box_line_p = it->start_of_box_run_p;
1414 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1415 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1416 || it->phys_descent > it->descent);
88d75730 1417 glyph->padding_p = 0;
ee569018 1418 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1419 glyph->face_id = it->face_id;
1420 glyph->u.ch = it->char_to_display;
06a2c219
GM
1421 ++it->glyph_row->used[area];
1422 }
1423}
1424
b4192550
KH
1425/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1426 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1427
1428static INLINE void
1429x_append_composite_glyph (it)
1430 struct it *it;
1431{
1432 struct glyph *glyph;
1433 enum glyph_row_area area = it->area;
1434
1435 xassert (it->glyph_row);
1436
1437 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1438 if (glyph < it->glyph_row->glyphs[area + 1])
1439 {
b4192550
KH
1440 glyph->charpos = CHARPOS (it->position);
1441 glyph->object = it->object;
88d75730 1442 glyph->pixel_width = it->pixel_width;
b4192550 1443 glyph->voffset = it->voffset;
88d75730 1444 glyph->type = COMPOSITE_GLYPH;
b4192550 1445 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1446 glyph->left_box_line_p = it->start_of_box_run_p;
1447 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1448 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1449 || it->phys_descent > it->descent);
88d75730
GM
1450 glyph->padding_p = 0;
1451 glyph->glyph_not_available_p = 0;
1452 glyph->face_id = it->face_id;
1453 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1454 ++it->glyph_row->used[area];
1455 }
1456}
1457
06a2c219
GM
1458
1459/* Change IT->ascent and IT->height according to the setting of
1460 IT->voffset. */
1461
1462static INLINE void
1463take_vertical_position_into_account (it)
1464 struct it *it;
1465{
1466 if (it->voffset)
1467 {
1468 if (it->voffset < 0)
1469 /* Increase the ascent so that we can display the text higher
1470 in the line. */
1471 it->ascent += abs (it->voffset);
1472 else
1473 /* Increase the descent so that we can display the text lower
1474 in the line. */
1475 it->descent += it->voffset;
1476 }
1477}
1478
1479
1480/* Produce glyphs/get display metrics for the image IT is loaded with.
1481 See the description of struct display_iterator in dispextern.h for
1482 an overview of struct display_iterator. */
1483
1484static void
1485x_produce_image_glyph (it)
1486 struct it *it;
1487{
1488 struct image *img;
1489 struct face *face;
1490
1491 xassert (it->what == IT_IMAGE);
1492
1493 face = FACE_FROM_ID (it->f, it->face_id);
1494 img = IMAGE_FROM_ID (it->f, it->image_id);
1495 xassert (img);
1496
1497 /* Make sure X resources of the face and image are loaded. */
1498 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1499 prepare_image_for_display (it->f, img);
1500
95af8492 1501 it->ascent = it->phys_ascent = image_ascent (img, face);
22d650b8
GM
1502 it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
1503 it->pixel_width = img->width + 2 * img->hmargin;
06a2c219
GM
1504
1505 it->nglyphs = 1;
1506
1507 if (face->box != FACE_NO_BOX)
1508 {
ea2ba0d4
KH
1509 if (face->box_line_width > 0)
1510 {
1511 it->ascent += face->box_line_width;
1512 it->descent += face->box_line_width;
1513 }
06a2c219
GM
1514
1515 if (it->start_of_box_run_p)
ea2ba0d4 1516 it->pixel_width += abs (face->box_line_width);
06a2c219 1517 if (it->end_of_box_run_p)
ea2ba0d4 1518 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1519 }
1520
1521 take_vertical_position_into_account (it);
1522
1523 if (it->glyph_row)
1524 {
1525 struct glyph *glyph;
1526 enum glyph_row_area area = it->area;
1527
1528 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1529 if (glyph < it->glyph_row->glyphs[area + 1])
1530 {
06a2c219
GM
1531 glyph->charpos = CHARPOS (it->position);
1532 glyph->object = it->object;
88d75730 1533 glyph->pixel_width = it->pixel_width;
06a2c219 1534 glyph->voffset = it->voffset;
88d75730 1535 glyph->type = IMAGE_GLYPH;
06a2c219 1536 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1537 glyph->left_box_line_p = it->start_of_box_run_p;
1538 glyph->right_box_line_p = it->end_of_box_run_p;
1539 glyph->overlaps_vertically_p = 0;
1540 glyph->padding_p = 0;
1541 glyph->glyph_not_available_p = 0;
1542 glyph->face_id = it->face_id;
1543 glyph->u.img_id = img->id;
06a2c219
GM
1544 ++it->glyph_row->used[area];
1545 }
1546 }
1547}
1548
1549
1550/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1551 of the glyph, WIDTH and HEIGHT are the width and height of the
1552 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1553 ascent of the glyph (0 <= ASCENT <= 1). */
1554
1555static void
1556x_append_stretch_glyph (it, object, width, height, ascent)
1557 struct it *it;
1558 Lisp_Object object;
1559 int width, height;
1560 double ascent;
1561{
1562 struct glyph *glyph;
1563 enum glyph_row_area area = it->area;
1564
1565 xassert (ascent >= 0 && ascent <= 1);
1566
1567 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1568 if (glyph < it->glyph_row->glyphs[area + 1])
1569 {
06a2c219
GM
1570 glyph->charpos = CHARPOS (it->position);
1571 glyph->object = object;
88d75730 1572 glyph->pixel_width = width;
06a2c219 1573 glyph->voffset = it->voffset;
88d75730 1574 glyph->type = STRETCH_GLYPH;
06a2c219 1575 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1576 glyph->left_box_line_p = it->start_of_box_run_p;
1577 glyph->right_box_line_p = it->end_of_box_run_p;
1578 glyph->overlaps_vertically_p = 0;
1579 glyph->padding_p = 0;
1580 glyph->glyph_not_available_p = 0;
1581 glyph->face_id = it->face_id;
1582 glyph->u.stretch.ascent = height * ascent;
1583 glyph->u.stretch.height = height;
06a2c219
GM
1584 ++it->glyph_row->used[area];
1585 }
1586}
1587
1588
1589/* Produce a stretch glyph for iterator IT. IT->object is the value
1590 of the glyph property displayed. The value must be a list
1591 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1592 being recognized:
1593
1594 1. `:width WIDTH' specifies that the space should be WIDTH *
1595 canonical char width wide. WIDTH may be an integer or floating
1596 point number.
1597
1598 2. `:relative-width FACTOR' specifies that the width of the stretch
1599 should be computed from the width of the first character having the
1600 `glyph' property, and should be FACTOR times that width.
1601
1602 3. `:align-to HPOS' specifies that the space should be wide enough
1603 to reach HPOS, a value in canonical character units.
1604
1605 Exactly one of the above pairs must be present.
1606
1607 4. `:height HEIGHT' specifies that the height of the stretch produced
1608 should be HEIGHT, measured in canonical character units.
1609
1610 5. `:relative-height FACTOR' specifies that the height of the the
1611 stretch should be FACTOR times the height of the characters having
1612 the glyph property.
1613
1614 Either none or exactly one of 4 or 5 must be present.
1615
1616 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1617 of the stretch should be used for the ascent of the stretch.
1618 ASCENT must be in the range 0 <= ASCENT <= 100. */
1619
1620#define NUMVAL(X) \
1621 ((INTEGERP (X) || FLOATP (X)) \
1622 ? XFLOATINT (X) \
1623 : - 1)
1624
1625
1626static void
1627x_produce_stretch_glyph (it)
1628 struct it *it;
1629{
1630 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1631#if GLYPH_DEBUG
1632 extern Lisp_Object Qspace;
1633#endif
1634 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1635 extern Lisp_Object QCrelative_width, QCrelative_height;
1636 extern Lisp_Object QCalign_to;
1637 Lisp_Object prop, plist;
1638 double width = 0, height = 0, ascent = 0;
1639 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1640 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1641
1642 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1643
1644 /* List should start with `space'. */
1645 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1646 plist = XCDR (it->object);
1647
1648 /* Compute the width of the stretch. */
1649 if (prop = Fplist_get (plist, QCwidth),
1650 NUMVAL (prop) > 0)
1651 /* Absolute width `:width WIDTH' specified and valid. */
1652 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1653 else if (prop = Fplist_get (plist, QCrelative_width),
1654 NUMVAL (prop) > 0)
1655 {
1656 /* Relative width `:relative-width FACTOR' specified and valid.
1657 Compute the width of the characters having the `glyph'
1658 property. */
1659 struct it it2;
1660 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1661
1662 it2 = *it;
1663 if (it->multibyte_p)
1664 {
1665 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1666 - IT_BYTEPOS (*it));
1667 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1668 }
1669 else
1670 it2.c = *p, it2.len = 1;
1671
1672 it2.glyph_row = NULL;
1673 it2.what = IT_CHARACTER;
1674 x_produce_glyphs (&it2);
1675 width = NUMVAL (prop) * it2.pixel_width;
1676 }
1677 else if (prop = Fplist_get (plist, QCalign_to),
1678 NUMVAL (prop) > 0)
1679 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1680 else
1681 /* Nothing specified -> width defaults to canonical char width. */
1682 width = CANON_X_UNIT (it->f);
1683
1684 /* Compute height. */
1685 if (prop = Fplist_get (plist, QCheight),
1686 NUMVAL (prop) > 0)
1687 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1688 else if (prop = Fplist_get (plist, QCrelative_height),
1689 NUMVAL (prop) > 0)
1690 height = FONT_HEIGHT (font) * NUMVAL (prop);
1691 else
1692 height = FONT_HEIGHT (font);
1693
1694 /* Compute percentage of height used for ascent. If
1695 `:ascent ASCENT' is present and valid, use that. Otherwise,
1696 derive the ascent from the font in use. */
1697 if (prop = Fplist_get (plist, QCascent),
1698 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1699 ascent = NUMVAL (prop) / 100.0;
1700 else
1701 ascent = (double) font->ascent / FONT_HEIGHT (font);
1702
1703 if (width <= 0)
1704 width = 1;
1705 if (height <= 0)
1706 height = 1;
1707
1708 if (it->glyph_row)
1709 {
1710 Lisp_Object object = it->stack[it->sp - 1].string;
1711 if (!STRINGP (object))
1712 object = it->w->buffer;
1713 x_append_stretch_glyph (it, object, width, height, ascent);
1714 }
1715
1716 it->pixel_width = width;
66ac4b0e
GM
1717 it->ascent = it->phys_ascent = height * ascent;
1718 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1719 it->nglyphs = 1;
1720
1721 if (face->box != FACE_NO_BOX)
1722 {
ea2ba0d4
KH
1723 if (face->box_line_width > 0)
1724 {
1725 it->ascent += face->box_line_width;
1726 it->descent += face->box_line_width;
1727 }
06a2c219
GM
1728
1729 if (it->start_of_box_run_p)
ea2ba0d4 1730 it->pixel_width += abs (face->box_line_width);
06a2c219 1731 if (it->end_of_box_run_p)
ea2ba0d4 1732 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1733 }
1734
1735 take_vertical_position_into_account (it);
1736}
1737
b4192550
KH
1738/* Return proper value to be used as baseline offset of font that has
1739 ASCENT and DESCENT to draw characters by the font at the vertical
1740 center of the line of frame F.
1741
1742 Here, out task is to find the value of BOFF in the following figure;
1743
1744 -------------------------+-----------+-
1745 -+-+---------+-+ | |
1746 | | | | | |
1747 | | | | F_ASCENT F_HEIGHT
1748 | | | ASCENT | |
1749 HEIGHT | | | | |
1750 | | |-|-+------+-----------|------- baseline
1751 | | | | BOFF | |
1752 | |---------|-+-+ | |
1753 | | | DESCENT | |
1754 -+-+---------+-+ F_DESCENT |
1755 -------------------------+-----------+-
1756
1757 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1758 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1759 DESCENT = FONT->descent
1760 HEIGHT = FONT_HEIGHT (FONT)
1761 F_DESCENT = (F->output_data.x->font->descent
1762 - F->output_data.x->baseline_offset)
1763 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1764*/
1765
458f45fa
KH
1766#define VCENTER_BASELINE_OFFSET(FONT, F) \
1767 ((FONT)->descent \
1768 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT)) \
1769 + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \
1770 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1771
1772/* Produce glyphs/get display metrics for the display element IT is
1773 loaded with. See the description of struct display_iterator in
1774 dispextern.h for an overview of struct display_iterator. */
1775
1776static void
1777x_produce_glyphs (it)
1778 struct it *it;
1779{
ee569018
KH
1780 it->glyph_not_available_p = 0;
1781
06a2c219
GM
1782 if (it->what == IT_CHARACTER)
1783 {
1784 XChar2b char2b;
1785 XFontStruct *font;
ee569018 1786 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1787 XCharStruct *pcm;
06a2c219 1788 int font_not_found_p;
b4192550
KH
1789 struct font_info *font_info;
1790 int boff; /* baseline offset */
a4249304
KH
1791 /* We may change it->multibyte_p upon unibyte<->multibyte
1792 conversion. So, save the current value now and restore it
1793 later.
1794
1795 Note: It seems that we don't have to record multibyte_p in
1796 struct glyph because the character code itself tells if or
1797 not the character is multibyte. Thus, in the future, we must
1798 consider eliminating the field `multibyte_p' in the struct
c347a1c3 1799 glyph. */
a4249304 1800 int saved_multibyte_p = it->multibyte_p;
06a2c219 1801
ee569018
KH
1802 /* Maybe translate single-byte characters to multibyte, or the
1803 other way. */
06a2c219 1804 it->char_to_display = it->c;
ee569018 1805 if (!ASCII_BYTE_P (it->c))
06a2c219 1806 {
ee569018
KH
1807 if (unibyte_display_via_language_environment
1808 && SINGLE_BYTE_CHAR_P (it->c)
1809 && (it->c >= 0240
1810 || !NILP (Vnonascii_translation_table)))
1811 {
1812 it->char_to_display = unibyte_char_to_multibyte (it->c);
a4249304 1813 it->multibyte_p = 1;
ee569018
KH
1814 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1815 face = FACE_FROM_ID (it->f, it->face_id);
1816 }
1817 else if (!SINGLE_BYTE_CHAR_P (it->c)
1818 && !it->multibyte_p)
1819 {
c347a1c3 1820 it->multibyte_p = 1;
ee569018
KH
1821 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1822 face = FACE_FROM_ID (it->f, it->face_id);
1823 }
06a2c219
GM
1824 }
1825
ee569018
KH
1826 /* Get font to use. Encode IT->char_to_display. */
1827 x_get_char_face_and_encoding (it->f, it->char_to_display,
1828 it->face_id, &char2b,
1829 it->multibyte_p);
06a2c219
GM
1830 font = face->font;
1831
1832 /* When no suitable font found, use the default font. */
1833 font_not_found_p = font == NULL;
1834 if (font_not_found_p)
b4192550
KH
1835 {
1836 font = FRAME_FONT (it->f);
1837 boff = it->f->output_data.x->baseline_offset;
1838 font_info = NULL;
1839 }
1840 else
1841 {
1842 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1843 boff = font_info->baseline_offset;
1844 if (font_info->vertical_centering)
1845 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1846 }
06a2c219
GM
1847
1848 if (it->char_to_display >= ' '
1849 && (!it->multibyte_p || it->char_to_display < 128))
1850 {
1851 /* Either unibyte or ASCII. */
1852 int stretched_p;
1853
1854 it->nglyphs = 1;
06a2c219
GM
1855
1856 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1857 it->ascent = font->ascent + boff;
1858 it->descent = font->descent - boff;
474848ac
GM
1859
1860 if (pcm)
1861 {
1862 it->phys_ascent = pcm->ascent + boff;
1863 it->phys_descent = pcm->descent - boff;
1864 it->pixel_width = pcm->width;
1865 }
1866 else
1867 {
1868 it->glyph_not_available_p = 1;
1869 it->phys_ascent = font->ascent + boff;
1870 it->phys_descent = font->descent - boff;
1871 it->pixel_width = FONT_WIDTH (font);
1872 }
06a2c219
GM
1873
1874 /* If this is a space inside a region of text with
1875 `space-width' property, change its width. */
1876 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1877 if (stretched_p)
1878 it->pixel_width *= XFLOATINT (it->space_width);
1879
1880 /* If face has a box, add the box thickness to the character
1881 height. If character has a box line to the left and/or
1882 right, add the box line width to the character's width. */
1883 if (face->box != FACE_NO_BOX)
1884 {
1885 int thick = face->box_line_width;
1886
ea2ba0d4
KH
1887 if (thick > 0)
1888 {
1889 it->ascent += thick;
1890 it->descent += thick;
1891 }
1892 else
1893 thick = -thick;
1894
06a2c219
GM
1895 if (it->start_of_box_run_p)
1896 it->pixel_width += thick;
1897 if (it->end_of_box_run_p)
1898 it->pixel_width += thick;
1899 }
1900
1901 /* If face has an overline, add the height of the overline
1902 (1 pixel) and a 1 pixel margin to the character height. */
1903 if (face->overline_p)
1904 it->ascent += 2;
1905
1906 take_vertical_position_into_account (it);
1907
1908 /* If we have to actually produce glyphs, do it. */
1909 if (it->glyph_row)
1910 {
1911 if (stretched_p)
1912 {
1913 /* Translate a space with a `space-width' property
1914 into a stretch glyph. */
1915 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1916 x_append_stretch_glyph (it, it->object, it->pixel_width,
1917 it->ascent + it->descent, ascent);
1918 }
1919 else
1920 x_append_glyph (it);
1921
1922 /* If characters with lbearing or rbearing are displayed
1923 in this line, record that fact in a flag of the
1924 glyph row. This is used to optimize X output code. */
1c7e22fd 1925 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1926 it->glyph_row->contains_overlapping_glyphs_p = 1;
1927 }
1928 }
1929 else if (it->char_to_display == '\n')
1930 {
1931 /* A newline has no width but we need the height of the line. */
1932 it->pixel_width = 0;
1933 it->nglyphs = 0;
b4192550
KH
1934 it->ascent = it->phys_ascent = font->ascent + boff;
1935 it->descent = it->phys_descent = font->descent - boff;
06a2c219 1936
ea2ba0d4
KH
1937 if (face->box != FACE_NO_BOX
1938 && face->box_line_width > 0)
06a2c219 1939 {
ea2ba0d4
KH
1940 it->ascent += face->box_line_width;
1941 it->descent += face->box_line_width;
06a2c219
GM
1942 }
1943 }
1944 else if (it->char_to_display == '\t')
1945 {
1946 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1947 int x = it->current_x + it->continuation_lines_width;
06a2c219 1948 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
2a32b5ea
GM
1949
1950 /* If the distance from the current position to the next tab
1951 stop is less than a canonical character width, use the
1952 tab stop after that. */
1953 if (next_tab_x - x < CANON_X_UNIT (it->f))
1954 next_tab_x += tab_width;
06a2c219
GM
1955
1956 it->pixel_width = next_tab_x - x;
1957 it->nglyphs = 1;
b4192550
KH
1958 it->ascent = it->phys_ascent = font->ascent + boff;
1959 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1960
1961 if (it->glyph_row)
1962 {
1963 double ascent = (double) it->ascent / (it->ascent + it->descent);
1964 x_append_stretch_glyph (it, it->object, it->pixel_width,
1965 it->ascent + it->descent, ascent);
1966 }
1967 }
1968 else
1969 {
1970 /* A multi-byte character. Assume that the display width of the
1971 character is the width of the character multiplied by the
b4192550 1972 width of the font. */
06a2c219 1973
b4192550
KH
1974 /* If we found a font, this font should give us the right
1975 metrics. If we didn't find a font, use the frame's
1976 default font and calculate the width of the character
1977 from the charset width; this is what old redisplay code
1978 did. */
1979 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
1980 if (font_not_found_p || !pcm)
1981 {
1982 int charset = CHAR_CHARSET (it->char_to_display);
1983
1984 it->glyph_not_available_p = 1;
1985 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
1986 * CHARSET_WIDTH (charset));
1987 it->phys_ascent = font->ascent + boff;
1988 it->phys_descent = font->descent - boff;
1989 }
1990 else
1991 {
1992 it->pixel_width = pcm->width;
1993 it->phys_ascent = pcm->ascent + boff;
1994 it->phys_descent = pcm->descent - boff;
1995 if (it->glyph_row
1996 && (pcm->lbearing < 0
1997 || pcm->rbearing > pcm->width))
1998 it->glyph_row->contains_overlapping_glyphs_p = 1;
1999 }
b4192550
KH
2000 it->nglyphs = 1;
2001 it->ascent = font->ascent + boff;
2002 it->descent = font->descent - boff;
06a2c219
GM
2003 if (face->box != FACE_NO_BOX)
2004 {
2005 int thick = face->box_line_width;
ea2ba0d4
KH
2006
2007 if (thick > 0)
2008 {
2009 it->ascent += thick;
2010 it->descent += thick;
2011 }
2012 else
2013 thick = - thick;
06a2c219
GM
2014
2015 if (it->start_of_box_run_p)
2016 it->pixel_width += thick;
2017 if (it->end_of_box_run_p)
2018 it->pixel_width += thick;
2019 }
2020
2021 /* If face has an overline, add the height of the overline
2022 (1 pixel) and a 1 pixel margin to the character height. */
2023 if (face->overline_p)
2024 it->ascent += 2;
2025
2026 take_vertical_position_into_account (it);
2027
2028 if (it->glyph_row)
2029 x_append_glyph (it);
2030 }
a4249304 2031 it->multibyte_p = saved_multibyte_p;
06a2c219 2032 }
b4192550
KH
2033 else if (it->what == IT_COMPOSITION)
2034 {
2035 /* Note: A composition is represented as one glyph in the
2036 glyph matrix. There are no padding glyphs. */
2037 XChar2b char2b;
2038 XFontStruct *font;
ee569018 2039 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2040 XCharStruct *pcm;
2041 int font_not_found_p;
2042 struct font_info *font_info;
2043 int boff; /* baseline offset */
2044 struct composition *cmp = composition_table[it->cmp_id];
2045
2046 /* Maybe translate single-byte characters to multibyte. */
2047 it->char_to_display = it->c;
2048 if (unibyte_display_via_language_environment
2049 && SINGLE_BYTE_CHAR_P (it->c)
2050 && (it->c >= 0240
2051 || (it->c >= 0200
2052 && !NILP (Vnonascii_translation_table))))
2053 {
2054 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2055 }
2056
2057 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2058 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2059 face = FACE_FROM_ID (it->f, it->face_id);
2060 x_get_char_face_and_encoding (it->f, it->char_to_display,
2061 it->face_id, &char2b, it->multibyte_p);
b4192550
KH
2062 font = face->font;
2063
2064 /* When no suitable font found, use the default font. */
2065 font_not_found_p = font == NULL;
2066 if (font_not_found_p)
2067 {
2068 font = FRAME_FONT (it->f);
2069 boff = it->f->output_data.x->baseline_offset;
2070 font_info = NULL;
2071 }
2072 else
2073 {
2074 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2075 boff = font_info->baseline_offset;
2076 if (font_info->vertical_centering)
2077 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2078 }
2079
2080 /* There are no padding glyphs, so there is only one glyph to
2081 produce for the composition. Important is that pixel_width,
2082 ascent and descent are the values of what is drawn by
2083 draw_glyphs (i.e. the values of the overall glyphs composed). */
2084 it->nglyphs = 1;
2085
2086 /* If we have not yet calculated pixel size data of glyphs of
2087 the composition for the current face font, calculate them
2088 now. Theoretically, we have to check all fonts for the
2089 glyphs, but that requires much time and memory space. So,
2090 here we check only the font of the first glyph. This leads
2091 to incorrect display very rarely, and C-l (recenter) can
2092 correct the display anyway. */
2093 if (cmp->font != (void *) font)
2094 {
2095 /* Ascent and descent of the font of the first character of
2096 this composition (adjusted by baseline offset). Ascent
2097 and descent of overall glyphs should not be less than
2098 them respectively. */
2099 int font_ascent = font->ascent + boff;
2100 int font_descent = font->descent - boff;
2101 /* Bounding box of the overall glyphs. */
2102 int leftmost, rightmost, lowest, highest;
329bed06 2103 int i, width, ascent, descent;
b4192550
KH
2104
2105 cmp->font = (void *) font;
2106
2107 /* Initialize the bounding box. */
1bdeec2e
KH
2108 if (font_info
2109 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2110 {
2111 width = pcm->width;
2112 ascent = pcm->ascent;
2113 descent = pcm->descent;
2114 }
2115 else
2116 {
2117 width = FONT_WIDTH (font);
2118 ascent = font->ascent;
2119 descent = font->descent;
2120 }
2121
2122 rightmost = width;
2123 lowest = - descent + boff;
2124 highest = ascent + boff;
b4192550 2125 leftmost = 0;
329bed06 2126
b4192550
KH
2127 if (font_info
2128 && font_info->default_ascent
2129 && CHAR_TABLE_P (Vuse_default_ascent)
2130 && !NILP (Faref (Vuse_default_ascent,
2131 make_number (it->char_to_display))))
2132 highest = font_info->default_ascent + boff;
2133
2134 /* Draw the first glyph at the normal position. It may be
2135 shifted to right later if some other glyphs are drawn at
2136 the left. */
2137 cmp->offsets[0] = 0;
2138 cmp->offsets[1] = boff;
2139
2140 /* Set cmp->offsets for the remaining glyphs. */
2141 for (i = 1; i < cmp->glyph_len; i++)
2142 {
2143 int left, right, btm, top;
2144 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2145 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2146
2147 face = FACE_FROM_ID (it->f, face_id);
2148 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2149 it->multibyte_p);
b4192550
KH
2150 font = face->font;
2151 if (font == NULL)
2152 {
2153 font = FRAME_FONT (it->f);
2154 boff = it->f->output_data.x->baseline_offset;
2155 font_info = NULL;
2156 }
2157 else
2158 {
2159 font_info
2160 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2161 boff = font_info->baseline_offset;
2162 if (font_info->vertical_centering)
2163 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2164 }
2165
1bdeec2e
KH
2166 if (font_info
2167 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2168 {
2169 width = pcm->width;
2170 ascent = pcm->ascent;
2171 descent = pcm->descent;
2172 }
2173 else
2174 {
2175 width = FONT_WIDTH (font);
1bdeec2e
KH
2176 ascent = 1;
2177 descent = 0;
329bed06 2178 }
b4192550
KH
2179
2180 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2181 {
2182 /* Relative composition with or without
2183 alternate chars. */
329bed06
GM
2184 left = (leftmost + rightmost - width) / 2;
2185 btm = - descent + boff;
b4192550
KH
2186 if (font_info && font_info->relative_compose
2187 && (! CHAR_TABLE_P (Vignore_relative_composition)
2188 || NILP (Faref (Vignore_relative_composition,
2189 make_number (ch)))))
2190 {
2191
329bed06 2192 if (- descent >= font_info->relative_compose)
b4192550
KH
2193 /* One extra pixel between two glyphs. */
2194 btm = highest + 1;
329bed06 2195 else if (ascent <= 0)
b4192550 2196 /* One extra pixel between two glyphs. */
329bed06 2197 btm = lowest - 1 - ascent - descent;
b4192550
KH
2198 }
2199 }
2200 else
2201 {
2202 /* A composition rule is specified by an integer
2203 value that encodes global and new reference
2204 points (GREF and NREF). GREF and NREF are
2205 specified by numbers as below:
2206
2207 0---1---2 -- ascent
2208 | |
2209 | |
2210 | |
2211 9--10--11 -- center
2212 | |
2213 ---3---4---5--- baseline
2214 | |
2215 6---7---8 -- descent
2216 */
2217 int rule = COMPOSITION_RULE (cmp, i);
2218 int gref, nref, grefx, grefy, nrefx, nrefy;
2219
2220 COMPOSITION_DECODE_RULE (rule, gref, nref);
2221 grefx = gref % 3, nrefx = nref % 3;
2222 grefy = gref / 3, nrefy = nref / 3;
2223
2224 left = (leftmost
2225 + grefx * (rightmost - leftmost) / 2
329bed06 2226 - nrefx * width / 2);
b4192550
KH
2227 btm = ((grefy == 0 ? highest
2228 : grefy == 1 ? 0
2229 : grefy == 2 ? lowest
2230 : (highest + lowest) / 2)
329bed06
GM
2231 - (nrefy == 0 ? ascent + descent
2232 : nrefy == 1 ? descent - boff
b4192550 2233 : nrefy == 2 ? 0
329bed06 2234 : (ascent + descent) / 2));
b4192550
KH
2235 }
2236
2237 cmp->offsets[i * 2] = left;
329bed06 2238 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2239
2240 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2241 right = left + width;
2242 top = btm + descent + ascent;
b4192550
KH
2243 if (left < leftmost)
2244 leftmost = left;
2245 if (right > rightmost)
2246 rightmost = right;
2247 if (top > highest)
2248 highest = top;
2249 if (btm < lowest)
2250 lowest = btm;
2251 }
2252
2253 /* If there are glyphs whose x-offsets are negative,
2254 shift all glyphs to the right and make all x-offsets
2255 non-negative. */
2256 if (leftmost < 0)
2257 {
2258 for (i = 0; i < cmp->glyph_len; i++)
2259 cmp->offsets[i * 2] -= leftmost;
2260 rightmost -= leftmost;
2261 }
2262
2263 cmp->pixel_width = rightmost;
2264 cmp->ascent = highest;
2265 cmp->descent = - lowest;
2266 if (cmp->ascent < font_ascent)
2267 cmp->ascent = font_ascent;
2268 if (cmp->descent < font_descent)
2269 cmp->descent = font_descent;
2270 }
2271
2272 it->pixel_width = cmp->pixel_width;
2273 it->ascent = it->phys_ascent = cmp->ascent;
2274 it->descent = it->phys_descent = cmp->descent;
2275
2276 if (face->box != FACE_NO_BOX)
2277 {
2278 int thick = face->box_line_width;
ea2ba0d4
KH
2279
2280 if (thick > 0)
2281 {
2282 it->ascent += thick;
2283 it->descent += thick;
2284 }
2285 else
2286 thick = - thick;
b4192550
KH
2287
2288 if (it->start_of_box_run_p)
2289 it->pixel_width += thick;
2290 if (it->end_of_box_run_p)
2291 it->pixel_width += thick;
2292 }
2293
2294 /* If face has an overline, add the height of the overline
2295 (1 pixel) and a 1 pixel margin to the character height. */
2296 if (face->overline_p)
2297 it->ascent += 2;
2298
2299 take_vertical_position_into_account (it);
2300
2301 if (it->glyph_row)
2302 x_append_composite_glyph (it);
2303 }
06a2c219
GM
2304 else if (it->what == IT_IMAGE)
2305 x_produce_image_glyph (it);
2306 else if (it->what == IT_STRETCH)
2307 x_produce_stretch_glyph (it);
2308
3017fdd1
GM
2309 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2310 because this isn't true for images with `:ascent 100'. */
2311 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2312 if (it->area == TEXT_AREA)
2313 it->current_x += it->pixel_width;
66ac4b0e 2314
d365f5bb
GM
2315 it->descent += it->extra_line_spacing;
2316
06a2c219
GM
2317 it->max_ascent = max (it->max_ascent, it->ascent);
2318 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2319 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2320 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2321}
2322
2323
2324/* Estimate the pixel height of the mode or top line on frame F.
2325 FACE_ID specifies what line's height to estimate. */
2326
2327int
2328x_estimate_mode_line_height (f, face_id)
2329 struct frame *f;
2330 enum face_id face_id;
2331{
43281ee3 2332 int height = FONT_HEIGHT (FRAME_FONT (f));
06a2c219
GM
2333
2334 /* This function is called so early when Emacs starts that the face
2335 cache and mode line face are not yet initialized. */
2336 if (FRAME_FACE_CACHE (f))
2337 {
2338 struct face *face = FACE_FROM_ID (f, face_id);
2339 if (face)
43281ee3
GM
2340 {
2341 if (face->font)
2342 height = FONT_HEIGHT (face->font);
ea2ba0d4
KH
2343 if (face->box_line_width > 0)
2344 height += 2 * face->box_line_width;
43281ee3 2345 }
06a2c219
GM
2346 }
2347
2348 return height;
2349}
2350
2351\f
2352/***********************************************************************
2353 Glyph display
2354 ***********************************************************************/
2355
2356/* A sequence of glyphs to be drawn in the same face.
2357
2358 This data structure is not really completely X specific, so it
2359 could possibly, at least partially, be useful for other systems. It
2360 is currently not part of the external redisplay interface because
2361 it's not clear what other systems will need. */
2362
2363struct glyph_string
2364{
2365 /* X-origin of the string. */
2366 int x;
2367
2368 /* Y-origin and y-position of the base line of this string. */
2369 int y, ybase;
2370
2371 /* The width of the string, not including a face extension. */
2372 int width;
2373
2374 /* The width of the string, including a face extension. */
2375 int background_width;
2376
2377 /* The height of this string. This is the height of the line this
2378 string is drawn in, and can be different from the height of the
2379 font the string is drawn in. */
2380 int height;
2381
2382 /* Number of pixels this string overwrites in front of its x-origin.
2383 This number is zero if the string has an lbearing >= 0; it is
2384 -lbearing, if the string has an lbearing < 0. */
2385 int left_overhang;
2386
2387 /* Number of pixels this string overwrites past its right-most
2388 nominal x-position, i.e. x + width. Zero if the string's
2389 rbearing is <= its nominal width, rbearing - width otherwise. */
2390 int right_overhang;
2391
2392 /* The frame on which the glyph string is drawn. */
2393 struct frame *f;
2394
2395 /* The window on which the glyph string is drawn. */
2396 struct window *w;
2397
2398 /* X display and window for convenience. */
2399 Display *display;
2400 Window window;
2401
2402 /* The glyph row for which this string was built. It determines the
2403 y-origin and height of the string. */
2404 struct glyph_row *row;
2405
2406 /* The area within row. */
2407 enum glyph_row_area area;
2408
2409 /* Characters to be drawn, and number of characters. */
2410 XChar2b *char2b;
2411 int nchars;
2412
06a2c219
GM
2413 /* A face-override for drawing cursors, mouse face and similar. */
2414 enum draw_glyphs_face hl;
2415
2416 /* Face in which this string is to be drawn. */
2417 struct face *face;
2418
2419 /* Font in which this string is to be drawn. */
2420 XFontStruct *font;
2421
2422 /* Font info for this string. */
2423 struct font_info *font_info;
2424
b4192550
KH
2425 /* Non-null means this string describes (part of) a composition.
2426 All characters from char2b are drawn composed. */
2427 struct composition *cmp;
06a2c219
GM
2428
2429 /* Index of this glyph string's first character in the glyph
b4192550
KH
2430 definition of CMP. If this is zero, this glyph string describes
2431 the first character of a composition. */
06a2c219
GM
2432 int gidx;
2433
2434 /* 1 means this glyph strings face has to be drawn to the right end
2435 of the window's drawing area. */
2436 unsigned extends_to_end_of_line_p : 1;
2437
2438 /* 1 means the background of this string has been drawn. */
2439 unsigned background_filled_p : 1;
2440
2441 /* 1 means glyph string must be drawn with 16-bit functions. */
2442 unsigned two_byte_p : 1;
2443
2444 /* 1 means that the original font determined for drawing this glyph
2445 string could not be loaded. The member `font' has been set to
2446 the frame's default font in this case. */
2447 unsigned font_not_found_p : 1;
2448
2449 /* 1 means that the face in which this glyph string is drawn has a
2450 stipple pattern. */
2451 unsigned stippled_p : 1;
2452
66ac4b0e
GM
2453 /* 1 means only the foreground of this glyph string must be drawn,
2454 and we should use the physical height of the line this glyph
2455 string appears in as clip rect. */
2456 unsigned for_overlaps_p : 1;
2457
06a2c219
GM
2458 /* The GC to use for drawing this glyph string. */
2459 GC gc;
2460
2461 /* A pointer to the first glyph in the string. This glyph
2462 corresponds to char2b[0]. Needed to draw rectangles if
2463 font_not_found_p is 1. */
2464 struct glyph *first_glyph;
2465
2466 /* Image, if any. */
2467 struct image *img;
2468
2469 struct glyph_string *next, *prev;
2470};
2471
2472
61869b99 2473#if GLYPH_DEBUG
06a2c219
GM
2474
2475static void
2476x_dump_glyph_string (s)
2477 struct glyph_string *s;
2478{
2479 fprintf (stderr, "glyph string\n");
2480 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2481 s->x, s->y, s->width, s->height);
2482 fprintf (stderr, " ybase = %d\n", s->ybase);
2483 fprintf (stderr, " hl = %d\n", s->hl);
2484 fprintf (stderr, " left overhang = %d, right = %d\n",
2485 s->left_overhang, s->right_overhang);
2486 fprintf (stderr, " nchars = %d\n", s->nchars);
2487 fprintf (stderr, " extends to end of line = %d\n",
2488 s->extends_to_end_of_line_p);
2489 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2490 fprintf (stderr, " bg width = %d\n", s->background_width);
2491}
2492
2493#endif /* GLYPH_DEBUG */
2494
2495
2496
2497static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2498 struct glyph_string **,
2499 struct glyph_string *,
2500 struct glyph_string *));
2501static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2502 struct glyph_string **,
2503 struct glyph_string *,
2504 struct glyph_string *));
2505static void x_append_glyph_string P_ ((struct glyph_string **,
2506 struct glyph_string **,
2507 struct glyph_string *));
2508static int x_left_overwritten P_ ((struct glyph_string *));
2509static int x_left_overwriting P_ ((struct glyph_string *));
2510static int x_right_overwritten P_ ((struct glyph_string *));
2511static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2512static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2513 int));
06a2c219
GM
2514static void x_init_glyph_string P_ ((struct glyph_string *,
2515 XChar2b *, struct window *,
2516 struct glyph_row *,
2517 enum glyph_row_area, int,
2518 enum draw_glyphs_face));
2519static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2520 enum glyph_row_area, int, int,
f0a48a01 2521 enum draw_glyphs_face, int));
06a2c219
GM
2522static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2523static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2524static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2525 int));
2526static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2527static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2528static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2529static void x_draw_glyph_string P_ ((struct glyph_string *));
2530static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2531static void x_set_cursor_gc P_ ((struct glyph_string *));
2532static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2533static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2534static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2535 int *, int *));
2536static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2537static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2538 unsigned long *, double, int));
06a2c219 2539static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2540 double, int, unsigned long));
06a2c219
GM
2541static void x_setup_relief_colors P_ ((struct glyph_string *));
2542static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2543static void x_draw_image_relief P_ ((struct glyph_string *));
2544static void x_draw_image_foreground P_ ((struct glyph_string *));
2545static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2546static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2547static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2548 int, int, int));
2549static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2550 int, int, int, int, XRectangle *));
2551static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2552 int, int, int, XRectangle *));
66ac4b0e
GM
2553static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2554 enum glyph_row_area));
209f68d9
GM
2555static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2556 struct glyph_row *,
2557 enum glyph_row_area, int, int));
06a2c219 2558
163dcff3
GM
2559#if GLYPH_DEBUG
2560static void x_check_font P_ ((struct frame *, XFontStruct *));
2561#endif
2562
06a2c219 2563
06a2c219
GM
2564/* Append the list of glyph strings with head H and tail T to the list
2565 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2566
2567static INLINE void
2568x_append_glyph_string_lists (head, tail, h, t)
2569 struct glyph_string **head, **tail;
2570 struct glyph_string *h, *t;
2571{
2572 if (h)
2573 {
2574 if (*head)
2575 (*tail)->next = h;
2576 else
2577 *head = h;
2578 h->prev = *tail;
2579 *tail = t;
2580 }
2581}
2582
2583
2584/* Prepend the list of glyph strings with head H and tail T to the
2585 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2586 result. */
2587
2588static INLINE void
2589x_prepend_glyph_string_lists (head, tail, h, t)
2590 struct glyph_string **head, **tail;
2591 struct glyph_string *h, *t;
2592{
2593 if (h)
2594 {
2595 if (*head)
2596 (*head)->prev = t;
2597 else
2598 *tail = t;
2599 t->next = *head;
2600 *head = h;
2601 }
2602}
2603
2604
2605/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2606 Set *HEAD and *TAIL to the resulting list. */
2607
2608static INLINE void
2609x_append_glyph_string (head, tail, s)
2610 struct glyph_string **head, **tail;
2611 struct glyph_string *s;
2612{
2613 s->next = s->prev = NULL;
2614 x_append_glyph_string_lists (head, tail, s, s);
2615}
2616
2617
2618/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2619 face. */
2620
2621static void
2622x_set_cursor_gc (s)
2623 struct glyph_string *s;
2624{
2625 if (s->font == FRAME_FONT (s->f)
2626 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2627 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2628 && !s->cmp)
06a2c219
GM
2629 s->gc = s->f->output_data.x->cursor_gc;
2630 else
2631 {
2632 /* Cursor on non-default face: must merge. */
2633 XGCValues xgcv;
2634 unsigned long mask;
2635
2636 xgcv.background = s->f->output_data.x->cursor_pixel;
2637 xgcv.foreground = s->face->background;
2638
2639 /* If the glyph would be invisible, try a different foreground. */
2640 if (xgcv.foreground == xgcv.background)
2641 xgcv.foreground = s->face->foreground;
2642 if (xgcv.foreground == xgcv.background)
2643 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2644 if (xgcv.foreground == xgcv.background)
2645 xgcv.foreground = s->face->foreground;
2646
2647 /* Make sure the cursor is distinct from text in this face. */
2648 if (xgcv.background == s->face->background
2649 && xgcv.foreground == s->face->foreground)
2650 {
2651 xgcv.background = s->face->foreground;
2652 xgcv.foreground = s->face->background;
2653 }
2654
2655 IF_DEBUG (x_check_font (s->f, s->font));
2656 xgcv.font = s->font->fid;
2657 xgcv.graphics_exposures = False;
2658 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2659
2660 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2661 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2662 mask, &xgcv);
2663 else
2664 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2665 = XCreateGC (s->display, s->window, mask, &xgcv);
2666
2667 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2668 }
2669}
2670
2671
2672/* Set up S->gc of glyph string S for drawing text in mouse face. */
2673
2674static void
2675x_set_mouse_face_gc (s)
2676 struct glyph_string *s;
2677{
2678 int face_id;
ee569018 2679 struct face *face;
06a2c219 2680
e4ded23c 2681 /* What face has to be used last for the mouse face? */
06a2c219 2682 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2683 face = FACE_FROM_ID (s->f, face_id);
e4ded23c
GM
2684 if (face == NULL)
2685 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2686
033e3e18
GM
2687 if (s->first_glyph->type == CHAR_GLYPH)
2688 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2689 else
2690 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2691 s->face = FACE_FROM_ID (s->f, face_id);
2692 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2693
2694 /* If font in this face is same as S->font, use it. */
2695 if (s->font == s->face->font)
2696 s->gc = s->face->gc;
2697 else
2698 {
2699 /* Otherwise construct scratch_cursor_gc with values from FACE
2700 but font FONT. */
2701 XGCValues xgcv;
2702 unsigned long mask;
2703
2704 xgcv.background = s->face->background;
2705 xgcv.foreground = s->face->foreground;
2706 IF_DEBUG (x_check_font (s->f, s->font));
2707 xgcv.font = s->font->fid;
2708 xgcv.graphics_exposures = False;
2709 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2710
2711 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2712 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2713 mask, &xgcv);
2714 else
2715 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2716 = XCreateGC (s->display, s->window, mask, &xgcv);
2717
2718 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2719 }
2720
2721 xassert (s->gc != 0);
2722}
2723
2724
2725/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2726 Faces to use in the mode line have already been computed when the
2727 matrix was built, so there isn't much to do, here. */
2728
2729static INLINE void
2730x_set_mode_line_face_gc (s)
2731 struct glyph_string *s;
2732{
2733 s->gc = s->face->gc;
06a2c219
GM
2734}
2735
2736
2737/* Set S->gc of glyph string S for drawing that glyph string. Set
2738 S->stippled_p to a non-zero value if the face of S has a stipple
2739 pattern. */
2740
2741static INLINE void
2742x_set_glyph_string_gc (s)
2743 struct glyph_string *s;
2744{
209f68d9
GM
2745 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2746
06a2c219
GM
2747 if (s->hl == DRAW_NORMAL_TEXT)
2748 {
2749 s->gc = s->face->gc;
2750 s->stippled_p = s->face->stipple != 0;
2751 }
2752 else if (s->hl == DRAW_INVERSE_VIDEO)
2753 {
2754 x_set_mode_line_face_gc (s);
2755 s->stippled_p = s->face->stipple != 0;
2756 }
2757 else if (s->hl == DRAW_CURSOR)
2758 {
2759 x_set_cursor_gc (s);
2760 s->stippled_p = 0;
2761 }
2762 else if (s->hl == DRAW_MOUSE_FACE)
2763 {
2764 x_set_mouse_face_gc (s);
2765 s->stippled_p = s->face->stipple != 0;
2766 }
2767 else if (s->hl == DRAW_IMAGE_RAISED
2768 || s->hl == DRAW_IMAGE_SUNKEN)
2769 {
2770 s->gc = s->face->gc;
2771 s->stippled_p = s->face->stipple != 0;
2772 }
2773 else
2774 {
2775 s->gc = s->face->gc;
2776 s->stippled_p = s->face->stipple != 0;
2777 }
2778
2779 /* GC must have been set. */
2780 xassert (s->gc != 0);
2781}
2782
2783
2784/* Return in *R the clipping rectangle for glyph string S. */
2785
2786static void
2787x_get_glyph_string_clip_rect (s, r)
2788 struct glyph_string *s;
2789 XRectangle *r;
2790{
2791 if (s->row->full_width_p)
2792 {
2793 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2794 int canon_x = CANON_X_UNIT (s->f);
2795
2796 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2797 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2798
2799 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2800 {
1da3fd71 2801 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2802 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2803 r->x -= width;
2804 }
2805
b9432a85 2806 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2807
06a2c219
GM
2808 /* Unless displaying a mode or menu bar line, which are always
2809 fully visible, clip to the visible part of the row. */
2810 if (s->w->pseudo_window_p)
2811 r->height = s->row->visible_height;
2812 else
2813 r->height = s->height;
2814 }
2815 else
2816 {
2817 /* This is a text line that may be partially visible. */
2818 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2819 r->width = window_box_width (s->w, s->area);
2820 r->height = s->row->visible_height;
2821 }
2822
66ac4b0e
GM
2823 /* If S draws overlapping rows, it's sufficient to use the top and
2824 bottom of the window for clipping because this glyph string
2825 intentionally draws over other lines. */
2826 if (s->for_overlaps_p)
2827 {
045dee35 2828 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2829 r->height = window_text_bottom_y (s->w) - r->y;
2830 }
98b8a90f
GM
2831 else
2832 {
2833 /* Don't use S->y for clipping because it doesn't take partially
2834 visible lines into account. For example, it can be negative for
2835 partially visible lines at the top of a window. */
2836 if (!s->row->full_width_p
2837 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
2838 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
2839 else
2840 r->y = max (0, s->row->y);
2841
2842 /* If drawing a tool-bar window, draw it over the internal border
2843 at the top of the window. */
2844 if (s->w == XWINDOW (s->f->tool_bar_window))
2845 r->y -= s->f->output_data.x->internal_border_width;
2846 }
2847
66ac4b0e 2848 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2849}
2850
2851
2852/* Set clipping for output of glyph string S. S may be part of a mode
2853 line or menu if we don't have X toolkit support. */
2854
2855static INLINE void
2856x_set_glyph_string_clipping (s)
2857 struct glyph_string *s;
2858{
2859 XRectangle r;
2860 x_get_glyph_string_clip_rect (s, &r);
2861 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2862}
2863
2864
2865/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2866 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2867
2868static INLINE void
2869x_compute_glyph_string_overhangs (s)
2870 struct glyph_string *s;
2871{
b4192550 2872 if (s->cmp == NULL
06a2c219
GM
2873 && s->first_glyph->type == CHAR_GLYPH)
2874 {
2875 XCharStruct cs;
2876 int direction, font_ascent, font_descent;
2877 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2878 &font_ascent, &font_descent, &cs);
2879 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2880 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2881 }
2882}
2883
2884
2885/* Compute overhangs and x-positions for glyph string S and its
2886 predecessors, or successors. X is the starting x-position for S.
2887 BACKWARD_P non-zero means process predecessors. */
2888
2889static void
2890x_compute_overhangs_and_x (s, x, backward_p)
2891 struct glyph_string *s;
2892 int x;
2893 int backward_p;
2894{
2895 if (backward_p)
2896 {
2897 while (s)
2898 {
2899 x_compute_glyph_string_overhangs (s);
2900 x -= s->width;
2901 s->x = x;
2902 s = s->prev;
2903 }
2904 }
2905 else
2906 {
2907 while (s)
2908 {
2909 x_compute_glyph_string_overhangs (s);
2910 s->x = x;
2911 x += s->width;
2912 s = s->next;
2913 }
2914 }
2915}
2916
2917
2918/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2919 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2920 assumed to be zero. */
06a2c219
GM
2921
2922static void
2923x_get_glyph_overhangs (glyph, f, left, right)
2924 struct glyph *glyph;
2925 struct frame *f;
2926 int *left, *right;
2927{
06a2c219
GM
2928 *left = *right = 0;
2929
b4192550 2930 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2931 {
2932 XFontStruct *font;
2933 struct face *face;
2934 struct font_info *font_info;
2935 XChar2b char2b;
ee569018
KH
2936 XCharStruct *pcm;
2937
2938 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2939 font = face->font;
2940 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2941 if (font
2942 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2943 {
06a2c219
GM
2944 if (pcm->rbearing > pcm->width)
2945 *right = pcm->rbearing - pcm->width;
2946 if (pcm->lbearing < 0)
2947 *left = -pcm->lbearing;
2948 }
2949 }
2950}
2951
2952
2953/* Return the index of the first glyph preceding glyph string S that
2954 is overwritten by S because of S's left overhang. Value is -1
2955 if no glyphs are overwritten. */
2956
2957static int
2958x_left_overwritten (s)
2959 struct glyph_string *s;
2960{
2961 int k;
2962
2963 if (s->left_overhang)
2964 {
2965 int x = 0, i;
2966 struct glyph *glyphs = s->row->glyphs[s->area];
2967 int first = s->first_glyph - glyphs;
2968
2969 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2970 x -= glyphs[i].pixel_width;
2971
2972 k = i + 1;
2973 }
2974 else
2975 k = -1;
2976
2977 return k;
2978}
2979
2980
2981/* Return the index of the first glyph preceding glyph string S that
2982 is overwriting S because of its right overhang. Value is -1 if no
2983 glyph in front of S overwrites S. */
2984
2985static int
2986x_left_overwriting (s)
2987 struct glyph_string *s;
2988{
2989 int i, k, x;
2990 struct glyph *glyphs = s->row->glyphs[s->area];
2991 int first = s->first_glyph - glyphs;
2992
2993 k = -1;
2994 x = 0;
2995 for (i = first - 1; i >= 0; --i)
2996 {
2997 int left, right;
2998 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2999 if (x + right > 0)
3000 k = i;
3001 x -= glyphs[i].pixel_width;
3002 }
3003
3004 return k;
3005}
3006
3007
3008/* Return the index of the last glyph following glyph string S that is
3009 not overwritten by S because of S's right overhang. Value is -1 if
3010 no such glyph is found. */
3011
3012static int
3013x_right_overwritten (s)
3014 struct glyph_string *s;
3015{
3016 int k = -1;
3017
3018 if (s->right_overhang)
3019 {
3020 int x = 0, i;
3021 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3022 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3023 int end = s->row->used[s->area];
3024
3025 for (i = first; i < end && s->right_overhang > x; ++i)
3026 x += glyphs[i].pixel_width;
3027
3028 k = i;
3029 }
3030
3031 return k;
3032}
3033
3034
3035/* Return the index of the last glyph following glyph string S that
3036 overwrites S because of its left overhang. Value is negative
3037 if no such glyph is found. */
3038
3039static int
3040x_right_overwriting (s)
3041 struct glyph_string *s;
3042{
3043 int i, k, x;
3044 int end = s->row->used[s->area];
3045 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3046 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3047
3048 k = -1;
3049 x = 0;
3050 for (i = first; i < end; ++i)
3051 {
3052 int left, right;
3053 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3054 if (x - left < 0)
3055 k = i;
3056 x += glyphs[i].pixel_width;
3057 }
3058
3059 return k;
3060}
3061
3062
3063/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3064
3065static INLINE void
3066x_clear_glyph_string_rect (s, x, y, w, h)
3067 struct glyph_string *s;
3068 int x, y, w, h;
3069{
3070 XGCValues xgcv;
3071 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3072 XSetForeground (s->display, s->gc, xgcv.background);
3073 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3074 XSetForeground (s->display, s->gc, xgcv.foreground);
3075}
3076
3077
3078/* Draw the background of glyph_string S. If S->background_filled_p
3079 is non-zero don't draw it. FORCE_P non-zero means draw the
3080 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3081 when a string preceding S draws into the background of S, or S
3082 contains the first component of a composition. */
06a2c219
GM
3083
3084static void
3085x_draw_glyph_string_background (s, force_p)
3086 struct glyph_string *s;
3087 int force_p;
3088{
3089 /* Nothing to do if background has already been drawn or if it
3090 shouldn't be drawn in the first place. */
3091 if (!s->background_filled_p)
3092 {
ea2ba0d4
KH
3093 int box_line_width = max (s->face->box_line_width, 0);
3094
b4192550 3095 if (s->stippled_p)
06a2c219
GM
3096 {
3097 /* Fill background with a stipple pattern. */
3098 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3099 XFillRectangle (s->display, s->window, s->gc, s->x,
ea2ba0d4 3100 s->y + box_line_width,
06a2c219 3101 s->background_width,
ea2ba0d4 3102 s->height - 2 * box_line_width);
06a2c219
GM
3103 XSetFillStyle (s->display, s->gc, FillSolid);
3104 s->background_filled_p = 1;
3105 }
ea2ba0d4 3106 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
06a2c219
GM
3107 || s->font_not_found_p
3108 || s->extends_to_end_of_line_p
06a2c219
GM
3109 || force_p)
3110 {
ea2ba0d4 3111 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
06a2c219 3112 s->background_width,
ea2ba0d4 3113 s->height - 2 * box_line_width);
06a2c219
GM
3114 s->background_filled_p = 1;
3115 }
3116 }
3117}
3118
3119
3120/* Draw the foreground of glyph string S. */
3121
3122static void
3123x_draw_glyph_string_foreground (s)
3124 struct glyph_string *s;
3125{
3126 int i, x;
3127
3128 /* If first glyph of S has a left box line, start drawing the text
3129 of S to the right of that box line. */
3130 if (s->face->box != FACE_NO_BOX
3131 && s->first_glyph->left_box_line_p)
ea2ba0d4 3132 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
3133 else
3134 x = s->x;
3135
b4192550
KH
3136 /* Draw characters of S as rectangles if S's font could not be
3137 loaded. */
3138 if (s->font_not_found_p)
06a2c219 3139 {
b4192550 3140 for (i = 0; i < s->nchars; ++i)
06a2c219 3141 {
b4192550
KH
3142 struct glyph *g = s->first_glyph + i;
3143 XDrawRectangle (s->display, s->window,
3144 s->gc, x, s->y, g->pixel_width - 1,
3145 s->height - 1);
3146 x += g->pixel_width;
06a2c219
GM
3147 }
3148 }
3149 else
3150 {
b4192550
KH
3151 char *char1b = (char *) s->char2b;
3152 int boff = s->font_info->baseline_offset;
06a2c219 3153
b4192550
KH
3154 if (s->font_info->vertical_centering)
3155 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3156
3157 /* If we can use 8-bit functions, condense S->char2b. */
3158 if (!s->two_byte_p)
3159 for (i = 0; i < s->nchars; ++i)
3160 char1b[i] = s->char2b[i].byte2;
3161
3162 /* Draw text with XDrawString if background has already been
3163 filled. Otherwise, use XDrawImageString. (Note that
3164 XDrawImageString is usually faster than XDrawString.) Always
3165 use XDrawImageString when drawing the cursor so that there is
3166 no chance that characters under a box cursor are invisible. */
3167 if (s->for_overlaps_p
3168 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3169 {
3170 /* Draw characters with 16-bit or 8-bit functions. */
3171 if (s->two_byte_p)
3172 XDrawString16 (s->display, s->window, s->gc, x,
3173 s->ybase - boff, s->char2b, s->nchars);
3174 else
3175 XDrawString (s->display, s->window, s->gc, x,
3176 s->ybase - boff, char1b, s->nchars);
3177 }
06a2c219
GM
3178 else
3179 {
b4192550
KH
3180 if (s->two_byte_p)
3181 XDrawImageString16 (s->display, s->window, s->gc, x,
3182 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3183 else
b4192550
KH
3184 XDrawImageString (s->display, s->window, s->gc, x,
3185 s->ybase - boff, char1b, s->nchars);
3186 }
3187 }
3188}
06a2c219 3189
b4192550 3190/* Draw the foreground of composite glyph string S. */
06a2c219 3191
b4192550
KH
3192static void
3193x_draw_composite_glyph_string_foreground (s)
3194 struct glyph_string *s;
3195{
3196 int i, x;
06a2c219 3197
b4192550
KH
3198 /* If first glyph of S has a left box line, start drawing the text
3199 of S to the right of that box line. */
3200 if (s->face->box != FACE_NO_BOX
3201 && s->first_glyph->left_box_line_p)
ea2ba0d4 3202 x = s->x + abs (s->face->box_line_width);
b4192550
KH
3203 else
3204 x = s->x;
06a2c219 3205
b4192550
KH
3206 /* S is a glyph string for a composition. S->gidx is the index of
3207 the first character drawn for glyphs of this composition.
3208 S->gidx == 0 means we are drawing the very first character of
3209 this composition. */
06a2c219 3210
b4192550
KH
3211 /* Draw a rectangle for the composition if the font for the very
3212 first character of the composition could not be loaded. */
3213 if (s->font_not_found_p)
3214 {
3215 if (s->gidx == 0)
3216 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3217 s->width - 1, s->height - 1);
3218 }
3219 else
3220 {
3221 for (i = 0; i < s->nchars; i++, ++s->gidx)
3222 XDrawString16 (s->display, s->window, s->gc,
3223 x + s->cmp->offsets[s->gidx * 2],
3224 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3225 s->char2b + i, 1);
06a2c219
GM
3226 }
3227}
3228
3229
80c32bcc
GM
3230#ifdef USE_X_TOOLKIT
3231
3e71d8f2 3232static struct frame *x_frame_of_widget P_ ((Widget));
651f03b6
GM
3233static Boolean cvt_string_to_pixel P_ ((Display *, XrmValue *, Cardinal *,
3234 XrmValue *, XrmValue *, XtPointer *));
3235static void cvt_pixel_dtor P_ ((XtAppContext, XrmValue *, XtPointer,
3236 XrmValue *, Cardinal *));
80c32bcc 3237
3e71d8f2
GM
3238
3239/* Return the frame on which widget WIDGET is used.. Abort if frame
3240 cannot be determined. */
3241
e851c833 3242static struct frame *
3e71d8f2 3243x_frame_of_widget (widget)
80c32bcc 3244 Widget widget;
80c32bcc 3245{
80c32bcc 3246 struct x_display_info *dpyinfo;
5c187dee 3247 Lisp_Object tail;
3e71d8f2
GM
3248 struct frame *f;
3249
80c32bcc
GM
3250 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3251
3252 /* Find the top-level shell of the widget. Note that this function
3253 can be called when the widget is not yet realized, so XtWindow
3254 (widget) == 0. That's the reason we can't simply use
3255 x_any_window_to_frame. */
3256 while (!XtIsTopLevelShell (widget))
3257 widget = XtParent (widget);
3258
3259 /* Look for a frame with that top-level widget. Allocate the color
3260 on that frame to get the right gamma correction value. */
3261 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3262 if (GC_FRAMEP (XCAR (tail))
3263 && (f = XFRAME (XCAR (tail)),
3264 (f->output_data.nothing != 1
3265 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3266 && f->output_data.x->widget == widget)
3e71d8f2 3267 return f;
80c32bcc
GM
3268
3269 abort ();
3270}
3271
3e71d8f2
GM
3272
3273/* Allocate the color COLOR->pixel on the screen and display of
3274 widget WIDGET in colormap CMAP. If an exact match cannot be
3275 allocated, try the nearest color available. Value is non-zero
3276 if successful. This is called from lwlib. */
3277
3278int
3279x_alloc_nearest_color_for_widget (widget, cmap, color)
3280 Widget widget;
3281 Colormap cmap;
3282 XColor *color;
3283{
3284 struct frame *f = x_frame_of_widget (widget);
3285 return x_alloc_nearest_color (f, cmap, color);
3286}
3287
3288
46d516e5
MB
3289/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3290 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3291 If this produces the same color as PIXEL, try a color where all RGB
3292 values have DELTA added. Return the allocated color in *PIXEL.
3293 DISPLAY is the X display, CMAP is the colormap to operate on.
3294 Value is non-zero if successful. */
3295
3296int
3297x_alloc_lighter_color_for_widget (widget, display, cmap, pixel, factor, delta)
3298 Widget widget;
3299 Display *display;
3300 Colormap cmap;
3301 unsigned long *pixel;
3302 double factor;
3303 int delta;
3304{
3305 struct frame *f = x_frame_of_widget (widget);
3306 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
3307}
3308
3309
651f03b6
GM
3310/* Structure specifying which arguments should be passed by Xt to
3311 cvt_string_to_pixel. We want the widget's screen and colormap. */
3312
3313static XtConvertArgRec cvt_string_to_pixel_args[] =
3314 {
3315 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.screen),
3316 sizeof (Screen *)},
3317 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.colormap),
3318 sizeof (Colormap)}
3319 };
3320
3321
3322/* The address of this variable is returned by
3323 cvt_string_to_pixel. */
3324
3325static Pixel cvt_string_to_pixel_value;
3326
3327
3328/* Convert a color name to a pixel color.
3329
3330 DPY is the display we are working on.
3331
3332 ARGS is an array of *NARGS XrmValue structures holding additional
3333 information about the widget for which the conversion takes place.
3334 The contents of this array are determined by the specification
3335 in cvt_string_to_pixel_args.
3336
3337 FROM is a pointer to an XrmValue which points to the color name to
3338 convert. TO is an XrmValue in which to return the pixel color.
3339
3340 CLOSURE_RET is a pointer to user-data, in which we record if
3341 we allocated the color or not.
3342
3343 Value is True if successful, False otherwise. */
3344
3345static Boolean
3346cvt_string_to_pixel (dpy, args, nargs, from, to, closure_ret)
3347 Display *dpy;
3348 XrmValue *args;
3349 Cardinal *nargs;
3350 XrmValue *from, *to;
3351 XtPointer *closure_ret;
3352{
3353 Screen *screen;
3354 Colormap cmap;
3355 Pixel pixel;
3356 String color_name;
3357 XColor color;
3358
3359 if (*nargs != 2)
3360 {
3361 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3362 "wrongParameters", "cvt_string_to_pixel",
3363 "XtToolkitError",
3364 "Screen and colormap args required", NULL, NULL);
3365 return False;
3366 }
3367
3368 screen = *(Screen **) args[0].addr;
3369 cmap = *(Colormap *) args[1].addr;
3370 color_name = (String) from->addr;
3371
3372 if (strcmp (color_name, XtDefaultBackground) == 0)
3373 {
3374 *closure_ret = (XtPointer) False;
3375 pixel = WhitePixelOfScreen (screen);
3376 }
3377 else if (strcmp (color_name, XtDefaultForeground) == 0)
3378 {
3379 *closure_ret = (XtPointer) False;
3380 pixel = BlackPixelOfScreen (screen);
3381 }
3382 else if (XParseColor (dpy, cmap, color_name, &color)
3383 && x_alloc_nearest_color_1 (dpy, cmap, &color))
3384 {
3385 pixel = color.pixel;
3386 *closure_ret = (XtPointer) True;
3387 }
3388 else
3389 {
3390 String params[1];
3391 Cardinal nparams = 1;
3392
3393 params[0] = color_name;
3394 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3395 "badValue", "cvt_string_to_pixel",
3396 "XtToolkitError", "Invalid color `%s'",
3397 params, &nparams);
3398 return False;
3399 }
3400
3401 if (to->addr != NULL)
3402 {
3403 if (to->size < sizeof (Pixel))
3404 {
3405 to->size = sizeof (Pixel);
3406 return False;
3407 }
3408
3409 *(Pixel *) to->addr = pixel;
3410 }
3411 else
3412 {
3413 cvt_string_to_pixel_value = pixel;
3414 to->addr = (XtPointer) &cvt_string_to_pixel_value;
3415 }
3416
3417 to->size = sizeof (Pixel);
3418 return True;
3419}
3420
3421
3422/* Free a pixel color which was previously allocated via
3423 cvt_string_to_pixel. This is registered as the destructor
3424 for this type of resource via XtSetTypeConverter.
3425
3426 APP is the application context in which we work.
3427
3428 TO is a pointer to an XrmValue holding the color to free.
3429 CLOSURE is the value we stored in CLOSURE_RET for this color
3430 in cvt_string_to_pixel.
3431
3432 ARGS and NARGS are like for cvt_string_to_pixel. */
3433
3434static void
3435cvt_pixel_dtor (app, to, closure, args, nargs)
3436 XtAppContext app;
3437 XrmValuePtr to;
3438 XtPointer closure;
3439 XrmValuePtr args;
3440 Cardinal *nargs;
3441{
3442 if (*nargs != 2)
3443 {
3444 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
3445 "XtToolkitError",
3446 "Screen and colormap arguments required",
3447 NULL, NULL);
3448 }
3449 else if (closure != NULL)
3450 {
3451 /* We did allocate the pixel, so free it. */
3452 Screen *screen = *(Screen **) args[0].addr;
3453 Colormap cmap = *(Colormap *) args[1].addr;
3454 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
97762eb7 3455 (Pixel *) to->addr, 1);
651f03b6
GM
3456 }
3457}
3458
3459
80c32bcc
GM
3460#endif /* USE_X_TOOLKIT */
3461
3462
f04e1297 3463/* Value is an array of XColor structures for the contents of the
651f03b6 3464 color map of display DPY. Set *NCELLS to the size of the array.
f04e1297
GM
3465 Note that this probably shouldn't be called for large color maps,
3466 say a 24-bit TrueColor map. */
3467
3468static const XColor *
651f03b6
GM
3469x_color_cells (dpy, ncells)
3470 Display *dpy;
f04e1297
GM
3471 int *ncells;
3472{
651f03b6 3473 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
f04e1297
GM
3474
3475 if (dpyinfo->color_cells == NULL)
3476 {
651f03b6 3477 Screen *screen = dpyinfo->screen;
f04e1297
GM
3478 int i;
3479
3480 dpyinfo->ncolor_cells
651f03b6 3481 = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
f04e1297
GM
3482 dpyinfo->color_cells
3483 = (XColor *) xmalloc (dpyinfo->ncolor_cells
3484 * sizeof *dpyinfo->color_cells);
3485
3486 for (i = 0; i < dpyinfo->ncolor_cells; ++i)
3487 dpyinfo->color_cells[i].pixel = i;
3488
651f03b6 3489 XQueryColors (dpy, dpyinfo->cmap,
f04e1297
GM
3490 dpyinfo->color_cells, dpyinfo->ncolor_cells);
3491 }
3492
3493 *ncells = dpyinfo->ncolor_cells;
3494 return dpyinfo->color_cells;
3495}
3496
3497
3498/* On frame F, translate pixel colors to RGB values for the NCOLORS
3499 colors in COLORS. Use cached information, if available. */
3500
3501void
3502x_query_colors (f, colors, ncolors)
3503 struct frame *f;
3504 XColor *colors;
3505 int ncolors;
3506{
3507 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3508
3509 if (dpyinfo->color_cells)
3510 {
3511 int i;
3512 for (i = 0; i < ncolors; ++i)
3513 {
3514 unsigned long pixel = colors[i].pixel;
3515 xassert (pixel < dpyinfo->ncolor_cells);
3516 xassert (dpyinfo->color_cells[pixel].pixel == pixel);
3517 colors[i] = dpyinfo->color_cells[pixel];
3518 }
3519 }
3520 else
3521 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
3522}
3523
3524
3525/* On frame F, translate pixel color to RGB values for the color in
3526 COLOR. Use cached information, if available. */
3527
3528void
3529x_query_color (f, color)
3530 struct frame *f;
3531 XColor *color;
3532{
3533 x_query_colors (f, color, 1);
3534}
3535
3536
651f03b6
GM
3537/* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
3538 exact match can't be allocated, try the nearest color available.
3539 Value is non-zero if successful. Set *COLOR to the color
3540 allocated. */
06a2c219 3541
651f03b6
GM
3542static int
3543x_alloc_nearest_color_1 (dpy, cmap, color)
3544 Display *dpy;
06a2c219
GM
3545 Colormap cmap;
3546 XColor *color;
3547{
80c32bcc
GM
3548 int rc;
3549
651f03b6 3550 rc = XAllocColor (dpy, cmap, color);
06a2c219
GM
3551 if (rc == 0)
3552 {
3553 /* If we got to this point, the colormap is full, so we're going
3554 to try to get the next closest color. The algorithm used is
3555 a least-squares matching, which is what X uses for closest
3556 color matching with StaticColor visuals. */
3557 int nearest, i;
3558 unsigned long nearest_delta = ~0;
f04e1297 3559 int ncells;
651f03b6 3560 const XColor *cells = x_color_cells (dpy, &ncells);
06a2c219
GM
3561
3562 for (nearest = i = 0; i < ncells; ++i)
3563 {
3564 long dred = (color->red >> 8) - (cells[i].red >> 8);
3565 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3566 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3567 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3568
3569 if (delta < nearest_delta)
3570 {
3571 nearest = i;
3572 nearest_delta = delta;
3573 }
3574 }
3575
3576 color->red = cells[nearest].red;
3577 color->green = cells[nearest].green;
3578 color->blue = cells[nearest].blue;
651f03b6 3579 rc = XAllocColor (dpy, cmap, color);
06a2c219 3580 }
35efe0a1
GM
3581 else
3582 {
3583 /* If allocation succeeded, and the allocated pixel color is not
3584 equal to a cached pixel color recorded earlier, there was a
3585 change in the colormap, so clear the color cache. */
651f03b6 3586 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
35efe0a1
GM
3587 XColor *cached_color;
3588
3589 if (dpyinfo->color_cells
3590 && (cached_color = &dpyinfo->color_cells[color->pixel],
cae71efe
GM
3591 (cached_color->red != color->red
3592 || cached_color->blue != color->blue
3593 || cached_color->green != color->green)))
35efe0a1
GM
3594 {
3595 xfree (dpyinfo->color_cells);
3596 dpyinfo->color_cells = NULL;
3597 dpyinfo->ncolor_cells = 0;
3598 }
3599 }
06a2c219 3600
d9c545da
GM
3601#ifdef DEBUG_X_COLORS
3602 if (rc)
3603 register_color (color->pixel);
3604#endif /* DEBUG_X_COLORS */
3605
06a2c219
GM
3606 return rc;
3607}
3608
3609
651f03b6
GM
3610/* Allocate the color COLOR->pixel on frame F, colormap CMAP. If an
3611 exact match can't be allocated, try the nearest color available.
3612 Value is non-zero if successful. Set *COLOR to the color
3613 allocated. */
3614
3615int
3616x_alloc_nearest_color (f, cmap, color)
3617 struct frame *f;
3618 Colormap cmap;
3619 XColor *color;
3620{
3621 gamma_correct (f, color);
3622 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
3623}
3624
3625
d9c545da
GM
3626/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3627 It's necessary to do this instead of just using PIXEL directly to
3628 get color reference counts right. */
3629
3630unsigned long
3631x_copy_color (f, pixel)
3632 struct frame *f;
3633 unsigned long pixel;
3634{
3635 XColor color;
3636
3637 color.pixel = pixel;
3638 BLOCK_INPUT;
f04e1297 3639 x_query_color (f, &color);
d9c545da
GM
3640 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3641 UNBLOCK_INPUT;
3642#ifdef DEBUG_X_COLORS
3643 register_color (pixel);
3644#endif
3645 return color.pixel;
3646}
3647
3648
3e71d8f2
GM
3649/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3650 It's necessary to do this instead of just using PIXEL directly to
3651 get color reference counts right. */
3652
3653unsigned long
3654x_copy_dpy_color (dpy, cmap, pixel)
3655 Display *dpy;
3656 Colormap cmap;
3657 unsigned long pixel;
3658{
3659 XColor color;
3660
3661 color.pixel = pixel;
3662 BLOCK_INPUT;
3663 XQueryColor (dpy, cmap, &color);
3664 XAllocColor (dpy, cmap, &color);
3665 UNBLOCK_INPUT;
3666#ifdef DEBUG_X_COLORS
3667 register_color (pixel);
3668#endif
3669 return color.pixel;
3670}
3671
3672
6d8b0acd 3673/* Brightness beyond which a color won't have its highlight brightness
d7361edf 3674 boosted.
6d8b0acd 3675
d7361edf
MB
3676 Nominally, highlight colors for `3d' faces are calculated by
3677 brightening an object's color by a constant scale factor, but this
3678 doesn't yield good results for dark colors, so for colors who's
3679 brightness is less than this value (on a scale of 0-65535) have an
3680 use an additional additive factor.
6d8b0acd
MB
3681
3682 The value here is set so that the default menu-bar/mode-line color
3683 (grey75) will not have its highlights changed at all. */
3684#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
3685
3686
06a2c219
GM
3687/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3688 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3689 If this produces the same color as PIXEL, try a color where all RGB
3690 values have DELTA added. Return the allocated color in *PIXEL.
3691 DISPLAY is the X display, CMAP is the colormap to operate on.
3692 Value is non-zero if successful. */
3693
3694static int
3695x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3696 struct frame *f;
3697 Display *display;
3698 Colormap cmap;
3699 unsigned long *pixel;
68c45bf0 3700 double factor;
06a2c219
GM
3701 int delta;
3702{
3703 XColor color, new;
6d8b0acd 3704 long bright;
06a2c219
GM
3705 int success_p;
3706
3707 /* Get RGB color values. */
3708 color.pixel = *pixel;
f04e1297 3709 x_query_color (f, &color);
06a2c219
GM
3710
3711 /* Change RGB values by specified FACTOR. Avoid overflow! */
3712 xassert (factor >= 0);
3713 new.red = min (0xffff, factor * color.red);
3714 new.green = min (0xffff, factor * color.green);
3715 new.blue = min (0xffff, factor * color.blue);
3716
d7361edf
MB
3717 /* Calculate brightness of COLOR. */
3718 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
6d8b0acd
MB
3719
3720 /* We only boost colors that are darker than
3721 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3722 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3723 /* Make an additive adjustment to NEW, because it's dark enough so
3724 that scaling by FACTOR alone isn't enough. */
3725 {
3726 /* How far below the limit this color is (0 - 1, 1 being darker). */
3727 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3728 /* The additive adjustment. */
d7361edf 3729 int min_delta = delta * dimness * factor / 2;
6d8b0acd
MB
3730
3731 if (factor < 1)
3732 {
6d8b0acd
MB
3733 new.red = max (0, new.red - min_delta);
3734 new.green = max (0, new.green - min_delta);
3735 new.blue = max (0, new.blue - min_delta);
3736 }
3737 else
3738 {
3739 new.red = min (0xffff, min_delta + new.red);
3740 new.green = min (0xffff, min_delta + new.green);
3741 new.blue = min (0xffff, min_delta + new.blue);
3742 }
3743 }
3744
06a2c219 3745 /* Try to allocate the color. */
80c32bcc 3746 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3747 if (success_p)
3748 {
3749 if (new.pixel == *pixel)
3750 {
3751 /* If we end up with the same color as before, try adding
3752 delta to the RGB values. */
0d605c67 3753 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3754
3755 new.red = min (0xffff, delta + color.red);
3756 new.green = min (0xffff, delta + color.green);
3757 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3758 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3759 }
3760 else
3761 success_p = 1;
3762 *pixel = new.pixel;
3763 }
3764
3765 return success_p;
3766}
3767
3768
3769/* Set up the foreground color for drawing relief lines of glyph
3770 string S. RELIEF is a pointer to a struct relief containing the GC
3771 with which lines will be drawn. Use a color that is FACTOR or
3772 DELTA lighter or darker than the relief's background which is found
3773 in S->f->output_data.x->relief_background. If such a color cannot
3774 be allocated, use DEFAULT_PIXEL, instead. */
3775
3776static void
3777x_setup_relief_color (f, relief, factor, delta, default_pixel)
3778 struct frame *f;
3779 struct relief *relief;
68c45bf0 3780 double factor;
06a2c219
GM
3781 int delta;
3782 unsigned long default_pixel;
3783{
3784 XGCValues xgcv;
3785 struct x_output *di = f->output_data.x;
3786 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3787 unsigned long pixel;
3788 unsigned long background = di->relief_background;
43bd1b2b 3789 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3790 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3791 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3792
3793 xgcv.graphics_exposures = False;
3794 xgcv.line_width = 1;
3795
3796 /* Free previously allocated color. The color cell will be reused
3797 when it has been freed as many times as it was allocated, so this
3798 doesn't affect faces using the same colors. */
3799 if (relief->gc
3800 && relief->allocated_p)
3801 {
0d605c67 3802 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3803 relief->allocated_p = 0;
3804 }
3805
3806 /* Allocate new color. */
3807 xgcv.foreground = default_pixel;
3808 pixel = background;
dcd08bfb
GM
3809 if (dpyinfo->n_planes != 1
3810 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3811 {
3812 relief->allocated_p = 1;
3813 xgcv.foreground = relief->pixel = pixel;
3814 }
3815
3816 if (relief->gc == 0)
3817 {
dcd08bfb 3818 xgcv.stipple = dpyinfo->gray;
06a2c219 3819 mask |= GCStipple;
dcd08bfb 3820 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3821 }
3822 else
dcd08bfb 3823 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3824}
3825
3826
3827/* Set up colors for the relief lines around glyph string S. */
3828
3829static void
3830x_setup_relief_colors (s)
3831 struct glyph_string *s;
3832{
3833 struct x_output *di = s->f->output_data.x;
3834 unsigned long color;
3835
3836 if (s->face->use_box_color_for_shadows_p)
3837 color = s->face->box_color;
e2a57b34
MB
3838 else if (s->first_glyph->type == IMAGE_GLYPH
3839 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3840 color = IMAGE_BACKGROUND (s->img, s->f, 0);
06a2c219
GM
3841 else
3842 {
3843 XGCValues xgcv;
3844
3845 /* Get the background color of the face. */
3846 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3847 color = xgcv.background;
3848 }
3849
3850 if (di->white_relief.gc == 0
3851 || color != di->relief_background)
3852 {
3853 di->relief_background = color;
3854 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3855 WHITE_PIX_DEFAULT (s->f));
3856 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3857 BLACK_PIX_DEFAULT (s->f));
3858 }
3859}
3860
3861
3862/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3863 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3864 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3865 relief. LEFT_P non-zero means draw a relief on the left side of
3866 the rectangle. RIGHT_P non-zero means draw a relief on the right
3867 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3868 when drawing. */
3869
3870static void
3871x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3872 raised_p, left_p, right_p, clip_rect)
3873 struct frame *f;
3874 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3875 XRectangle *clip_rect;
3876{
de507556
GM
3877 Display *dpy = FRAME_X_DISPLAY (f);
3878 Window window = FRAME_X_WINDOW (f);
06a2c219
GM
3879 int i;
3880 GC gc;
3881
3882 if (raised_p)
3883 gc = f->output_data.x->white_relief.gc;
3884 else
3885 gc = f->output_data.x->black_relief.gc;
de507556 3886 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3887
3888 /* Top. */
3889 for (i = 0; i < width; ++i)
de507556 3890 XDrawLine (dpy, window, gc,
06a2c219
GM
3891 left_x + i * left_p, top_y + i,
3892 right_x + 1 - i * right_p, top_y + i);
3893
3894 /* Left. */
3895 if (left_p)
3896 for (i = 0; i < width; ++i)
de507556 3897 XDrawLine (dpy, window, gc,
44655e77 3898 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
06a2c219 3899
de507556 3900 XSetClipMask (dpy, gc, None);
06a2c219
GM
3901 if (raised_p)
3902 gc = f->output_data.x->black_relief.gc;
3903 else
3904 gc = f->output_data.x->white_relief.gc;
de507556 3905 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3906
3907 /* Bottom. */
3908 for (i = 0; i < width; ++i)
de507556
GM
3909 XDrawLine (dpy, window, gc,
3910 left_x + i * left_p, bottom_y - i,
327f42ee 3911 right_x + 1 - i * right_p, bottom_y - i);
06a2c219
GM
3912
3913 /* Right. */
3914 if (right_p)
3915 for (i = 0; i < width; ++i)
de507556 3916 XDrawLine (dpy, window, gc,
06a2c219
GM
3917 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3918
de507556 3919 XSetClipMask (dpy, gc, None);
06a2c219
GM
3920}
3921
3922
3923/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3924 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3925 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3926 left side of the rectangle. RIGHT_P non-zero means draw a line
3927 on the right side of the rectangle. CLIP_RECT is the clipping
3928 rectangle to use when drawing. */
3929
3930static void
3931x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3932 left_p, right_p, clip_rect)
3933 struct glyph_string *s;
3934 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3935 XRectangle *clip_rect;
3936{
3937 XGCValues xgcv;
3938
3939 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3940 XSetForeground (s->display, s->gc, s->face->box_color);
3941 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3942
3943 /* Top. */
3944 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3945 left_x, top_y, right_x - left_x + 1, width);
06a2c219
GM
3946
3947 /* Left. */
3948 if (left_p)
3949 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3950 left_x, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3951
3952 /* Bottom. */
3953 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3954 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
06a2c219
GM
3955
3956 /* Right. */
3957 if (right_p)
3958 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3959 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3960
3961 XSetForeground (s->display, s->gc, xgcv.foreground);
3962 XSetClipMask (s->display, s->gc, None);
3963}
3964
3965
3966/* Draw a box around glyph string S. */
3967
3968static void
3969x_draw_glyph_string_box (s)
3970 struct glyph_string *s;
3971{
3972 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3973 int left_p, right_p;
3974 struct glyph *last_glyph;
3975 XRectangle clip_rect;
3976
3977 last_x = window_box_right (s->w, s->area);
3978 if (s->row->full_width_p
3979 && !s->w->pseudo_window_p)
3980 {
110859fc 3981 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
06a2c219
GM
3982 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3983 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3984 }
3985
3986 /* The glyph that may have a right box line. */
b4192550 3987 last_glyph = (s->cmp || s->img
06a2c219
GM
3988 ? s->first_glyph
3989 : s->first_glyph + s->nchars - 1);
3990
ea2ba0d4 3991 width = abs (s->face->box_line_width);
06a2c219
GM
3992 raised_p = s->face->box == FACE_RAISED_BOX;
3993 left_x = s->x;
57ac7c81
GM
3994 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
3995 ? last_x - 1
3996 : min (last_x, s->x + s->background_width) - 1);
06a2c219
GM
3997 top_y = s->y;
3998 bottom_y = top_y + s->height - 1;
3999
4000 left_p = (s->first_glyph->left_box_line_p
4001 || (s->hl == DRAW_MOUSE_FACE
4002 && (s->prev == NULL
4003 || s->prev->hl != s->hl)));
4004 right_p = (last_glyph->right_box_line_p
4005 || (s->hl == DRAW_MOUSE_FACE
4006 && (s->next == NULL
4007 || s->next->hl != s->hl)));
327f42ee 4008
06a2c219
GM
4009 x_get_glyph_string_clip_rect (s, &clip_rect);
4010
4011 if (s->face->box == FACE_SIMPLE_BOX)
4012 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4013 left_p, right_p, &clip_rect);
4014 else
4015 {
4016 x_setup_relief_colors (s);
4017 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
4018 width, raised_p, left_p, right_p, &clip_rect);
4019 }
4020}
4021
4022
4023/* Draw foreground of image glyph string S. */
4024
4025static void
4026x_draw_image_foreground (s)
4027 struct glyph_string *s;
4028{
4029 int x;
95af8492 4030 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4031
4032 /* If first glyph of S has a left box line, start drawing it to the
4033 right of that line. */
4034 if (s->face->box != FACE_NO_BOX
4035 && s->first_glyph->left_box_line_p)
ea2ba0d4 4036 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4037 else
4038 x = s->x;
4039
4040 /* If there is a margin around the image, adjust x- and y-position
4041 by that margin. */
22d650b8
GM
4042 x += s->img->hmargin;
4043 y += s->img->vmargin;
06a2c219
GM
4044
4045 if (s->img->pixmap)
4046 {
4047 if (s->img->mask)
4048 {
4049 /* We can't set both a clip mask and use XSetClipRectangles
4050 because the latter also sets a clip mask. We also can't
4051 trust on the shape extension to be available
4052 (XShapeCombineRegion). So, compute the rectangle to draw
4053 manually. */
4054 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4055 | GCFunction);
4056 XGCValues xgcv;
4057 XRectangle clip_rect, image_rect, r;
4058
4059 xgcv.clip_mask = s->img->mask;
4060 xgcv.clip_x_origin = x;
4061 xgcv.clip_y_origin = y;
4062 xgcv.function = GXcopy;
4063 XChangeGC (s->display, s->gc, mask, &xgcv);
4064
4065 x_get_glyph_string_clip_rect (s, &clip_rect);
4066 image_rect.x = x;
4067 image_rect.y = y;
4068 image_rect.width = s->img->width;
4069 image_rect.height = s->img->height;
4070 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4071 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4072 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
4073 }
4074 else
4075 {
49ad1d99
GM
4076 XRectangle clip_rect, image_rect, r;
4077
4078 x_get_glyph_string_clip_rect (s, &clip_rect);
4079 image_rect.x = x;
4080 image_rect.y = y;
4081 image_rect.width = s->img->width;
4082 image_rect.height = s->img->height;
4083 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4084 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4085 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
06a2c219
GM
4086
4087 /* When the image has a mask, we can expect that at
4088 least part of a mouse highlight or a block cursor will
4089 be visible. If the image doesn't have a mask, make
4090 a block cursor visible by drawing a rectangle around
4091 the image. I believe it's looking better if we do
4092 nothing here for mouse-face. */
4093 if (s->hl == DRAW_CURSOR)
4094 XDrawRectangle (s->display, s->window, s->gc, x, y,
4095 s->img->width - 1, s->img->height - 1);
4096 }
4097 }
4098 else
4099 /* Draw a rectangle if image could not be loaded. */
4100 XDrawRectangle (s->display, s->window, s->gc, x, y,
4101 s->img->width - 1, s->img->height - 1);
4102}
4103
4104
4105/* Draw a relief around the image glyph string S. */
4106
4107static void
4108x_draw_image_relief (s)
4109 struct glyph_string *s;
4110{
4111 int x0, y0, x1, y1, thick, raised_p;
4112 XRectangle r;
4113 int x;
95af8492 4114 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4115
4116 /* If first glyph of S has a left box line, start drawing it to the
4117 right of that line. */
4118 if (s->face->box != FACE_NO_BOX
4119 && s->first_glyph->left_box_line_p)
ea2ba0d4 4120 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4121 else
4122 x = s->x;
4123
4124 /* If there is a margin around the image, adjust x- and y-position
4125 by that margin. */
22d650b8
GM
4126 x += s->img->hmargin;
4127 y += s->img->vmargin;
06a2c219
GM
4128
4129 if (s->hl == DRAW_IMAGE_SUNKEN
4130 || s->hl == DRAW_IMAGE_RAISED)
4131 {
9ea173e8 4132 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
06a2c219
GM
4133 raised_p = s->hl == DRAW_IMAGE_RAISED;
4134 }
4135 else
4136 {
4137 thick = abs (s->img->relief);
4138 raised_p = s->img->relief > 0;
4139 }
4140
4141 x0 = x - thick;
4142 y0 = y - thick;
4143 x1 = x + s->img->width + thick - 1;
4144 y1 = y + s->img->height + thick - 1;
4145
4146 x_setup_relief_colors (s);
4147 x_get_glyph_string_clip_rect (s, &r);
4148 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
4149}
4150
4151
4152/* Draw the foreground of image glyph string S to PIXMAP. */
4153
4154static void
4155x_draw_image_foreground_1 (s, pixmap)
4156 struct glyph_string *s;
4157 Pixmap pixmap;
4158{
4159 int x;
95af8492 4160 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
4161
4162 /* If first glyph of S has a left box line, start drawing it to the
4163 right of that line. */
4164 if (s->face->box != FACE_NO_BOX
4165 && s->first_glyph->left_box_line_p)
ea2ba0d4 4166 x = abs (s->face->box_line_width);
06a2c219
GM
4167 else
4168 x = 0;
4169
4170 /* If there is a margin around the image, adjust x- and y-position
4171 by that margin. */
22d650b8
GM
4172 x += s->img->hmargin;
4173 y += s->img->vmargin;
dc43ef94 4174
06a2c219
GM
4175 if (s->img->pixmap)
4176 {
4177 if (s->img->mask)
4178 {
4179 /* We can't set both a clip mask and use XSetClipRectangles
4180 because the latter also sets a clip mask. We also can't
4181 trust on the shape extension to be available
4182 (XShapeCombineRegion). So, compute the rectangle to draw
4183 manually. */
4184 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4185 | GCFunction);
4186 XGCValues xgcv;
4187
4188 xgcv.clip_mask = s->img->mask;
4189 xgcv.clip_x_origin = x;
4190 xgcv.clip_y_origin = y;
4191 xgcv.function = GXcopy;
4192 XChangeGC (s->display, s->gc, mask, &xgcv);
4193
4194 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4195 0, 0, s->img->width, s->img->height, x, y);
4196 XSetClipMask (s->display, s->gc, None);
4197 }
4198 else
4199 {
4200 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4201 0, 0, s->img->width, s->img->height, x, y);
4202
4203 /* When the image has a mask, we can expect that at
4204 least part of a mouse highlight or a block cursor will
4205 be visible. If the image doesn't have a mask, make
4206 a block cursor visible by drawing a rectangle around
4207 the image. I believe it's looking better if we do
4208 nothing here for mouse-face. */
4209 if (s->hl == DRAW_CURSOR)
4210 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4211 s->img->width - 1, s->img->height - 1);
4212 }
4213 }
4214 else
4215 /* Draw a rectangle if image could not be loaded. */
4216 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4217 s->img->width - 1, s->img->height - 1);
4218}
dc43ef94 4219
990ba854 4220
06a2c219
GM
4221/* Draw part of the background of glyph string S. X, Y, W, and H
4222 give the rectangle to draw. */
a9a5b0a5 4223
06a2c219
GM
4224static void
4225x_draw_glyph_string_bg_rect (s, x, y, w, h)
4226 struct glyph_string *s;
4227 int x, y, w, h;
4228{
4229 if (s->stippled_p)
4230 {
4231 /* Fill background with a stipple pattern. */
4232 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4233 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4234 XSetFillStyle (s->display, s->gc, FillSolid);
4235 }
4236 else
4237 x_clear_glyph_string_rect (s, x, y, w, h);
4238}
07e34cb0 4239
b5210ea7 4240
06a2c219 4241/* Draw image glyph string S.
dc43ef94 4242
06a2c219
GM
4243 s->y
4244 s->x +-------------------------
4245 | s->face->box
4246 |
4247 | +-------------------------
4248 | | s->img->margin
4249 | |
4250 | | +-------------------
4251 | | | the image
dc43ef94 4252
06a2c219 4253 */
dc43ef94 4254
06a2c219
GM
4255static void
4256x_draw_image_glyph_string (s)
4257 struct glyph_string *s;
4258{
4259 int x, y;
ea2ba0d4
KH
4260 int box_line_hwidth = abs (s->face->box_line_width);
4261 int box_line_vwidth = max (s->face->box_line_width, 0);
06a2c219
GM
4262 int height;
4263 Pixmap pixmap = None;
4264
ea2ba0d4 4265 height = s->height - 2 * box_line_vwidth;
06a2c219
GM
4266
4267 /* Fill background with face under the image. Do it only if row is
4268 taller than image or if image has a clip mask to reduce
4269 flickering. */
4270 s->stippled_p = s->face->stipple != 0;
4271 if (height > s->img->height
22d650b8
GM
4272 || s->img->hmargin
4273 || s->img->vmargin
06a2c219
GM
4274 || s->img->mask
4275 || s->img->pixmap == 0
4276 || s->width != s->background_width)
4277 {
ea2ba0d4
KH
4278 if (box_line_hwidth && s->first_glyph->left_box_line_p)
4279 x = s->x + box_line_hwidth;
06a2c219
GM
4280 else
4281 x = s->x;
4282
ea2ba0d4 4283 y = s->y + box_line_vwidth;
06a2c219
GM
4284
4285 if (s->img->mask)
4286 {
f9b5db02
GM
4287 /* Create a pixmap as large as the glyph string. Fill it
4288 with the background color. Copy the image to it, using
4289 its mask. Copy the temporary pixmap to the display. */
06a2c219
GM
4290 Screen *screen = FRAME_X_SCREEN (s->f);
4291 int depth = DefaultDepthOfScreen (screen);
4292
4293 /* Create a pixmap as large as the glyph string. */
4294 pixmap = XCreatePixmap (s->display, s->window,
4295 s->background_width,
4296 s->height, depth);
4297
4298 /* Don't clip in the following because we're working on the
4299 pixmap. */
4300 XSetClipMask (s->display, s->gc, None);
4301
4302 /* Fill the pixmap with the background color/stipple. */
4303 if (s->stippled_p)
4304 {
4305 /* Fill background with a stipple pattern. */
4306 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4307 XFillRectangle (s->display, pixmap, s->gc,
4308 0, 0, s->background_width, s->height);
4309 XSetFillStyle (s->display, s->gc, FillSolid);
4310 }
4311 else
4312 {
4313 XGCValues xgcv;
4314 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4315 &xgcv);
4316 XSetForeground (s->display, s->gc, xgcv.background);
4317 XFillRectangle (s->display, pixmap, s->gc,
4318 0, 0, s->background_width, s->height);
4319 XSetForeground (s->display, s->gc, xgcv.foreground);
4320 }
4321 }
4322 else
06a2c219
GM
4323 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
4324
4325 s->background_filled_p = 1;
4326 }
dc43ef94 4327
06a2c219
GM
4328 /* Draw the foreground. */
4329 if (pixmap != None)
4330 {
4331 x_draw_image_foreground_1 (s, pixmap);
4332 x_set_glyph_string_clipping (s);
4333 XCopyArea (s->display, pixmap, s->window, s->gc,
4334 0, 0, s->background_width, s->height, s->x, s->y);
4335 XFreePixmap (s->display, pixmap);
4336 }
4337 else
4338 x_draw_image_foreground (s);
b5210ea7 4339
06a2c219
GM
4340 /* If we must draw a relief around the image, do it. */
4341 if (s->img->relief
4342 || s->hl == DRAW_IMAGE_RAISED
4343 || s->hl == DRAW_IMAGE_SUNKEN)
4344 x_draw_image_relief (s);
4345}
8c1a6a84 4346
990ba854 4347
06a2c219 4348/* Draw stretch glyph string S. */
dc43ef94 4349
06a2c219
GM
4350static void
4351x_draw_stretch_glyph_string (s)
4352 struct glyph_string *s;
4353{
4354 xassert (s->first_glyph->type == STRETCH_GLYPH);
4355 s->stippled_p = s->face->stipple != 0;
990ba854 4356
06a2c219
GM
4357 if (s->hl == DRAW_CURSOR
4358 && !x_stretch_cursor_p)
4359 {
4360 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4361 as wide as the stretch glyph. */
4362 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4363
06a2c219
GM
4364 /* Draw cursor. */
4365 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4366
06a2c219
GM
4367 /* Clear rest using the GC of the original non-cursor face. */
4368 if (width < s->background_width)
4369 {
06a2c219
GM
4370 int x = s->x + width, y = s->y;
4371 int w = s->background_width - width, h = s->height;
4372 XRectangle r;
b7f83f9e 4373 GC gc;
dc43ef94 4374
b7f83f9e
GM
4375 if (s->row->mouse_face_p
4376 && cursor_in_mouse_face_p (s->w))
4377 {
4378 x_set_mouse_face_gc (s);
4379 gc = s->gc;
4380 }
4381 else
4382 gc = s->face->gc;
4383
06a2c219
GM
4384 x_get_glyph_string_clip_rect (s, &r);
4385 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
b7f83f9e 4386
06a2c219
GM
4387 if (s->face->stipple)
4388 {
4389 /* Fill background with a stipple pattern. */
4390 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4391 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4392 XSetFillStyle (s->display, gc, FillSolid);
4393 }
4394 else
4395 {
4396 XGCValues xgcv;
4397 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4398 XSetForeground (s->display, gc, xgcv.background);
4399 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4400 XSetForeground (s->display, gc, xgcv.foreground);
4401 }
4402 }
4403 }
61e9f9f3 4404 else if (!s->background_filled_p)
06a2c219
GM
4405 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4406 s->height);
4407
4408 s->background_filled_p = 1;
4409}
4410
4411
4412/* Draw glyph string S. */
4413
4414static void
4415x_draw_glyph_string (s)
4416 struct glyph_string *s;
4417{
4458cf11
KH
4418 int relief_drawn_p = 0;
4419
06a2c219
GM
4420 /* If S draws into the background of its successor, draw the
4421 background of the successor first so that S can draw into it.
4422 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4423 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4424 {
4425 xassert (s->next->img == NULL);
4426 x_set_glyph_string_gc (s->next);
4427 x_set_glyph_string_clipping (s->next);
4428 x_draw_glyph_string_background (s->next, 1);
4429 }
97210f4e 4430
06a2c219
GM
4431 /* Set up S->gc, set clipping and draw S. */
4432 x_set_glyph_string_gc (s);
06a2c219 4433
4458cf11
KH
4434 /* Draw relief (if any) in advance for char/composition so that the
4435 glyph string can be drawn over it. */
4436 if (!s->for_overlaps_p
4437 && s->face->box != FACE_NO_BOX
4438 && (s->first_glyph->type == CHAR_GLYPH
4439 || s->first_glyph->type == COMPOSITE_GLYPH))
4440
4441 {
e6269cbb 4442 x_set_glyph_string_clipping (s);
4458cf11
KH
4443 x_draw_glyph_string_background (s, 1);
4444 x_draw_glyph_string_box (s);
e6269cbb 4445 x_set_glyph_string_clipping (s);
4458cf11
KH
4446 relief_drawn_p = 1;
4447 }
e6269cbb
GM
4448 else
4449 x_set_glyph_string_clipping (s);
4458cf11 4450
06a2c219
GM
4451 switch (s->first_glyph->type)
4452 {
4453 case IMAGE_GLYPH:
4454 x_draw_image_glyph_string (s);
4455 break;
4456
4457 case STRETCH_GLYPH:
4458 x_draw_stretch_glyph_string (s);
4459 break;
4460
4461 case CHAR_GLYPH:
66ac4b0e
GM
4462 if (s->for_overlaps_p)
4463 s->background_filled_p = 1;
4464 else
4465 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4466 x_draw_glyph_string_foreground (s);
4467 break;
4468
b4192550
KH
4469 case COMPOSITE_GLYPH:
4470 if (s->for_overlaps_p || s->gidx > 0)
4471 s->background_filled_p = 1;
4472 else
4473 x_draw_glyph_string_background (s, 1);
4474 x_draw_composite_glyph_string_foreground (s);
4475 break;
4476
06a2c219
GM
4477 default:
4478 abort ();
4479 }
4480
66ac4b0e 4481 if (!s->for_overlaps_p)
06a2c219 4482 {
66ac4b0e
GM
4483 /* Draw underline. */
4484 if (s->face->underline_p)
4485 {
e24e84cc
GM
4486 unsigned long tem, h;
4487 int y;
06a2c219 4488
e24e84cc 4489 /* Get the underline thickness. Default is 1 pixel. */
66ac4b0e
GM
4490 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4491 h = 1;
e24e84cc
GM
4492
4493 /* Get the underline position. This is the recommended
4494 vertical offset in pixels from the baseline to the top of
4495 the underline. This is a signed value according to the
4496 specs, and its default is
4497
4498 ROUND ((maximum descent) / 2), with
4499 ROUND(x) = floor (x + 0.5) */
4500
a72d5ce5
GM
4501 if (x_use_underline_position_properties
4502 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
e24e84cc
GM
4503 y = s->ybase + (long) tem;
4504 else if (s->face->font)
4505 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4506 else
a02f1be0 4507 y = s->y + s->height - h;
06a2c219 4508
66ac4b0e 4509 if (s->face->underline_defaulted_p)
e24e84cc
GM
4510 XFillRectangle (s->display, s->window, s->gc,
4511 s->x, y, s->width, h);
66ac4b0e
GM
4512 else
4513 {
4514 XGCValues xgcv;
4515 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4516 XSetForeground (s->display, s->gc, s->face->underline_color);
e24e84cc
GM
4517 XFillRectangle (s->display, s->window, s->gc,
4518 s->x, y, s->width, h);
66ac4b0e
GM
4519 XSetForeground (s->display, s->gc, xgcv.foreground);
4520 }
dc6f92b8 4521 }
07e34cb0 4522
66ac4b0e
GM
4523 /* Draw overline. */
4524 if (s->face->overline_p)
06a2c219 4525 {
66ac4b0e
GM
4526 unsigned long dy = 0, h = 1;
4527
4528 if (s->face->overline_color_defaulted_p)
4529 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4530 s->width, h);
4531 else
4532 {
4533 XGCValues xgcv;
4534 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4535 XSetForeground (s->display, s->gc, s->face->overline_color);
4536 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4537 s->width, h);
4538 XSetForeground (s->display, s->gc, xgcv.foreground);
4539 }
06a2c219 4540 }
06a2c219 4541
66ac4b0e
GM
4542 /* Draw strike-through. */
4543 if (s->face->strike_through_p)
06a2c219 4544 {
66ac4b0e
GM
4545 unsigned long h = 1;
4546 unsigned long dy = (s->height - h) / 2;
4547
4548 if (s->face->strike_through_color_defaulted_p)
4549 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4550 s->width, h);
4551 else
4552 {
4553 XGCValues xgcv;
4554 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4555 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4556 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4557 s->width, h);
4558 XSetForeground (s->display, s->gc, xgcv.foreground);
4559 }
06a2c219 4560 }
06a2c219 4561
4458cf11
KH
4562 /* Draw relief if not yet drawn. */
4563 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
66ac4b0e
GM
4564 x_draw_glyph_string_box (s);
4565 }
06a2c219
GM
4566
4567 /* Reset clipping. */
4568 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4569}
07e34cb0 4570
06a2c219 4571
b4192550
KH
4572static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4573 struct face **, int));
06a2c219 4574
06a2c219 4575
209f68d9
GM
4576/* Fill glyph string S with composition components specified by S->cmp.
4577
b4192550
KH
4578 FACES is an array of faces for all components of this composition.
4579 S->gidx is the index of the first component for S.
4580 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4581 use its physical height for clipping.
06a2c219 4582
b4192550 4583 Value is the index of a component not in S. */
07e34cb0 4584
b4192550
KH
4585static int
4586x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4587 struct glyph_string *s;
b4192550 4588 struct face **faces;
66ac4b0e 4589 int overlaps_p;
07e34cb0 4590{
b4192550 4591 int i;
06a2c219 4592
b4192550 4593 xassert (s);
06a2c219 4594
b4192550 4595 s->for_overlaps_p = overlaps_p;
06a2c219 4596
b4192550
KH
4597 s->face = faces[s->gidx];
4598 s->font = s->face->font;
4599 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4600
b4192550
KH
4601 /* For all glyphs of this composition, starting at the offset
4602 S->gidx, until we reach the end of the definition or encounter a
4603 glyph that requires the different face, add it to S. */
4604 ++s->nchars;
4605 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4606 ++s->nchars;
06a2c219 4607
b4192550
KH
4608 /* All glyph strings for the same composition has the same width,
4609 i.e. the width set for the first component of the composition. */
06a2c219 4610
06a2c219
GM
4611 s->width = s->first_glyph->pixel_width;
4612
4613 /* If the specified font could not be loaded, use the frame's
4614 default font, but record the fact that we couldn't load it in
4615 the glyph string so that we can draw rectangles for the
4616 characters of the glyph string. */
4617 if (s->font == NULL)
4618 {
4619 s->font_not_found_p = 1;
4620 s->font = FRAME_FONT (s->f);
4621 }
4622
4623 /* Adjust base line for subscript/superscript text. */
4624 s->ybase += s->first_glyph->voffset;
4625
4626 xassert (s->face && s->face->gc);
4627
4628 /* This glyph string must always be drawn with 16-bit functions. */
4629 s->two_byte_p = 1;
b4192550
KH
4630
4631 return s->gidx + s->nchars;
06a2c219
GM
4632}
4633
4634
209f68d9
GM
4635/* Fill glyph string S from a sequence of character glyphs.
4636
06a2c219 4637 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4638 first glyph to consider, END is the index of the last + 1.
4639 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4640 use its physical height for clipping.
66ac4b0e
GM
4641
4642 Value is the index of the first glyph not in S. */
06a2c219
GM
4643
4644static int
66ac4b0e 4645x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4646 struct glyph_string *s;
4647 int face_id;
66ac4b0e 4648 int start, end, overlaps_p;
06a2c219
GM
4649{
4650 struct glyph *glyph, *last;
4651 int voffset;
ee569018 4652 int glyph_not_available_p;
06a2c219 4653
06a2c219
GM
4654 xassert (s->f == XFRAME (s->w->frame));
4655 xassert (s->nchars == 0);
4656 xassert (start >= 0 && end > start);
4657
66ac4b0e 4658 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4659 glyph = s->row->glyphs[s->area] + start;
4660 last = s->row->glyphs[s->area] + end;
4661 voffset = glyph->voffset;
4662
ee569018
KH
4663 glyph_not_available_p = glyph->glyph_not_available_p;
4664
06a2c219
GM
4665 while (glyph < last
4666 && glyph->type == CHAR_GLYPH
4667 && glyph->voffset == voffset
ee569018
KH
4668 /* Same face id implies same font, nowadays. */
4669 && glyph->face_id == face_id
4670 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4671 {
ee569018
KH
4672 int two_byte_p;
4673
06a2c219 4674 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4675 s->char2b + s->nchars,
4676 &two_byte_p);
4677 s->two_byte_p = two_byte_p;
06a2c219
GM
4678 ++s->nchars;
4679 xassert (s->nchars <= end - start);
4680 s->width += glyph->pixel_width;
4681 ++glyph;
4682 }
4683
4684 s->font = s->face->font;
4685 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4686
4687 /* If the specified font could not be loaded, use the frame's font,
4688 but record the fact that we couldn't load it in
4689 S->font_not_found_p so that we can draw rectangles for the
4690 characters of the glyph string. */
ee569018 4691 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4692 {
4693 s->font_not_found_p = 1;
4694 s->font = FRAME_FONT (s->f);
4695 }
4696
4697 /* Adjust base line for subscript/superscript text. */
4698 s->ybase += voffset;
66ac4b0e 4699
06a2c219
GM
4700 xassert (s->face && s->face->gc);
4701 return glyph - s->row->glyphs[s->area];
07e34cb0 4702}
dc6f92b8 4703
06a2c219
GM
4704
4705/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4706
dfcf069d 4707static void
06a2c219
GM
4708x_fill_image_glyph_string (s)
4709 struct glyph_string *s;
4710{
4711 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4712 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4713 xassert (s->img);
43d120d8 4714 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4715 s->font = s->face->font;
4716 s->width = s->first_glyph->pixel_width;
4717
4718 /* Adjust base line for subscript/superscript text. */
4719 s->ybase += s->first_glyph->voffset;
4720}
4721
4722
209f68d9 4723/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4724
209f68d9
GM
4725 ROW is the glyph row in which the glyphs are found, AREA is the
4726 area within the row. START is the index of the first glyph to
4727 consider, END is the index of the last + 1.
4728
4729 Value is the index of the first glyph not in S. */
4730
4731static int
4732x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4733 struct glyph_string *s;
209f68d9
GM
4734 struct glyph_row *row;
4735 enum glyph_row_area area;
4736 int start, end;
06a2c219 4737{
209f68d9
GM
4738 struct glyph *glyph, *last;
4739 int voffset, face_id;
4740
06a2c219 4741 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4742
4743 glyph = s->row->glyphs[s->area] + start;
4744 last = s->row->glyphs[s->area] + end;
4745 face_id = glyph->face_id;
4746 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4747 s->font = s->face->font;
209f68d9
GM
4748 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4749 s->width = glyph->pixel_width;
4750 voffset = glyph->voffset;
4751
4752 for (++glyph;
4753 (glyph < last
4754 && glyph->type == STRETCH_GLYPH
4755 && glyph->voffset == voffset
4756 && glyph->face_id == face_id);
4757 ++glyph)
4758 s->width += glyph->pixel_width;
06a2c219
GM
4759
4760 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4761 s->ybase += voffset;
4762
c296fc01
GM
4763 /* The case that face->gc == 0 is handled when drawing the glyph
4764 string by calling PREPARE_FACE_FOR_DISPLAY. */
4765 xassert (s->face);
209f68d9 4766 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4767}
4768
4769
4770/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4771 of XChar2b structures for S; it can't be allocated in
4772 x_init_glyph_string because it must be allocated via `alloca'. W
4773 is the window on which S is drawn. ROW and AREA are the glyph row
4774 and area within the row from which S is constructed. START is the
4775 index of the first glyph structure covered by S. HL is a
4776 face-override for drawing S. */
4777
4778static void
4779x_init_glyph_string (s, char2b, w, row, area, start, hl)
4780 struct glyph_string *s;
4781 XChar2b *char2b;
4782 struct window *w;
4783 struct glyph_row *row;
4784 enum glyph_row_area area;
4785 int start;
4786 enum draw_glyphs_face hl;
4787{
4788 bzero (s, sizeof *s);
4789 s->w = w;
4790 s->f = XFRAME (w->frame);
4791 s->display = FRAME_X_DISPLAY (s->f);
4792 s->window = FRAME_X_WINDOW (s->f);
4793 s->char2b = char2b;
4794 s->hl = hl;
4795 s->row = row;
4796 s->area = area;
4797 s->first_glyph = row->glyphs[area] + start;
4798 s->height = row->height;
4799 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4800
9ea173e8
GM
4801 /* Display the internal border below the tool-bar window. */
4802 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4803 s->y -= s->f->output_data.x->internal_border_width;
4804
4805 s->ybase = s->y + row->ascent;
4806}
4807
4808
4809/* Set background width of glyph string S. START is the index of the
4810 first glyph following S. LAST_X is the right-most x-position + 1
4811 in the drawing area. */
4812
4813static INLINE void
4814x_set_glyph_string_background_width (s, start, last_x)
4815 struct glyph_string *s;
4816 int start;
4817 int last_x;
4818{
4819 /* If the face of this glyph string has to be drawn to the end of
4820 the drawing area, set S->extends_to_end_of_line_p. */
4821 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4822
4823 if (start == s->row->used[s->area]
eb79f5cc 4824 && s->area == TEXT_AREA
7b0870b2
GM
4825 && ((s->hl == DRAW_NORMAL_TEXT
4826 && (s->row->fill_line_p
4827 || s->face->background != default_face->background
4828 || s->face->stipple != default_face->stipple
4829 || s->row->mouse_face_p))
327f42ee
GM
4830 || s->hl == DRAW_MOUSE_FACE
4831 || ((s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN)
4832 && s->row->fill_line_p)))
7b0870b2 4833 s->extends_to_end_of_line_p = 1;
06a2c219
GM
4834
4835 /* If S extends its face to the end of the line, set its
4836 background_width to the distance to the right edge of the drawing
4837 area. */
4838 if (s->extends_to_end_of_line_p)
1da3fd71 4839 s->background_width = last_x - s->x + 1;
06a2c219
GM
4840 else
4841 s->background_width = s->width;
4842}
4843
4844
4845/* Add a glyph string for a stretch glyph to the list of strings
4846 between HEAD and TAIL. START is the index of the stretch glyph in
4847 row area AREA of glyph row ROW. END is the index of the last glyph
4848 in that glyph row area. X is the current output position assigned
4849 to the new glyph string constructed. HL overrides that face of the
4850 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4851 is the right-most x-position of the drawing area. */
4852
8abee2e1
DL
4853/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4854 and below -- keep them on one line. */
4855#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4856 do \
4857 { \
4858 s = (struct glyph_string *) alloca (sizeof *s); \
4859 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4860 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4861 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4862 s->x = (X); \
4863 } \
4864 while (0)
4865
4866
4867/* Add a glyph string for an image glyph to the list of strings
4868 between HEAD and TAIL. START is the index of the image glyph in
4869 row area AREA of glyph row ROW. END is the index of the last glyph
4870 in that glyph row area. X is the current output position assigned
4871 to the new glyph string constructed. HL overrides that face of the
4872 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4873 is the right-most x-position of the drawing area. */
4874
8abee2e1 4875#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4876 do \
4877 { \
4878 s = (struct glyph_string *) alloca (sizeof *s); \
4879 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4880 x_fill_image_glyph_string (s); \
4881 x_append_glyph_string (&HEAD, &TAIL, s); \
4882 ++START; \
4883 s->x = (X); \
4884 } \
4885 while (0)
4886
4887
4888/* Add a glyph string for a sequence of character glyphs to the list
4889 of strings between HEAD and TAIL. START is the index of the first
4890 glyph in row area AREA of glyph row ROW that is part of the new
4891 glyph string. END is the index of the last glyph in that glyph row
4892 area. X is the current output position assigned to the new glyph
4893 string constructed. HL overrides that face of the glyph; e.g. it
4894 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4895 right-most x-position of the drawing area. */
4896
8abee2e1 4897#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4898 do \
4899 { \
3e71d8f2 4900 int c, face_id; \
06a2c219
GM
4901 XChar2b *char2b; \
4902 \
43d120d8 4903 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4904 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4905 \
b4192550
KH
4906 s = (struct glyph_string *) alloca (sizeof *s); \
4907 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4908 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4909 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4910 s->x = (X); \
4911 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4912 OVERLAPS_P); \
06a2c219
GM
4913 } \
4914 while (0)
4915
4916
b4192550
KH
4917/* Add a glyph string for a composite sequence to the list of strings
4918 between HEAD and TAIL. START is the index of the first glyph in
4919 row area AREA of glyph row ROW that is part of the new glyph
4920 string. END is the index of the last glyph in that glyph row area.
4921 X is the current output position assigned to the new glyph string
4922 constructed. HL overrides that face of the glyph; e.g. it is
4923 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4924 x-position of the drawing area. */
4925
6c27ec25 4926#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4927 do { \
43d120d8
KH
4928 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4929 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4930 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4931 struct composition *cmp = composition_table[cmp_id]; \
4932 int glyph_len = cmp->glyph_len; \
4933 XChar2b *char2b; \
4934 struct face **faces; \
4935 struct glyph_string *first_s = NULL; \
4936 int n; \
4937 \
ee569018 4938 base_face = base_face->ascii_face; \
b4192550
KH
4939 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4940 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4941 /* At first, fill in `char2b' and `faces'. */ \
4942 for (n = 0; n < glyph_len; n++) \
4943 { \
43d120d8 4944 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4945 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4946 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4947 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4948 this_face_id, char2b + n, 1); \
b4192550
KH
4949 } \
4950 \
4951 /* Make glyph_strings for each glyph sequence that is drawable by \
4952 the same face, and append them to HEAD/TAIL. */ \
4953 for (n = 0; n < cmp->glyph_len;) \
4954 { \
4955 s = (struct glyph_string *) alloca (sizeof *s); \
4956 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4957 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4958 s->cmp = cmp; \
4959 s->gidx = n; \
b4192550
KH
4960 s->x = (X); \
4961 \
4962 if (n == 0) \
4963 first_s = s; \
4964 \
4965 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4966 } \
4967 \
4968 ++START; \
4969 s = first_s; \
4970 } while (0)
4971
4972
06a2c219
GM
4973/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4974 of AREA of glyph row ROW on window W between indices START and END.
4975 HL overrides the face for drawing glyph strings, e.g. it is
4976 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4977 x-positions of the drawing area.
4978
4979 This is an ugly monster macro construct because we must use alloca
4980 to allocate glyph strings (because x_draw_glyphs can be called
4981 asynchronously). */
4982
8abee2e1 4983#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4984 do \
4985 { \
4986 HEAD = TAIL = NULL; \
4987 while (START < END) \
4988 { \
4989 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4990 switch (first_glyph->type) \
4991 { \
4992 case CHAR_GLYPH: \
4993 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
4994 TAIL, HL, X, LAST_X, \
4995 OVERLAPS_P); \
06a2c219
GM
4996 break; \
4997 \
b4192550
KH
4998 case COMPOSITE_GLYPH: \
4999 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
5000 HEAD, TAIL, HL, X, LAST_X,\
5001 OVERLAPS_P); \
5002 break; \
5003 \
06a2c219
GM
5004 case STRETCH_GLYPH: \
5005 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
5006 HEAD, TAIL, HL, X, LAST_X); \
5007 break; \
5008 \
5009 case IMAGE_GLYPH: \
5010 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
5011 TAIL, HL, X, LAST_X); \
5012 break; \
5013 \
5014 default: \
5015 abort (); \
5016 } \
5017 \
5018 x_set_glyph_string_background_width (s, START, LAST_X); \
5019 (X) += s->width; \
5020 } \
5021 } \
5022 while (0)
5023
5024
5025/* Draw glyphs between START and END in AREA of ROW on window W,
5026 starting at x-position X. X is relative to AREA in W. HL is a
5027 face-override with the following meaning:
5028
5029 DRAW_NORMAL_TEXT draw normally
5030 DRAW_CURSOR draw in cursor face
5031 DRAW_MOUSE_FACE draw in mouse face.
5032 DRAW_INVERSE_VIDEO draw in mode line face
5033 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
5034 DRAW_IMAGE_RAISED draw an image with a raised relief around it
5035
66ac4b0e
GM
5036 If OVERLAPS_P is non-zero, draw only the foreground of characters
5037 and clip to the physical height of ROW.
5038
06a2c219
GM
5039 Value is the x-position reached, relative to AREA of W. */
5040
5041static int
f0a48a01 5042x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
06a2c219
GM
5043 struct window *w;
5044 int x;
5045 struct glyph_row *row;
5046 enum glyph_row_area area;
5047 int start, end;
5048 enum draw_glyphs_face hl;
66ac4b0e 5049 int overlaps_p;
dc6f92b8 5050{
06a2c219
GM
5051 struct glyph_string *head, *tail;
5052 struct glyph_string *s;
5053 int last_x, area_width;
5054 int x_reached;
5055 int i, j;
5056
5057 /* Let's rather be paranoid than getting a SEGV. */
06a2c219 5058 end = min (end, row->used[area]);
a8710abf
GM
5059 start = max (0, start);
5060 start = min (end, start);
06a2c219
GM
5061
5062 /* Translate X to frame coordinates. Set last_x to the right
5063 end of the drawing area. */
5064 if (row->full_width_p)
5065 {
5066 /* X is relative to the left edge of W, without scroll bars
5067 or flag areas. */
5068 struct frame *f = XFRAME (w->frame);
110859fc 5069 /* int width = FRAME_FLAGS_AREA_WIDTH (f); */
06a2c219 5070 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 5071
06a2c219
GM
5072 x += window_left_x;
5073 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
5074 last_x = window_left_x + area_width;
5075
5076 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5077 {
110859fc 5078 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
5079 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
5080 last_x += width;
5081 else
5082 x -= width;
5083 }
dc6f92b8 5084
b9432a85 5085 x += FRAME_INTERNAL_BORDER_WIDTH (f);
98fedd97 5086 last_x += FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
5087 }
5088 else
dc6f92b8 5089 {
06a2c219
GM
5090 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
5091 area_width = window_box_width (w, area);
5092 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
5093 }
5094
06a2c219
GM
5095 /* Build a doubly-linked list of glyph_string structures between
5096 head and tail from what we have to draw. Note that the macro
5097 BUILD_GLYPH_STRINGS will modify its start parameter. That's
5098 the reason we use a separate variable `i'. */
5099 i = start;
66ac4b0e
GM
5100 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
5101 overlaps_p);
06a2c219
GM
5102 if (tail)
5103 x_reached = tail->x + tail->background_width;
5104 else
5105 x_reached = x;
90e65f07 5106
06a2c219
GM
5107 /* If there are any glyphs with lbearing < 0 or rbearing > width in
5108 the row, redraw some glyphs in front or following the glyph
5109 strings built above. */
a8710abf 5110 if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
5111 {
5112 int dummy_x = 0;
5113 struct glyph_string *h, *t;
5114
5115 /* Compute overhangs for all glyph strings. */
5116 for (s = head; s; s = s->next)
5117 x_compute_glyph_string_overhangs (s);
5118
5119 /* Prepend glyph strings for glyphs in front of the first glyph
5120 string that are overwritten because of the first glyph
5121 string's left overhang. The background of all strings
5122 prepended must be drawn because the first glyph string
5123 draws over it. */
5124 i = x_left_overwritten (head);
5125 if (i >= 0)
5126 {
5127 j = i;
5128 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
5129 DRAW_NORMAL_TEXT, dummy_x, last_x,
5130 overlaps_p);
06a2c219 5131 start = i;
06a2c219
GM
5132 x_compute_overhangs_and_x (t, head->x, 1);
5133 x_prepend_glyph_string_lists (&head, &tail, h, t);
5134 }
58769bee 5135
06a2c219
GM
5136 /* Prepend glyph strings for glyphs in front of the first glyph
5137 string that overwrite that glyph string because of their
5138 right overhang. For these strings, only the foreground must
5139 be drawn, because it draws over the glyph string at `head'.
5140 The background must not be drawn because this would overwrite
5141 right overhangs of preceding glyphs for which no glyph
5142 strings exist. */
5143 i = x_left_overwriting (head);
5144 if (i >= 0)
5145 {
5146 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
5147 DRAW_NORMAL_TEXT, dummy_x, last_x,
5148 overlaps_p);
06a2c219
GM
5149 for (s = h; s; s = s->next)
5150 s->background_filled_p = 1;
06a2c219
GM
5151 x_compute_overhangs_and_x (t, head->x, 1);
5152 x_prepend_glyph_string_lists (&head, &tail, h, t);
5153 }
dbcb258a 5154
06a2c219
GM
5155 /* Append glyphs strings for glyphs following the last glyph
5156 string tail that are overwritten by tail. The background of
5157 these strings has to be drawn because tail's foreground draws
5158 over it. */
5159 i = x_right_overwritten (tail);
5160 if (i >= 0)
5161 {
5162 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5163 DRAW_NORMAL_TEXT, x, last_x,
5164 overlaps_p);
06a2c219
GM
5165 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5166 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219 5167 }
dc6f92b8 5168
06a2c219
GM
5169 /* Append glyph strings for glyphs following the last glyph
5170 string tail that overwrite tail. The foreground of such
5171 glyphs has to be drawn because it writes into the background
5172 of tail. The background must not be drawn because it could
5173 paint over the foreground of following glyphs. */
5174 i = x_right_overwriting (tail);
5175 if (i >= 0)
5176 {
5177 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5178 DRAW_NORMAL_TEXT, x, last_x,
5179 overlaps_p);
06a2c219
GM
5180 for (s = h; s; s = s->next)
5181 s->background_filled_p = 1;
5182 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5183 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219
GM
5184 }
5185 }
58769bee 5186
06a2c219
GM
5187 /* Draw all strings. */
5188 for (s = head; s; s = s->next)
5189 x_draw_glyph_string (s);
dc6f92b8 5190
d9e3b8c6 5191 if (area == TEXT_AREA && !row->full_width_p)
f0a48a01
GM
5192 {
5193 int x0 = head ? head->x : x;
5194 int x1 = tail ? tail->x + tail->background_width : x;
5195
5196 x0 = FRAME_TO_WINDOW_PIXEL_X (w, x0);
5197 x1 = FRAME_TO_WINDOW_PIXEL_X (w, x1);
5198
5199 if (!row->full_width_p && XFASTINT (w->left_margin_width) != 0)
5200 {
5201 int left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
5202 x0 -= left_area_width;
5203 x1 -= left_area_width;
5204 }
5205
5206 notice_overwritten_cursor (w, x0, x1);
5207 }
5208
06a2c219
GM
5209 /* Value is the x-position up to which drawn, relative to AREA of W.
5210 This doesn't include parts drawn because of overhangs. */
5211 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
5212 if (!row->full_width_p)
5213 {
f0a48a01 5214 if (area > LEFT_MARGIN_AREA && XFASTINT (w->left_margin_width) != 0)
06a2c219
GM
5215 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
5216 if (area > TEXT_AREA)
5217 x_reached -= window_box_width (w, TEXT_AREA);
5218 }
a8710abf 5219
06a2c219
GM
5220 return x_reached;
5221}
dc6f92b8 5222
dc6f92b8 5223
66ac4b0e
GM
5224/* Fix the display of area AREA of overlapping row ROW in window W. */
5225
5226static void
5227x_fix_overlapping_area (w, row, area)
5228 struct window *w;
5229 struct glyph_row *row;
5230 enum glyph_row_area area;
5231{
5232 int i, x;
5233
5234 BLOCK_INPUT;
5235
5236 if (area == LEFT_MARGIN_AREA)
5237 x = 0;
5238 else if (area == TEXT_AREA)
5239 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5240 else
5241 x = (window_box_width (w, LEFT_MARGIN_AREA)
5242 + window_box_width (w, TEXT_AREA));
5243
5244 for (i = 0; i < row->used[area];)
5245 {
5246 if (row->glyphs[area][i].overlaps_vertically_p)
5247 {
5248 int start = i, start_x = x;
5249
5250 do
5251 {
5252 x += row->glyphs[area][i].pixel_width;
5253 ++i;
5254 }
5255 while (i < row->used[area]
5256 && row->glyphs[area][i].overlaps_vertically_p);
5257
5258 x_draw_glyphs (w, start_x, row, area, start, i,
f0a48a01 5259 DRAW_NORMAL_TEXT, 1);
66ac4b0e
GM
5260 }
5261 else
5262 {
5263 x += row->glyphs[area][i].pixel_width;
5264 ++i;
5265 }
5266 }
5267
5268 UNBLOCK_INPUT;
5269}
5270
5271
06a2c219
GM
5272/* Output LEN glyphs starting at START at the nominal cursor position.
5273 Advance the nominal cursor over the text. The global variable
5274 updated_window contains the window being updated, updated_row is
5275 the glyph row being updated, and updated_area is the area of that
5276 row being updated. */
dc6f92b8 5277
06a2c219
GM
5278static void
5279x_write_glyphs (start, len)
5280 struct glyph *start;
5281 int len;
5282{
f0a48a01 5283 int x, hpos;
d9cdbb3d 5284
06a2c219 5285 xassert (updated_window && updated_row);
dc6f92b8 5286 BLOCK_INPUT;
06a2c219
GM
5287
5288 /* Write glyphs. */
dc6f92b8 5289
06a2c219
GM
5290 hpos = start - updated_row->glyphs[updated_area];
5291 x = x_draw_glyphs (updated_window, output_cursor.x,
5292 updated_row, updated_area,
5293 hpos, hpos + len,
f0a48a01 5294 DRAW_NORMAL_TEXT, 0);
dc6f92b8
JB
5295
5296 UNBLOCK_INPUT;
06a2c219
GM
5297
5298 /* Advance the output cursor. */
5299 output_cursor.hpos += len;
5300 output_cursor.x = x;
dc6f92b8
JB
5301}
5302
0cdd0c9f 5303
06a2c219 5304/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 5305
06a2c219
GM
5306static void
5307x_insert_glyphs (start, len)
5308 struct glyph *start;
5309 register int len;
5310{
5311 struct frame *f;
5312 struct window *w;
5313 int line_height, shift_by_width, shifted_region_width;
5314 struct glyph_row *row;
5315 struct glyph *glyph;
2beb36f9 5316 int frame_x, frame_y, hpos;
58769bee 5317
06a2c219 5318 xassert (updated_window && updated_row);
0cdd0c9f 5319 BLOCK_INPUT;
06a2c219
GM
5320 w = updated_window;
5321 f = XFRAME (WINDOW_FRAME (w));
5322
5323 /* Get the height of the line we are in. */
5324 row = updated_row;
5325 line_height = row->height;
5326
5327 /* Get the width of the glyphs to insert. */
5328 shift_by_width = 0;
5329 for (glyph = start; glyph < start + len; ++glyph)
5330 shift_by_width += glyph->pixel_width;
5331
5332 /* Get the width of the region to shift right. */
5333 shifted_region_width = (window_box_width (w, updated_area)
5334 - output_cursor.x
5335 - shift_by_width);
5336
5337 /* Shift right. */
bf0ab8a2 5338 frame_x = window_box_left (w, updated_area) + output_cursor.x;
06a2c219
GM
5339 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
5340 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5341 f->output_data.x->normal_gc,
5342 frame_x, frame_y,
5343 shifted_region_width, line_height,
5344 frame_x + shift_by_width, frame_y);
5345
5346 /* Write the glyphs. */
5347 hpos = start - row->glyphs[updated_area];
5348 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
f0a48a01 5349 DRAW_NORMAL_TEXT, 0);
06a2c219
GM
5350
5351 /* Advance the output cursor. */
5352 output_cursor.hpos += len;
5353 output_cursor.x += shift_by_width;
0cdd0c9f
RS
5354 UNBLOCK_INPUT;
5355}
0cdd0c9f 5356
0cdd0c9f 5357
06a2c219
GM
5358/* Delete N glyphs at the nominal cursor position. Not implemented
5359 for X frames. */
c83febd7
RS
5360
5361static void
06a2c219
GM
5362x_delete_glyphs (n)
5363 register int n;
c83febd7 5364{
06a2c219 5365 abort ();
c83febd7
RS
5366}
5367
0cdd0c9f 5368
c5e6e06b
GM
5369/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
5370 If they are <= 0, this is probably an error. */
5371
5372void
5373x_clear_area (dpy, window, x, y, width, height, exposures)
5374 Display *dpy;
5375 Window window;
5376 int x, y;
5377 int width, height;
5378 int exposures;
5379{
5380 xassert (width > 0 && height > 0);
5381 XClearArea (dpy, window, x, y, width, height, exposures);
5382}
5383
5384
06a2c219
GM
5385/* Erase the current text line from the nominal cursor position
5386 (inclusive) to pixel column TO_X (exclusive). The idea is that
5387 everything from TO_X onward is already erased.
5388
5389 TO_X is a pixel position relative to updated_area of
5390 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 5391
06a2c219
GM
5392static void
5393x_clear_end_of_line (to_x)
5394 int to_x;
5395{
5396 struct frame *f;
5397 struct window *w = updated_window;
5398 int max_x, min_y, max_y;
5399 int from_x, from_y, to_y;
5400
5401 xassert (updated_window && updated_row);
5402 f = XFRAME (w->frame);
5403
5404 if (updated_row->full_width_p)
5405 {
5406 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
5407 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5408 && !w->pseudo_window_p)
5409 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 5410 }
06a2c219
GM
5411 else
5412 max_x = window_box_width (w, updated_area);
5413 max_y = window_text_bottom_y (w);
dc6f92b8 5414
06a2c219
GM
5415 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5416 of window. For TO_X > 0, truncate to end of drawing area. */
5417 if (to_x == 0)
5418 return;
5419 else if (to_x < 0)
5420 to_x = max_x;
5421 else
5422 to_x = min (to_x, max_x);
dbc4e1c1 5423
06a2c219
GM
5424 to_y = min (max_y, output_cursor.y + updated_row->height);
5425
5426 /* Notice if the cursor will be cleared by this operation. */
5427 if (!updated_row->full_width_p)
f0a48a01 5428 notice_overwritten_cursor (w, output_cursor.x, -1);
dbc4e1c1 5429
06a2c219
GM
5430 from_x = output_cursor.x;
5431
5432 /* Translate to frame coordinates. */
5433 if (updated_row->full_width_p)
5434 {
5435 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5436 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5437 }
0cdd0c9f
RS
5438 else
5439 {
06a2c219
GM
5440 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5441 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5442 }
5443
045dee35 5444 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5445 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5446 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5447
5448 /* Prevent inadvertently clearing to end of the X window. */
5449 if (to_x > from_x && to_y > from_y)
5450 {
5451 BLOCK_INPUT;
c5e6e06b
GM
5452 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5453 from_x, from_y, to_x - from_x, to_y - from_y,
5454 False);
06a2c219 5455 UNBLOCK_INPUT;
0cdd0c9f 5456 }
0cdd0c9f 5457}
dbc4e1c1 5458
0cdd0c9f 5459
06a2c219 5460/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5461 frame. Otherwise clear the selected frame. */
06a2c219
GM
5462
5463static void
5464x_clear_frame ()
0cdd0c9f 5465{
06a2c219 5466 struct frame *f;
0cdd0c9f 5467
06a2c219
GM
5468 if (updating_frame)
5469 f = updating_frame;
0cdd0c9f 5470 else
b86bd3dd 5471 f = SELECTED_FRAME ();
58769bee 5472
06a2c219
GM
5473 /* Clearing the frame will erase any cursor, so mark them all as no
5474 longer visible. */
5475 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5476 output_cursor.hpos = output_cursor.vpos = 0;
5477 output_cursor.x = -1;
5478
5479 /* We don't set the output cursor here because there will always
5480 follow an explicit cursor_to. */
5481 BLOCK_INPUT;
5482 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5483
5484 /* We have to clear the scroll bars, too. If we have changed
5485 colors or something like that, then they should be notified. */
5486 x_scroll_bar_clear (f);
0cdd0c9f 5487
06a2c219
GM
5488 XFlush (FRAME_X_DISPLAY (f));
5489 UNBLOCK_INPUT;
dc6f92b8 5490}
06a2c219
GM
5491
5492
dc6f92b8 5493\f
dbc4e1c1
JB
5494/* Invert the middle quarter of the frame for .15 sec. */
5495
06a2c219
GM
5496/* We use the select system call to do the waiting, so we have to make
5497 sure it's available. If it isn't, we just won't do visual bells. */
5498
dbc4e1c1
JB
5499#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5500
06a2c219
GM
5501
5502/* Subtract the `struct timeval' values X and Y, storing the result in
5503 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5504
5505static int
5506timeval_subtract (result, x, y)
5507 struct timeval *result, x, y;
5508{
06a2c219
GM
5509 /* Perform the carry for the later subtraction by updating y. This
5510 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5511 if (x.tv_usec < y.tv_usec)
5512 {
5513 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5514 y.tv_usec -= 1000000 * nsec;
5515 y.tv_sec += nsec;
5516 }
06a2c219 5517
dbc4e1c1
JB
5518 if (x.tv_usec - y.tv_usec > 1000000)
5519 {
5520 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5521 y.tv_usec += 1000000 * nsec;
5522 y.tv_sec -= nsec;
5523 }
5524
06a2c219
GM
5525 /* Compute the time remaining to wait. tv_usec is certainly
5526 positive. */
dbc4e1c1
JB
5527 result->tv_sec = x.tv_sec - y.tv_sec;
5528 result->tv_usec = x.tv_usec - y.tv_usec;
5529
06a2c219
GM
5530 /* Return indication of whether the result should be considered
5531 negative. */
dbc4e1c1
JB
5532 return x.tv_sec < y.tv_sec;
5533}
dc6f92b8 5534
dfcf069d 5535void
f676886a
JB
5536XTflash (f)
5537 struct frame *f;
dc6f92b8 5538{
dbc4e1c1 5539 BLOCK_INPUT;
dc6f92b8 5540
dbc4e1c1
JB
5541 {
5542 GC gc;
dc6f92b8 5543
06a2c219
GM
5544 /* Create a GC that will use the GXxor function to flip foreground
5545 pixels into background pixels. */
dbc4e1c1
JB
5546 {
5547 XGCValues values;
dc6f92b8 5548
dbc4e1c1 5549 values.function = GXxor;
7556890b
RS
5550 values.foreground = (f->output_data.x->foreground_pixel
5551 ^ f->output_data.x->background_pixel);
58769bee 5552
334208b7 5553 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5554 GCFunction | GCForeground, &values);
5555 }
dc6f92b8 5556
dbc4e1c1 5557 {
e84e14c3
RS
5558 /* Get the height not including a menu bar widget. */
5559 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5560 /* Height of each line to flash. */
5561 int flash_height = FRAME_LINE_HEIGHT (f);
5562 /* These will be the left and right margins of the rectangles. */
5563 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5564 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5565
5566 int width;
5567
5568 /* Don't flash the area between a scroll bar and the frame
5569 edge it is next to. */
5570 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5571 {
5572 case vertical_scroll_bar_left:
5573 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5574 break;
5575
5576 case vertical_scroll_bar_right:
5577 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5578 break;
06a2c219
GM
5579
5580 default:
5581 break;
e84e14c3
RS
5582 }
5583
5584 width = flash_right - flash_left;
5585
5586 /* If window is tall, flash top and bottom line. */
5587 if (height > 3 * FRAME_LINE_HEIGHT (f))
5588 {
5589 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5590 flash_left,
5591 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5592 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5593 width, flash_height);
5594 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5595 flash_left,
5596 (height - flash_height
5597 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5598 width, flash_height);
5599 }
5600 else
5601 /* If it is short, flash it all. */
5602 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5603 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5604 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5605
06a2c219 5606 x_flush (f);
dc6f92b8 5607
dbc4e1c1 5608 {
06a2c219 5609 struct timeval wakeup;
dc6f92b8 5610
66c30ea1 5611 EMACS_GET_TIME (wakeup);
dc6f92b8 5612
dbc4e1c1
JB
5613 /* Compute time to wait until, propagating carry from usecs. */
5614 wakeup.tv_usec += 150000;
5615 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5616 wakeup.tv_usec %= 1000000;
5617
101922c3
GM
5618 /* Keep waiting until past the time wakeup or any input gets
5619 available. */
5620 while (! detect_input_pending ())
dbc4e1c1 5621 {
101922c3 5622 struct timeval current;
dbc4e1c1
JB
5623 struct timeval timeout;
5624
101922c3 5625 EMACS_GET_TIME (current);
dbc4e1c1 5626
101922c3
GM
5627 /* Break if result would be negative. */
5628 if (timeval_subtract (&current, wakeup, current))
dbc4e1c1
JB
5629 break;
5630
101922c3
GM
5631 /* How long `select' should wait. */
5632 timeout.tv_sec = 0;
5633 timeout.tv_usec = 10000;
5634
dbc4e1c1 5635 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5636 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5637 }
5638 }
58769bee 5639
e84e14c3
RS
5640 /* If window is tall, flash top and bottom line. */
5641 if (height > 3 * FRAME_LINE_HEIGHT (f))
5642 {
5643 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5644 flash_left,
5645 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5646 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5647 width, flash_height);
5648 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5649 flash_left,
5650 (height - flash_height
5651 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5652 width, flash_height);
5653 }
5654 else
5655 /* If it is short, flash it all. */
5656 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5657 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5658 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5659
334208b7 5660 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5661 x_flush (f);
dc6f92b8 5662 }
dbc4e1c1
JB
5663 }
5664
5665 UNBLOCK_INPUT;
dc6f92b8
JB
5666}
5667
06a2c219 5668#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5669
5670
dc6f92b8
JB
5671/* Make audible bell. */
5672
dfcf069d 5673void
dc6f92b8
JB
5674XTring_bell ()
5675{
b86bd3dd
GM
5676 struct frame *f = SELECTED_FRAME ();
5677
5678 if (FRAME_X_DISPLAY (f))
5679 {
dbc4e1c1 5680#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5681 if (visible_bell)
5682 XTflash (f);
5683 else
dbc4e1c1 5684#endif
b86bd3dd
GM
5685 {
5686 BLOCK_INPUT;
5687 XBell (FRAME_X_DISPLAY (f), 0);
5688 XFlush (FRAME_X_DISPLAY (f));
5689 UNBLOCK_INPUT;
5690 }
dc6f92b8
JB
5691 }
5692}
06a2c219 5693
dc6f92b8 5694\f
06a2c219
GM
5695/* Specify how many text lines, from the top of the window,
5696 should be affected by insert-lines and delete-lines operations.
5697 This, and those operations, are used only within an update
5698 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5699
dfcf069d 5700static void
06a2c219
GM
5701XTset_terminal_window (n)
5702 register int n;
dc6f92b8 5703{
06a2c219 5704 /* This function intentionally left blank. */
dc6f92b8
JB
5705}
5706
06a2c219
GM
5707
5708\f
5709/***********************************************************************
5710 Line Dance
5711 ***********************************************************************/
5712
5713/* Perform an insert-lines or delete-lines operation, inserting N
5714 lines or deleting -N lines at vertical position VPOS. */
5715
dfcf069d 5716static void
06a2c219
GM
5717x_ins_del_lines (vpos, n)
5718 int vpos, n;
dc6f92b8
JB
5719{
5720 abort ();
5721}
06a2c219
GM
5722
5723
5724/* Scroll part of the display as described by RUN. */
dc6f92b8 5725
dfcf069d 5726static void
06a2c219
GM
5727x_scroll_run (w, run)
5728 struct window *w;
5729 struct run *run;
dc6f92b8 5730{
06a2c219
GM
5731 struct frame *f = XFRAME (w->frame);
5732 int x, y, width, height, from_y, to_y, bottom_y;
5733
5734 /* Get frame-relative bounding box of the text display area of W,
5735 without mode lines. Include in this box the flags areas to the
5736 left and right of W. */
5737 window_box (w, -1, &x, &y, &width, &height);
110859fc
GM
5738 width += FRAME_X_FLAGS_AREA_WIDTH (f);
5739 x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
5740
5741 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5742 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5743 bottom_y = y + height;
dc6f92b8 5744
06a2c219
GM
5745 if (to_y < from_y)
5746 {
5747 /* Scrolling up. Make sure we don't copy part of the mode
5748 line at the bottom. */
5749 if (from_y + run->height > bottom_y)
5750 height = bottom_y - from_y;
5751 else
5752 height = run->height;
5753 }
dc6f92b8 5754 else
06a2c219
GM
5755 {
5756 /* Scolling down. Make sure we don't copy over the mode line.
5757 at the bottom. */
5758 if (to_y + run->height > bottom_y)
5759 height = bottom_y - to_y;
5760 else
5761 height = run->height;
5762 }
7a13e894 5763
06a2c219
GM
5764 BLOCK_INPUT;
5765
5766 /* Cursor off. Will be switched on again in x_update_window_end. */
5767 updated_window = w;
5768 x_clear_cursor (w);
5769
5770 XCopyArea (FRAME_X_DISPLAY (f),
5771 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5772 f->output_data.x->normal_gc,
5773 x, from_y,
5774 width, height,
5775 x, to_y);
5776
5777 UNBLOCK_INPUT;
5778}
dc6f92b8 5779
dc6f92b8 5780
06a2c219
GM
5781\f
5782/***********************************************************************
5783 Exposure Events
5784 ***********************************************************************/
5785
5786/* Redisplay an exposed area of frame F. X and Y are the upper-left
5787 corner of the exposed rectangle. W and H are width and height of
5788 the exposed area. All are pixel values. W or H zero means redraw
5789 the entire frame. */
dc6f92b8 5790
06a2c219
GM
5791static void
5792expose_frame (f, x, y, w, h)
5793 struct frame *f;
5794 int x, y, w, h;
dc6f92b8 5795{
06a2c219 5796 XRectangle r;
82f053ab 5797 int mouse_face_overwritten_p = 0;
dc6f92b8 5798
06a2c219 5799 TRACE ((stderr, "expose_frame "));
dc6f92b8 5800
06a2c219
GM
5801 /* No need to redraw if frame will be redrawn soon. */
5802 if (FRAME_GARBAGED_P (f))
dc6f92b8 5803 {
06a2c219
GM
5804 TRACE ((stderr, " garbaged\n"));
5805 return;
5806 }
5807
5808 /* If basic faces haven't been realized yet, there is no point in
5809 trying to redraw anything. This can happen when we get an expose
5810 event while Emacs is starting, e.g. by moving another window. */
5811 if (FRAME_FACE_CACHE (f) == NULL
5812 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5813 {
5814 TRACE ((stderr, " no faces\n"));
5815 return;
58769bee 5816 }
06a2c219
GM
5817
5818 if (w == 0 || h == 0)
58769bee 5819 {
06a2c219
GM
5820 r.x = r.y = 0;
5821 r.width = CANON_X_UNIT (f) * f->width;
5822 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5823 }
5824 else
5825 {
06a2c219
GM
5826 r.x = x;
5827 r.y = y;
5828 r.width = w;
5829 r.height = h;
5830 }
5831
5832 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
82f053ab 5833 mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
06a2c219 5834
9ea173e8 5835 if (WINDOWP (f->tool_bar_window))
82f053ab
GM
5836 mouse_face_overwritten_p
5837 |= expose_window (XWINDOW (f->tool_bar_window), &r);
06a2c219
GM
5838
5839#ifndef USE_X_TOOLKIT
5840 if (WINDOWP (f->menu_bar_window))
82f053ab
GM
5841 mouse_face_overwritten_p
5842 |= expose_window (XWINDOW (f->menu_bar_window), &r);
06a2c219 5843#endif /* not USE_X_TOOLKIT */
82f053ab
GM
5844
5845 /* Some window managers support a focus-follows-mouse style with
5846 delayed raising of frames. Imagine a partially obscured frame,
5847 and moving the mouse into partially obscured mouse-face on that
5848 frame. The visible part of the mouse-face will be highlighted,
5849 then the WM raises the obscured frame. With at least one WM, KDE
5850 2.1, Emacs is not getting any event for the raising of the frame
5851 (even tried with SubstructureRedirectMask), only Expose events.
5852 These expose events will draw text normally, i.e. not
5853 highlighted. Which means we must redo the highlight here.
5854 Subsume it under ``we love X''. --gerd 2001-08-15 */
5855 if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
5856 {
5857 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5858 if (f == dpyinfo->mouse_face_mouse_frame)
5859 {
5860 int x = dpyinfo->mouse_face_mouse_x;
5861 int y = dpyinfo->mouse_face_mouse_y;
5862 clear_mouse_face (dpyinfo);
5863 note_mouse_highlight (f, x, y);
5864 }
5865 }
dc6f92b8
JB
5866}
5867
06a2c219
GM
5868
5869/* Redraw (parts) of all windows in the window tree rooted at W that
82f053ab
GM
5870 intersect R. R contains frame pixel coordinates. Value is
5871 non-zero if the exposure overwrites mouse-face. */
06a2c219 5872
82f053ab 5873static int
06a2c219
GM
5874expose_window_tree (w, r)
5875 struct window *w;
5876 XRectangle *r;
dc6f92b8 5877{
82f053ab
GM
5878 struct frame *f = XFRAME (w->frame);
5879 int mouse_face_overwritten_p = 0;
5880
5881 while (w && !FRAME_GARBAGED_P (f))
06a2c219
GM
5882 {
5883 if (!NILP (w->hchild))
82f053ab
GM
5884 mouse_face_overwritten_p
5885 |= expose_window_tree (XWINDOW (w->hchild), r);
06a2c219 5886 else if (!NILP (w->vchild))
82f053ab
GM
5887 mouse_face_overwritten_p
5888 |= expose_window_tree (XWINDOW (w->vchild), r);
5889 else
5890 mouse_face_overwritten_p |= expose_window (w, r);
5891
a02f1be0 5892 w = NILP (w->next) ? NULL : XWINDOW (w->next);
06a2c219 5893 }
82f053ab
GM
5894
5895 return mouse_face_overwritten_p;
06a2c219 5896}
58769bee 5897
dc6f92b8 5898
06a2c219
GM
5899/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5900 which intersects rectangle R. R is in window-relative coordinates. */
5901
5902static void
5903expose_area (w, row, r, area)
5904 struct window *w;
5905 struct glyph_row *row;
5906 XRectangle *r;
5907 enum glyph_row_area area;
5908{
06a2c219
GM
5909 struct glyph *first = row->glyphs[area];
5910 struct glyph *end = row->glyphs[area] + row->used[area];
5911 struct glyph *last;
4bc6dcc7 5912 int first_x, start_x, x;
06a2c219 5913
6fb13182
GM
5914 if (area == TEXT_AREA && row->fill_line_p)
5915 /* If row extends face to end of line write the whole line. */
153f5ed7 5916 x_draw_glyphs (w, 0, row, area, 0, row->used[area],
f0a48a01 5917 DRAW_NORMAL_TEXT, 0);
6fb13182
GM
5918 else
5919 {
4bc6dcc7
GM
5920 /* Set START_X to the window-relative start position for drawing glyphs of
5921 AREA. The first glyph of the text area can be partially visible.
5922 The first glyphs of other areas cannot. */
5923 if (area == LEFT_MARGIN_AREA)
5924 start_x = 0;
5925 else if (area == TEXT_AREA)
5926 start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5927 else
5928 start_x = (window_box_width (w, LEFT_MARGIN_AREA)
5929 + window_box_width (w, TEXT_AREA));
5930 x = start_x;
5931
6fb13182
GM
5932 /* Find the first glyph that must be redrawn. */
5933 while (first < end
5934 && x + first->pixel_width < r->x)
5935 {
5936 x += first->pixel_width;
5937 ++first;
5938 }
5939
5940 /* Find the last one. */
5941 last = first;
5942 first_x = x;
5943 while (last < end
5944 && x < r->x + r->width)
5945 {
5946 x += last->pixel_width;
5947 ++last;
5948 }
5949
5950 /* Repaint. */
5951 if (last > first)
4bc6dcc7 5952 x_draw_glyphs (w, first_x - start_x, row, area,
6fb13182
GM
5953 first - row->glyphs[area],
5954 last - row->glyphs[area],
f0a48a01 5955 DRAW_NORMAL_TEXT, 0);
6fb13182 5956 }
06a2c219
GM
5957}
5958
58769bee 5959
06a2c219 5960/* Redraw the parts of the glyph row ROW on window W intersecting
82f053ab
GM
5961 rectangle R. R is in window-relative coordinates. Value is
5962 non-zero if mouse-face was overwritten. */
dc6f92b8 5963
82f053ab 5964static int
06a2c219
GM
5965expose_line (w, row, r)
5966 struct window *w;
5967 struct glyph_row *row;
5968 XRectangle *r;
5969{
5970 xassert (row->enabled_p);
5971
5972 if (row->mode_line_p || w->pseudo_window_p)
5973 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
f0a48a01 5974 DRAW_NORMAL_TEXT, 0);
06a2c219
GM
5975 else
5976 {
5977 if (row->used[LEFT_MARGIN_AREA])
5978 expose_area (w, row, r, LEFT_MARGIN_AREA);
5979 if (row->used[TEXT_AREA])
5980 expose_area (w, row, r, TEXT_AREA);
5981 if (row->used[RIGHT_MARGIN_AREA])
5982 expose_area (w, row, r, RIGHT_MARGIN_AREA);
5983 x_draw_row_bitmaps (w, row);
5984 }
82f053ab
GM
5985
5986 return row->mouse_face_p;
06a2c219 5987}
dc6f92b8 5988
58769bee 5989
06a2c219
GM
5990/* Return non-zero if W's cursor intersects rectangle R. */
5991
5992static int
5993x_phys_cursor_in_rect_p (w, r)
5994 struct window *w;
5995 XRectangle *r;
5996{
5997 XRectangle cr, result;
5998 struct glyph *cursor_glyph;
5999
6000 cursor_glyph = get_phys_cursor_glyph (w);
6001 if (cursor_glyph)
6002 {
6003 cr.x = w->phys_cursor.x;
6004 cr.y = w->phys_cursor.y;
6005 cr.width = cursor_glyph->pixel_width;
6006 cr.height = w->phys_cursor_height;
6007 return x_intersect_rectangles (&cr, r, &result);
6008 }
6009 else
6010 return 0;
dc6f92b8 6011}
dc6f92b8 6012
06a2c219 6013
a02f1be0
GM
6014/* Redraw the part of window W intersection rectangle FR. Pixel
6015 coordinates in FR are frame-relative. Call this function with
82f053ab
GM
6016 input blocked. Value is non-zero if the exposure overwrites
6017 mouse-face. */
dc6f92b8 6018
a39202f6 6019static int
a02f1be0 6020expose_window (w, fr)
06a2c219 6021 struct window *w;
a02f1be0 6022 XRectangle *fr;
dc6f92b8 6023{
a02f1be0 6024 struct frame *f = XFRAME (w->frame);
a02f1be0 6025 XRectangle wr, r;
82f053ab 6026 int mouse_face_overwritten_p = 0;
dc6f92b8 6027
80c32bcc
GM
6028 /* If window is not yet fully initialized, do nothing. This can
6029 happen when toolkit scroll bars are used and a window is split.
6030 Reconfiguring the scroll bar will generate an expose for a newly
6031 created window. */
a39202f6 6032 if (w->current_matrix == NULL)
82f053ab 6033 return 0;
a39202f6
GM
6034
6035 /* When we're currently updating the window, display and current
6036 matrix usually don't agree. Arrange for a thorough display
6037 later. */
6038 if (w == updated_window)
6039 {
6040 SET_FRAME_GARBAGED (f);
6041 return 0;
6042 }
80c32bcc 6043
a39202f6 6044 /* Frame-relative pixel rectangle of W. */
a02f1be0
GM
6045 wr.x = XFASTINT (w->left) * CANON_X_UNIT (f);
6046 wr.y = XFASTINT (w->top) * CANON_Y_UNIT (f);
6047 wr.width = XFASTINT (w->width) * CANON_X_UNIT (f);
6048 wr.height = XFASTINT (w->height) * CANON_Y_UNIT (f);
6049
a39202f6
GM
6050 if (x_intersect_rectangles (fr, &wr, &r))
6051 {
6052 int yb = window_text_bottom_y (w);
6053 struct glyph_row *row;
6054 int cursor_cleared_p;
a02f1be0 6055
a39202f6
GM
6056 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
6057 r.x, r.y, r.width, r.height));
dc6f92b8 6058
a39202f6
GM
6059 /* Convert to window coordinates. */
6060 r.x = FRAME_TO_WINDOW_PIXEL_X (w, r.x);
6061 r.y = FRAME_TO_WINDOW_PIXEL_Y (w, r.y);
dc6f92b8 6062
a39202f6
GM
6063 /* Turn off the cursor. */
6064 if (!w->pseudo_window_p
6065 && x_phys_cursor_in_rect_p (w, &r))
6066 {
6067 x_clear_cursor (w);
6068 cursor_cleared_p = 1;
6069 }
6070 else
6071 cursor_cleared_p = 0;
06a2c219 6072
a39202f6
GM
6073 /* Find the first row intersecting the rectangle R. */
6074 for (row = w->current_matrix->rows;
6075 row->enabled_p;
6076 ++row)
6077 {
6078 int y0 = row->y;
6079 int y1 = MATRIX_ROW_BOTTOM_Y (row);
6080
6081 if ((y0 >= r.y && y0 < r.y + r.height)
6082 || (y1 > r.y && y1 < r.y + r.height)
6083 || (r.y >= y0 && r.y < y1)
6084 || (r.y + r.height > y0 && r.y + r.height < y1))
82f053ab
GM
6085 {
6086 if (expose_line (w, row, &r))
6087 mouse_face_overwritten_p = 1;
6088 }
6089
a39202f6
GM
6090 if (y1 >= yb)
6091 break;
6092 }
dc6f92b8 6093
a39202f6
GM
6094 /* Display the mode line if there is one. */
6095 if (WINDOW_WANTS_MODELINE_P (w)
6096 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
6097 row->enabled_p)
6098 && row->y < r.y + r.height)
82f053ab
GM
6099 {
6100 if (expose_line (w, row, &r))
6101 mouse_face_overwritten_p = 1;
6102 }
a39202f6
GM
6103
6104 if (!w->pseudo_window_p)
6105 {
6106 /* Draw border between windows. */
6107 x_draw_vertical_border (w);
06a2c219 6108
a39202f6
GM
6109 /* Turn the cursor on again. */
6110 if (cursor_cleared_p)
6111 x_update_window_cursor (w, 1);
6112 }
06a2c219 6113 }
82f053ab
GM
6114
6115 return mouse_face_overwritten_p;
06a2c219 6116}
dc6f92b8 6117
dc6f92b8 6118
06a2c219
GM
6119/* Determine the intersection of two rectangles R1 and R2. Return
6120 the intersection in *RESULT. Value is non-zero if RESULT is not
6121 empty. */
6122
6123static int
6124x_intersect_rectangles (r1, r2, result)
6125 XRectangle *r1, *r2, *result;
6126{
6127 XRectangle *left, *right;
6128 XRectangle *upper, *lower;
6129 int intersection_p = 0;
6130
6131 /* Rearrange so that R1 is the left-most rectangle. */
6132 if (r1->x < r2->x)
6133 left = r1, right = r2;
6134 else
6135 left = r2, right = r1;
6136
6137 /* X0 of the intersection is right.x0, if this is inside R1,
6138 otherwise there is no intersection. */
6139 if (right->x <= left->x + left->width)
6140 {
6141 result->x = right->x;
6142
6143 /* The right end of the intersection is the minimum of the
6144 the right ends of left and right. */
6145 result->width = (min (left->x + left->width, right->x + right->width)
6146 - result->x);
6147
6148 /* Same game for Y. */
6149 if (r1->y < r2->y)
6150 upper = r1, lower = r2;
6151 else
6152 upper = r2, lower = r1;
6153
6154 /* The upper end of the intersection is lower.y0, if this is inside
6155 of upper. Otherwise, there is no intersection. */
6156 if (lower->y <= upper->y + upper->height)
dc43ef94 6157 {
06a2c219
GM
6158 result->y = lower->y;
6159
6160 /* The lower end of the intersection is the minimum of the lower
6161 ends of upper and lower. */
6162 result->height = (min (lower->y + lower->height,
6163 upper->y + upper->height)
6164 - result->y);
6165 intersection_p = 1;
dc43ef94 6166 }
dc6f92b8
JB
6167 }
6168
06a2c219 6169 return intersection_p;
dc6f92b8 6170}
06a2c219
GM
6171
6172
6173
6174
dc6f92b8 6175\f
dc6f92b8 6176static void
334208b7
RS
6177frame_highlight (f)
6178 struct frame *f;
dc6f92b8 6179{
b3e1e05c
JB
6180 /* We used to only do this if Vx_no_window_manager was non-nil, but
6181 the ICCCM (section 4.1.6) says that the window's border pixmap
6182 and border pixel are window attributes which are "private to the
6183 client", so we can always change it to whatever we want. */
6184 BLOCK_INPUT;
334208b7 6185 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6186 f->output_data.x->border_pixel);
b3e1e05c 6187 UNBLOCK_INPUT;
5d46f928 6188 x_update_cursor (f, 1);
dc6f92b8
JB
6189}
6190
6191static void
334208b7
RS
6192frame_unhighlight (f)
6193 struct frame *f;
dc6f92b8 6194{
b3e1e05c
JB
6195 /* We used to only do this if Vx_no_window_manager was non-nil, but
6196 the ICCCM (section 4.1.6) says that the window's border pixmap
6197 and border pixel are window attributes which are "private to the
6198 client", so we can always change it to whatever we want. */
6199 BLOCK_INPUT;
334208b7 6200 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6201 f->output_data.x->border_tile);
b3e1e05c 6202 UNBLOCK_INPUT;
5d46f928 6203 x_update_cursor (f, 1);
dc6f92b8 6204}
dc6f92b8 6205
f676886a
JB
6206/* The focus has changed. Update the frames as necessary to reflect
6207 the new situation. Note that we can't change the selected frame
c5acd733 6208 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 6209 Each event gets marked with the frame in which it occurred, so the
c5acd733 6210 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 6211
6d4238f3 6212static void
0f941935
KH
6213x_new_focus_frame (dpyinfo, frame)
6214 struct x_display_info *dpyinfo;
f676886a 6215 struct frame *frame;
dc6f92b8 6216{
0f941935 6217 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 6218
0f941935 6219 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 6220 {
58769bee 6221 /* Set this before calling other routines, so that they see
f676886a 6222 the correct value of x_focus_frame. */
0f941935 6223 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
6224
6225 if (old_focus && old_focus->auto_lower)
f676886a 6226 x_lower_frame (old_focus);
dc6f92b8
JB
6227
6228#if 0
f676886a 6229 selected_frame = frame;
e0c1aef2
KH
6230 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6231 selected_frame);
f676886a
JB
6232 Fselect_window (selected_frame->selected_window);
6233 choose_minibuf_frame ();
c118dd06 6234#endif /* ! 0 */
dc6f92b8 6235
0f941935
KH
6236 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6237 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
6238 else
6239 pending_autoraise_frame = 0;
6d4238f3 6240 }
dc6f92b8 6241
0f941935 6242 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
6243}
6244
37c2c98b
RS
6245/* Handle an event saying the mouse has moved out of an Emacs frame. */
6246
6247void
0f941935
KH
6248x_mouse_leave (dpyinfo)
6249 struct x_display_info *dpyinfo;
37c2c98b 6250{
0f941935 6251 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 6252}
6d4238f3 6253
f451eb13
JB
6254/* The focus has changed, or we have redirected a frame's focus to
6255 another frame (this happens when a frame uses a surrogate
06a2c219 6256 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
6257
6258 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 6259 frame is being highlighted or un-highlighted; we only use it to find
0f941935 6260 the appropriate X display info. */
06a2c219 6261
6d4238f3 6262static void
0f941935
KH
6263XTframe_rehighlight (frame)
6264 struct frame *frame;
6d4238f3 6265{
0f941935
KH
6266 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6267}
6d4238f3 6268
0f941935
KH
6269static void
6270x_frame_rehighlight (dpyinfo)
6271 struct x_display_info *dpyinfo;
6272{
6273 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6274
6275 if (dpyinfo->x_focus_frame)
6d4238f3 6276 {
0f941935
KH
6277 dpyinfo->x_highlight_frame
6278 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6279 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6280 : dpyinfo->x_focus_frame);
6281 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 6282 {
0f941935
KH
6283 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6284 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 6285 }
dc6f92b8 6286 }
6d4238f3 6287 else
0f941935 6288 dpyinfo->x_highlight_frame = 0;
dc6f92b8 6289
0f941935 6290 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
6291 {
6292 if (old_highlight)
f676886a 6293 frame_unhighlight (old_highlight);
0f941935
KH
6294 if (dpyinfo->x_highlight_frame)
6295 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 6296 }
dc6f92b8 6297}
06a2c219
GM
6298
6299
dc6f92b8 6300\f
06a2c219 6301/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 6302
28430d3c
JB
6303/* Initialize mode_switch_bit and modifier_meaning. */
6304static void
334208b7
RS
6305x_find_modifier_meanings (dpyinfo)
6306 struct x_display_info *dpyinfo;
28430d3c 6307{
f689eb05 6308 int min_code, max_code;
28430d3c
JB
6309 KeySym *syms;
6310 int syms_per_code;
6311 XModifierKeymap *mods;
6312
334208b7
RS
6313 dpyinfo->meta_mod_mask = 0;
6314 dpyinfo->shift_lock_mask = 0;
6315 dpyinfo->alt_mod_mask = 0;
6316 dpyinfo->super_mod_mask = 0;
6317 dpyinfo->hyper_mod_mask = 0;
58769bee 6318
9658a521 6319#ifdef HAVE_X11R4
334208b7 6320 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 6321#else
4a60f8c5
RS
6322 min_code = dpyinfo->display->min_keycode;
6323 max_code = dpyinfo->display->max_keycode;
9658a521
JB
6324#endif
6325
334208b7 6326 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
6327 min_code, max_code - min_code + 1,
6328 &syms_per_code);
334208b7 6329 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 6330
58769bee 6331 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 6332 Alt keysyms are on. */
28430d3c 6333 {
06a2c219 6334 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
6335
6336 for (row = 3; row < 8; row++)
6337 for (col = 0; col < mods->max_keypermod; col++)
6338 {
0299d313
RS
6339 KeyCode code
6340 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 6341
af92970c
KH
6342 /* Zeroes are used for filler. Skip them. */
6343 if (code == 0)
6344 continue;
6345
28430d3c
JB
6346 /* Are any of this keycode's keysyms a meta key? */
6347 {
6348 int code_col;
6349
6350 for (code_col = 0; code_col < syms_per_code; code_col++)
6351 {
f689eb05 6352 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 6353
f689eb05 6354 switch (sym)
28430d3c 6355 {
f689eb05
JB
6356 case XK_Meta_L:
6357 case XK_Meta_R:
334208b7 6358 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 6359 break;
f689eb05
JB
6360
6361 case XK_Alt_L:
6362 case XK_Alt_R:
334208b7 6363 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
6364 break;
6365
6366 case XK_Hyper_L:
6367 case XK_Hyper_R:
334208b7 6368 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
6369 break;
6370
6371 case XK_Super_L:
6372 case XK_Super_R:
334208b7 6373 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 6374 break;
11edeb03
JB
6375
6376 case XK_Shift_Lock:
6377 /* Ignore this if it's not on the lock modifier. */
6378 if ((1 << row) == LockMask)
334208b7 6379 dpyinfo->shift_lock_mask = LockMask;
11edeb03 6380 break;
28430d3c
JB
6381 }
6382 }
6383 }
6384 }
6385 }
6386
f689eb05 6387 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 6388 if (! dpyinfo->meta_mod_mask)
a3c44b14 6389 {
334208b7
RS
6390 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6391 dpyinfo->alt_mod_mask = 0;
a3c44b14 6392 }
f689eb05 6393
148c4b70
RS
6394 /* If some keys are both alt and meta,
6395 make them just meta, not alt. */
334208b7 6396 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 6397 {
334208b7 6398 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 6399 }
58769bee 6400
28430d3c 6401 XFree ((char *) syms);
f689eb05 6402 XFreeModifiermap (mods);
28430d3c
JB
6403}
6404
dfeccd2d
JB
6405/* Convert between the modifier bits X uses and the modifier bits
6406 Emacs uses. */
06a2c219 6407
7c5283e4 6408static unsigned int
334208b7
RS
6409x_x_to_emacs_modifiers (dpyinfo, state)
6410 struct x_display_info *dpyinfo;
dc6f92b8
JB
6411 unsigned int state;
6412{
334208b7
RS
6413 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
6414 | ((state & ControlMask) ? ctrl_modifier : 0)
6415 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
6416 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
6417 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
6418 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
6419}
6420
dfeccd2d 6421static unsigned int
334208b7
RS
6422x_emacs_to_x_modifiers (dpyinfo, state)
6423 struct x_display_info *dpyinfo;
dfeccd2d
JB
6424 unsigned int state;
6425{
334208b7
RS
6426 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
6427 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6428 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6429 | ((state & shift_modifier) ? ShiftMask : 0)
6430 | ((state & ctrl_modifier) ? ControlMask : 0)
6431 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6432}
d047c4eb
KH
6433
6434/* Convert a keysym to its name. */
6435
6436char *
6437x_get_keysym_name (keysym)
6438 KeySym keysym;
6439{
6440 char *value;
6441
6442 BLOCK_INPUT;
6443 value = XKeysymToString (keysym);
6444 UNBLOCK_INPUT;
6445
6446 return value;
6447}
06a2c219
GM
6448
6449
e4571a43
JB
6450\f
6451/* Mouse clicks and mouse movement. Rah. */
e4571a43 6452
06a2c219
GM
6453/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6454 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6455 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6456 not force the value into range. */
69388238 6457
c8dba240 6458void
69388238 6459pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6460 FRAME_PTR f;
69388238 6461 register int pix_x, pix_y;
e4571a43
JB
6462 register int *x, *y;
6463 XRectangle *bounds;
69388238 6464 int noclip;
e4571a43 6465{
06a2c219 6466 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6467 even for negative values. */
6468 if (pix_x < 0)
7556890b 6469 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6470 if (pix_y < 0)
7556890b 6471 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6472
e4571a43
JB
6473 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6474 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6475
6476 if (bounds)
6477 {
7556890b
RS
6478 bounds->width = FONT_WIDTH (f->output_data.x->font);
6479 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6480 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6481 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6482 }
6483
69388238
RS
6484 if (!noclip)
6485 {
6486 if (pix_x < 0)
6487 pix_x = 0;
3cbd2e0b
RS
6488 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6489 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6490
6491 if (pix_y < 0)
6492 pix_y = 0;
6493 else if (pix_y > f->height)
6494 pix_y = f->height;
6495 }
e4571a43
JB
6496
6497 *x = pix_x;
6498 *y = pix_y;
6499}
6500
06a2c219
GM
6501
6502/* Given HPOS/VPOS in the current matrix of W, return corresponding
6503 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6504 can't tell the positions because W's display is not up to date,
6505 return 0. */
6506
6507int
6508glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6509 struct window *w;
6510 int hpos, vpos;
6511 int *frame_x, *frame_y;
2b5c9e71 6512{
06a2c219
GM
6513 int success_p;
6514
6515 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6516 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6517
6518 if (display_completed)
6519 {
6520 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6521 struct glyph *glyph = row->glyphs[TEXT_AREA];
6522 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6523
6524 *frame_y = row->y;
6525 *frame_x = row->x;
6526 while (glyph < end)
6527 {
6528 *frame_x += glyph->pixel_width;
6529 ++glyph;
6530 }
6531
6532 success_p = 1;
6533 }
6534 else
6535 {
6536 *frame_y = *frame_x = 0;
6537 success_p = 0;
6538 }
6539
6540 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6541 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6542 return success_p;
2b5c9e71
RS
6543}
6544
06a2c219 6545
dc6f92b8
JB
6546/* Prepare a mouse-event in *RESULT for placement in the input queue.
6547
6548 If the event is a button press, then note that we have grabbed
f451eb13 6549 the mouse. */
dc6f92b8
JB
6550
6551static Lisp_Object
f451eb13 6552construct_mouse_click (result, event, f)
dc6f92b8
JB
6553 struct input_event *result;
6554 XButtonEvent *event;
f676886a 6555 struct frame *f;
dc6f92b8 6556{
f451eb13 6557 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6558 otherwise. */
f451eb13 6559 result->kind = mouse_click;
69388238 6560 result->code = event->button - Button1;
1113d9db 6561 result->timestamp = event->time;
334208b7
RS
6562 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6563 event->state)
f689eb05 6564 | (event->type == ButtonRelease
58769bee 6565 ? up_modifier
f689eb05 6566 : down_modifier));
dc6f92b8 6567
06a2c219
GM
6568 XSETINT (result->x, event->x);
6569 XSETINT (result->y, event->y);
6570 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6571 result->arg = Qnil;
06a2c219 6572 return Qnil;
dc6f92b8 6573}
b849c413 6574
69388238 6575\f
90e65f07
JB
6576/* Function to report a mouse movement to the mainstream Emacs code.
6577 The input handler calls this.
6578
6579 We have received a mouse movement event, which is given in *event.
6580 If the mouse is over a different glyph than it was last time, tell
6581 the mainstream emacs code by setting mouse_moved. If not, ask for
6582 another motion event, so we can check again the next time it moves. */
b8009dd1 6583
06a2c219
GM
6584static XMotionEvent last_mouse_motion_event;
6585static Lisp_Object last_mouse_motion_frame;
6586
90e65f07 6587static void
12ba150f 6588note_mouse_movement (frame, event)
f676886a 6589 FRAME_PTR frame;
90e65f07 6590 XMotionEvent *event;
90e65f07 6591{
e5d77022 6592 last_mouse_movement_time = event->time;
06a2c219
GM
6593 last_mouse_motion_event = *event;
6594 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6595
27f338af
RS
6596 if (event->window != FRAME_X_WINDOW (frame))
6597 {
39d8bb4d 6598 frame->mouse_moved = 1;
27f338af 6599 last_mouse_scroll_bar = Qnil;
27f338af 6600 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6601 }
6602
90e65f07 6603 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6604 else if (event->x < last_mouse_glyph.x
6605 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6606 || event->y < last_mouse_glyph.y
6607 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6608 {
39d8bb4d 6609 frame->mouse_moved = 1;
ab648270 6610 last_mouse_scroll_bar = Qnil;
b8009dd1 6611 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6612 }
6613}
6614
bf1c0ba1 6615/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6616
06a2c219
GM
6617 int disable_mouse_highlight;
6618
6619
6620\f
6621/************************************************************************
6622 Mouse Face
6623 ************************************************************************/
6624
6625/* Find the glyph under window-relative coordinates X/Y in window W.
6626 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6627 strings. Return in *HPOS and *VPOS the row and column number of
6628 the glyph found. Return in *AREA the glyph area containing X.
6629 Value is a pointer to the glyph found or null if X/Y is not on
6630 text, or we can't tell because W's current matrix is not up to
6631 date. */
6632
6633static struct glyph *
f9db2310 6634x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
06a2c219
GM
6635 struct window *w;
6636 int x, y;
6637 int *hpos, *vpos, *area;
f9db2310 6638 int buffer_only_p;
06a2c219
GM
6639{
6640 struct glyph *glyph, *end;
3e71d8f2 6641 struct glyph_row *row = NULL;
06a2c219
GM
6642 int x0, i, left_area_width;
6643
6644 /* Find row containing Y. Give up if some row is not enabled. */
6645 for (i = 0; i < w->current_matrix->nrows; ++i)
6646 {
6647 row = MATRIX_ROW (w->current_matrix, i);
6648 if (!row->enabled_p)
6649 return NULL;
6650 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6651 break;
6652 }
6653
6654 *vpos = i;
6655 *hpos = 0;
6656
6657 /* Give up if Y is not in the window. */
6658 if (i == w->current_matrix->nrows)
6659 return NULL;
6660
6661 /* Get the glyph area containing X. */
6662 if (w->pseudo_window_p)
6663 {
6664 *area = TEXT_AREA;
6665 x0 = 0;
6666 }
6667 else
6668 {
6669 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6670 if (x < left_area_width)
6671 {
6672 *area = LEFT_MARGIN_AREA;
6673 x0 = 0;
6674 }
6675 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6676 {
6677 *area = TEXT_AREA;
6678 x0 = row->x + left_area_width;
6679 }
6680 else
6681 {
6682 *area = RIGHT_MARGIN_AREA;
6683 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6684 }
6685 }
6686
6687 /* Find glyph containing X. */
6688 glyph = row->glyphs[*area];
6689 end = glyph + row->used[*area];
6690 while (glyph < end)
6691 {
6692 if (x < x0 + glyph->pixel_width)
6693 {
6694 if (w->pseudo_window_p)
6695 break;
f9db2310 6696 else if (!buffer_only_p || BUFFERP (glyph->object))
06a2c219
GM
6697 break;
6698 }
6699
6700 x0 += glyph->pixel_width;
6701 ++glyph;
6702 }
6703
6704 if (glyph == end)
6705 return NULL;
6706
6707 *hpos = glyph - row->glyphs[*area];
6708 return glyph;
6709}
6710
6711
6712/* Convert frame-relative x/y to coordinates relative to window W.
6713 Takes pseudo-windows into account. */
6714
6715static void
6716frame_to_window_pixel_xy (w, x, y)
6717 struct window *w;
6718 int *x, *y;
6719{
6720 if (w->pseudo_window_p)
6721 {
6722 /* A pseudo-window is always full-width, and starts at the
6723 left edge of the frame, plus a frame border. */
6724 struct frame *f = XFRAME (w->frame);
6725 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6726 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6727 }
6728 else
6729 {
6730 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6731 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6732 }
6733}
6734
6735
e371a781 6736/* Take proper action when mouse has moved to the mode or header line of
06a2c219
GM
6737 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6738 mode line. X is relative to the start of the text display area of
6739 W, so the width of bitmap areas and scroll bars must be subtracted
6740 to get a position relative to the start of the mode line. */
6741
6742static void
6743note_mode_line_highlight (w, x, mode_line_p)
6744 struct window *w;
6745 int x, mode_line_p;
6746{
6747 struct frame *f = XFRAME (w->frame);
6748 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6749 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6750 struct glyph_row *row;
6751
6752 if (mode_line_p)
6753 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6754 else
045dee35 6755 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
e371a781 6756
06a2c219
GM
6757 if (row->enabled_p)
6758 {
6759 struct glyph *glyph, *end;
6760 Lisp_Object help, map;
6761 int x0;
6762
6763 /* Find the glyph under X. */
6764 glyph = row->glyphs[TEXT_AREA];
6765 end = glyph + row->used[TEXT_AREA];
6766 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
110859fc 6767 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
e371a781 6768
06a2c219
GM
6769 while (glyph < end
6770 && x >= x0 + glyph->pixel_width)
6771 {
6772 x0 += glyph->pixel_width;
6773 ++glyph;
6774 }
6775
6776 if (glyph < end
6777 && STRINGP (glyph->object)
6778 && XSTRING (glyph->object)->intervals
6779 && glyph->charpos >= 0
6780 && glyph->charpos < XSTRING (glyph->object)->size)
6781 {
6782 /* If we're on a string with `help-echo' text property,
6783 arrange for the help to be displayed. This is done by
6784 setting the global variable help_echo to the help string. */
6785 help = Fget_text_property (make_number (glyph->charpos),
6786 Qhelp_echo, glyph->object);
b7e80413 6787 if (!NILP (help))
be010514
GM
6788 {
6789 help_echo = help;
7cea38bc 6790 XSETWINDOW (help_echo_window, w);
be010514
GM
6791 help_echo_object = glyph->object;
6792 help_echo_pos = glyph->charpos;
6793 }
06a2c219
GM
6794
6795 /* Change the mouse pointer according to what is under X/Y. */
6796 map = Fget_text_property (make_number (glyph->charpos),
6797 Qlocal_map, glyph->object);
02067692 6798 if (KEYMAPP (map))
06a2c219 6799 cursor = f->output_data.x->nontext_cursor;
be010514
GM
6800 else
6801 {
6802 map = Fget_text_property (make_number (glyph->charpos),
6803 Qkeymap, glyph->object);
02067692 6804 if (KEYMAPP (map))
be010514
GM
6805 cursor = f->output_data.x->nontext_cursor;
6806 }
06a2c219
GM
6807 }
6808 }
6809
6810 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6811}
6812
6813
6814/* Take proper action when the mouse has moved to position X, Y on
6815 frame F as regards highlighting characters that have mouse-face
6816 properties. Also de-highlighting chars where the mouse was before.
27f338af 6817 X and Y can be negative or out of range. */
b8009dd1
RS
6818
6819static void
6820note_mouse_highlight (f, x, y)
06a2c219 6821 struct frame *f;
c32cdd9a 6822 int x, y;
b8009dd1 6823{
06a2c219
GM
6824 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6825 int portion;
b8009dd1
RS
6826 Lisp_Object window;
6827 struct window *w;
0d487c52
GM
6828 Cursor cursor = None;
6829 struct buffer *b;
b8009dd1 6830
06a2c219
GM
6831 /* When a menu is active, don't highlight because this looks odd. */
6832#ifdef USE_X_TOOLKIT
6833 if (popup_activated ())
6834 return;
6835#endif
6836
04fff9c0
GM
6837 if (disable_mouse_highlight
6838 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6839 return;
6840
06a2c219
GM
6841 dpyinfo->mouse_face_mouse_x = x;
6842 dpyinfo->mouse_face_mouse_y = y;
6843 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6844
06a2c219 6845 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6846 return;
6847
514e4681
RS
6848 if (gc_in_progress)
6849 {
06a2c219 6850 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6851 return;
6852 }
6853
b8009dd1 6854 /* Which window is that in? */
06a2c219 6855 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6856
6857 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6858 if (! EQ (window, dpyinfo->mouse_face_window))
6859 clear_mouse_face (dpyinfo);
6860
6861 /* Not on a window -> return. */
6862 if (!WINDOWP (window))
6863 return;
6864
6865 /* Convert to window-relative pixel coordinates. */
6866 w = XWINDOW (window);
6867 frame_to_window_pixel_xy (w, &x, &y);
6868
9ea173e8 6869 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6870 buffer. */
9ea173e8 6871 if (EQ (window, f->tool_bar_window))
06a2c219 6872 {
9ea173e8 6873 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6874 return;
6875 }
6876
0d487c52 6877 /* Mouse is on the mode or header line? */
06a2c219
GM
6878 if (portion == 1 || portion == 3)
6879 {
06a2c219
GM
6880 note_mode_line_highlight (w, x, portion == 1);
6881 return;
6882 }
0d487c52
GM
6883
6884 if (portion == 2)
6885 cursor = f->output_data.x->horizontal_drag_cursor;
06a2c219 6886 else
0d487c52 6887 cursor = f->output_data.x->text_cursor;
b8009dd1 6888
0cdd0c9f
RS
6889 /* Are we in a window whose display is up to date?
6890 And verify the buffer's text has not changed. */
0d487c52 6891 b = XBUFFER (w->buffer);
06a2c219
GM
6892 if (/* Within text portion of the window. */
6893 portion == 0
0cdd0c9f 6894 && EQ (w->window_end_valid, w->buffer)
0d487c52
GM
6895 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
6896 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
b8009dd1 6897 {
06a2c219
GM
6898 int hpos, vpos, pos, i, area;
6899 struct glyph *glyph;
f9db2310 6900 Lisp_Object object;
0d487c52
GM
6901 Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
6902 Lisp_Object *overlay_vec = NULL;
6903 int len, noverlays;
6904 struct buffer *obuf;
6905 int obegv, ozv, same_region;
b8009dd1 6906
06a2c219 6907 /* Find the glyph under X/Y. */
f9db2310 6908 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
06a2c219
GM
6909
6910 /* Clear mouse face if X/Y not over text. */
6911 if (glyph == NULL
6912 || area != TEXT_AREA
6913 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6914 {
fa262c07
GM
6915 if (clear_mouse_face (dpyinfo))
6916 cursor = None;
6917 goto set_cursor;
06a2c219
GM
6918 }
6919
6920 pos = glyph->charpos;
f9db2310
GM
6921 object = glyph->object;
6922 if (!STRINGP (object) && !BUFFERP (object))
fa262c07 6923 goto set_cursor;
06a2c219 6924
0d487c52
GM
6925 /* If we get an out-of-range value, return now; avoid an error. */
6926 if (BUFFERP (object) && pos > BUF_Z (b))
fa262c07 6927 goto set_cursor;
06a2c219 6928
0d487c52
GM
6929 /* Make the window's buffer temporarily current for
6930 overlays_at and compute_char_face. */
6931 obuf = current_buffer;
6932 current_buffer = b;
6933 obegv = BEGV;
6934 ozv = ZV;
6935 BEGV = BEG;
6936 ZV = Z;
06a2c219 6937
0d487c52
GM
6938 /* Is this char mouse-active or does it have help-echo? */
6939 position = make_number (pos);
f9db2310 6940
0d487c52
GM
6941 if (BUFFERP (object))
6942 {
6943 /* Put all the overlays we want in a vector in overlay_vec.
6944 Store the length in len. If there are more than 10, make
6945 enough space for all, and try again. */
6946 len = 10;
6947 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6948 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
6949 if (noverlays > len)
6950 {
6951 len = noverlays;
6952 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6953 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
6954 }
f8349001 6955
0d487c52
GM
6956 /* Sort overlays into increasing priority order. */
6957 noverlays = sort_overlays (overlay_vec, noverlays, w);
6958 }
6959 else
6960 noverlays = 0;
6961
6962 same_region = (EQ (window, dpyinfo->mouse_face_window)
6963 && vpos >= dpyinfo->mouse_face_beg_row
6964 && vpos <= dpyinfo->mouse_face_end_row
6965 && (vpos > dpyinfo->mouse_face_beg_row
6966 || hpos >= dpyinfo->mouse_face_beg_col)
6967 && (vpos < dpyinfo->mouse_face_end_row
6968 || hpos < dpyinfo->mouse_face_end_col
6969 || dpyinfo->mouse_face_past_end));
6970
6971 if (same_region)
6972 cursor = None;
6973
6974 /* Check mouse-face highlighting. */
6975 if (! same_region
6976 /* If there exists an overlay with mouse-face overlapping
6977 the one we are currently highlighting, we have to
6978 check if we enter the overlapping overlay, and then
6979 highlight only that. */
6980 || (OVERLAYP (dpyinfo->mouse_face_overlay)
6981 && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
6982 {
0d487c52
GM
6983 /* Find the highest priority overlay that has a mouse-face
6984 property. */
6985 overlay = Qnil;
6986 for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
6987 {
6988 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6989 if (!NILP (mouse_face))
6990 overlay = overlay_vec[i];
6991 }
8bd189fb
GM
6992
6993 /* If we're actually highlighting the same overlay as
6994 before, there's no need to do that again. */
6995 if (!NILP (overlay)
6996 && EQ (overlay, dpyinfo->mouse_face_overlay))
6997 goto check_help_echo;
f9db2310 6998
8bd189fb
GM
6999 dpyinfo->mouse_face_overlay = overlay;
7000
7001 /* Clear the display of the old active region, if any. */
7002 if (clear_mouse_face (dpyinfo))
7003 cursor = None;
7004
0d487c52
GM
7005 /* If no overlay applies, get a text property. */
7006 if (NILP (overlay))
7007 mouse_face = Fget_text_property (position, Qmouse_face, object);
06a2c219 7008
0d487c52
GM
7009 /* Handle the overlay case. */
7010 if (!NILP (overlay))
7011 {
7012 /* Find the range of text around this char that
7013 should be active. */
7014 Lisp_Object before, after;
7015 int ignore;
7016
7017 before = Foverlay_start (overlay);
7018 after = Foverlay_end (overlay);
7019 /* Record this as the current active region. */
7020 fast_find_position (w, XFASTINT (before),
7021 &dpyinfo->mouse_face_beg_col,
7022 &dpyinfo->mouse_face_beg_row,
7023 &dpyinfo->mouse_face_beg_x,
7e376260
GM
7024 &dpyinfo->mouse_face_beg_y, Qnil);
7025
0d487c52
GM
7026 dpyinfo->mouse_face_past_end
7027 = !fast_find_position (w, XFASTINT (after),
7028 &dpyinfo->mouse_face_end_col,
7029 &dpyinfo->mouse_face_end_row,
7030 &dpyinfo->mouse_face_end_x,
7e376260 7031 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7032 dpyinfo->mouse_face_window = window;
7033 dpyinfo->mouse_face_face_id
7034 = face_at_buffer_position (w, pos, 0, 0,
7035 &ignore, pos + 1, 1);
7036
7037 /* Display it as active. */
7038 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7039 cursor = None;
0d487c52
GM
7040 }
7041 /* Handle the text property case. */
7042 else if (!NILP (mouse_face) && BUFFERP (object))
7043 {
7044 /* Find the range of text around this char that
7045 should be active. */
7046 Lisp_Object before, after, beginning, end;
7047 int ignore;
7048
7049 beginning = Fmarker_position (w->start);
7050 end = make_number (BUF_Z (XBUFFER (object))
7051 - XFASTINT (w->window_end_pos));
7052 before
7053 = Fprevious_single_property_change (make_number (pos + 1),
7054 Qmouse_face,
7055 object, beginning);
7056 after
7057 = Fnext_single_property_change (position, Qmouse_face,
7058 object, end);
7059
7060 /* Record this as the current active region. */
7061 fast_find_position (w, XFASTINT (before),
7062 &dpyinfo->mouse_face_beg_col,
7063 &dpyinfo->mouse_face_beg_row,
7064 &dpyinfo->mouse_face_beg_x,
7e376260 7065 &dpyinfo->mouse_face_beg_y, Qnil);
0d487c52
GM
7066 dpyinfo->mouse_face_past_end
7067 = !fast_find_position (w, XFASTINT (after),
7068 &dpyinfo->mouse_face_end_col,
7069 &dpyinfo->mouse_face_end_row,
7070 &dpyinfo->mouse_face_end_x,
7e376260 7071 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7072 dpyinfo->mouse_face_window = window;
7073
7074 if (BUFFERP (object))
06a2c219
GM
7075 dpyinfo->mouse_face_face_id
7076 = face_at_buffer_position (w, pos, 0, 0,
7077 &ignore, pos + 1, 1);
7078
0d487c52
GM
7079 /* Display it as active. */
7080 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7081 cursor = None;
0d487c52
GM
7082 }
7083 else if (!NILP (mouse_face) && STRINGP (object))
7084 {
7085 Lisp_Object b, e;
7086 int ignore;
f9db2310 7087
0d487c52
GM
7088 b = Fprevious_single_property_change (make_number (pos + 1),
7089 Qmouse_face,
7090 object, Qnil);
7091 e = Fnext_single_property_change (position, Qmouse_face,
7092 object, Qnil);
7093 if (NILP (b))
7094 b = make_number (0);
7095 if (NILP (e))
7096 e = make_number (XSTRING (object)->size - 1);
7097 fast_find_string_pos (w, XINT (b), object,
06a2c219
GM
7098 &dpyinfo->mouse_face_beg_col,
7099 &dpyinfo->mouse_face_beg_row,
7100 &dpyinfo->mouse_face_beg_x,
0d487c52
GM
7101 &dpyinfo->mouse_face_beg_y, 0);
7102 fast_find_string_pos (w, XINT (e), object,
7103 &dpyinfo->mouse_face_end_col,
7104 &dpyinfo->mouse_face_end_row,
7105 &dpyinfo->mouse_face_end_x,
7106 &dpyinfo->mouse_face_end_y, 1);
7107 dpyinfo->mouse_face_past_end = 0;
7108 dpyinfo->mouse_face_window = window;
7109 dpyinfo->mouse_face_face_id
7110 = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
7111 glyph->face_id, 1);
7112 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7113 cursor = None;
0d487c52 7114 }
7e376260
GM
7115 else if (STRINGP (object) && NILP (mouse_face))
7116 {
7117 /* A string which doesn't have mouse-face, but
7118 the text ``under'' it might have. */
7119 struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
7120 int start = MATRIX_ROW_START_CHARPOS (r);
7121
7122 pos = string_buffer_position (w, object, start);
7123 if (pos > 0)
7124 mouse_face = get_char_property_and_overlay (make_number (pos),
7125 Qmouse_face,
7126 w->buffer,
7127 &overlay);
7128 if (!NILP (mouse_face) && !NILP (overlay))
7129 {
7130 Lisp_Object before = Foverlay_start (overlay);
7131 Lisp_Object after = Foverlay_end (overlay);
7132 Lisp_Object ignore;
7133
7134 /* Note that we might not be able to find position
7135 BEFORE in the glyph matrix if the overlay is
7136 entirely covered by a `display' property. In
7137 this case, we overshoot. So let's stop in
7138 the glyph matrix before glyphs for OBJECT. */
7139 fast_find_position (w, XFASTINT (before),
7140 &dpyinfo->mouse_face_beg_col,
7141 &dpyinfo->mouse_face_beg_row,
7142 &dpyinfo->mouse_face_beg_x,
7143 &dpyinfo->mouse_face_beg_y,
7144 object);
7145
7146 dpyinfo->mouse_face_past_end
7147 = !fast_find_position (w, XFASTINT (after),
7148 &dpyinfo->mouse_face_end_col,
7149 &dpyinfo->mouse_face_end_row,
7150 &dpyinfo->mouse_face_end_x,
7151 &dpyinfo->mouse_face_end_y,
7152 Qnil);
7153 dpyinfo->mouse_face_window = window;
7154 dpyinfo->mouse_face_face_id
7155 = face_at_buffer_position (w, pos, 0, 0,
7156 &ignore, pos + 1, 1);
7157
7158 /* Display it as active. */
7159 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
7160 cursor = None;
7161 }
7162 }
0d487c52 7163 }
06a2c219 7164
8bd189fb
GM
7165 check_help_echo:
7166
0d487c52
GM
7167 /* Look for a `help-echo' property. */
7168 {
7169 Lisp_Object help, overlay;
06a2c219 7170
0d487c52
GM
7171 /* Check overlays first. */
7172 help = overlay = Qnil;
7173 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
7174 {
7175 overlay = overlay_vec[i];
7176 help = Foverlay_get (overlay, Qhelp_echo);
7177 }
be010514 7178
0d487c52
GM
7179 if (!NILP (help))
7180 {
7181 help_echo = help;
7182 help_echo_window = window;
7183 help_echo_object = overlay;
7184 help_echo_pos = pos;
7185 }
7186 else
7187 {
7188 Lisp_Object object = glyph->object;
7189 int charpos = glyph->charpos;
7177d86b 7190
0d487c52
GM
7191 /* Try text properties. */
7192 if (STRINGP (object)
7193 && charpos >= 0
7194 && charpos < XSTRING (object)->size)
7195 {
7196 help = Fget_text_property (make_number (charpos),
7197 Qhelp_echo, object);
7198 if (NILP (help))
7199 {
7200 /* If the string itself doesn't specify a help-echo,
7201 see if the buffer text ``under'' it does. */
7202 struct glyph_row *r
7203 = MATRIX_ROW (w->current_matrix, vpos);
7204 int start = MATRIX_ROW_START_CHARPOS (r);
7205 int pos = string_buffer_position (w, object, start);
7206 if (pos > 0)
7207 {
7e376260 7208 help = Fget_char_property (make_number (pos),
0d487c52
GM
7209 Qhelp_echo, w->buffer);
7210 if (!NILP (help))
7211 {
7212 charpos = pos;
7213 object = w->buffer;
7214 }
7215 }
7216 }
7217 }
7218 else if (BUFFERP (object)
7219 && charpos >= BEGV
7220 && charpos < ZV)
7221 help = Fget_text_property (make_number (charpos), Qhelp_echo,
7222 object);
06a2c219 7223
0d487c52
GM
7224 if (!NILP (help))
7225 {
7226 help_echo = help;
7227 help_echo_window = window;
7228 help_echo_object = object;
7229 help_echo_pos = charpos;
7230 }
7231 }
06a2c219 7232 }
0d487c52
GM
7233
7234 BEGV = obegv;
7235 ZV = ozv;
7236 current_buffer = obuf;
06a2c219 7237 }
0d487c52 7238
fa262c07
GM
7239 set_cursor:
7240
0d487c52
GM
7241 if (cursor != None)
7242 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
06a2c219
GM
7243}
7244
7245static void
7246redo_mouse_highlight ()
7247{
7248 if (!NILP (last_mouse_motion_frame)
7249 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
7250 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
7251 last_mouse_motion_event.x,
7252 last_mouse_motion_event.y);
7253}
7254
7255
7256\f
7257/***********************************************************************
9ea173e8 7258 Tool-bars
06a2c219
GM
7259 ***********************************************************************/
7260
9ea173e8
GM
7261static int x_tool_bar_item P_ ((struct frame *, int, int,
7262 struct glyph **, int *, int *, int *));
06a2c219 7263
9ea173e8 7264/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
7265 or -1. */
7266
9ea173e8 7267static int last_tool_bar_item;
06a2c219
GM
7268
7269
9ea173e8
GM
7270/* Get information about the tool-bar item at position X/Y on frame F.
7271 Return in *GLYPH a pointer to the glyph of the tool-bar item in
7272 the current matrix of the tool-bar window of F, or NULL if not
7273 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
8daf1204 7274 item in F->tool_bar_items. Value is
06a2c219 7275
9ea173e8 7276 -1 if X/Y is not on a tool-bar item
06a2c219
GM
7277 0 if X/Y is on the same item that was highlighted before.
7278 1 otherwise. */
7279
7280static int
9ea173e8 7281x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
7282 struct frame *f;
7283 int x, y;
7284 struct glyph **glyph;
7285 int *hpos, *vpos, *prop_idx;
7286{
7287 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7288 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7289 int area;
7290
7291 /* Find the glyph under X/Y. */
f9db2310 7292 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
06a2c219
GM
7293 if (*glyph == NULL)
7294 return -1;
7295
9ea173e8 7296 /* Get the start of this tool-bar item's properties in
8daf1204 7297 f->tool_bar_items. */
9ea173e8 7298 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
7299 return -1;
7300
7301 /* Is mouse on the highlighted item? */
9ea173e8 7302 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
7303 && *vpos >= dpyinfo->mouse_face_beg_row
7304 && *vpos <= dpyinfo->mouse_face_end_row
7305 && (*vpos > dpyinfo->mouse_face_beg_row
7306 || *hpos >= dpyinfo->mouse_face_beg_col)
7307 && (*vpos < dpyinfo->mouse_face_end_row
7308 || *hpos < dpyinfo->mouse_face_end_col
7309 || dpyinfo->mouse_face_past_end))
7310 return 0;
7311
7312 return 1;
7313}
7314
7315
9ea173e8 7316/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
7317 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
7318 or ButtonRelase. */
7319
7320static void
9ea173e8 7321x_handle_tool_bar_click (f, button_event)
06a2c219
GM
7322 struct frame *f;
7323 XButtonEvent *button_event;
7324{
7325 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7326 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7327 int hpos, vpos, prop_idx;
7328 struct glyph *glyph;
7329 Lisp_Object enabled_p;
7330 int x = button_event->x;
7331 int y = button_event->y;
7332
9ea173e8 7333 /* If not on the highlighted tool-bar item, return. */
06a2c219 7334 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 7335 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
7336 return;
7337
7338 /* If item is disabled, do nothing. */
8daf1204 7339 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7340 if (NILP (enabled_p))
7341 return;
7342
7343 if (button_event->type == ButtonPress)
7344 {
7345 /* Show item in pressed state. */
7346 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
7347 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 7348 last_tool_bar_item = prop_idx;
06a2c219
GM
7349 }
7350 else
7351 {
7352 Lisp_Object key, frame;
7353 struct input_event event;
7354
7355 /* Show item in released state. */
7356 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
7357 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
7358
8daf1204 7359 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
06a2c219
GM
7360
7361 XSETFRAME (frame, f);
9ea173e8 7362 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7363 event.frame_or_window = frame;
7364 event.arg = frame;
06a2c219
GM
7365 kbd_buffer_store_event (&event);
7366
9ea173e8 7367 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7368 event.frame_or_window = frame;
7369 event.arg = key;
06a2c219
GM
7370 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7371 button_event->state);
7372 kbd_buffer_store_event (&event);
9ea173e8 7373 last_tool_bar_item = -1;
06a2c219
GM
7374 }
7375}
7376
7377
9ea173e8
GM
7378/* Possibly highlight a tool-bar item on frame F when mouse moves to
7379 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
7380 note_mouse_highlight. */
7381
7382static void
9ea173e8 7383note_tool_bar_highlight (f, x, y)
06a2c219
GM
7384 struct frame *f;
7385 int x, y;
7386{
9ea173e8 7387 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
7388 struct window *w = XWINDOW (window);
7389 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7390 int hpos, vpos;
7391 struct glyph *glyph;
7392 struct glyph_row *row;
5c187dee 7393 int i;
06a2c219
GM
7394 Lisp_Object enabled_p;
7395 int prop_idx;
140330de 7396 enum draw_glyphs_face draw;
5c187dee 7397 int mouse_down_p, rc;
06a2c219
GM
7398
7399 /* Function note_mouse_highlight is called with negative x(y
7400 values when mouse moves outside of the frame. */
7401 if (x <= 0 || y <= 0)
7402 {
7403 clear_mouse_face (dpyinfo);
7404 return;
7405 }
7406
9ea173e8 7407 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
7408 if (rc < 0)
7409 {
9ea173e8 7410 /* Not on tool-bar item. */
06a2c219
GM
7411 clear_mouse_face (dpyinfo);
7412 return;
7413 }
7414 else if (rc == 0)
06a2c219 7415 goto set_help_echo;
b8009dd1 7416
06a2c219
GM
7417 clear_mouse_face (dpyinfo);
7418
9ea173e8 7419 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
7420 mouse_down_p = (dpyinfo->grabbed
7421 && f == last_mouse_frame
7422 && FRAME_LIVE_P (f));
7423 if (mouse_down_p
9ea173e8 7424 && last_tool_bar_item != prop_idx)
06a2c219
GM
7425 return;
7426
7427 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7428 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7429
9ea173e8 7430 /* If tool-bar item is not enabled, don't highlight it. */
8daf1204 7431 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7432 if (!NILP (enabled_p))
7433 {
7434 /* Compute the x-position of the glyph. In front and past the
7435 image is a space. We include this is the highlighted area. */
7436 row = MATRIX_ROW (w->current_matrix, vpos);
7437 for (i = x = 0; i < hpos; ++i)
7438 x += row->glyphs[TEXT_AREA][i].pixel_width;
7439
7440 /* Record this as the current active region. */
7441 dpyinfo->mouse_face_beg_col = hpos;
7442 dpyinfo->mouse_face_beg_row = vpos;
7443 dpyinfo->mouse_face_beg_x = x;
7444 dpyinfo->mouse_face_beg_y = row->y;
7445 dpyinfo->mouse_face_past_end = 0;
7446
7447 dpyinfo->mouse_face_end_col = hpos + 1;
7448 dpyinfo->mouse_face_end_row = vpos;
7449 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7450 dpyinfo->mouse_face_end_y = row->y;
7451 dpyinfo->mouse_face_window = window;
9ea173e8 7452 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
7453
7454 /* Display it as active. */
7455 show_mouse_face (dpyinfo, draw);
7456 dpyinfo->mouse_face_image_state = draw;
b8009dd1 7457 }
06a2c219
GM
7458
7459 set_help_echo:
7460
9ea173e8 7461 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 7462 XTread_socket does the rest. */
7cea38bc 7463 help_echo_object = help_echo_window = Qnil;
be010514 7464 help_echo_pos = -1;
8daf1204 7465 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
b7e80413 7466 if (NILP (help_echo))
8daf1204 7467 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
b8009dd1 7468}
4d73d038 7469
06a2c219
GM
7470
7471\f
9f8531e5
GM
7472/* Find the glyph matrix position of buffer position CHARPOS in window
7473 *W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7474 current glyphs must be up to date. If CHARPOS is above window
7475 start return (0, 0, 0, 0). If CHARPOS is after end of W, return end
7476 of last line in W. In the row containing CHARPOS, stop before glyphs
7e376260 7477 having STOP as object. */
b8009dd1 7478
9f8531e5
GM
7479#if 0 /* This is a version of fast_find_position that's more correct
7480 in the presence of hscrolling, for example. I didn't install
7481 it right away because the problem fixed is minor, it failed
7482 in 20.x as well, and I think it's too risky to install
7483 so near the release of 21.1. 2001-09-25 gerd. */
7484
7485static int
7486fast_find_position (w, charpos, hpos, vpos, x, y, stop)
7487 struct window *w;
7488 int charpos;
7489 int *hpos, *vpos, *x, *y;
7490 Lisp_Object stop;
7491{
7492 struct glyph_row *row, *first;
7493 struct glyph *glyph, *end;
7494 int i, past_end = 0;
7495
7496 first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
62e33982 7497 row = row_containing_pos (w, charpos, first, NULL, 0);
9f8531e5
GM
7498 if (row == NULL)
7499 {
7500 if (charpos < MATRIX_ROW_START_CHARPOS (first))
7501 {
7502 *x = *y = *hpos = *vpos = 0;
7503 return 0;
7504 }
7505 else
7506 {
7507 row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
7508 past_end = 1;
7509 }
7510 }
7511
7512 *x = row->x;
7513 *y = row->y;
7514 *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7515
7516 glyph = row->glyphs[TEXT_AREA];
7517 end = glyph + row->used[TEXT_AREA];
7518
7519 /* Skip over glyphs not having an object at the start of the row.
7520 These are special glyphs like truncation marks on terminal
7521 frames. */
7522 if (row->displays_text_p)
7523 while (glyph < end
7524 && INTEGERP (glyph->object)
7525 && !EQ (stop, glyph->object)
7526 && glyph->charpos < 0)
7527 {
7528 *x += glyph->pixel_width;
7529 ++glyph;
7530 }
7531
7532 while (glyph < end
7533 && !INTEGERP (glyph->object)
7534 && !EQ (stop, glyph->object)
7535 && (!BUFFERP (glyph->object)
7536 || glyph->charpos < charpos))
7537 {
7538 *x += glyph->pixel_width;
7539 ++glyph;
7540 }
7541
7542 *hpos = glyph - row->glyphs[TEXT_AREA];
7543 return past_end;
7544}
7545
7546#else /* not 0 */
7547
b8009dd1 7548static int
7e376260 7549fast_find_position (w, pos, hpos, vpos, x, y, stop)
06a2c219 7550 struct window *w;
b8009dd1 7551 int pos;
06a2c219 7552 int *hpos, *vpos, *x, *y;
7e376260 7553 Lisp_Object stop;
b8009dd1 7554{
b8009dd1 7555 int i;
bf1c0ba1 7556 int lastcol;
06a2c219
GM
7557 int maybe_next_line_p = 0;
7558 int line_start_position;
7559 int yb = window_text_bottom_y (w);
03d1a189
GM
7560 struct glyph_row *row, *best_row;
7561 int row_vpos, best_row_vpos;
06a2c219
GM
7562 int current_x;
7563
03d1a189
GM
7564 row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7565 row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7566
06a2c219 7567 while (row->y < yb)
b8009dd1 7568 {
06a2c219
GM
7569 if (row->used[TEXT_AREA])
7570 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7571 else
7572 line_start_position = 0;
7573
7574 if (line_start_position > pos)
b8009dd1 7575 break;
77b68646
RS
7576 /* If the position sought is the end of the buffer,
7577 don't include the blank lines at the bottom of the window. */
06a2c219
GM
7578 else if (line_start_position == pos
7579 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 7580 {
06a2c219 7581 maybe_next_line_p = 1;
77b68646
RS
7582 break;
7583 }
06a2c219
GM
7584 else if (line_start_position > 0)
7585 {
7586 best_row = row;
7587 best_row_vpos = row_vpos;
7588 }
4b0bb6f3
GM
7589
7590 if (row->y + row->height >= yb)
7591 break;
06a2c219
GM
7592
7593 ++row;
7594 ++row_vpos;
b8009dd1 7595 }
06a2c219
GM
7596
7597 /* Find the right column within BEST_ROW. */
7598 lastcol = 0;
7599 current_x = best_row->x;
7600 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 7601 {
06a2c219 7602 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7e376260 7603 int charpos = glyph->charpos;
06a2c219 7604
7e376260 7605 if (BUFFERP (glyph->object))
bf1c0ba1 7606 {
7e376260
GM
7607 if (charpos == pos)
7608 {
7609 *hpos = i;
7610 *vpos = best_row_vpos;
7611 *x = current_x;
7612 *y = best_row->y;
7613 return 1;
7614 }
7615 else if (charpos > pos)
7616 break;
bf1c0ba1 7617 }
7e376260 7618 else if (EQ (glyph->object, stop))
4d73d038 7619 break;
06a2c219 7620
7e376260
GM
7621 if (charpos > 0)
7622 lastcol = i;
06a2c219 7623 current_x += glyph->pixel_width;
bf1c0ba1 7624 }
b8009dd1 7625
77b68646
RS
7626 /* If we're looking for the end of the buffer,
7627 and we didn't find it in the line we scanned,
7628 use the start of the following line. */
06a2c219 7629 if (maybe_next_line_p)
77b68646 7630 {
06a2c219
GM
7631 ++best_row;
7632 ++best_row_vpos;
7633 lastcol = 0;
7634 current_x = best_row->x;
77b68646
RS
7635 }
7636
06a2c219
GM
7637 *vpos = best_row_vpos;
7638 *hpos = lastcol + 1;
7639 *x = current_x;
7640 *y = best_row->y;
b8009dd1
RS
7641 return 0;
7642}
7643
9f8531e5
GM
7644#endif /* not 0 */
7645
06a2c219 7646
f9db2310
GM
7647/* Find the position of the the glyph for position POS in OBJECT in
7648 window W's current matrix, and return in *X/*Y the pixel
7649 coordinates, and return in *HPOS/*VPOS the column/row of the glyph.
7650
7651 RIGHT_P non-zero means return the position of the right edge of the
7652 glyph, RIGHT_P zero means return the left edge position.
7653
7654 If no glyph for POS exists in the matrix, return the position of
7655 the glyph with the next smaller position that is in the matrix, if
7656 RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS
7657 exists in the matrix, return the position of the glyph with the
7658 next larger position in OBJECT.
7659
7660 Value is non-zero if a glyph was found. */
7661
7662static int
7663fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
7664 struct window *w;
7665 int pos;
7666 Lisp_Object object;
7667 int *hpos, *vpos, *x, *y;
7668 int right_p;
7669{
7670 int yb = window_text_bottom_y (w);
7671 struct glyph_row *r;
7672 struct glyph *best_glyph = NULL;
7673 struct glyph_row *best_row = NULL;
7674 int best_x = 0;
7675
7676 for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7677 r->enabled_p && r->y < yb;
7678 ++r)
7679 {
7680 struct glyph *g = r->glyphs[TEXT_AREA];
7681 struct glyph *e = g + r->used[TEXT_AREA];
7682 int gx;
7683
7684 for (gx = r->x; g < e; gx += g->pixel_width, ++g)
7685 if (EQ (g->object, object))
7686 {
7687 if (g->charpos == pos)
7688 {
7689 best_glyph = g;
7690 best_x = gx;
7691 best_row = r;
7692 goto found;
7693 }
7694 else if (best_glyph == NULL
7695 || ((abs (g->charpos - pos)
7696 < abs (best_glyph->charpos - pos))
7697 && (right_p
7698 ? g->charpos < pos
7699 : g->charpos > pos)))
7700 {
7701 best_glyph = g;
7702 best_x = gx;
7703 best_row = r;
7704 }
7705 }
7706 }
7707
7708 found:
7709
7710 if (best_glyph)
7711 {
7712 *x = best_x;
7713 *hpos = best_glyph - best_row->glyphs[TEXT_AREA];
7714
7715 if (right_p)
7716 {
7717 *x += best_glyph->pixel_width;
7718 ++*hpos;
7719 }
7720
7721 *y = best_row->y;
7722 *vpos = best_row - w->current_matrix->rows;
7723 }
7724
7725 return best_glyph != NULL;
7726}
7727
7728
b8009dd1
RS
7729/* Display the active region described by mouse_face_*
7730 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7731
7732static void
06a2c219 7733show_mouse_face (dpyinfo, draw)
7a13e894 7734 struct x_display_info *dpyinfo;
06a2c219 7735 enum draw_glyphs_face draw;
b8009dd1 7736{
7a13e894 7737 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7738 struct frame *f = XFRAME (WINDOW_FRAME (w));
06a2c219 7739
b2bbd509
GM
7740 if (/* If window is in the process of being destroyed, don't bother
7741 to do anything. */
7742 w->current_matrix != NULL
7743 /* Recognize when we are called to operate on rows that don't exist
7744 anymore. This can happen when a window is split. */
7745 && dpyinfo->mouse_face_end_row < w->current_matrix->nrows)
06a2c219 7746 {
b2bbd509
GM
7747 int phys_cursor_on_p = w->phys_cursor_on_p;
7748 struct glyph_row *row, *first, *last;
06a2c219 7749
b2bbd509
GM
7750 first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row);
7751 last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row);
7752
7753 for (row = first; row <= last && row->enabled_p; ++row)
06a2c219 7754 {
b2bbd509 7755 int start_hpos, end_hpos, start_x;
06a2c219 7756
b2bbd509
GM
7757 /* For all but the first row, the highlight starts at column 0. */
7758 if (row == first)
7759 {
7760 start_hpos = dpyinfo->mouse_face_beg_col;
7761 start_x = dpyinfo->mouse_face_beg_x;
7762 }
7763 else
7764 {
7765 start_hpos = 0;
7766 start_x = 0;
7767 }
06a2c219 7768
b2bbd509
GM
7769 if (row == last)
7770 end_hpos = dpyinfo->mouse_face_end_col;
7771 else
7772 end_hpos = row->used[TEXT_AREA];
b8009dd1 7773
b2bbd509
GM
7774 if (end_hpos > start_hpos)
7775 {
7776 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7777 start_hpos, end_hpos, draw, 0);
b8009dd1 7778
b2bbd509
GM
7779 row->mouse_face_p = draw == DRAW_MOUSE_FACE || DRAW_IMAGE_RAISED;
7780 }
7781 }
2729a2b5 7782
b2bbd509
GM
7783 /* When we've written over the cursor, arrange for it to
7784 be displayed again. */
7785 if (phys_cursor_on_p && !w->phys_cursor_on_p)
7786 x_display_cursor (w, 1,
7787 w->phys_cursor.hpos, w->phys_cursor.vpos,
7788 w->phys_cursor.x, w->phys_cursor.y);
7789 }
fb3b7de5 7790
06a2c219
GM
7791 /* Change the mouse cursor. */
7792 if (draw == DRAW_NORMAL_TEXT)
7793 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7794 f->output_data.x->text_cursor);
7795 else if (draw == DRAW_MOUSE_FACE)
334208b7 7796 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7797 f->output_data.x->cross_cursor);
27ead1d5 7798 else
334208b7 7799 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7800 f->output_data.x->nontext_cursor);
b8009dd1
RS
7801}
7802
7803/* Clear out the mouse-highlighted active region.
fa262c07
GM
7804 Redraw it un-highlighted first. Value is non-zero if mouse
7805 face was actually drawn unhighlighted. */
b8009dd1 7806
fa262c07 7807static int
7a13e894
RS
7808clear_mouse_face (dpyinfo)
7809 struct x_display_info *dpyinfo;
b8009dd1 7810{
fa262c07 7811 int cleared = 0;
06a2c219 7812
fa262c07
GM
7813 if (!NILP (dpyinfo->mouse_face_window))
7814 {
7815 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
7816 cleared = 1;
7817 }
b8009dd1 7818
7a13e894
RS
7819 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7820 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7821 dpyinfo->mouse_face_window = Qnil;
1b85dc1c 7822 dpyinfo->mouse_face_overlay = Qnil;
fa262c07 7823 return cleared;
b8009dd1 7824}
e687d06e 7825
71b8321e
GM
7826
7827/* Clear any mouse-face on window W. This function is part of the
7828 redisplay interface, and is called from try_window_id and similar
7829 functions to ensure the mouse-highlight is off. */
7830
7831static void
7832x_clear_mouse_face (w)
7833 struct window *w;
7834{
7835 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7836 Lisp_Object window;
7837
2e636f9d 7838 BLOCK_INPUT;
71b8321e
GM
7839 XSETWINDOW (window, w);
7840 if (EQ (window, dpyinfo->mouse_face_window))
7841 clear_mouse_face (dpyinfo);
2e636f9d 7842 UNBLOCK_INPUT;
71b8321e
GM
7843}
7844
7845
e687d06e
RS
7846/* Just discard the mouse face information for frame F, if any.
7847 This is used when the size of F is changed. */
7848
dfcf069d 7849void
e687d06e
RS
7850cancel_mouse_face (f)
7851 FRAME_PTR f;
7852{
7853 Lisp_Object window;
7854 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7855
7856 window = dpyinfo->mouse_face_window;
7857 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7858 {
7859 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7860 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7861 dpyinfo->mouse_face_window = Qnil;
7862 }
7863}
b52b65bd 7864
b8009dd1 7865\f
b52b65bd
GM
7866static int glyph_rect P_ ((struct frame *f, int, int, XRectangle *));
7867
7868
7869/* Try to determine frame pixel position and size of the glyph under
7870 frame pixel coordinates X/Y on frame F . Return the position and
7871 size in *RECT. Value is non-zero if we could compute these
7872 values. */
7873
7874static int
7875glyph_rect (f, x, y, rect)
7876 struct frame *f;
7877 int x, y;
7878 XRectangle *rect;
7879{
7880 Lisp_Object window;
7881 int part, found = 0;
7882
7883 window = window_from_coordinates (f, x, y, &part, 0);
7884 if (!NILP (window))
7885 {
7886 struct window *w = XWINDOW (window);
7887 struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7888 struct glyph_row *end = r + w->current_matrix->nrows - 1;
b52b65bd
GM
7889
7890 frame_to_window_pixel_xy (w, &x, &y);
7891
7892 for (; !found && r < end && r->enabled_p; ++r)
7893 if (r->y >= y)
7894 {
7895 struct glyph *g = r->glyphs[TEXT_AREA];
7896 struct glyph *end = g + r->used[TEXT_AREA];
7897 int gx;
7898
7899 for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
7900 if (gx >= x)
7901 {
7902 rect->width = g->pixel_width;
7903 rect->height = r->height;
7904 rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
7905 rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
7906 found = 1;
7907 }
7908 }
7909 }
7910
7911 return found;
7912}
7913
12ba150f 7914
90e65f07 7915/* Return the current position of the mouse.
b52b65bd 7916 *FP should be a frame which indicates which display to ask about.
90e65f07 7917
b52b65bd
GM
7918 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
7919 and *PART to the frame, window, and scroll bar part that the mouse
7920 is over. Set *X and *Y to the portion and whole of the mouse's
ab648270 7921 position on the scroll bar.
12ba150f 7922
b52b65bd
GM
7923 If the mouse movement started elsewhere, set *FP to the frame the
7924 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
12ba150f
JB
7925 the mouse is over.
7926
b52b65bd 7927 Set *TIME to the server time-stamp for the time at which the mouse
12ba150f
JB
7928 was at this position.
7929
a135645a
RS
7930 Don't store anything if we don't have a valid set of values to report.
7931
90e65f07 7932 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7933 movement. */
90e65f07
JB
7934
7935static void
1cf412ec 7936XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7937 FRAME_PTR *fp;
1cf412ec 7938 int insist;
12ba150f 7939 Lisp_Object *bar_window;
ab648270 7940 enum scroll_bar_part *part;
90e65f07 7941 Lisp_Object *x, *y;
e5d77022 7942 unsigned long *time;
90e65f07 7943{
a135645a
RS
7944 FRAME_PTR f1;
7945
90e65f07
JB
7946 BLOCK_INPUT;
7947
8bcee03e 7948 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7949 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7950 else
7951 {
12ba150f
JB
7952 Window root;
7953 int root_x, root_y;
90e65f07 7954
12ba150f
JB
7955 Window dummy_window;
7956 int dummy;
7957
39d8bb4d
KH
7958 Lisp_Object frame, tail;
7959
7960 /* Clear the mouse-moved flag for every frame on this display. */
7961 FOR_EACH_FRAME (tail, frame)
7962 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7963 XFRAME (frame)->mouse_moved = 0;
7964
ab648270 7965 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7966
7967 /* Figure out which root window we're on. */
334208b7
RS
7968 XQueryPointer (FRAME_X_DISPLAY (*fp),
7969 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7970
7971 /* The root window which contains the pointer. */
7972 &root,
7973
7974 /* Trash which we can't trust if the pointer is on
7975 a different screen. */
7976 &dummy_window,
7977
7978 /* The position on that root window. */
58769bee 7979 &root_x, &root_y,
12ba150f
JB
7980
7981 /* More trash we can't trust. */
7982 &dummy, &dummy,
7983
7984 /* Modifier keys and pointer buttons, about which
7985 we don't care. */
7986 (unsigned int *) &dummy);
7987
7988 /* Now we have a position on the root; find the innermost window
7989 containing the pointer. */
7990 {
7991 Window win, child;
7992 int win_x, win_y;
06a2c219 7993 int parent_x = 0, parent_y = 0;
e99db5a1 7994 int count;
12ba150f
JB
7995
7996 win = root;
69388238 7997
2d7fc7e8
RS
7998 /* XTranslateCoordinates can get errors if the window
7999 structure is changing at the same time this function
8000 is running. So at least we must not crash from them. */
8001
e99db5a1 8002 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 8003
334208b7 8004 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 8005 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 8006 {
69388238
RS
8007 /* If mouse was grabbed on a frame, give coords for that frame
8008 even if the mouse is now outside it. */
334208b7 8009 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 8010
12ba150f 8011 /* From-window, to-window. */
69388238 8012 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
8013
8014 /* From-position, to-position. */
8015 root_x, root_y, &win_x, &win_y,
8016
8017 /* Child of win. */
8018 &child);
69388238
RS
8019 f1 = last_mouse_frame;
8020 }
8021 else
8022 {
8023 while (1)
8024 {
334208b7 8025 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 8026
69388238
RS
8027 /* From-window, to-window. */
8028 root, win,
12ba150f 8029
69388238
RS
8030 /* From-position, to-position. */
8031 root_x, root_y, &win_x, &win_y,
8032
8033 /* Child of win. */
8034 &child);
8035
9af3143a 8036 if (child == None || child == win)
69388238
RS
8037 break;
8038
8039 win = child;
8040 parent_x = win_x;
8041 parent_y = win_y;
8042 }
12ba150f 8043
69388238
RS
8044 /* Now we know that:
8045 win is the innermost window containing the pointer
8046 (XTC says it has no child containing the pointer),
8047 win_x and win_y are the pointer's position in it
8048 (XTC did this the last time through), and
8049 parent_x and parent_y are the pointer's position in win's parent.
8050 (They are what win_x and win_y were when win was child.
8051 If win is the root window, it has no parent, and
8052 parent_{x,y} are invalid, but that's okay, because we'll
8053 never use them in that case.) */
8054
8055 /* Is win one of our frames? */
19126e11 8056 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
aad0f6ab
GM
8057
8058#ifdef USE_X_TOOLKIT
8059 /* If we end up with the menu bar window, say it's not
8060 on the frame. */
8061 if (f1 != NULL
8062 && f1->output_data.x->menubar_widget
8063 && win == XtWindow (f1->output_data.x->menubar_widget))
8064 f1 = NULL;
8065#endif /* USE_X_TOOLKIT */
69388238 8066 }
58769bee 8067
2d7fc7e8
RS
8068 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
8069 f1 = 0;
8070
e99db5a1 8071 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 8072
ab648270 8073 /* If not, is it one of our scroll bars? */
a135645a 8074 if (! f1)
12ba150f 8075 {
ab648270 8076 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
8077
8078 if (bar)
8079 {
a135645a 8080 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
8081 win_x = parent_x;
8082 win_y = parent_y;
8083 }
8084 }
90e65f07 8085
8bcee03e 8086 if (f1 == 0 && insist > 0)
b86bd3dd 8087 f1 = SELECTED_FRAME ();
1cf412ec 8088
a135645a 8089 if (f1)
12ba150f 8090 {
06a2c219
GM
8091 /* Ok, we found a frame. Store all the values.
8092 last_mouse_glyph is a rectangle used to reduce the
8093 generation of mouse events. To not miss any motion
8094 events, we must divide the frame into rectangles of the
8095 size of the smallest character that could be displayed
8096 on it, i.e. into the same rectangles that matrices on
8097 the frame are divided into. */
8098
b52b65bd
GM
8099 int width, height, gx, gy;
8100 XRectangle rect;
8101
8102 if (glyph_rect (f1, win_x, win_y, &rect))
8103 last_mouse_glyph = rect;
8104 else
8105 {
8106 width = FRAME_SMALLEST_CHAR_WIDTH (f1);
8107 height = FRAME_SMALLEST_FONT_HEIGHT (f1);
8108 gx = win_x;
8109 gy = win_y;
06a2c219 8110
b52b65bd
GM
8111 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
8112 round down even for negative values. */
8113 if (gx < 0)
8114 gx -= width - 1;
4f00e84d 8115 if (gy < 0)
b52b65bd
GM
8116 gy -= height - 1;
8117 gx = (gx + width - 1) / width * width;
8118 gy = (gy + height - 1) / height * height;
8119
8120 last_mouse_glyph.width = width;
8121 last_mouse_glyph.height = height;
8122 last_mouse_glyph.x = gx;
8123 last_mouse_glyph.y = gy;
8124 }
12ba150f
JB
8125
8126 *bar_window = Qnil;
8127 *part = 0;
334208b7 8128 *fp = f1;
e0c1aef2
KH
8129 XSETINT (*x, win_x);
8130 XSETINT (*y, win_y);
12ba150f
JB
8131 *time = last_mouse_movement_time;
8132 }
8133 }
8134 }
90e65f07
JB
8135
8136 UNBLOCK_INPUT;
8137}
f451eb13 8138
06a2c219 8139
06a2c219 8140#ifdef USE_X_TOOLKIT
bffcfca9
GM
8141
8142/* Atimer callback function for TIMER. Called every 0.1s to process
8143 Xt timeouts, if needed. We must avoid calling XtAppPending as
8144 much as possible because that function does an implicit XFlush
8145 that slows us down. */
8146
8147static void
8148x_process_timeouts (timer)
8149 struct atimer *timer;
8150{
8151 if (toolkit_scroll_bar_interaction || popup_activated_flag)
8152 {
8153 BLOCK_INPUT;
8154 while (XtAppPending (Xt_app_con) & XtIMTimer)
8155 XtAppProcessEvent (Xt_app_con, XtIMTimer);
8156 UNBLOCK_INPUT;
8157 }
06a2c219
GM
8158}
8159
bffcfca9 8160#endif /* USE_X_TOOLKIT */
06a2c219
GM
8161
8162\f
8163/* Scroll bar support. */
8164
8165/* Given an X window ID, find the struct scroll_bar which manages it.
8166 This can be called in GC, so we have to make sure to strip off mark
8167 bits. */
bffcfca9 8168
06a2c219
GM
8169static struct scroll_bar *
8170x_window_to_scroll_bar (window_id)
8171 Window window_id;
8172{
8173 Lisp_Object tail;
8174
8175 for (tail = Vframe_list;
8176 XGCTYPE (tail) == Lisp_Cons;
8e713be6 8177 tail = XCDR (tail))
06a2c219
GM
8178 {
8179 Lisp_Object frame, bar, condemned;
8180
8e713be6 8181 frame = XCAR (tail);
06a2c219
GM
8182 /* All elements of Vframe_list should be frames. */
8183 if (! GC_FRAMEP (frame))
8184 abort ();
8185
8186 /* Scan this frame's scroll bar list for a scroll bar with the
8187 right window ID. */
8188 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
8189 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
8190 /* This trick allows us to search both the ordinary and
8191 condemned scroll bar lists with one loop. */
8192 ! GC_NILP (bar) || (bar = condemned,
8193 condemned = Qnil,
8194 ! GC_NILP (bar));
8195 bar = XSCROLL_BAR (bar)->next)
8196 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
8197 return XSCROLL_BAR (bar);
8198 }
8199
8200 return 0;
8201}
8202
8203
01f67d2c 8204#if defined USE_LUCID
c95fc5f1
GM
8205
8206/* Return the Lucid menu bar WINDOW is part of. Return null
8207 if WINDOW is not part of a menu bar. */
8208
8209static Widget
8210x_window_to_menu_bar (window)
8211 Window window;
8212{
8213 Lisp_Object tail;
8214
8215 for (tail = Vframe_list;
8216 XGCTYPE (tail) == Lisp_Cons;
8217 tail = XCDR (tail))
8218 {
8219 Lisp_Object frame = XCAR (tail);
8220 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
8221
8222 if (menu_bar && xlwmenu_window_p (menu_bar, window))
8223 return menu_bar;
8224 }
8225
8226 return NULL;
8227}
8228
01f67d2c 8229#endif /* USE_LUCID */
c95fc5f1 8230
06a2c219
GM
8231\f
8232/************************************************************************
8233 Toolkit scroll bars
8234 ************************************************************************/
8235
eccc05db 8236#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8237
8238static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
8239static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
8240static void x_create_toolkit_scroll_bar P_ ((struct frame *,
8241 struct scroll_bar *));
8242static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
8243 int, int, int));
8244
8245
8246/* Id of action hook installed for scroll bars. */
8247
8248static XtActionHookId action_hook_id;
8249
8250/* Lisp window being scrolled. Set when starting to interact with
8251 a toolkit scroll bar, reset to nil when ending the interaction. */
8252
8253static Lisp_Object window_being_scrolled;
8254
8255/* Last scroll bar part sent in xm_scroll_callback. */
8256
8257static int last_scroll_bar_part;
8258
ec18280f
SM
8259/* Whether this is an Xaw with arrow-scrollbars. This should imply
8260 that movements of 1/20 of the screen size are mapped to up/down. */
8261
8262static Boolean xaw3d_arrow_scroll;
8263
8264/* Whether the drag scrolling maintains the mouse at the top of the
8265 thumb. If not, resizing the thumb needs to be done more carefully
8266 to avoid jerkyness. */
8267
8268static Boolean xaw3d_pick_top;
8269
06a2c219
GM
8270
8271/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 8272 bars are used.. The hook is responsible for detecting when
06a2c219
GM
8273 the user ends an interaction with the scroll bar, and generates
8274 a `end-scroll' scroll_bar_click' event if so. */
8275
8276static void
8277xt_action_hook (widget, client_data, action_name, event, params,
8278 num_params)
8279 Widget widget;
8280 XtPointer client_data;
8281 String action_name;
8282 XEvent *event;
8283 String *params;
8284 Cardinal *num_params;
8285{
8286 int scroll_bar_p;
8287 char *end_action;
8288
8289#ifdef USE_MOTIF
8290 scroll_bar_p = XmIsScrollBar (widget);
8291 end_action = "Release";
ec18280f 8292#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8293 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
8294 end_action = "EndScroll";
ec18280f 8295#endif /* USE_MOTIF */
06a2c219 8296
06a2c219
GM
8297 if (scroll_bar_p
8298 && strcmp (action_name, end_action) == 0
8299 && WINDOWP (window_being_scrolled))
8300 {
8301 struct window *w;
8302
8303 x_send_scroll_bar_event (window_being_scrolled,
8304 scroll_bar_end_scroll, 0, 0);
8305 w = XWINDOW (window_being_scrolled);
8306 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
8307 window_being_scrolled = Qnil;
8308 last_scroll_bar_part = -1;
bffcfca9
GM
8309
8310 /* Xt timeouts no longer needed. */
8311 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
8312 }
8313}
8314
07b3d16e
GM
8315/* A vector of windows used for communication between
8316 x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
8317
8318static struct window **scroll_bar_windows;
8319static int scroll_bar_windows_size;
8320
06a2c219
GM
8321
8322/* Send a client message with message type Xatom_Scrollbar for a
8323 scroll action to the frame of WINDOW. PART is a value identifying
8324 the part of the scroll bar that was clicked on. PORTION is the
8325 amount to scroll of a whole of WHOLE. */
8326
8327static void
8328x_send_scroll_bar_event (window, part, portion, whole)
8329 Lisp_Object window;
8330 int part, portion, whole;
8331{
8332 XEvent event;
8333 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
07b3d16e
GM
8334 struct window *w = XWINDOW (window);
8335 struct frame *f = XFRAME (w->frame);
8336 int i;
06a2c219 8337
07b3d16e
GM
8338 BLOCK_INPUT;
8339
06a2c219
GM
8340 /* Construct a ClientMessage event to send to the frame. */
8341 ev->type = ClientMessage;
8342 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
8343 ev->display = FRAME_X_DISPLAY (f);
8344 ev->window = FRAME_X_WINDOW (f);
8345 ev->format = 32;
07b3d16e
GM
8346
8347 /* We can only transfer 32 bits in the XClientMessageEvent, which is
8348 not enough to store a pointer or Lisp_Object on a 64 bit system.
8349 So, store the window in scroll_bar_windows and pass the index
8350 into that array in the event. */
8351 for (i = 0; i < scroll_bar_windows_size; ++i)
8352 if (scroll_bar_windows[i] == NULL)
8353 break;
8354
8355 if (i == scroll_bar_windows_size)
8356 {
8357 int new_size = max (10, 2 * scroll_bar_windows_size);
8358 size_t nbytes = new_size * sizeof *scroll_bar_windows;
8359 size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows;
8360
8361 scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
8362 nbytes);
8363 bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
8364 scroll_bar_windows_size = new_size;
8365 }
8366
8367 scroll_bar_windows[i] = w;
8368 ev->data.l[0] = (long) i;
06a2c219
GM
8369 ev->data.l[1] = (long) part;
8370 ev->data.l[2] = (long) 0;
8371 ev->data.l[3] = (long) portion;
8372 ev->data.l[4] = (long) whole;
8373
bffcfca9
GM
8374 /* Make Xt timeouts work while the scroll bar is active. */
8375 toolkit_scroll_bar_interaction = 1;
8376
06a2c219
GM
8377 /* Setting the event mask to zero means that the message will
8378 be sent to the client that created the window, and if that
8379 window no longer exists, no event will be sent. */
06a2c219
GM
8380 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
8381 UNBLOCK_INPUT;
8382}
8383
8384
8385/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
8386 in *IEVENT. */
8387
8388static void
8389x_scroll_bar_to_input_event (event, ievent)
8390 XEvent *event;
8391 struct input_event *ievent;
8392{
8393 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
8394 Lisp_Object window;
8395 struct frame *f;
07b3d16e
GM
8396 struct window *w;
8397
8398 w = scroll_bar_windows[ev->data.l[0]];
8399 scroll_bar_windows[ev->data.l[0]] = NULL;
52e386c2 8400
07b3d16e
GM
8401 XSETWINDOW (window, w);
8402 f = XFRAME (w->frame);
06a2c219
GM
8403
8404 ievent->kind = scroll_bar_click;
8405 ievent->frame_or_window = window;
0f8aabe9 8406 ievent->arg = Qnil;
06a2c219
GM
8407 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
8408 ievent->part = ev->data.l[1];
8409 ievent->code = ev->data.l[2];
8410 ievent->x = make_number ((int) ev->data.l[3]);
8411 ievent->y = make_number ((int) ev->data.l[4]);
8412 ievent->modifiers = 0;
8413}
8414
8415
8416#ifdef USE_MOTIF
8417
8418/* Minimum and maximum values used for Motif scroll bars. */
8419
8420#define XM_SB_MIN 1
8421#define XM_SB_MAX 10000000
8422#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
8423
8424
8425/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
8426 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
8427 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
8428
8429static void
8430xm_scroll_callback (widget, client_data, call_data)
8431 Widget widget;
8432 XtPointer client_data, call_data;
8433{
8434 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8435 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
06a2c219
GM
8436 int part = -1, whole = 0, portion = 0;
8437
8438 switch (cs->reason)
8439 {
8440 case XmCR_DECREMENT:
8441 bar->dragging = Qnil;
8442 part = scroll_bar_up_arrow;
8443 break;
8444
8445 case XmCR_INCREMENT:
8446 bar->dragging = Qnil;
8447 part = scroll_bar_down_arrow;
8448 break;
8449
8450 case XmCR_PAGE_DECREMENT:
8451 bar->dragging = Qnil;
8452 part = scroll_bar_above_handle;
8453 break;
8454
8455 case XmCR_PAGE_INCREMENT:
8456 bar->dragging = Qnil;
8457 part = scroll_bar_below_handle;
8458 break;
8459
8460 case XmCR_TO_TOP:
8461 bar->dragging = Qnil;
8462 part = scroll_bar_to_top;
8463 break;
8464
8465 case XmCR_TO_BOTTOM:
8466 bar->dragging = Qnil;
8467 part = scroll_bar_to_bottom;
8468 break;
8469
8470 case XmCR_DRAG:
8471 {
8472 int slider_size;
8473 int dragging_down_p = (INTEGERP (bar->dragging)
8474 && XINT (bar->dragging) <= cs->value);
8475
8476 /* Get the slider size. */
8477 BLOCK_INPUT;
8478 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
8479 UNBLOCK_INPUT;
8480
8481 /* At the max position of the scroll bar, do a line-wise
23442ae4
GM
8482 movement. Without doing anything, we would be called with
8483 the same cs->value again and again. If we want to make
8484 sure that we can reach the end of the buffer, we have to do
8485 something.
06a2c219
GM
8486
8487 Implementation note: setting bar->dragging always to
8488 cs->value gives a smoother movement at the max position.
8489 Setting it to nil when doing line-wise movement gives
8490 a better slider behavior. */
8491
8492 if (cs->value + slider_size == XM_SB_MAX
8493 || (dragging_down_p
8494 && last_scroll_bar_part == scroll_bar_down_arrow))
8495 {
8496 part = scroll_bar_down_arrow;
8497 bar->dragging = Qnil;
8498 }
8499 else
8500 {
8501 whole = XM_SB_RANGE;
8502 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
8503 part = scroll_bar_handle;
8504 bar->dragging = make_number (cs->value);
8505 }
8506 }
8507 break;
8508
8509 case XmCR_VALUE_CHANGED:
8510 break;
8511 };
8512
8513 if (part >= 0)
8514 {
8515 window_being_scrolled = bar->window;
8516 last_scroll_bar_part = part;
8517 x_send_scroll_bar_event (bar->window, part, portion, whole);
8518 }
8519}
8520
8521
ec18280f 8522#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
8523
8524
ec18280f 8525/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
8526 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
8527 scroll bar struct. CALL_DATA is a pointer to a float saying where
8528 the thumb is. */
8529
8530static void
ec18280f 8531xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
8532 Widget widget;
8533 XtPointer client_data, call_data;
8534{
8535 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8536 float top = *(float *) call_data;
8537 float shown;
ec18280f
SM
8538 int whole, portion, height;
8539 int part;
06a2c219
GM
8540
8541 /* Get the size of the thumb, a value between 0 and 1. */
8542 BLOCK_INPUT;
ec18280f 8543 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
8544 UNBLOCK_INPUT;
8545
8546 whole = 10000000;
8547 portion = shown < 1 ? top * whole : 0;
06a2c219 8548
ec18280f
SM
8549 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
8550 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
8551 the bottom, so we force the scrolling whenever we see that we're
8552 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
8553 we try to ensure that we always stay two pixels away from the
8554 bottom). */
06a2c219
GM
8555 part = scroll_bar_down_arrow;
8556 else
8557 part = scroll_bar_handle;
8558
8559 window_being_scrolled = bar->window;
8560 bar->dragging = make_number (portion);
8561 last_scroll_bar_part = part;
8562 x_send_scroll_bar_event (bar->window, part, portion, whole);
8563}
8564
8565
ec18280f
SM
8566/* Xaw scroll bar callback. Invoked for incremental scrolling.,
8567 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
8568 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
8569 the scroll bar. CALL_DATA is an integer specifying the action that
8570 has taken place. It's magnitude is in the range 0..height of the
8571 scroll bar. Negative values mean scroll towards buffer start.
8572 Values < height of scroll bar mean line-wise movement. */
8573
8574static void
ec18280f 8575xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
8576 Widget widget;
8577 XtPointer client_data, call_data;
8578{
8579 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8580 int position = (int) call_data;
8581 Dimension height;
8582 int part;
8583
8584 /* Get the height of the scroll bar. */
8585 BLOCK_INPUT;
8586 XtVaGetValues (widget, XtNheight, &height, NULL);
8587 UNBLOCK_INPUT;
8588
ec18280f
SM
8589 if (abs (position) >= height)
8590 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
8591
8592 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
8593 it maps line-movement to call_data = max(5, height/20). */
8594 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
8595 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 8596 else
ec18280f 8597 part = scroll_bar_move_ratio;
06a2c219
GM
8598
8599 window_being_scrolled = bar->window;
8600 bar->dragging = Qnil;
8601 last_scroll_bar_part = part;
ec18280f 8602 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
8603}
8604
8605
8606#endif /* not USE_MOTIF */
8607
8608
8609/* Create the widget for scroll bar BAR on frame F. Record the widget
8610 and X window of the scroll bar in BAR. */
8611
8612static void
8613x_create_toolkit_scroll_bar (f, bar)
8614 struct frame *f;
8615 struct scroll_bar *bar;
8616{
8617 Window xwindow;
8618 Widget widget;
8619 Arg av[20];
8620 int ac = 0;
8621 char *scroll_bar_name = "verticalScrollBar";
8622 unsigned long pixel;
8623
8624 BLOCK_INPUT;
8625
8626#ifdef USE_MOTIF
06a2c219
GM
8627 /* Set resources. Create the widget. */
8628 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8629 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
8630 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
8631 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
8632 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
8633 XtSetArg (av[ac], XmNincrement, 1); ++ac;
8634 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
8635
8636 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8637 if (pixel != -1)
8638 {
8639 XtSetArg (av[ac], XmNforeground, pixel);
8640 ++ac;
8641 }
8642
8643 pixel = f->output_data.x->scroll_bar_background_pixel;
8644 if (pixel != -1)
8645 {
8646 XtSetArg (av[ac], XmNbackground, pixel);
8647 ++ac;
8648 }
8649
8650 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
8651 scroll_bar_name, av, ac);
8652
8653 /* Add one callback for everything that can happen. */
8654 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
8655 (XtPointer) bar);
8656 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
8657 (XtPointer) bar);
8658 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
8659 (XtPointer) bar);
8660 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
8661 (XtPointer) bar);
8662 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
8663 (XtPointer) bar);
8664 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
8665 (XtPointer) bar);
8666 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
8667 (XtPointer) bar);
8668
8669 /* Realize the widget. Only after that is the X window created. */
8670 XtRealizeWidget (widget);
8671
8672 /* Set the cursor to an arrow. I didn't find a resource to do that.
8673 And I'm wondering why it hasn't an arrow cursor by default. */
8674 XDefineCursor (XtDisplay (widget), XtWindow (widget),
8675 f->output_data.x->nontext_cursor);
8676
ec18280f 8677#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8678
8679 /* Set resources. Create the widget. The background of the
8680 Xaw3d scroll bar widget is a little bit light for my taste.
8681 We don't alter it here to let users change it according
8682 to their taste with `emacs*verticalScrollBar.background: xxx'. */
8683 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8684 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
8685 /* For smoother scrolling with Xaw3d -sm */
8686 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
06a2c219
GM
8687
8688 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8689 if (pixel != -1)
8690 {
8691 XtSetArg (av[ac], XtNforeground, pixel);
8692 ++ac;
8693 }
8694
8695 pixel = f->output_data.x->scroll_bar_background_pixel;
8696 if (pixel != -1)
8697 {
8698 XtSetArg (av[ac], XtNbackground, pixel);
8699 ++ac;
8700 }
7c1bef7a
MB
8701
8702 /* Top/bottom shadow colors. */
8703
8704 /* Allocate them, if necessary. */
8705 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
8706 {
8707 pixel = f->output_data.x->scroll_bar_background_pixel;
8708 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8709 &pixel, 1.2, 0x8000))
8710 pixel = -1;
8711 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
8712 }
8713 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8714 {
8715 pixel = f->output_data.x->scroll_bar_background_pixel;
8716 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8717 &pixel, 0.6, 0x4000))
8718 pixel = -1;
8719 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
8720 }
8721
8722 /* Tell the toolkit about them. */
8723 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
8724 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8725 /* We tried to allocate a color for the top/bottom shadow, and
8726 failed, so tell Xaw3d to use dithering instead. */
8727 {
8728 XtSetArg (av[ac], XtNbeNiceToColormap, True);
8729 ++ac;
8730 }
8731 else
8732 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
8733 be more consistent with other emacs 3d colors, and since Xaw3d is
8734 not good at dealing with allocation failure. */
8735 {
8736 /* This tells Xaw3d to use real colors instead of dithering for
8737 the shadows. */
8738 XtSetArg (av[ac], XtNbeNiceToColormap, False);
8739 ++ac;
8740
8741 /* Specify the colors. */
8742 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
8743 if (pixel != -1)
8744 {
8745 XtSetArg (av[ac], "topShadowPixel", pixel);
8746 ++ac;
8747 }
8748 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
8749 if (pixel != -1)
8750 {
8751 XtSetArg (av[ac], "bottomShadowPixel", pixel);
8752 ++ac;
8753 }
8754 }
8755
06a2c219
GM
8756 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
8757 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
8758
8759 {
8760 char *initial = "";
8761 char *val = initial;
8762 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
8763 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
8764 if (val == initial)
8765 { /* ARROW_SCROLL */
8766 xaw3d_arrow_scroll = True;
8767 /* Isn't that just a personal preference ? -sm */
8768 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
8769 }
8770 }
06a2c219
GM
8771
8772 /* Define callbacks. */
ec18280f
SM
8773 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
8774 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
8775 (XtPointer) bar);
8776
8777 /* Realize the widget. Only after that is the X window created. */
8778 XtRealizeWidget (widget);
8779
ec18280f 8780#endif /* !USE_MOTIF */
06a2c219
GM
8781
8782 /* Install an action hook that let's us detect when the user
8783 finishes interacting with a scroll bar. */
8784 if (action_hook_id == 0)
8785 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
8786
8787 /* Remember X window and widget in the scroll bar vector. */
8788 SET_SCROLL_BAR_X_WIDGET (bar, widget);
8789 xwindow = XtWindow (widget);
8790 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
8791
8792 UNBLOCK_INPUT;
8793}
8794
8795
8796/* Set the thumb size and position of scroll bar BAR. We are currently
8797 displaying PORTION out of a whole WHOLE, and our position POSITION. */
8798
8799static void
8800x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
8801 struct scroll_bar *bar;
8802 int portion, position, whole;
f451eb13 8803{
e83dc917
GM
8804 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8805 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
06a2c219 8806 float top, shown;
f451eb13 8807
06a2c219
GM
8808 if (whole == 0)
8809 top = 0, shown = 1;
8810 else
f451eb13 8811 {
06a2c219
GM
8812 top = (float) position / whole;
8813 shown = (float) portion / whole;
8814 }
f451eb13 8815
06a2c219 8816 BLOCK_INPUT;
f451eb13 8817
06a2c219
GM
8818#ifdef USE_MOTIF
8819 {
8820 int size, value;
06a2c219 8821
ec18280f 8822 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
8823 is the scroll bar's maximum and MIN is the scroll bar's minimum
8824 value. */
8825 size = shown * XM_SB_RANGE;
8826 size = min (size, XM_SB_RANGE);
8827 size = max (size, 1);
8828
8829 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
8830 value = top * XM_SB_RANGE;
8831 value = min (value, XM_SB_MAX - size);
8832 value = max (value, XM_SB_MIN);
8833
06a2c219
GM
8834 if (NILP (bar->dragging))
8835 XmScrollBarSetValues (widget, value, size, 0, 0, False);
8836 else if (last_scroll_bar_part == scroll_bar_down_arrow)
8837 /* This has the negative side effect that the slider value is
ec18280f 8838 not what it would be if we scrolled here using line-wise or
06a2c219
GM
8839 page-wise movement. */
8840 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
8841 else
8842 {
8843 /* If currently dragging, only update the slider size.
8844 This reduces flicker effects. */
8845 int old_value, old_size, increment, page_increment;
8846
8847 XmScrollBarGetValues (widget, &old_value, &old_size,
8848 &increment, &page_increment);
8849 XmScrollBarSetValues (widget, old_value,
8850 min (size, XM_SB_RANGE - old_value),
8851 0, 0, False);
8852 }
06a2c219 8853 }
ec18280f 8854#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 8855 {
ec18280f
SM
8856 float old_top, old_shown;
8857 Dimension height;
8858 XtVaGetValues (widget,
8859 XtNtopOfThumb, &old_top,
8860 XtNshown, &old_shown,
8861 XtNheight, &height,
8862 NULL);
8863
8864 /* Massage the top+shown values. */
8865 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8866 top = max (0, min (1, top));
8867 else
8868 top = old_top;
8869 /* Keep two pixels available for moving the thumb down. */
8870 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8871
8872 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8873 check that your system's configuration file contains a define
8874 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8875 if (top != old_top || shown != old_shown)
eb393530 8876 {
ec18280f 8877 if (NILP (bar->dragging))
eb393530 8878 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8879 else
8880 {
ec18280f
SM
8881#ifdef HAVE_XAW3D
8882 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8883 int scroll_mode = 0;
ec18280f
SM
8884
8885 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8886 if (xaw3d_arrow_scroll)
8887 {
8888 /* Xaw3d stupidly ignores resize requests while dragging
8889 so we have to make it believe it's not in dragging mode. */
8890 scroll_mode = sb->scrollbar.scroll_mode;
8891 if (scroll_mode == 2)
8892 sb->scrollbar.scroll_mode = 0;
8893 }
8894#endif
8895 /* Try to make the scrolling a tad smoother. */
8896 if (!xaw3d_pick_top)
8897 shown = min (shown, old_shown);
8898
8899 XawScrollbarSetThumb (widget, top, shown);
8900
8901#ifdef HAVE_XAW3D
8902 if (xaw3d_arrow_scroll && scroll_mode == 2)
8903 sb->scrollbar.scroll_mode = scroll_mode;
8904#endif
06a2c219 8905 }
06a2c219
GM
8906 }
8907 }
ec18280f 8908#endif /* !USE_MOTIF */
06a2c219
GM
8909
8910 UNBLOCK_INPUT;
f451eb13
JB
8911}
8912
06a2c219
GM
8913#endif /* USE_TOOLKIT_SCROLL_BARS */
8914
8915
8916\f
8917/************************************************************************
8918 Scroll bars, general
8919 ************************************************************************/
8920
8921/* Create a scroll bar and return the scroll bar vector for it. W is
8922 the Emacs window on which to create the scroll bar. TOP, LEFT,
8923 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8924 scroll bar. */
8925
ab648270 8926static struct scroll_bar *
06a2c219
GM
8927x_scroll_bar_create (w, top, left, width, height)
8928 struct window *w;
f451eb13
JB
8929 int top, left, width, height;
8930{
06a2c219 8931 struct frame *f = XFRAME (w->frame);
334208b7
RS
8932 struct scroll_bar *bar
8933 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8934
8935 BLOCK_INPUT;
8936
eccc05db 8937#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8938 x_create_toolkit_scroll_bar (f, bar);
8939#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8940 {
8941 XSetWindowAttributes a;
8942 unsigned long mask;
5c187dee 8943 Window window;
06a2c219
GM
8944
8945 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8946 if (a.background_pixel == -1)
8947 a.background_pixel = f->output_data.x->background_pixel;
8948
12ba150f 8949 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 8950 | ButtonMotionMask | PointerMotionHintMask
12ba150f 8951 | ExposureMask);
7a13e894 8952 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 8953
dbc4e1c1 8954 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8955
06a2c219
GM
8956 /* Clear the area of W that will serve as a scroll bar. This is
8957 for the case that a window has been split horizontally. In
8958 this case, no clear_frame is generated to reduce flickering. */
7b49b9d2
GM
8959 if (width > 0 && height > 0)
8960 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8961 left, top, width,
8962 window_box_height (w), False);
06a2c219
GM
8963
8964 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8965 /* Position and size of scroll bar. */
8966 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8967 top,
8968 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8969 height,
8970 /* Border width, depth, class, and visual. */
8971 0,
8972 CopyFromParent,
8973 CopyFromParent,
8974 CopyFromParent,
8975 /* Attributes. */
8976 mask, &a);
8977 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 8978 }
06a2c219 8979#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8980
06a2c219 8981 XSETWINDOW (bar->window, w);
e0c1aef2
KH
8982 XSETINT (bar->top, top);
8983 XSETINT (bar->left, left);
8984 XSETINT (bar->width, width);
8985 XSETINT (bar->height, height);
8986 XSETINT (bar->start, 0);
8987 XSETINT (bar->end, 0);
12ba150f 8988 bar->dragging = Qnil;
f451eb13
JB
8989
8990 /* Add bar to its frame's list of scroll bars. */
334208b7 8991 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8992 bar->prev = Qnil;
334208b7 8993 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 8994 if (!NILP (bar->next))
e0c1aef2 8995 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 8996
06a2c219 8997 /* Map the window/widget. */
eccc05db 8998#ifdef USE_TOOLKIT_SCROLL_BARS
f964b4d7
GM
8999 {
9000 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
9001 XtConfigureWidget (scroll_bar,
9002 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9003 top,
9004 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
9005 max (height, 1), 0);
9006 XtMapWidget (scroll_bar);
9007 }
06a2c219 9008#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 9009 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 9010#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9011
9012 UNBLOCK_INPUT;
12ba150f 9013 return bar;
f451eb13
JB
9014}
9015
06a2c219 9016
12ba150f 9017/* Draw BAR's handle in the proper position.
06a2c219 9018
12ba150f
JB
9019 If the handle is already drawn from START to END, don't bother
9020 redrawing it, unless REBUILD is non-zero; in that case, always
9021 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 9022 events.)
12ba150f
JB
9023
9024 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
9025 fit inside its rectangle, but if the user is dragging the scroll
9026 bar handle, we want to let them drag it down all the way, so that
9027 the bar's top is as far down as it goes; otherwise, there's no way
9028 to move to the very end of the buffer. */
9029
5c187dee
GM
9030#ifndef USE_TOOLKIT_SCROLL_BARS
9031
f451eb13 9032static void
ab648270
JB
9033x_scroll_bar_set_handle (bar, start, end, rebuild)
9034 struct scroll_bar *bar;
f451eb13 9035 int start, end;
12ba150f 9036 int rebuild;
f451eb13 9037{
12ba150f 9038 int dragging = ! NILP (bar->dragging);
ab648270 9039 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9040 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9041 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
9042
9043 /* If the display is already accurate, do nothing. */
9044 if (! rebuild
9045 && start == XINT (bar->start)
9046 && end == XINT (bar->end))
9047 return;
9048
f451eb13
JB
9049 BLOCK_INPUT;
9050
9051 {
d9cdbb3d
RS
9052 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
9053 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
9054 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
9055
9056 /* Make sure the values are reasonable, and try to preserve
9057 the distance between start and end. */
12ba150f
JB
9058 {
9059 int length = end - start;
9060
9061 if (start < 0)
9062 start = 0;
9063 else if (start > top_range)
9064 start = top_range;
9065 end = start + length;
9066
9067 if (end < start)
9068 end = start;
9069 else if (end > top_range && ! dragging)
9070 end = top_range;
9071 }
f451eb13 9072
ab648270 9073 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
9074 XSETINT (bar->start, start);
9075 XSETINT (bar->end, end);
f451eb13 9076
12ba150f
JB
9077 /* Clip the end position, just for display. */
9078 if (end > top_range)
9079 end = top_range;
f451eb13 9080
ab648270 9081 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
9082 below top positions, to make sure the handle is always at least
9083 that many pixels tall. */
ab648270 9084 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 9085
12ba150f
JB
9086 /* Draw the empty space above the handle. Note that we can't clear
9087 zero-height areas; that means "clear to end of window." */
9088 if (0 < start)
c5e6e06b
GM
9089 x_clear_area (FRAME_X_DISPLAY (f), w,
9090 /* x, y, width, height, and exposures. */
9091 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9092 VERTICAL_SCROLL_BAR_TOP_BORDER,
9093 inside_width, start,
9094 False);
f451eb13 9095
06a2c219
GM
9096 /* Change to proper foreground color if one is specified. */
9097 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9098 XSetForeground (FRAME_X_DISPLAY (f), gc,
9099 f->output_data.x->scroll_bar_foreground_pixel);
9100
12ba150f 9101 /* Draw the handle itself. */
334208b7 9102 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
12ba150f 9103 /* x, y, width, height */
ab648270
JB
9104 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9105 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 9106 inside_width, end - start);
f451eb13 9107
06a2c219
GM
9108 /* Restore the foreground color of the GC if we changed it above. */
9109 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9110 XSetForeground (FRAME_X_DISPLAY (f), gc,
9111 f->output_data.x->foreground_pixel);
f451eb13 9112
12ba150f
JB
9113 /* Draw the empty space below the handle. Note that we can't
9114 clear zero-height areas; that means "clear to end of window." */
9115 if (end < inside_height)
c5e6e06b
GM
9116 x_clear_area (FRAME_X_DISPLAY (f), w,
9117 /* x, y, width, height, and exposures. */
9118 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9119 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
9120 inside_width, inside_height - end,
9121 False);
f451eb13 9122
f451eb13
JB
9123 }
9124
f451eb13
JB
9125 UNBLOCK_INPUT;
9126}
9127
5c187dee 9128#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 9129
06a2c219
GM
9130/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
9131 nil. */
58769bee 9132
12ba150f 9133static void
ab648270
JB
9134x_scroll_bar_remove (bar)
9135 struct scroll_bar *bar;
12ba150f 9136{
e83dc917 9137 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
9138 BLOCK_INPUT;
9139
eccc05db 9140#ifdef USE_TOOLKIT_SCROLL_BARS
e83dc917
GM
9141 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
9142#else
9143 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
9144#endif
06a2c219 9145
ab648270
JB
9146 /* Disassociate this scroll bar from its window. */
9147 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
9148
9149 UNBLOCK_INPUT;
9150}
9151
06a2c219 9152
12ba150f
JB
9153/* Set the handle of the vertical scroll bar for WINDOW to indicate
9154 that we are displaying PORTION characters out of a total of WHOLE
ab648270 9155 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 9156 create one. */
06a2c219 9157
12ba150f 9158static void
06a2c219
GM
9159XTset_vertical_scroll_bar (w, portion, whole, position)
9160 struct window *w;
f451eb13
JB
9161 int portion, whole, position;
9162{
06a2c219 9163 struct frame *f = XFRAME (w->frame);
ab648270 9164 struct scroll_bar *bar;
3c6ede7b 9165 int top, height, left, sb_left, width, sb_width;
06a2c219 9166 int window_x, window_y, window_width, window_height;
06a2c219 9167
3c6ede7b 9168 /* Get window dimensions. */
06a2c219 9169 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
9170 top = window_y;
9171 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9172 height = window_height;
06a2c219 9173
3c6ede7b 9174 /* Compute the left edge of the scroll bar area. */
06a2c219 9175 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
9176 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
9177 else
9178 left = XFASTINT (w->left);
9179 left *= CANON_X_UNIT (f);
9180 left += FRAME_INTERNAL_BORDER_WIDTH (f);
9181
9182 /* Compute the width of the scroll bar which might be less than
9183 the width of the area reserved for the scroll bar. */
9184 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
9185 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 9186 else
3c6ede7b 9187 sb_width = width;
12ba150f 9188
3c6ede7b
GM
9189 /* Compute the left edge of the scroll bar. */
9190#ifdef USE_TOOLKIT_SCROLL_BARS
9191 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9192 sb_left = left + width - sb_width - (width - sb_width) / 2;
9193 else
9194 sb_left = left + (width - sb_width) / 2;
9195#else
9196 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9197 sb_left = left + width - sb_width;
9198 else
9199 sb_left = left;
9200#endif
9201
ab648270 9202 /* Does the scroll bar exist yet? */
06a2c219 9203 if (NILP (w->vertical_scroll_bar))
3c6ede7b 9204 {
7b49b9d2 9205 if (width > 0 && height > 0)
b547b6e8
GM
9206 {
9207 BLOCK_INPUT;
9208 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9209 left, top, width, height, False);
9210 UNBLOCK_INPUT;
9211 }
9212
3c6ede7b
GM
9213 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
9214 }
f451eb13 9215 else
12ba150f
JB
9216 {
9217 /* It may just need to be moved and resized. */
06a2c219
GM
9218 unsigned int mask = 0;
9219
9220 bar = XSCROLL_BAR (w->vertical_scroll_bar);
9221
9222 BLOCK_INPUT;
9223
3c6ede7b 9224 if (sb_left != XINT (bar->left))
06a2c219 9225 mask |= CWX;
3c6ede7b 9226 if (top != XINT (bar->top))
06a2c219 9227 mask |= CWY;
3c6ede7b 9228 if (sb_width != XINT (bar->width))
06a2c219 9229 mask |= CWWidth;
3c6ede7b 9230 if (height != XINT (bar->height))
06a2c219
GM
9231 mask |= CWHeight;
9232
9233#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
9234
9235 /* Since toolkit scroll bars are smaller than the space reserved
9236 for them on the frame, we have to clear "under" them. */
7b49b9d2 9237 if (width > 0 && height > 0)
f964b4d7
GM
9238 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9239 left, top, width, height, False);
06a2c219
GM
9240
9241 /* Move/size the scroll bar widget. */
9242 if (mask)
e83dc917 9243 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
3c6ede7b
GM
9244 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9245 top,
9246 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
f964b4d7 9247 max (height, 1), 0);
06a2c219
GM
9248
9249#else /* not USE_TOOLKIT_SCROLL_BARS */
9250
357e7376
GM
9251 /* Clear areas not covered by the scroll bar because of
9252 VERTICAL_SCROLL_BAR_WIDTH_TRIM. */
e1f6572f
RS
9253 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
9254 {
c5e6e06b
GM
9255 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9256 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9257 height, False);
9258 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9259 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9260 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9261 height, False);
e1f6572f 9262 }
357e7376
GM
9263
9264 /* Clear areas not covered by the scroll bar because it's not as
9265 wide as the area reserved for it . This makes sure a
9266 previous mode line display is cleared after C-x 2 C-x 1, for
9267 example. */
9268 {
9269 int area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9270 int rest = area_width - sb_width;
38d2af0c
GM
9271 if (rest > 0 && height > 0)
9272 {
9273 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
9274 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9275 left + area_width - rest, top,
9276 rest, height, False);
9277 else
9278 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9279 left, top, rest, height, False);
9280 }
357e7376 9281 }
06a2c219
GM
9282
9283 /* Move/size the scroll bar window. */
9284 if (mask)
9285 {
9286 XWindowChanges wc;
9287
3c6ede7b
GM
9288 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
9289 wc.y = top;
9290 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
9291 wc.height = height;
06a2c219
GM
9292 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
9293 mask, &wc);
9294 }
9295
9296#endif /* not USE_TOOLKIT_SCROLL_BARS */
9297
9298 /* Remember new settings. */
3c6ede7b
GM
9299 XSETINT (bar->left, sb_left);
9300 XSETINT (bar->top, top);
9301 XSETINT (bar->width, sb_width);
9302 XSETINT (bar->height, height);
06a2c219
GM
9303
9304 UNBLOCK_INPUT;
12ba150f 9305 }
f451eb13 9306
eccc05db 9307#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
9308 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
9309#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 9310 /* Set the scroll bar's current state, unless we're currently being
f451eb13 9311 dragged. */
12ba150f 9312 if (NILP (bar->dragging))
f451eb13 9313 {
92857db0 9314 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 9315
12ba150f 9316 if (whole == 0)
ab648270 9317 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
9318 else
9319 {
43f868f5
JB
9320 int start = ((double) position * top_range) / whole;
9321 int end = ((double) (position + portion) * top_range) / whole;
ab648270 9322 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 9323 }
f451eb13 9324 }
06a2c219 9325#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9326
06a2c219 9327 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
9328}
9329
12ba150f 9330
f451eb13 9331/* The following three hooks are used when we're doing a thorough
ab648270 9332 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 9333 are going to be deleted, because keeping track of when windows go
12ba150f
JB
9334 away is a real pain - "Can you say set-window-configuration, boys
9335 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 9336 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 9337 from the fiery pit when we actually redisplay its window. */
f451eb13 9338
ab648270
JB
9339/* Arrange for all scroll bars on FRAME to be removed at the next call
9340 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
9341 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
9342
58769bee 9343static void
ab648270 9344XTcondemn_scroll_bars (frame)
f451eb13
JB
9345 FRAME_PTR frame;
9346{
f9e24cb9
RS
9347 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
9348 while (! NILP (FRAME_SCROLL_BARS (frame)))
9349 {
9350 Lisp_Object bar;
9351 bar = FRAME_SCROLL_BARS (frame);
9352 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
9353 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
9354 XSCROLL_BAR (bar)->prev = Qnil;
9355 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
9356 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
9357 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
9358 }
f451eb13
JB
9359}
9360
fa2dfc30 9361
06a2c219 9362/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 9363 Note that WINDOW isn't necessarily condemned at all. */
fa2dfc30 9364
f451eb13 9365static void
ab648270 9366XTredeem_scroll_bar (window)
12ba150f 9367 struct window *window;
f451eb13 9368{
ab648270 9369 struct scroll_bar *bar;
fa2dfc30 9370 struct frame *f;
12ba150f 9371
ab648270
JB
9372 /* We can't redeem this window's scroll bar if it doesn't have one. */
9373 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
9374 abort ();
9375
ab648270 9376 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
9377
9378 /* Unlink it from the condemned list. */
fa2dfc30
GM
9379 f = XFRAME (WINDOW_FRAME (window));
9380 if (NILP (bar->prev))
9381 {
9382 /* If the prev pointer is nil, it must be the first in one of
9383 the lists. */
9384 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
9385 /* It's not condemned. Everything's fine. */
9386 return;
9387 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
9388 window->vertical_scroll_bar))
9389 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
9390 else
9391 /* If its prev pointer is nil, it must be at the front of
9392 one or the other! */
9393 abort ();
9394 }
9395 else
9396 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f 9397
fa2dfc30
GM
9398 if (! NILP (bar->next))
9399 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 9400
fa2dfc30
GM
9401 bar->next = FRAME_SCROLL_BARS (f);
9402 bar->prev = Qnil;
9403 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
9404 if (! NILP (bar->next))
9405 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13
JB
9406}
9407
ab648270
JB
9408/* Remove all scroll bars on FRAME that haven't been saved since the
9409 last call to `*condemn_scroll_bars_hook'. */
06a2c219 9410
f451eb13 9411static void
ab648270 9412XTjudge_scroll_bars (f)
12ba150f 9413 FRAME_PTR f;
f451eb13 9414{
12ba150f 9415 Lisp_Object bar, next;
f451eb13 9416
ab648270 9417 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
9418
9419 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
9420 more events on the hapless scroll bars. */
9421 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
9422
9423 for (; ! NILP (bar); bar = next)
f451eb13 9424 {
ab648270 9425 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 9426
ab648270 9427 x_scroll_bar_remove (b);
12ba150f
JB
9428
9429 next = b->next;
9430 b->next = b->prev = Qnil;
f451eb13 9431 }
12ba150f 9432
ab648270 9433 /* Now there should be no references to the condemned scroll bars,
12ba150f 9434 and they should get garbage-collected. */
f451eb13
JB
9435}
9436
9437
06a2c219
GM
9438/* Handle an Expose or GraphicsExpose event on a scroll bar. This
9439 is a no-op when using toolkit scroll bars.
ab648270
JB
9440
9441 This may be called from a signal handler, so we have to ignore GC
9442 mark bits. */
06a2c219 9443
f451eb13 9444static void
ab648270
JB
9445x_scroll_bar_expose (bar, event)
9446 struct scroll_bar *bar;
f451eb13
JB
9447 XEvent *event;
9448{
06a2c219
GM
9449#ifndef USE_TOOLKIT_SCROLL_BARS
9450
ab648270 9451 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9452 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9453 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 9454 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 9455
f451eb13
JB
9456 BLOCK_INPUT;
9457
ab648270 9458 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 9459
06a2c219 9460 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 9461 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
9462
9463 /* x, y, width, height */
d9cdbb3d 9464 0, 0,
3cbd2e0b 9465 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
9466 XINT (bar->height) - 1);
9467
f451eb13 9468 UNBLOCK_INPUT;
06a2c219
GM
9469
9470#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9471}
9472
ab648270
JB
9473/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
9474 is set to something other than no_event, it is enqueued.
9475
9476 This may be called from a signal handler, so we have to ignore GC
9477 mark bits. */
06a2c219 9478
5c187dee
GM
9479#ifndef USE_TOOLKIT_SCROLL_BARS
9480
f451eb13 9481static void
ab648270
JB
9482x_scroll_bar_handle_click (bar, event, emacs_event)
9483 struct scroll_bar *bar;
f451eb13
JB
9484 XEvent *event;
9485 struct input_event *emacs_event;
9486{
0299d313 9487 if (! GC_WINDOWP (bar->window))
12ba150f
JB
9488 abort ();
9489
ab648270 9490 emacs_event->kind = scroll_bar_click;
69388238 9491 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
9492 emacs_event->modifiers
9493 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
9494 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
9495 event->xbutton.state)
9496 | (event->type == ButtonRelease
9497 ? up_modifier
9498 : down_modifier));
12ba150f 9499 emacs_event->frame_or_window = bar->window;
0f8aabe9 9500 emacs_event->arg = Qnil;
f451eb13 9501 emacs_event->timestamp = event->xbutton.time;
12ba150f 9502 {
06a2c219 9503#if 0
d9cdbb3d 9504 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 9505 int internal_height
d9cdbb3d 9506 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9507#endif
0299d313 9508 int top_range
d9cdbb3d 9509 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 9510 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
9511
9512 if (y < 0) y = 0;
9513 if (y > top_range) y = top_range;
9514
9515 if (y < XINT (bar->start))
ab648270
JB
9516 emacs_event->part = scroll_bar_above_handle;
9517 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9518 emacs_event->part = scroll_bar_handle;
12ba150f 9519 else
ab648270 9520 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
9521
9522 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
9523 they want to drag it. Lisp code needs to be able to decide
9524 whether or not we're dragging. */
929787e1 9525#if 0
12ba150f
JB
9526 /* If the user has just clicked on the handle, record where they're
9527 holding it. */
9528 if (event->type == ButtonPress
ab648270 9529 && emacs_event->part == scroll_bar_handle)
e0c1aef2 9530 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 9531#endif
12ba150f
JB
9532
9533 /* If the user has released the handle, set it to its final position. */
9534 if (event->type == ButtonRelease
9535 && ! NILP (bar->dragging))
9536 {
9537 int new_start = y - XINT (bar->dragging);
9538 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 9539
ab648270 9540 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
9541 bar->dragging = Qnil;
9542 }
f451eb13 9543
5116f055
JB
9544 /* Same deal here as the other #if 0. */
9545#if 0
58769bee 9546 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 9547 the handle. */
ab648270 9548 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
9549 emacs_event->x = bar->start;
9550 else
e0c1aef2 9551 XSETINT (emacs_event->x, y);
5116f055 9552#else
e0c1aef2 9553 XSETINT (emacs_event->x, y);
5116f055 9554#endif
f451eb13 9555
e0c1aef2 9556 XSETINT (emacs_event->y, top_range);
12ba150f
JB
9557 }
9558}
f451eb13 9559
ab648270
JB
9560/* Handle some mouse motion while someone is dragging the scroll bar.
9561
9562 This may be called from a signal handler, so we have to ignore GC
9563 mark bits. */
06a2c219 9564
f451eb13 9565static void
ab648270
JB
9566x_scroll_bar_note_movement (bar, event)
9567 struct scroll_bar *bar;
f451eb13
JB
9568 XEvent *event;
9569{
39d8bb4d
KH
9570 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
9571
f451eb13
JB
9572 last_mouse_movement_time = event->xmotion.time;
9573
39d8bb4d 9574 f->mouse_moved = 1;
e0c1aef2 9575 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
9576
9577 /* If we're dragging the bar, display it. */
ab648270 9578 if (! GC_NILP (bar->dragging))
f451eb13
JB
9579 {
9580 /* Where should the handle be now? */
12ba150f 9581 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 9582
12ba150f 9583 if (new_start != XINT (bar->start))
f451eb13 9584 {
12ba150f 9585 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 9586
ab648270 9587 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
9588 }
9589 }
f451eb13
JB
9590}
9591
5c187dee
GM
9592#endif /* !USE_TOOLKIT_SCROLL_BARS */
9593
12ba150f 9594/* Return information to the user about the current position of the mouse
ab648270 9595 on the scroll bar. */
06a2c219 9596
12ba150f 9597static void
334208b7
RS
9598x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
9599 FRAME_PTR *fp;
12ba150f 9600 Lisp_Object *bar_window;
ab648270 9601 enum scroll_bar_part *part;
12ba150f
JB
9602 Lisp_Object *x, *y;
9603 unsigned long *time;
9604{
ab648270 9605 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
9606 Window w = SCROLL_BAR_X_WINDOW (bar);
9607 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 9608 int win_x, win_y;
559cb2fb
JB
9609 Window dummy_window;
9610 int dummy_coord;
9611 unsigned int dummy_mask;
12ba150f 9612
cf7cb199
JB
9613 BLOCK_INPUT;
9614
ab648270 9615 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 9616 report that. */
334208b7 9617 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 9618
559cb2fb
JB
9619 /* Root, child, root x and root y. */
9620 &dummy_window, &dummy_window,
9621 &dummy_coord, &dummy_coord,
12ba150f 9622
559cb2fb
JB
9623 /* Position relative to scroll bar. */
9624 &win_x, &win_y,
12ba150f 9625
559cb2fb
JB
9626 /* Mouse buttons and modifier keys. */
9627 &dummy_mask))
7a13e894 9628 ;
559cb2fb
JB
9629 else
9630 {
06a2c219 9631#if 0
559cb2fb 9632 int inside_height
d9cdbb3d 9633 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9634#endif
559cb2fb 9635 int top_range
d9cdbb3d 9636 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
9637
9638 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
9639
9640 if (! NILP (bar->dragging))
9641 win_y -= XINT (bar->dragging);
9642
9643 if (win_y < 0)
9644 win_y = 0;
9645 if (win_y > top_range)
9646 win_y = top_range;
9647
334208b7 9648 *fp = f;
7a13e894 9649 *bar_window = bar->window;
559cb2fb
JB
9650
9651 if (! NILP (bar->dragging))
9652 *part = scroll_bar_handle;
9653 else if (win_y < XINT (bar->start))
9654 *part = scroll_bar_above_handle;
9655 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9656 *part = scroll_bar_handle;
9657 else
9658 *part = scroll_bar_below_handle;
12ba150f 9659
e0c1aef2
KH
9660 XSETINT (*x, win_y);
9661 XSETINT (*y, top_range);
12ba150f 9662
39d8bb4d 9663 f->mouse_moved = 0;
559cb2fb
JB
9664 last_mouse_scroll_bar = Qnil;
9665 }
12ba150f 9666
559cb2fb 9667 *time = last_mouse_movement_time;
cf7cb199 9668
cf7cb199 9669 UNBLOCK_INPUT;
12ba150f
JB
9670}
9671
f451eb13 9672
dbc4e1c1 9673/* The screen has been cleared so we may have changed foreground or
ab648270
JB
9674 background colors, and the scroll bars may need to be redrawn.
9675 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
9676 redraw them. */
9677
dfcf069d 9678void
ab648270 9679x_scroll_bar_clear (f)
dbc4e1c1
JB
9680 FRAME_PTR f;
9681{
06a2c219 9682#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
9683 Lisp_Object bar;
9684
b80c363e
RS
9685 /* We can have scroll bars even if this is 0,
9686 if we just turned off scroll bar mode.
9687 But in that case we should not clear them. */
9688 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
9689 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
9690 bar = XSCROLL_BAR (bar)->next)
c5e6e06b
GM
9691 XClearArea (FRAME_X_DISPLAY (f),
9692 SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
b80c363e 9693 0, 0, 0, 0, True);
06a2c219 9694#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
9695}
9696
06a2c219 9697/* This processes Expose events from the menu-bar specific X event
19126e11 9698 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 9699 when handling menu-bar or pop-up items. */
3afe33e7 9700
06a2c219 9701int
3afe33e7
RS
9702process_expose_from_menu (event)
9703 XEvent event;
9704{
9705 FRAME_PTR f;
19126e11 9706 struct x_display_info *dpyinfo;
06a2c219 9707 int frame_exposed_p = 0;
3afe33e7 9708
f94397b5
KH
9709 BLOCK_INPUT;
9710
19126e11
KH
9711 dpyinfo = x_display_info_for_display (event.xexpose.display);
9712 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
9713 if (f)
9714 {
9715 if (f->async_visible == 0)
9716 {
9717 f->async_visible = 1;
9718 f->async_iconified = 0;
06c488fd 9719 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
9720 SET_FRAME_GARBAGED (f);
9721 }
9722 else
9723 {
06a2c219
GM
9724 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
9725 event.xexpose.x, event.xexpose.y,
9726 event.xexpose.width, event.xexpose.height);
9727 frame_exposed_p = 1;
3afe33e7
RS
9728 }
9729 }
9730 else
9731 {
9732 struct scroll_bar *bar
9733 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9734
3afe33e7
RS
9735 if (bar)
9736 x_scroll_bar_expose (bar, &event);
9737 }
f94397b5
KH
9738
9739 UNBLOCK_INPUT;
06a2c219 9740 return frame_exposed_p;
3afe33e7 9741}
09756a85
RS
9742\f
9743/* Define a queue to save up SelectionRequest events for later handling. */
9744
9745struct selection_event_queue
9746 {
9747 XEvent event;
9748 struct selection_event_queue *next;
9749 };
9750
9751static struct selection_event_queue *queue;
9752
9753/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 9754
09756a85
RS
9755static int x_queue_selection_requests;
9756
9757/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 9758
09756a85 9759static void
334208b7
RS
9760x_queue_event (f, event)
9761 FRAME_PTR f;
09756a85
RS
9762 XEvent *event;
9763{
9764 struct selection_event_queue *queue_tmp
06a2c219 9765 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 9766
58769bee 9767 if (queue_tmp != NULL)
09756a85
RS
9768 {
9769 queue_tmp->event = *event;
9770 queue_tmp->next = queue;
9771 queue = queue_tmp;
9772 }
9773}
9774
9775/* Take all the queued events and put them back
9776 so that they get processed afresh. */
9777
9778static void
db3906fd
RS
9779x_unqueue_events (display)
9780 Display *display;
09756a85 9781{
58769bee 9782 while (queue != NULL)
09756a85
RS
9783 {
9784 struct selection_event_queue *queue_tmp = queue;
db3906fd 9785 XPutBackEvent (display, &queue_tmp->event);
09756a85 9786 queue = queue_tmp->next;
06a2c219 9787 xfree ((char *)queue_tmp);
09756a85
RS
9788 }
9789}
9790
9791/* Start queuing SelectionRequest events. */
9792
9793void
db3906fd
RS
9794x_start_queuing_selection_requests (display)
9795 Display *display;
09756a85
RS
9796{
9797 x_queue_selection_requests++;
9798}
9799
9800/* Stop queuing SelectionRequest events. */
9801
9802void
db3906fd
RS
9803x_stop_queuing_selection_requests (display)
9804 Display *display;
09756a85
RS
9805{
9806 x_queue_selection_requests--;
db3906fd 9807 x_unqueue_events (display);
09756a85 9808}
f451eb13
JB
9809\f
9810/* The main X event-reading loop - XTread_socket. */
dc6f92b8 9811
06a2c219 9812/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
9813 but we have to put it out here, since static variables within functions
9814 sometimes don't work. */
06a2c219 9815
dc6f92b8
JB
9816static Time enter_timestamp;
9817
11edeb03 9818/* This holds the state XLookupString needs to implement dead keys
58769bee 9819 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
9820 says that a portable program can't use this, but Stephen Gildea assures
9821 me that letting the compiler initialize it to zeros will work okay.
9822
9823 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
9824 given for enter_time stamp, above. */
9825
11edeb03
JB
9826static XComposeStatus compose_status;
9827
10e6549c
RS
9828/* Record the last 100 characters stored
9829 to help debug the loss-of-chars-during-GC problem. */
06a2c219 9830
2224b905
RS
9831static int temp_index;
9832static short temp_buffer[100];
10e6549c 9833
7a13e894
RS
9834/* Set this to nonzero to fake an "X I/O error"
9835 on a particular display. */
06a2c219 9836
7a13e894
RS
9837struct x_display_info *XTread_socket_fake_io_error;
9838
2224b905
RS
9839/* When we find no input here, we occasionally do a no-op command
9840 to verify that the X server is still running and we can still talk with it.
9841 We try all the open displays, one by one.
9842 This variable is used for cycling thru the displays. */
06a2c219 9843
2224b905
RS
9844static struct x_display_info *next_noop_dpyinfo;
9845
06a2c219
GM
9846#define SET_SAVED_MENU_EVENT(size) \
9847 do \
9848 { \
9849 if (f->output_data.x->saved_menu_event == 0) \
9850 f->output_data.x->saved_menu_event \
9851 = (XEvent *) xmalloc (sizeof (XEvent)); \
9852 bcopy (&event, f->output_data.x->saved_menu_event, size); \
9853 if (numchars >= 1) \
9854 { \
9855 bufp->kind = menu_bar_activate_event; \
9856 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 9857 bufp->arg = Qnil; \
06a2c219
GM
9858 bufp++; \
9859 count++; \
9860 numchars--; \
9861 } \
9862 } \
9863 while (0)
9864
8805890a 9865#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 9866#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 9867
dc6f92b8
JB
9868/* Read events coming from the X server.
9869 This routine is called by the SIGIO handler.
9870 We return as soon as there are no more events to be read.
9871
9872 Events representing keys are stored in buffer BUFP,
9873 which can hold up to NUMCHARS characters.
9874 We return the number of characters stored into the buffer,
9875 thus pretending to be `read'.
9876
dc6f92b8
JB
9877 EXPECTED is nonzero if the caller knows input is available. */
9878
7c5283e4 9879int
f66868ba 9880XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 9881 register int sd;
8805890a
KH
9882 /* register */ struct input_event *bufp;
9883 /* register */ int numchars;
dc6f92b8
JB
9884 int expected;
9885{
9886 int count = 0;
9887 int nbytes = 0;
dc6f92b8 9888 XEvent event;
f676886a 9889 struct frame *f;
66f55a9d 9890 int event_found = 0;
334208b7 9891 struct x_display_info *dpyinfo;
379b5ac0 9892 struct coding_system coding;
dc6f92b8 9893
9ac0d9e0 9894 if (interrupt_input_blocked)
dc6f92b8 9895 {
9ac0d9e0 9896 interrupt_input_pending = 1;
dc6f92b8
JB
9897 return -1;
9898 }
9899
9ac0d9e0 9900 interrupt_input_pending = 0;
dc6f92b8 9901 BLOCK_INPUT;
c0a04927
RS
9902
9903 /* So people can tell when we have read the available input. */
9904 input_signal_count++;
9905
dc6f92b8 9906 if (numchars <= 0)
06a2c219 9907 abort (); /* Don't think this happens. */
dc6f92b8 9908
bde5503b
GM
9909 ++handling_signal;
9910
379b5ac0
KH
9911 /* The input should be decoded if it is from XIM. Currently the
9912 locale of XIM is the same as that of the system. So, we can use
9913 Vlocale_coding_system which is initialized properly at Emacs
9914 startup time. */
9915 setup_coding_system (Vlocale_coding_system, &coding);
9916 coding.src_multibyte = 0;
9917 coding.dst_multibyte = 1;
9918 /* The input is converted to events, thus we can't handle
9919 composition. Anyway, there's no XIM that gives us composition
9920 information. */
9921 coding.composing = COMPOSITION_DISABLED;
9922
7a13e894
RS
9923 /* Find the display we are supposed to read input for.
9924 It's the one communicating on descriptor SD. */
9925 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9926 {
9927#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9928#ifdef FIOSNBIO
7a13e894
RS
9929 /* If available, Xlib uses FIOSNBIO to make the socket
9930 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9931 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9932 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9933 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9934#endif /* ! defined (FIOSNBIO) */
7a13e894 9935#endif
dc6f92b8 9936
7a13e894
RS
9937#if 0 /* This code can't be made to work, with multiple displays,
9938 and appears not to be used on any system any more.
9939 Also keyboard.c doesn't turn O_NDELAY on and off
9940 for X connections. */
dc6f92b8
JB
9941#ifndef SIGIO
9942#ifndef HAVE_SELECT
7a13e894
RS
9943 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9944 {
9945 extern int read_alarm_should_throw;
9946 read_alarm_should_throw = 1;
9947 XPeekEvent (dpyinfo->display, &event);
9948 read_alarm_should_throw = 0;
9949 }
c118dd06
JB
9950#endif /* HAVE_SELECT */
9951#endif /* SIGIO */
7a13e894 9952#endif
dc6f92b8 9953
7a13e894
RS
9954 /* For debugging, this gives a way to fake an I/O error. */
9955 if (dpyinfo == XTread_socket_fake_io_error)
9956 {
9957 XTread_socket_fake_io_error = 0;
9958 x_io_error_quitter (dpyinfo->display);
9959 }
dc6f92b8 9960
06a2c219 9961 while (XPending (dpyinfo->display))
dc6f92b8 9962 {
7a13e894 9963 XNextEvent (dpyinfo->display, &event);
06a2c219 9964
531483fb 9965#ifdef HAVE_X_I18N
d1bc4182 9966 {
f2be1146
GM
9967 /* Filter events for the current X input method.
9968 XFilterEvent returns non-zero if the input method has
9969 consumed the event. We pass the frame's X window to
9970 XFilterEvent because that's the one for which the IC
9971 was created. */
f5d11644
GM
9972 struct frame *f1 = x_any_window_to_frame (dpyinfo,
9973 event.xclient.window);
9974 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
9975 break;
9976 }
0cd6403b 9977#endif
7a13e894
RS
9978 event_found = 1;
9979
9980 switch (event.type)
9981 {
9982 case ClientMessage:
c047688c 9983 {
7a13e894
RS
9984 if (event.xclient.message_type
9985 == dpyinfo->Xatom_wm_protocols
9986 && event.xclient.format == 32)
c047688c 9987 {
7a13e894
RS
9988 if (event.xclient.data.l[0]
9989 == dpyinfo->Xatom_wm_take_focus)
c047688c 9990 {
8c1a6a84
RS
9991 /* Use x_any_window_to_frame because this
9992 could be the shell widget window
9993 if the frame has no title bar. */
9994 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
9995#ifdef HAVE_X_I18N
9996 /* Not quite sure this is needed -pd */
8c1a6a84 9997 if (f && FRAME_XIC (f))
6c183ba5
RS
9998 XSetICFocus (FRAME_XIC (f));
9999#endif
f1da8f06
GM
10000#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
10001 instructs the WM to set the input focus automatically for
10002 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
10003 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
10004 it has set the focus. So, XSetInputFocus below is not
10005 needed.
10006
10007 The call to XSetInputFocus below has also caused trouble. In
10008 cases where the XSetInputFocus done by the WM and the one
10009 below are temporally close (on a fast machine), the call
10010 below can generate additional FocusIn events which confuse
10011 Emacs. */
10012
bf7253f4
RS
10013 /* Since we set WM_TAKE_FOCUS, we must call
10014 XSetInputFocus explicitly. But not if f is null,
10015 since that might be an event for a deleted frame. */
7a13e894 10016 if (f)
bf7253f4
RS
10017 {
10018 Display *d = event.xclient.display;
10019 /* Catch and ignore errors, in case window has been
10020 iconified by a window manager such as GWM. */
10021 int count = x_catch_errors (d);
10022 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
10023 /* The ICCCM says this is
10024 the only valid choice. */
10025 RevertToParent,
bf7253f4
RS
10026 event.xclient.data.l[1]);
10027 /* This is needed to detect the error
10028 if there is an error. */
10029 XSync (d, False);
10030 x_uncatch_errors (d, count);
10031 }
7a13e894 10032 /* Not certain about handling scroll bars here */
f1da8f06 10033#endif /* 0 */
c047688c 10034 }
7a13e894
RS
10035 else if (event.xclient.data.l[0]
10036 == dpyinfo->Xatom_wm_save_yourself)
10037 {
10038 /* Save state modify the WM_COMMAND property to
06a2c219 10039 something which can reinstate us. This notifies
7a13e894
RS
10040 the session manager, who's looking for such a
10041 PropertyNotify. Can restart processing when
06a2c219 10042 a keyboard or mouse event arrives. */
7a13e894
RS
10043 if (numchars > 0)
10044 {
19126e11
KH
10045 f = x_top_window_to_frame (dpyinfo,
10046 event.xclient.window);
7a13e894
RS
10047
10048 /* This is just so we only give real data once
10049 for a single Emacs process. */
b86bd3dd 10050 if (f == SELECTED_FRAME ())
7a13e894
RS
10051 XSetCommand (FRAME_X_DISPLAY (f),
10052 event.xclient.window,
10053 initial_argv, initial_argc);
f000f5c5 10054 else if (f)
7a13e894
RS
10055 XSetCommand (FRAME_X_DISPLAY (f),
10056 event.xclient.window,
10057 0, 0);
10058 }
10059 }
10060 else if (event.xclient.data.l[0]
10061 == dpyinfo->Xatom_wm_delete_window)
1fb20991 10062 {
19126e11
KH
10063 struct frame *f
10064 = x_any_window_to_frame (dpyinfo,
10065 event.xclient.window);
1fb20991 10066
7a13e894
RS
10067 if (f)
10068 {
10069 if (numchars == 0)
10070 abort ();
1fb20991 10071
7a13e894
RS
10072 bufp->kind = delete_window_event;
10073 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10074 bufp->arg = Qnil;
7a13e894
RS
10075 bufp++;
10076
10077 count += 1;
10078 numchars -= 1;
10079 }
1fb20991 10080 }
c047688c 10081 }
7a13e894
RS
10082 else if (event.xclient.message_type
10083 == dpyinfo->Xatom_wm_configure_denied)
10084 {
10085 }
10086 else if (event.xclient.message_type
10087 == dpyinfo->Xatom_wm_window_moved)
10088 {
10089 int new_x, new_y;
19126e11
KH
10090 struct frame *f
10091 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 10092
7a13e894
RS
10093 new_x = event.xclient.data.s[0];
10094 new_y = event.xclient.data.s[1];
1fb20991 10095
7a13e894
RS
10096 if (f)
10097 {
7556890b
RS
10098 f->output_data.x->left_pos = new_x;
10099 f->output_data.x->top_pos = new_y;
7a13e894 10100 }
1fb20991 10101 }
0fdff6bb 10102#ifdef HACK_EDITRES
7a13e894
RS
10103 else if (event.xclient.message_type
10104 == dpyinfo->Xatom_editres)
10105 {
19126e11
KH
10106 struct frame *f
10107 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 10108 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 10109 &event, NULL);
7a13e894 10110 }
0fdff6bb 10111#endif /* HACK_EDITRES */
06a2c219
GM
10112 else if ((event.xclient.message_type
10113 == dpyinfo->Xatom_DONE)
10114 || (event.xclient.message_type
10115 == dpyinfo->Xatom_PAGE))
10116 {
10117 /* Ghostview job completed. Kill it. We could
10118 reply with "Next" if we received "Page", but we
10119 currently never do because we are interested in
10120 images, only, which should have 1 page. */
06a2c219
GM
10121 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
10122 struct frame *f
10123 = x_window_to_frame (dpyinfo, event.xclient.window);
10124 x_kill_gs_process (pixmap, f);
10125 expose_frame (f, 0, 0, 0, 0);
10126 }
10127#ifdef USE_TOOLKIT_SCROLL_BARS
10128 /* Scroll bar callbacks send a ClientMessage from which
10129 we construct an input_event. */
10130 else if (event.xclient.message_type
10131 == dpyinfo->Xatom_Scrollbar)
10132 {
10133 x_scroll_bar_to_input_event (&event, bufp);
10134 ++bufp, ++count, --numchars;
10135 goto out;
10136 }
10137#endif /* USE_TOOLKIT_SCROLL_BARS */
10138 else
10139 goto OTHER;
7a13e894
RS
10140 }
10141 break;
dc6f92b8 10142
7a13e894 10143 case SelectionNotify:
3afe33e7 10144#ifdef USE_X_TOOLKIT
19126e11 10145 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 10146 goto OTHER;
3afe33e7 10147#endif /* not USE_X_TOOLKIT */
dfcf069d 10148 x_handle_selection_notify (&event.xselection);
7a13e894 10149 break;
d56a553a 10150
06a2c219 10151 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 10152#ifdef USE_X_TOOLKIT
19126e11 10153 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 10154 goto OTHER;
3afe33e7 10155#endif /* USE_X_TOOLKIT */
7a13e894
RS
10156 {
10157 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 10158
7a13e894
RS
10159 if (numchars == 0)
10160 abort ();
d56a553a 10161
7a13e894
RS
10162 bufp->kind = selection_clear_event;
10163 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10164 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10165 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10166 bufp->frame_or_window = Qnil;
0f8aabe9 10167 bufp->arg = Qnil;
7a13e894 10168 bufp++;
d56a553a 10169
7a13e894
RS
10170 count += 1;
10171 numchars -= 1;
10172 }
10173 break;
dc6f92b8 10174
06a2c219 10175 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 10176#ifdef USE_X_TOOLKIT
19126e11 10177 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 10178 goto OTHER;
3afe33e7 10179#endif /* USE_X_TOOLKIT */
7a13e894 10180 if (x_queue_selection_requests)
19126e11 10181 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
10182 &event);
10183 else
10184 {
1d2b2268
GM
10185 XSelectionRequestEvent *eventp
10186 = (XSelectionRequestEvent *) &event;
dc6f92b8 10187
7a13e894
RS
10188 if (numchars == 0)
10189 abort ();
10190
10191 bufp->kind = selection_request_event;
10192 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10193 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
10194 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10195 SELECTION_EVENT_TARGET (bufp) = eventp->target;
10196 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
10197 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10198 bufp->frame_or_window = Qnil;
0f8aabe9 10199 bufp->arg = Qnil;
7a13e894
RS
10200 bufp++;
10201
10202 count += 1;
10203 numchars -= 1;
10204 }
10205 break;
10206
10207 case PropertyNotify:
1d2b2268
GM
10208#if 0 /* This is plain wrong. In the case that we are waiting for a
10209 PropertyNotify used as an ACK in incremental selection
10210 transfer, the property will be on the receiver's window. */
10211#if defined USE_X_TOOLKIT
19126e11 10212 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 10213 goto OTHER;
1d2b2268
GM
10214#endif
10215#endif
dfcf069d 10216 x_handle_property_notify (&event.xproperty);
1d2b2268 10217 goto OTHER;
dc6f92b8 10218
7a13e894 10219 case ReparentNotify:
19126e11 10220 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
10221 if (f)
10222 {
10223 int x, y;
7556890b 10224 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 10225 x_real_positions (f, &x, &y);
7556890b
RS
10226 f->output_data.x->left_pos = x;
10227 f->output_data.x->top_pos = y;
7a13e894
RS
10228 }
10229 break;
3bd330d4 10230
7a13e894 10231 case Expose:
19126e11 10232 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 10233 if (f)
dc6f92b8 10234 {
7a13e894
RS
10235 if (f->async_visible == 0)
10236 {
10237 f->async_visible = 1;
10238 f->async_iconified = 0;
06c488fd 10239 f->output_data.x->has_been_visible = 1;
7a13e894
RS
10240 SET_FRAME_GARBAGED (f);
10241 }
10242 else
06a2c219
GM
10243 expose_frame (x_window_to_frame (dpyinfo,
10244 event.xexpose.window),
10245 event.xexpose.x, event.xexpose.y,
10246 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
10247 }
10248 else
7a13e894 10249 {
12949a7f
EZ
10250#ifndef USE_TOOLKIT_SCROLL_BARS
10251 struct scroll_bar *bar;
10252#endif
01f67d2c 10253#if defined USE_LUCID
c95fc5f1
GM
10254 /* Submenus of the Lucid menu bar aren't widgets
10255 themselves, so there's no way to dispatch events
10256 to them. Recognize this case separately. */
10257 {
10258 Widget widget
10259 = x_window_to_menu_bar (event.xexpose.window);
10260 if (widget)
10261 xlwmenu_redisplay (widget);
10262 }
01f67d2c
PJ
10263#endif /* USE_LUCID */
10264
06a2c219
GM
10265#ifdef USE_TOOLKIT_SCROLL_BARS
10266 /* Dispatch event to the widget. */
10267 goto OTHER;
10268#else /* not USE_TOOLKIT_SCROLL_BARS */
12949a7f 10269 bar = x_window_to_scroll_bar (event.xexpose.window);
58769bee 10270
7a13e894
RS
10271 if (bar)
10272 x_scroll_bar_expose (bar, &event);
3afe33e7 10273#ifdef USE_X_TOOLKIT
7a13e894
RS
10274 else
10275 goto OTHER;
3afe33e7 10276#endif /* USE_X_TOOLKIT */
06a2c219 10277#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10278 }
10279 break;
dc6f92b8 10280
7a13e894 10281 case GraphicsExpose: /* This occurs when an XCopyArea's
d624284c
PJ
10282 source area was obscured or not
10283 available. */
19126e11 10284 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
10285 if (f)
10286 {
06a2c219
GM
10287 expose_frame (f,
10288 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
10289 event.xgraphicsexpose.width,
10290 event.xgraphicsexpose.height);
7a13e894 10291 }
3afe33e7 10292#ifdef USE_X_TOOLKIT
7a13e894
RS
10293 else
10294 goto OTHER;
3afe33e7 10295#endif /* USE_X_TOOLKIT */
7a13e894 10296 break;
dc6f92b8 10297
7a13e894 10298 case NoExpose: /* This occurs when an XCopyArea's
06a2c219 10299 source area was completely
d624284c 10300 available. */
7a13e894 10301 break;
dc6f92b8 10302
7a13e894 10303 case UnmapNotify:
06a2c219
GM
10304 /* Redo the mouse-highlight after the tooltip has gone. */
10305 if (event.xmap.window == tip_window)
10306 {
10307 tip_window = 0;
10308 redo_mouse_highlight ();
10309 }
10310
91ea2a7a 10311 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894 10312 if (f) /* F may no longer exist if
d624284c 10313 the frame was deleted. */
7a13e894
RS
10314 {
10315 /* While a frame is unmapped, display generation is
10316 disabled; you don't want to spend time updating a
10317 display that won't ever be seen. */
10318 f->async_visible = 0;
10319 /* We can't distinguish, from the event, whether the window
10320 has become iconified or invisible. So assume, if it
10321 was previously visible, than now it is iconified.
1aa6072f
RS
10322 But x_make_frame_invisible clears both
10323 the visible flag and the iconified flag;
10324 and that way, we know the window is not iconified now. */
7a13e894 10325 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
10326 {
10327 f->async_iconified = 1;
bddd097c 10328
1aa6072f
RS
10329 bufp->kind = iconify_event;
10330 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10331 bufp->arg = Qnil;
1aa6072f
RS
10332 bufp++;
10333 count++;
10334 numchars--;
10335 }
7a13e894 10336 }
7a13e894 10337 goto OTHER;
dc6f92b8 10338
7a13e894 10339 case MapNotify:
06a2c219
GM
10340 if (event.xmap.window == tip_window)
10341 /* The tooltip has been drawn already. Avoid
10342 the SET_FRAME_GARBAGED below. */
10343 goto OTHER;
10344
10345 /* We use x_top_window_to_frame because map events can
10346 come for sub-windows and they don't mean that the
10347 frame is visible. */
19126e11 10348 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
10349 if (f)
10350 {
10351 f->async_visible = 1;
10352 f->async_iconified = 0;
06c488fd 10353 f->output_data.x->has_been_visible = 1;
dc6f92b8 10354
7a13e894
RS
10355 /* wait_reading_process_input will notice this and update
10356 the frame's display structures. */
10357 SET_FRAME_GARBAGED (f);
bddd097c 10358
d806e720
RS
10359 if (f->iconified)
10360 {
10361 bufp->kind = deiconify_event;
10362 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10363 bufp->arg = Qnil;
d806e720
RS
10364 bufp++;
10365 count++;
10366 numchars--;
10367 }
e73ec6fa 10368 else if (! NILP (Vframe_list)
8e713be6 10369 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
10370 /* Force a redisplay sooner or later
10371 to update the frame titles
10372 in case this is the second frame. */
10373 record_asynch_buffer_change ();
7a13e894 10374 }
7a13e894 10375 goto OTHER;
dc6f92b8 10376
7a13e894 10377 case KeyPress:
19126e11 10378 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 10379
eccc05db 10380#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
10381 if (f == 0)
10382 {
2564ea1b
GM
10383 /* Scroll bars consume key events, but we want
10384 the keys to go to the scroll bar's frame. */
06a2c219
GM
10385 Widget widget = XtWindowToWidget (dpyinfo->display,
10386 event.xkey.window);
10387 if (widget && XmIsScrollBar (widget))
10388 {
10389 widget = XtParent (widget);
10390 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
10391 }
10392 }
eccc05db 10393#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
06a2c219 10394
7a13e894
RS
10395 if (f != 0)
10396 {
10397 KeySym keysym, orig_keysym;
379b5ac0
KH
10398 /* al%imercury@uunet.uu.net says that making this 81
10399 instead of 80 fixed a bug whereby meta chars made
10400 his Emacs hang.
10401
10402 It seems that some version of XmbLookupString has
10403 a bug of not returning XBufferOverflow in
10404 status_return even if the input is too long to
10405 fit in 81 bytes. So, we must prepare sufficient
10406 bytes for copy_buffer. 513 bytes (256 chars for
10407 two-byte character set) seems to be a faily good
10408 approximation. -- 2000.8.10 handa@etl.go.jp */
10409 unsigned char copy_buffer[513];
10410 unsigned char *copy_bufptr = copy_buffer;
10411 int copy_bufsiz = sizeof (copy_buffer);
7a13e894 10412 int modifiers;
64bb1782 10413
7a13e894
RS
10414 event.xkey.state
10415 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
10416 extra_keyboard_modifiers);
10417 modifiers = event.xkey.state;
3a2712f9 10418
7a13e894 10419 /* This will have to go some day... */
752a043f 10420
7a13e894
RS
10421 /* make_lispy_event turns chars into control chars.
10422 Don't do it here because XLookupString is too eager. */
10423 event.xkey.state &= ~ControlMask;
5d46f928
RS
10424 event.xkey.state &= ~(dpyinfo->meta_mod_mask
10425 | dpyinfo->super_mod_mask
10426 | dpyinfo->hyper_mod_mask
10427 | dpyinfo->alt_mod_mask);
10428
1cf4a0d1
RS
10429 /* In case Meta is ComposeCharacter,
10430 clear its status. According to Markus Ehrnsperger
10431 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
10432 this enables ComposeCharacter to work whether or
10433 not it is combined with Meta. */
10434 if (modifiers & dpyinfo->meta_mod_mask)
10435 bzero (&compose_status, sizeof (compose_status));
10436
6c183ba5
RS
10437#ifdef HAVE_X_I18N
10438 if (FRAME_XIC (f))
10439 {
f5d11644
GM
10440 Status status_return;
10441
6c183ba5 10442 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
10443 &event.xkey, copy_bufptr,
10444 copy_bufsiz, &keysym,
6c183ba5 10445 &status_return);
f5d11644
GM
10446 if (status_return == XBufferOverflow)
10447 {
10448 copy_bufsiz = nbytes + 1;
10449 copy_bufptr = (char *) alloca (copy_bufsiz);
10450 nbytes = XmbLookupString (FRAME_XIC (f),
10451 &event.xkey, copy_bufptr,
10452 copy_bufsiz, &keysym,
10453 &status_return);
10454 }
10455
1decb680
PE
10456 if (status_return == XLookupNone)
10457 break;
10458 else if (status_return == XLookupChars)
fdd9d55e
GM
10459 {
10460 keysym = NoSymbol;
10461 modifiers = 0;
10462 }
1decb680
PE
10463 else if (status_return != XLookupKeySym
10464 && status_return != XLookupBoth)
10465 abort ();
6c183ba5
RS
10466 }
10467 else
379b5ac0
KH
10468 nbytes = XLookupString (&event.xkey, copy_bufptr,
10469 copy_bufsiz, &keysym,
10470 &compose_status);
6c183ba5 10471#else
379b5ac0
KH
10472 nbytes = XLookupString (&event.xkey, copy_bufptr,
10473 copy_bufsiz, &keysym,
10474 &compose_status);
6c183ba5 10475#endif
dc6f92b8 10476
7a13e894 10477 orig_keysym = keysym;
55123275 10478
7a13e894
RS
10479 if (numchars > 1)
10480 {
10481 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
10482 || keysym == XK_Delete
1097aea0 10483#ifdef XK_ISO_Left_Tab
441affdb 10484 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 10485#endif
852bff8f 10486 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
10487 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
10488 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 10489#ifdef HPUX
7a13e894
RS
10490 /* This recognizes the "extended function keys".
10491 It seems there's no cleaner way.
10492 Test IsModifierKey to avoid handling mode_switch
10493 incorrectly. */
10494 || ((unsigned) (keysym) >= XK_Select
10495 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
10496#endif
10497#ifdef XK_dead_circumflex
7a13e894 10498 || orig_keysym == XK_dead_circumflex
69388238
RS
10499#endif
10500#ifdef XK_dead_grave
7a13e894 10501 || orig_keysym == XK_dead_grave
69388238
RS
10502#endif
10503#ifdef XK_dead_tilde
7a13e894 10504 || orig_keysym == XK_dead_tilde
69388238
RS
10505#endif
10506#ifdef XK_dead_diaeresis
7a13e894 10507 || orig_keysym == XK_dead_diaeresis
69388238
RS
10508#endif
10509#ifdef XK_dead_macron
7a13e894 10510 || orig_keysym == XK_dead_macron
69388238
RS
10511#endif
10512#ifdef XK_dead_degree
7a13e894 10513 || orig_keysym == XK_dead_degree
69388238
RS
10514#endif
10515#ifdef XK_dead_acute
7a13e894 10516 || orig_keysym == XK_dead_acute
69388238
RS
10517#endif
10518#ifdef XK_dead_cedilla
7a13e894 10519 || orig_keysym == XK_dead_cedilla
69388238
RS
10520#endif
10521#ifdef XK_dead_breve
7a13e894 10522 || orig_keysym == XK_dead_breve
69388238
RS
10523#endif
10524#ifdef XK_dead_ogonek
7a13e894 10525 || orig_keysym == XK_dead_ogonek
69388238
RS
10526#endif
10527#ifdef XK_dead_caron
7a13e894 10528 || orig_keysym == XK_dead_caron
69388238
RS
10529#endif
10530#ifdef XK_dead_doubleacute
7a13e894 10531 || orig_keysym == XK_dead_doubleacute
69388238
RS
10532#endif
10533#ifdef XK_dead_abovedot
7a13e894 10534 || orig_keysym == XK_dead_abovedot
c34790e0 10535#endif
7a13e894
RS
10536 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
10537 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
10538 /* Any "vendor-specific" key is ok. */
f0e299de
GM
10539 || (orig_keysym & (1 << 28))
10540 || (keysym != NoSymbol && nbytes == 0))
7a13e894 10541 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
10542#ifndef HAVE_X11R5
10543#ifdef XK_Mode_switch
7a13e894 10544 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
10545#endif
10546#ifdef XK_Num_Lock
7a13e894 10547 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
10548#endif
10549#endif /* not HAVE_X11R5 */
7a13e894 10550 ))
dc6f92b8 10551 {
10e6549c
RS
10552 if (temp_index == sizeof temp_buffer / sizeof (short))
10553 temp_index = 0;
7a13e894
RS
10554 temp_buffer[temp_index++] = keysym;
10555 bufp->kind = non_ascii_keystroke;
10556 bufp->code = keysym;
e0c1aef2 10557 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10558 bufp->arg = Qnil;
334208b7
RS
10559 bufp->modifiers
10560 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10561 modifiers);
1113d9db 10562 bufp->timestamp = event.xkey.time;
dc6f92b8 10563 bufp++;
7a13e894
RS
10564 count++;
10565 numchars--;
dc6f92b8 10566 }
7a13e894
RS
10567 else if (numchars > nbytes)
10568 {
10569 register int i;
379b5ac0 10570 register int c;
379b5ac0 10571 int nchars, len;
7a13e894
RS
10572
10573 for (i = 0; i < nbytes; i++)
10574 {
379b5ac0
KH
10575 if (temp_index == (sizeof temp_buffer
10576 / sizeof (short)))
7a13e894 10577 temp_index = 0;
379b5ac0
KH
10578 temp_buffer[temp_index++] = copy_bufptr[i];
10579 }
10580
10581 if (/* If the event is not from XIM, */
10582 event.xkey.keycode != 0
10583 /* or the current locale doesn't request
10584 decoding of the intup data, ... */
10585 || coding.type == coding_type_raw_text
10586 || coding.type == coding_type_no_conversion)
10587 {
10588 /* ... we can use the input data as is. */
10589 nchars = nbytes;
10590 }
10591 else
10592 {
10593 /* We have to decode the input data. */
10594 int require;
10595 unsigned char *p;
10596
10597 require = decoding_buffer_size (&coding, nbytes);
10598 p = (unsigned char *) alloca (require);
10599 coding.mode |= CODING_MODE_LAST_BLOCK;
10600 decode_coding (&coding, copy_bufptr, p,
10601 nbytes, require);
10602 nbytes = coding.produced;
10603 nchars = coding.produced_char;
10604 copy_bufptr = p;
10605 }
10606
10607 /* Convert the input data to a sequence of
10608 character events. */
10609 for (i = 0; i < nbytes; i += len)
10610 {
fee2aedc
GM
10611 if (nchars == nbytes)
10612 c = copy_bufptr[i], len = 1;
10613 else
10614 c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
10615 nbytes - i, len);
10616
379b5ac0
KH
10617 bufp->kind = (SINGLE_BYTE_CHAR_P (c)
10618 ? ascii_keystroke
10619 : multibyte_char_keystroke);
10620 bufp->code = c;
7a13e894 10621 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10622 bufp->arg = Qnil;
7a13e894
RS
10623 bufp->modifiers
10624 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10625 modifiers);
10626 bufp->timestamp = event.xkey.time;
10627 bufp++;
10628 }
10629
379b5ac0
KH
10630 count += nchars;
10631 numchars -= nchars;
1decb680
PE
10632
10633 if (keysym == NoSymbol)
10634 break;
7a13e894
RS
10635 }
10636 else
10637 abort ();
dc6f92b8 10638 }
10e6549c
RS
10639 else
10640 abort ();
dc6f92b8 10641 }
59ddecde
GM
10642#ifdef HAVE_X_I18N
10643 /* Don't dispatch this event since XtDispatchEvent calls
10644 XFilterEvent, and two calls in a row may freeze the
10645 client. */
10646 break;
10647#else
717ca130 10648 goto OTHER;
59ddecde 10649#endif
f451eb13 10650
f5d11644 10651 case KeyRelease:
59ddecde
GM
10652#ifdef HAVE_X_I18N
10653 /* Don't dispatch this event since XtDispatchEvent calls
10654 XFilterEvent, and two calls in a row may freeze the
10655 client. */
10656 break;
10657#else
f5d11644 10658 goto OTHER;
59ddecde 10659#endif
f5d11644 10660
7a13e894 10661 /* Here's a possible interpretation of the whole
06a2c219
GM
10662 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
10663 you get a FocusIn event, you have to get a FocusOut
10664 event before you relinquish the focus. If you
10665 haven't received a FocusIn event, then a mere
10666 LeaveNotify is enough to free you. */
f451eb13 10667
7a13e894 10668 case EnterNotify:
06a2c219 10669 {
06a2c219
GM
10670 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
10671
582c60f8 10672 if (event.xcrossing.focus)
06a2c219
GM
10673 {
10674 /* Avoid nasty pop/raise loops. */
10675 if (f && (!(f->auto_raise)
10676 || !(f->auto_lower)
10677 || (event.xcrossing.time - enter_timestamp) > 500))
10678 {
10679 x_new_focus_frame (dpyinfo, f);
10680 enter_timestamp = event.xcrossing.time;
10681 }
10682 }
10683 else if (f == dpyinfo->x_focus_frame)
10684 x_new_focus_frame (dpyinfo, 0);
10685
10686 /* EnterNotify counts as mouse movement,
10687 so update things that depend on mouse position. */
2533c408 10688 if (f && !f->output_data.x->hourglass_p)
06a2c219
GM
10689 note_mouse_movement (f, &event.xmotion);
10690 goto OTHER;
10691 }
dc6f92b8 10692
7a13e894 10693 case FocusIn:
19126e11 10694 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10695 if (event.xfocus.detail != NotifyPointer)
0f941935 10696 dpyinfo->x_focus_event_frame = f;
7a13e894 10697 if (f)
eb72635f
GM
10698 {
10699 x_new_focus_frame (dpyinfo, f);
10700
10701 /* Don't stop displaying the initial startup message
10702 for a switch-frame event we don't need. */
10703 if (GC_NILP (Vterminal_frame)
10704 && GC_CONSP (Vframe_list)
10705 && !GC_NILP (XCDR (Vframe_list)))
10706 {
10707 bufp->kind = FOCUS_IN_EVENT;
10708 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10709 bufp->arg = Qnil;
eb72635f
GM
10710 ++bufp, ++count, --numchars;
10711 }
10712 }
f9e24cb9 10713
6c183ba5
RS
10714#ifdef HAVE_X_I18N
10715 if (f && FRAME_XIC (f))
10716 XSetICFocus (FRAME_XIC (f));
10717#endif
10718
7a13e894 10719 goto OTHER;
10c5e63d 10720
7a13e894 10721 case LeaveNotify:
19126e11 10722 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 10723 if (f)
10c5e63d 10724 {
7a13e894 10725 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
10726 {
10727 /* If we move outside the frame, then we're
10728 certainly no longer on any text in the frame. */
10729 clear_mouse_face (dpyinfo);
10730 dpyinfo->mouse_face_mouse_frame = 0;
10731 }
10732
10733 /* Generate a nil HELP_EVENT to cancel a help-echo.
10734 Do it only if there's something to cancel.
10735 Otherwise, the startup message is cleared when
10736 the mouse leaves the frame. */
10737 if (any_help_event_p)
10738 {
be010514
GM
10739 Lisp_Object frame;
10740 int n;
10741
06a2c219 10742 XSETFRAME (frame, f);
82c5d67a 10743 help_echo = Qnil;
5ab2570d
GM
10744 n = gen_help_event (bufp, numchars,
10745 Qnil, frame, Qnil, Qnil, 0);
be010514 10746 bufp += n, count += n, numchars -= n;
06a2c219 10747 }
7a13e894 10748
582c60f8 10749 if (event.xcrossing.focus)
0f941935 10750 x_mouse_leave (dpyinfo);
10c5e63d 10751 else
7a13e894 10752 {
0f941935
KH
10753 if (f == dpyinfo->x_focus_event_frame)
10754 dpyinfo->x_focus_event_frame = 0;
10755 if (f == dpyinfo->x_focus_frame)
10756 x_new_focus_frame (dpyinfo, 0);
7a13e894 10757 }
10c5e63d 10758 }
7a13e894 10759 goto OTHER;
dc6f92b8 10760
7a13e894 10761 case FocusOut:
19126e11 10762 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10763 if (event.xfocus.detail != NotifyPointer
0f941935
KH
10764 && f == dpyinfo->x_focus_event_frame)
10765 dpyinfo->x_focus_event_frame = 0;
10766 if (f && f == dpyinfo->x_focus_frame)
10767 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 10768
6c183ba5
RS
10769#ifdef HAVE_X_I18N
10770 if (f && FRAME_XIC (f))
10771 XUnsetICFocus (FRAME_XIC (f));
10772#endif
10773
7a13e894 10774 goto OTHER;
dc6f92b8 10775
7a13e894 10776 case MotionNotify:
dc6f92b8 10777 {
06a2c219 10778 previous_help_echo = help_echo;
7cea38bc 10779 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 10780 help_echo_pos = -1;
06a2c219 10781
7a13e894
RS
10782 if (dpyinfo->grabbed && last_mouse_frame
10783 && FRAME_LIVE_P (last_mouse_frame))
10784 f = last_mouse_frame;
10785 else
19126e11 10786 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 10787
7a13e894
RS
10788 if (f)
10789 note_mouse_movement (f, &event.xmotion);
10790 else
10791 {
e88b3c50 10792#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10793 struct scroll_bar *bar
10794 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 10795
7a13e894
RS
10796 if (bar)
10797 x_scroll_bar_note_movement (bar, &event);
e88b3c50 10798#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 10799
06a2c219
GM
10800 /* If we move outside the frame, then we're
10801 certainly no longer on any text in the frame. */
7a13e894
RS
10802 clear_mouse_face (dpyinfo);
10803 }
06a2c219
GM
10804
10805 /* If the contents of the global variable help_echo
10806 has changed, generate a HELP_EVENT. */
b7e80413
SM
10807 if (!NILP (help_echo)
10808 || !NILP (previous_help_echo))
06a2c219
GM
10809 {
10810 Lisp_Object frame;
be010514 10811 int n;
06a2c219
GM
10812
10813 if (f)
10814 XSETFRAME (frame, f);
10815 else
10816 frame = Qnil;
10817
10818 any_help_event_p = 1;
5ab2570d 10819 n = gen_help_event (bufp, numchars, help_echo, frame,
7cea38bc
GM
10820 help_echo_window, help_echo_object,
10821 help_echo_pos);
be010514 10822 bufp += n, count += n, numchars -= n;
06a2c219
GM
10823 }
10824
10825 goto OTHER;
dc6f92b8 10826 }
dc6f92b8 10827
7a13e894 10828 case ConfigureNotify:
9829ddba
RS
10829 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
10830 if (f)
af395ec1 10831 {
5c187dee 10832#ifndef USE_X_TOOLKIT
bf1b7b30
KH
10833 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
10834 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 10835
2d7fc7e8
RS
10836 /* In the toolkit version, change_frame_size
10837 is called by the code that handles resizing
10838 of the EmacsFrame widget. */
7a13e894 10839
7a13e894
RS
10840 /* Even if the number of character rows and columns has
10841 not changed, the font size may have changed, so we need
10842 to check the pixel dimensions as well. */
10843 if (columns != f->width
10844 || rows != f->height
7556890b
RS
10845 || event.xconfigure.width != f->output_data.x->pixel_width
10846 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 10847 {
7d1e984f 10848 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 10849 SET_FRAME_GARBAGED (f);
e687d06e 10850 cancel_mouse_face (f);
7a13e894 10851 }
2d7fc7e8 10852#endif
af395ec1 10853
7556890b
RS
10854 f->output_data.x->pixel_width = event.xconfigure.width;
10855 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
10856
10857 /* What we have now is the position of Emacs's own window.
10858 Convert that to the position of the window manager window. */
dcb07ae9
RS
10859 x_real_positions (f, &f->output_data.x->left_pos,
10860 &f->output_data.x->top_pos);
10861
f5d11644
GM
10862#ifdef HAVE_X_I18N
10863 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
10864 xic_set_statusarea (f);
10865#endif
10866
dcb07ae9
RS
10867 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
10868 {
10869 /* Since the WM decorations come below top_pos now,
10870 we must put them below top_pos in the future. */
10871 f->output_data.x->win_gravity = NorthWestGravity;
10872 x_wm_set_size_hint (f, (long) 0, 0);
10873 }
8f08dc93
KH
10874#ifdef USE_MOTIF
10875 /* Some window managers pass (0,0) as the location of
10876 the window, and the Motif event handler stores it
10877 in the emacs widget, which messes up Motif menus. */
10878 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
10879 {
10880 event.xconfigure.x = f->output_data.x->widget->core.x;
10881 event.xconfigure.y = f->output_data.x->widget->core.y;
10882 }
06a2c219 10883#endif /* USE_MOTIF */
7a13e894 10884 }
2d7fc7e8 10885 goto OTHER;
dc6f92b8 10886
7a13e894
RS
10887 case ButtonPress:
10888 case ButtonRelease:
10889 {
10890 /* If we decide we want to generate an event to be seen
10891 by the rest of Emacs, we put it here. */
10892 struct input_event emacs_event;
9ea173e8 10893 int tool_bar_p = 0;
06a2c219 10894
7a13e894 10895 emacs_event.kind = no_event;
7a13e894 10896 bzero (&compose_status, sizeof (compose_status));
9b07615b 10897
06a2c219
GM
10898 if (dpyinfo->grabbed
10899 && last_mouse_frame
9f67f20b
RS
10900 && FRAME_LIVE_P (last_mouse_frame))
10901 f = last_mouse_frame;
10902 else
2224b905 10903 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 10904
06a2c219
GM
10905 if (f)
10906 {
9ea173e8
GM
10907 /* Is this in the tool-bar? */
10908 if (WINDOWP (f->tool_bar_window)
10909 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
10910 {
10911 Lisp_Object window;
10912 int p, x, y;
10913
10914 x = event.xbutton.x;
10915 y = event.xbutton.y;
10916
10917 /* Set x and y. */
10918 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 10919 if (EQ (window, f->tool_bar_window))
06a2c219 10920 {
9ea173e8
GM
10921 x_handle_tool_bar_click (f, &event.xbutton);
10922 tool_bar_p = 1;
06a2c219
GM
10923 }
10924 }
10925
9ea173e8 10926 if (!tool_bar_p)
06a2c219
GM
10927 if (!dpyinfo->x_focus_frame
10928 || f == dpyinfo->x_focus_frame)
10929 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
10930 }
10931 else
10932 {
06a2c219 10933#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10934 struct scroll_bar *bar
10935 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 10936
7a13e894
RS
10937 if (bar)
10938 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 10939#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10940 }
10941
10942 if (event.type == ButtonPress)
10943 {
10944 dpyinfo->grabbed |= (1 << event.xbutton.button);
10945 last_mouse_frame = f;
edad46f6
KH
10946 /* Ignore any mouse motion that happened
10947 before this event; any subsequent mouse-movement
10948 Emacs events should reflect only motion after
10949 the ButtonPress. */
a00e91cd
KH
10950 if (f != 0)
10951 f->mouse_moved = 0;
06a2c219 10952
9ea173e8
GM
10953 if (!tool_bar_p)
10954 last_tool_bar_item = -1;
7a13e894 10955 }
3afe33e7
RS
10956 else
10957 {
7a13e894 10958 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10959 }
23faf38f 10960
7a13e894
RS
10961 if (numchars >= 1 && emacs_event.kind != no_event)
10962 {
10963 bcopy (&emacs_event, bufp, sizeof (struct input_event));
10964 bufp++;
10965 count++;
10966 numchars--;
10967 }
3afe33e7
RS
10968
10969#ifdef USE_X_TOOLKIT
2224b905
RS
10970 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
10971 /* For a down-event in the menu bar,
10972 don't pass it to Xt right now.
10973 Instead, save it away
10974 and we will pass it to Xt from kbd_buffer_get_event.
10975 That way, we can run some Lisp code first. */
91375f8f
RS
10976 if (f && event.type == ButtonPress
10977 /* Verify the event is really within the menu bar
10978 and not just sent to it due to grabbing. */
10979 && event.xbutton.x >= 0
10980 && event.xbutton.x < f->output_data.x->pixel_width
10981 && event.xbutton.y >= 0
10982 && event.xbutton.y < f->output_data.x->menubar_height
10983 && event.xbutton.same_screen)
2224b905 10984 {
8805890a 10985 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
10986 XSETFRAME (last_mouse_press_frame, f);
10987 }
10988 else if (event.type == ButtonPress)
10989 {
10990 last_mouse_press_frame = Qnil;
30e671c3 10991 goto OTHER;
ce89ef46 10992 }
06a2c219 10993
2237cac9
RS
10994#ifdef USE_MOTIF /* This should do not harm for Lucid,
10995 but I am trying to be cautious. */
ce89ef46
RS
10996 else if (event.type == ButtonRelease)
10997 {
2237cac9 10998 if (!NILP (last_mouse_press_frame))
f10ded1c 10999 {
2237cac9
RS
11000 f = XFRAME (last_mouse_press_frame);
11001 if (f->output_data.x)
06a2c219 11002 SET_SAVED_BUTTON_EVENT;
f10ded1c 11003 }
06a2c219 11004 else
30e671c3 11005 goto OTHER;
2224b905 11006 }
2237cac9 11007#endif /* USE_MOTIF */
2224b905
RS
11008 else
11009 goto OTHER;
3afe33e7 11010#endif /* USE_X_TOOLKIT */
7a13e894
RS
11011 }
11012 break;
dc6f92b8 11013
7a13e894 11014 case CirculateNotify:
06a2c219
GM
11015 goto OTHER;
11016
7a13e894 11017 case CirculateRequest:
06a2c219
GM
11018 goto OTHER;
11019
11020 case VisibilityNotify:
11021 goto OTHER;
dc6f92b8 11022
7a13e894
RS
11023 case MappingNotify:
11024 /* Someone has changed the keyboard mapping - update the
11025 local cache. */
11026 switch (event.xmapping.request)
11027 {
11028 case MappingModifier:
11029 x_find_modifier_meanings (dpyinfo);
11030 /* This is meant to fall through. */
11031 case MappingKeyboard:
11032 XRefreshKeyboardMapping (&event.xmapping);
11033 }
7a13e894 11034 goto OTHER;
dc6f92b8 11035
7a13e894 11036 default:
7a13e894 11037 OTHER:
717ca130 11038#ifdef USE_X_TOOLKIT
7a13e894
RS
11039 BLOCK_INPUT;
11040 XtDispatchEvent (&event);
11041 UNBLOCK_INPUT;
3afe33e7 11042#endif /* USE_X_TOOLKIT */
7a13e894
RS
11043 break;
11044 }
dc6f92b8
JB
11045 }
11046 }
11047
06a2c219
GM
11048 out:;
11049
9a5196d0
RS
11050 /* On some systems, an X bug causes Emacs to get no more events
11051 when the window is destroyed. Detect that. (1994.) */
58769bee 11052 if (! event_found)
ef2a22d0 11053 {
ef2a22d0
RS
11054 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
11055 One XNOOP in 100 loops will make Emacs terminate.
11056 B. Bretthauer, 1994 */
11057 x_noop_count++;
58769bee 11058 if (x_noop_count >= 100)
ef2a22d0
RS
11059 {
11060 x_noop_count=0;
2224b905
RS
11061
11062 if (next_noop_dpyinfo == 0)
11063 next_noop_dpyinfo = x_display_list;
11064
11065 XNoOp (next_noop_dpyinfo->display);
11066
11067 /* Each time we get here, cycle through the displays now open. */
11068 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
11069 }
11070 }
502add23 11071
06a2c219 11072 /* If the focus was just given to an auto-raising frame,
0134a210 11073 raise it now. */
7a13e894 11074 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
11075 if (pending_autoraise_frame)
11076 {
11077 x_raise_frame (pending_autoraise_frame);
11078 pending_autoraise_frame = 0;
11079 }
0134a210 11080
dc6f92b8 11081 UNBLOCK_INPUT;
bde5503b 11082 --handling_signal;
dc6f92b8
JB
11083 return count;
11084}
06a2c219
GM
11085
11086
11087
dc6f92b8 11088\f
06a2c219
GM
11089/***********************************************************************
11090 Text Cursor
11091 ***********************************************************************/
11092
78a9a4c5 11093/* Notice if the text cursor of window W has been overwritten by a
f0a48a01
GM
11094 drawing operation that outputs N glyphs starting at START_X and
11095 ending at END_X in the line given by output_cursor.vpos.
bb4600a4 11096 Coordinates are area-relative. END_X < 0 means all the rest
f0a48a01 11097 of the line after START_X has been written. */
06a2c219
GM
11098
11099static void
f0a48a01 11100notice_overwritten_cursor (w, start_x, end_x)
06a2c219 11101 struct window *w;
f0a48a01 11102 int start_x, end_x;
06a2c219
GM
11103{
11104 if (updated_area == TEXT_AREA
f0a48a01 11105 && w->phys_cursor_on_p
06a2c219 11106 && output_cursor.vpos == w->phys_cursor.vpos
f0a48a01
GM
11107 && start_x <= w->phys_cursor.x
11108 && end_x > w->phys_cursor.x)
11109 w->phys_cursor_on_p = 0;
06a2c219 11110}
f451eb13
JB
11111
11112
06a2c219
GM
11113/* Set clipping for output in glyph row ROW. W is the window in which
11114 we operate. GC is the graphics context to set clipping in.
11115 WHOLE_LINE_P non-zero means include the areas used for truncation
11116 mark display and alike in the clipping rectangle.
11117
11118 ROW may be a text row or, e.g., a mode line. Text rows must be
11119 clipped to the interior of the window dedicated to text display,
11120 mode lines must be clipped to the whole window. */
dc6f92b8
JB
11121
11122static void
06a2c219
GM
11123x_clip_to_row (w, row, gc, whole_line_p)
11124 struct window *w;
11125 struct glyph_row *row;
11126 GC gc;
11127 int whole_line_p;
dc6f92b8 11128{
06a2c219
GM
11129 struct frame *f = XFRAME (WINDOW_FRAME (w));
11130 XRectangle clip_rect;
11131 int window_x, window_y, window_width, window_height;
dc6f92b8 11132
06a2c219 11133 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 11134
06a2c219
GM
11135 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
11136 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
11137 clip_rect.y = max (clip_rect.y, window_y);
11138 clip_rect.width = window_width;
11139 clip_rect.height = row->visible_height;
5c1aae96 11140
06a2c219
GM
11141 /* If clipping to the whole line, including trunc marks, extend
11142 the rectangle to the left and increase its width. */
11143 if (whole_line_p)
11144 {
110859fc
GM
11145 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
11146 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 11147 }
5c1aae96 11148
06a2c219 11149 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
11150}
11151
06a2c219
GM
11152
11153/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
11154
11155static void
06a2c219
GM
11156x_draw_hollow_cursor (w, row)
11157 struct window *w;
11158 struct glyph_row *row;
dc6f92b8 11159{
06a2c219
GM
11160 struct frame *f = XFRAME (WINDOW_FRAME (w));
11161 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11162 Display *dpy = FRAME_X_DISPLAY (f);
11163 int x, y, wd, h;
11164 XGCValues xgcv;
11165 struct glyph *cursor_glyph;
11166 GC gc;
11167
11168 /* Compute frame-relative coordinates from window-relative
11169 coordinates. */
11170 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11171 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
11172 + row->ascent - w->phys_cursor_ascent);
11173 h = row->height - 1;
11174
11175 /* Get the glyph the cursor is on. If we can't tell because
11176 the current matrix is invalid or such, give up. */
11177 cursor_glyph = get_phys_cursor_glyph (w);
11178 if (cursor_glyph == NULL)
dc6f92b8
JB
11179 return;
11180
06a2c219
GM
11181 /* Compute the width of the rectangle to draw. If on a stretch
11182 glyph, and `x-stretch-block-cursor' is nil, don't draw a
11183 rectangle as wide as the glyph, but use a canonical character
11184 width instead. */
11185 wd = cursor_glyph->pixel_width - 1;
11186 if (cursor_glyph->type == STRETCH_GLYPH
11187 && !x_stretch_cursor_p)
11188 wd = min (CANON_X_UNIT (f), wd);
11189
11190 /* The foreground of cursor_gc is typically the same as the normal
11191 background color, which can cause the cursor box to be invisible. */
11192 xgcv.foreground = f->output_data.x->cursor_pixel;
11193 if (dpyinfo->scratch_cursor_gc)
11194 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
11195 else
11196 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
11197 GCForeground, &xgcv);
11198 gc = dpyinfo->scratch_cursor_gc;
11199
11200 /* Set clipping, draw the rectangle, and reset clipping again. */
11201 x_clip_to_row (w, row, gc, 0);
11202 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
11203 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
11204}
11205
06a2c219
GM
11206
11207/* Draw a bar cursor on window W in glyph row ROW.
11208
11209 Implementation note: One would like to draw a bar cursor with an
11210 angle equal to the one given by the font property XA_ITALIC_ANGLE.
11211 Unfortunately, I didn't find a font yet that has this property set.
11212 --gerd. */
dc6f92b8
JB
11213
11214static void
f02d8aa0 11215x_draw_bar_cursor (w, row, width)
06a2c219
GM
11216 struct window *w;
11217 struct glyph_row *row;
f02d8aa0 11218 int width;
dc6f92b8 11219{
92f424df
GM
11220 struct frame *f = XFRAME (w->frame);
11221 struct glyph *cursor_glyph;
11222 GC gc;
11223 int x;
11224 unsigned long mask;
11225 XGCValues xgcv;
11226 Display *dpy;
11227 Window window;
06a2c219 11228
92f424df
GM
11229 /* If cursor is out of bounds, don't draw garbage. This can happen
11230 in mini-buffer windows when switching between echo area glyphs
11231 and mini-buffer. */
11232 cursor_glyph = get_phys_cursor_glyph (w);
11233 if (cursor_glyph == NULL)
11234 return;
06a2c219 11235
92f424df
GM
11236 /* If on an image, draw like a normal cursor. That's usually better
11237 visible than drawing a bar, esp. if the image is large so that
11238 the bar might not be in the window. */
11239 if (cursor_glyph->type == IMAGE_GLYPH)
11240 {
11241 struct glyph_row *row;
11242 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
11243 x_draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
11244 }
11245 else
11246 {
06a2c219
GM
11247 xgcv.background = f->output_data.x->cursor_pixel;
11248 xgcv.foreground = f->output_data.x->cursor_pixel;
11249 xgcv.graphics_exposures = 0;
11250 mask = GCForeground | GCBackground | GCGraphicsExposures;
11251 dpy = FRAME_X_DISPLAY (f);
11252 window = FRAME_X_WINDOW (f);
11253 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
92f424df 11254
06a2c219
GM
11255 if (gc)
11256 XChangeGC (dpy, gc, mask, &xgcv);
11257 else
11258 {
11259 gc = XCreateGC (dpy, window, mask, &xgcv);
11260 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
11261 }
92f424df 11262
f02d8aa0
GM
11263 if (width < 0)
11264 width = f->output_data.x->cursor_width;
92f424df 11265
06a2c219
GM
11266 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11267 x_clip_to_row (w, row, gc, 0);
11268 XFillRectangle (dpy, window, gc,
11269 x,
11270 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
f02d8aa0 11271 min (cursor_glyph->pixel_width, width),
06a2c219
GM
11272 row->height);
11273 XSetClipMask (dpy, gc, None);
11274 }
dc6f92b8
JB
11275}
11276
06a2c219
GM
11277
11278/* Clear the cursor of window W to background color, and mark the
11279 cursor as not shown. This is used when the text where the cursor
11280 is is about to be rewritten. */
11281
dc6f92b8 11282static void
06a2c219
GM
11283x_clear_cursor (w)
11284 struct window *w;
dc6f92b8 11285{
06a2c219
GM
11286 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
11287 x_update_window_cursor (w, 0);
11288}
90e65f07 11289
dbc4e1c1 11290
06a2c219
GM
11291/* Draw the cursor glyph of window W in glyph row ROW. See the
11292 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 11293
06a2c219
GM
11294static void
11295x_draw_phys_cursor_glyph (w, row, hl)
11296 struct window *w;
11297 struct glyph_row *row;
11298 enum draw_glyphs_face hl;
11299{
11300 /* If cursor hpos is out of bounds, don't draw garbage. This can
11301 happen in mini-buffer windows when switching between echo area
11302 glyphs and mini-buffer. */
11303 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e 11304 {
f0a48a01
GM
11305 int on_p = w->phys_cursor_on_p;
11306
66ac4b0e
GM
11307 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
11308 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
f0a48a01
GM
11309 hl, 0);
11310 w->phys_cursor_on_p = on_p;
66ac4b0e
GM
11311
11312 /* When we erase the cursor, and ROW is overlapped by other
11313 rows, make sure that these overlapping parts of other rows
11314 are redrawn. */
11315 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
11316 {
11317 if (row > w->current_matrix->rows
11318 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
11319 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
11320
11321 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
11322 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
11323 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
11324 }
11325 }
06a2c219 11326}
dbc4e1c1 11327
eea6af04 11328
06a2c219 11329/* Erase the image of a cursor of window W from the screen. */
eea6af04 11330
06a2c219
GM
11331static void
11332x_erase_phys_cursor (w)
11333 struct window *w;
11334{
11335 struct frame *f = XFRAME (w->frame);
11336 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11337 int hpos = w->phys_cursor.hpos;
11338 int vpos = w->phys_cursor.vpos;
11339 int mouse_face_here_p = 0;
11340 struct glyph_matrix *active_glyphs = w->current_matrix;
11341 struct glyph_row *cursor_row;
11342 struct glyph *cursor_glyph;
11343 enum draw_glyphs_face hl;
11344
11345 /* No cursor displayed or row invalidated => nothing to do on the
11346 screen. */
11347 if (w->phys_cursor_type == NO_CURSOR)
11348 goto mark_cursor_off;
11349
11350 /* VPOS >= active_glyphs->nrows means that window has been resized.
11351 Don't bother to erase the cursor. */
11352 if (vpos >= active_glyphs->nrows)
11353 goto mark_cursor_off;
11354
11355 /* If row containing cursor is marked invalid, there is nothing we
11356 can do. */
11357 cursor_row = MATRIX_ROW (active_glyphs, vpos);
11358 if (!cursor_row->enabled_p)
11359 goto mark_cursor_off;
11360
11361 /* This can happen when the new row is shorter than the old one.
11362 In this case, either x_draw_glyphs or clear_end_of_line
11363 should have cleared the cursor. Note that we wouldn't be
11364 able to erase the cursor in this case because we don't have a
11365 cursor glyph at hand. */
11366 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
11367 goto mark_cursor_off;
11368
11369 /* If the cursor is in the mouse face area, redisplay that when
11370 we clear the cursor. */
8801a864
KR
11371 if (! NILP (dpyinfo->mouse_face_window)
11372 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
11373 && (vpos > dpyinfo->mouse_face_beg_row
11374 || (vpos == dpyinfo->mouse_face_beg_row
11375 && hpos >= dpyinfo->mouse_face_beg_col))
11376 && (vpos < dpyinfo->mouse_face_end_row
11377 || (vpos == dpyinfo->mouse_face_end_row
11378 && hpos < dpyinfo->mouse_face_end_col))
11379 /* Don't redraw the cursor's spot in mouse face if it is at the
11380 end of a line (on a newline). The cursor appears there, but
11381 mouse highlighting does not. */
11382 && cursor_row->used[TEXT_AREA] > hpos)
11383 mouse_face_here_p = 1;
11384
11385 /* Maybe clear the display under the cursor. */
11386 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
11387 {
11388 int x;
045dee35 11389 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 11390
06a2c219
GM
11391 cursor_glyph = get_phys_cursor_glyph (w);
11392 if (cursor_glyph == NULL)
11393 goto mark_cursor_off;
dbc4e1c1 11394
e0300d33 11395 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
06a2c219 11396
c5e6e06b
GM
11397 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11398 x,
11399 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
11400 cursor_row->y)),
11401 cursor_glyph->pixel_width,
11402 cursor_row->visible_height,
11403 False);
dbc4e1c1 11404 }
06a2c219
GM
11405
11406 /* Erase the cursor by redrawing the character underneath it. */
11407 if (mouse_face_here_p)
11408 hl = DRAW_MOUSE_FACE;
06a2c219
GM
11409 else
11410 hl = DRAW_NORMAL_TEXT;
11411 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 11412
06a2c219
GM
11413 mark_cursor_off:
11414 w->phys_cursor_on_p = 0;
11415 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
11416}
11417
11418
b7f83f9e
GM
11419/* Non-zero if physical cursor of window W is within mouse face. */
11420
11421static int
11422cursor_in_mouse_face_p (w)
11423 struct window *w;
11424{
11425 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
11426 int in_mouse_face = 0;
11427
11428 if (WINDOWP (dpyinfo->mouse_face_window)
11429 && XWINDOW (dpyinfo->mouse_face_window) == w)
11430 {
11431 int hpos = w->phys_cursor.hpos;
11432 int vpos = w->phys_cursor.vpos;
11433
11434 if (vpos >= dpyinfo->mouse_face_beg_row
11435 && vpos <= dpyinfo->mouse_face_end_row
11436 && (vpos > dpyinfo->mouse_face_beg_row
11437 || hpos >= dpyinfo->mouse_face_beg_col)
11438 && (vpos < dpyinfo->mouse_face_end_row
11439 || hpos < dpyinfo->mouse_face_end_col
11440 || dpyinfo->mouse_face_past_end))
11441 in_mouse_face = 1;
11442 }
11443
11444 return in_mouse_face;
11445}
11446
11447
06a2c219
GM
11448/* Display or clear cursor of window W. If ON is zero, clear the
11449 cursor. If it is non-zero, display the cursor. If ON is nonzero,
11450 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 11451
06a2c219
GM
11452void
11453x_display_and_set_cursor (w, on, hpos, vpos, x, y)
11454 struct window *w;
11455 int on, hpos, vpos, x, y;
dbc4e1c1 11456{
06a2c219
GM
11457 struct frame *f = XFRAME (w->frame);
11458 int new_cursor_type;
f02d8aa0 11459 int new_cursor_width;
06a2c219
GM
11460 struct glyph_matrix *current_glyphs;
11461 struct glyph_row *glyph_row;
11462 struct glyph *glyph;
dbc4e1c1 11463
49d838ea 11464 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
11465 windows and frames; in the latter case, the frame or window may
11466 be in the midst of changing its size, and x and y may be off the
11467 window. */
11468 if (! FRAME_VISIBLE_P (f)
11469 || FRAME_GARBAGED_P (f)
11470 || vpos >= w->current_matrix->nrows
11471 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
11472 return;
11473
11474 /* If cursor is off and we want it off, return quickly. */
06a2c219 11475 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
11476 return;
11477
06a2c219
GM
11478 current_glyphs = w->current_matrix;
11479 glyph_row = MATRIX_ROW (current_glyphs, vpos);
11480 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
11481
11482 /* If cursor row is not enabled, we don't really know where to
11483 display the cursor. */
11484 if (!glyph_row->enabled_p)
11485 {
11486 w->phys_cursor_on_p = 0;
11487 return;
11488 }
11489
11490 xassert (interrupt_input_blocked);
11491
11492 /* Set new_cursor_type to the cursor we want to be displayed. In a
11493 mini-buffer window, we want the cursor only to appear if we are
11494 reading input from this window. For the selected window, we want
11495 the cursor type given by the frame parameter. If explicitly
11496 marked off, draw no cursor. In all other cases, we want a hollow
11497 box cursor. */
f02d8aa0 11498 new_cursor_width = -1;
9b4a7047
GM
11499 if (cursor_in_echo_area
11500 && FRAME_HAS_MINIBUF_P (f)
11501 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 11502 {
9b4a7047
GM
11503 if (w == XWINDOW (echo_area_window))
11504 new_cursor_type = FRAME_DESIRED_CURSOR (f);
9a7bdceb 11505 else if (cursor_in_non_selected_windows)
06a2c219 11506 new_cursor_type = HOLLOW_BOX_CURSOR;
9a7bdceb
GM
11507 else
11508 new_cursor_type = NO_CURSOR;
06a2c219 11509 }
06a2c219 11510 else
9b4a7047 11511 {
7a58ab59
GM
11512 if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
11513 || w != XWINDOW (f->selected_window))
9b4a7047 11514 {
e55a0b79
GM
11515 extern int cursor_in_non_selected_windows;
11516
5cefa566
GM
11517 if (MINI_WINDOW_P (w)
11518 || !cursor_in_non_selected_windows
11519 || NILP (XBUFFER (w->buffer)->cursor_type))
9b4a7047
GM
11520 new_cursor_type = NO_CURSOR;
11521 else
11522 new_cursor_type = HOLLOW_BOX_CURSOR;
11523 }
11524 else if (w->cursor_off_p)
11525 new_cursor_type = NO_CURSOR;
11526 else
f02d8aa0
GM
11527 {
11528 struct buffer *b = XBUFFER (w->buffer);
11529
11530 if (EQ (b->cursor_type, Qt))
11531 new_cursor_type = FRAME_DESIRED_CURSOR (f);
11532 else
11533 new_cursor_type = x_specified_cursor_type (b->cursor_type,
11534 &new_cursor_width);
11535 }
9b4a7047 11536 }
06a2c219
GM
11537
11538 /* If cursor is currently being shown and we don't want it to be or
11539 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 11540 erase it. */
06a2c219 11541 if (w->phys_cursor_on_p
dc6f92b8 11542 && (!on
06a2c219
GM
11543 || w->phys_cursor.x != x
11544 || w->phys_cursor.y != y
11545 || new_cursor_type != w->phys_cursor_type))
11546 x_erase_phys_cursor (w);
11547
11548 /* If the cursor is now invisible and we want it to be visible,
11549 display it. */
11550 if (on && !w->phys_cursor_on_p)
11551 {
11552 w->phys_cursor_ascent = glyph_row->ascent;
11553 w->phys_cursor_height = glyph_row->height;
11554
11555 /* Set phys_cursor_.* before x_draw_.* is called because some
11556 of them may need the information. */
11557 w->phys_cursor.x = x;
11558 w->phys_cursor.y = glyph_row->y;
11559 w->phys_cursor.hpos = hpos;
11560 w->phys_cursor.vpos = vpos;
11561 w->phys_cursor_type = new_cursor_type;
11562 w->phys_cursor_on_p = 1;
11563
11564 switch (new_cursor_type)
dc6f92b8 11565 {
06a2c219
GM
11566 case HOLLOW_BOX_CURSOR:
11567 x_draw_hollow_cursor (w, glyph_row);
11568 break;
11569
11570 case FILLED_BOX_CURSOR:
11571 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
11572 break;
11573
11574 case BAR_CURSOR:
f02d8aa0 11575 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
11576 break;
11577
11578 case NO_CURSOR:
11579 break;
dc6f92b8 11580
06a2c219
GM
11581 default:
11582 abort ();
11583 }
59ddecde
GM
11584
11585#ifdef HAVE_X_I18N
11586 if (w == XWINDOW (f->selected_window))
11587 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
11588 xic_set_preeditarea (w, x, y);
11589#endif
dc6f92b8
JB
11590 }
11591
06a2c219 11592#ifndef XFlush
f676886a 11593 if (updating_frame != f)
334208b7 11594 XFlush (FRAME_X_DISPLAY (f));
06a2c219 11595#endif
dc6f92b8
JB
11596}
11597
06a2c219
GM
11598
11599/* Display the cursor on window W, or clear it. X and Y are window
11600 relative pixel coordinates. HPOS and VPOS are glyph matrix
11601 positions. If W is not the selected window, display a hollow
11602 cursor. ON non-zero means display the cursor at X, Y which
11603 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 11604
dfcf069d 11605void
06a2c219
GM
11606x_display_cursor (w, on, hpos, vpos, x, y)
11607 struct window *w;
11608 int on, hpos, vpos, x, y;
dc6f92b8 11609{
f94397b5 11610 BLOCK_INPUT;
06a2c219 11611 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
11612 UNBLOCK_INPUT;
11613}
11614
06a2c219
GM
11615
11616/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
11617 Don't change the cursor's position. */
11618
dfcf069d 11619void
06a2c219 11620x_update_cursor (f, on_p)
5d46f928 11621 struct frame *f;
5d46f928 11622{
06a2c219
GM
11623 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
11624}
11625
11626
11627/* Call x_update_window_cursor with parameter ON_P on all leaf windows
11628 in the window tree rooted at W. */
11629
11630static void
11631x_update_cursor_in_window_tree (w, on_p)
11632 struct window *w;
11633 int on_p;
11634{
11635 while (w)
11636 {
11637 if (!NILP (w->hchild))
11638 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
11639 else if (!NILP (w->vchild))
11640 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
11641 else
11642 x_update_window_cursor (w, on_p);
11643
11644 w = NILP (w->next) ? 0 : XWINDOW (w->next);
11645 }
11646}
5d46f928 11647
f94397b5 11648
06a2c219
GM
11649/* Switch the display of W's cursor on or off, according to the value
11650 of ON. */
11651
11652static void
11653x_update_window_cursor (w, on)
11654 struct window *w;
11655 int on;
11656{
16b5d424
GM
11657 /* Don't update cursor in windows whose frame is in the process
11658 of being deleted. */
11659 if (w->current_matrix)
11660 {
11661 BLOCK_INPUT;
11662 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
11663 w->phys_cursor.x, w->phys_cursor.y);
11664 UNBLOCK_INPUT;
11665 }
dc6f92b8 11666}
06a2c219
GM
11667
11668
11669
dc6f92b8
JB
11670\f
11671/* Icons. */
11672
dbc4e1c1 11673/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
11674
11675int
990ba854 11676x_bitmap_icon (f, file)
f676886a 11677 struct frame *f;
990ba854 11678 Lisp_Object file;
dc6f92b8 11679{
06a2c219 11680 int bitmap_id;
dc6f92b8 11681
c118dd06 11682 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11683 return 1;
11684
990ba854 11685 /* Free up our existing icon bitmap if any. */
7556890b
RS
11686 if (f->output_data.x->icon_bitmap > 0)
11687 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11688 f->output_data.x->icon_bitmap = 0;
990ba854
RS
11689
11690 if (STRINGP (file))
7f2ae036
RS
11691 bitmap_id = x_create_bitmap_from_file (f, file);
11692 else
11693 {
990ba854 11694 /* Create the GNU bitmap if necessary. */
5bf01b68 11695 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
11696 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
11697 = x_create_bitmap_from_data (f, gnu_bits,
11698 gnu_width, gnu_height);
990ba854
RS
11699
11700 /* The first time we create the GNU bitmap,
06a2c219 11701 this increments the ref-count one extra time.
990ba854
RS
11702 As a result, the GNU bitmap is never freed.
11703 That way, we don't have to worry about allocating it again. */
334208b7 11704 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 11705
334208b7 11706 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
11707 }
11708
11709 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 11710 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
11711
11712 return 0;
11713}
11714
11715
1be2d067
KH
11716/* Make the x-window of frame F use a rectangle with text.
11717 Use ICON_NAME as the text. */
dc6f92b8
JB
11718
11719int
f676886a
JB
11720x_text_icon (f, icon_name)
11721 struct frame *f;
dc6f92b8
JB
11722 char *icon_name;
11723{
c118dd06 11724 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11725 return 1;
11726
1be2d067
KH
11727#ifdef HAVE_X11R4
11728 {
11729 XTextProperty text;
11730 text.value = (unsigned char *) icon_name;
11731 text.encoding = XA_STRING;
11732 text.format = 8;
11733 text.nitems = strlen (icon_name);
11734#ifdef USE_X_TOOLKIT
7556890b 11735 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
11736 &text);
11737#else /* not USE_X_TOOLKIT */
11738 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
11739#endif /* not USE_X_TOOLKIT */
11740 }
11741#else /* not HAVE_X11R4 */
11742 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
11743#endif /* not HAVE_X11R4 */
58769bee 11744
7556890b
RS
11745 if (f->output_data.x->icon_bitmap > 0)
11746 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11747 f->output_data.x->icon_bitmap = 0;
b1c884c3 11748 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
11749
11750 return 0;
11751}
11752\f
e99db5a1
RS
11753#define X_ERROR_MESSAGE_SIZE 200
11754
11755/* If non-nil, this should be a string.
11756 It means catch X errors and store the error message in this string. */
11757
11758static Lisp_Object x_error_message_string;
11759
11760/* An X error handler which stores the error message in
11761 x_error_message_string. This is called from x_error_handler if
11762 x_catch_errors is in effect. */
11763
06a2c219 11764static void
e99db5a1
RS
11765x_error_catcher (display, error)
11766 Display *display;
11767 XErrorEvent *error;
11768{
11769 XGetErrorText (display, error->error_code,
11770 XSTRING (x_error_message_string)->data,
11771 X_ERROR_MESSAGE_SIZE);
11772}
11773
11774/* Begin trapping X errors for display DPY. Actually we trap X errors
11775 for all displays, but DPY should be the display you are actually
11776 operating on.
11777
11778 After calling this function, X protocol errors no longer cause
11779 Emacs to exit; instead, they are recorded in the string
11780 stored in x_error_message_string.
11781
11782 Calling x_check_errors signals an Emacs error if an X error has
11783 occurred since the last call to x_catch_errors or x_check_errors.
11784
11785 Calling x_uncatch_errors resumes the normal error handling. */
11786
11787void x_check_errors ();
11788static Lisp_Object x_catch_errors_unwind ();
11789
11790int
11791x_catch_errors (dpy)
11792 Display *dpy;
11793{
11794 int count = specpdl_ptr - specpdl;
11795
11796 /* Make sure any errors from previous requests have been dealt with. */
11797 XSync (dpy, False);
11798
11799 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
11800
11801 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
11802 XSTRING (x_error_message_string)->data[0] = 0;
11803
11804 return count;
11805}
11806
11807/* Unbind the binding that we made to check for X errors. */
11808
11809static Lisp_Object
11810x_catch_errors_unwind (old_val)
11811 Lisp_Object old_val;
11812{
11813 x_error_message_string = old_val;
11814 return Qnil;
11815}
11816
11817/* If any X protocol errors have arrived since the last call to
11818 x_catch_errors or x_check_errors, signal an Emacs error using
11819 sprintf (a buffer, FORMAT, the x error message text) as the text. */
11820
11821void
11822x_check_errors (dpy, format)
11823 Display *dpy;
11824 char *format;
11825{
11826 /* Make sure to catch any errors incurred so far. */
11827 XSync (dpy, False);
11828
11829 if (XSTRING (x_error_message_string)->data[0])
11830 error (format, XSTRING (x_error_message_string)->data);
11831}
11832
9829ddba
RS
11833/* Nonzero if we had any X protocol errors
11834 since we did x_catch_errors on DPY. */
e99db5a1
RS
11835
11836int
11837x_had_errors_p (dpy)
11838 Display *dpy;
11839{
11840 /* Make sure to catch any errors incurred so far. */
11841 XSync (dpy, False);
11842
11843 return XSTRING (x_error_message_string)->data[0] != 0;
11844}
11845
9829ddba
RS
11846/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
11847
06a2c219 11848void
9829ddba
RS
11849x_clear_errors (dpy)
11850 Display *dpy;
11851{
11852 XSTRING (x_error_message_string)->data[0] = 0;
11853}
11854
e99db5a1
RS
11855/* Stop catching X protocol errors and let them make Emacs die.
11856 DPY should be the display that was passed to x_catch_errors.
11857 COUNT should be the value that was returned by
11858 the corresponding call to x_catch_errors. */
11859
11860void
11861x_uncatch_errors (dpy, count)
11862 Display *dpy;
11863 int count;
11864{
11865 unbind_to (count, Qnil);
11866}
11867
11868#if 0
11869static unsigned int x_wire_count;
11870x_trace_wire ()
11871{
11872 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
11873}
11874#endif /* ! 0 */
11875
11876\f
11877/* Handle SIGPIPE, which can happen when the connection to a server
11878 simply goes away. SIGPIPE is handled by x_connection_signal.
11879 Don't need to do anything, because the write which caused the
11880 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 11881 which will do the appropriate cleanup for us. */
e99db5a1
RS
11882
11883static SIGTYPE
11884x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 11885 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
11886{
11887#ifdef USG
11888 /* USG systems forget handlers when they are used;
11889 must reestablish each time */
11890 signal (signalnum, x_connection_signal);
11891#endif /* USG */
11892}
0da1ab50 11893
e99db5a1 11894\f
0da1ab50
GM
11895/************************************************************************
11896 Handling X errors
11897 ************************************************************************/
4746118a 11898
f0e299de
GM
11899/* Error message passed to x_connection_closed. */
11900
11901static char *error_msg;
11902
a7248e4f 11903/* Function installed as fatal_error_signal_hook in
f0e299de
GM
11904 x_connection_closed. Print the X error message, and exit normally,
11905 instead of dumping core when XtCloseDisplay fails. */
11906
11907static void
11908x_fatal_error_signal ()
11909{
11910 fprintf (stderr, "%s\n", error_msg);
11911 exit (70);
11912}
11913
0da1ab50
GM
11914/* Handle the loss of connection to display DPY. ERROR_MESSAGE is
11915 the text of an error message that lead to the connection loss. */
16bd92ea 11916
4746118a 11917static SIGTYPE
5978125e
GM
11918x_connection_closed (dpy, error_message)
11919 Display *dpy;
7a13e894 11920 char *error_message;
4746118a 11921{
5978125e 11922 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
7a13e894 11923 Lisp_Object frame, tail;
0da1ab50 11924 int count;
0da1ab50 11925
f0e299de
GM
11926 error_msg = (char *) alloca (strlen (error_message) + 1);
11927 strcpy (error_msg, error_message);
1a532e54
GM
11928 handling_signal = 0;
11929
0da1ab50
GM
11930 /* Prevent being called recursively because of an error condition
11931 below. Otherwise, we might end up with printing ``can't find per
11932 display information'' in the recursive call instead of printing
11933 the original message here. */
11934 count = x_catch_errors (dpy);
11935
8a4f36cc
GM
11936 /* We have to close the display to inform Xt that it doesn't
11937 exist anymore. If we don't, Xt will continue to wait for
11938 events from the display. As a consequence, a sequence of
11939
11940 M-x make-frame-on-display RET :1 RET
11941 ...kill the new frame, so that we get an IO error...
11942 M-x make-frame-on-display RET :1 RET
11943
11944 will indefinitely wait in Xt for events for display `:1', opened
11945 in the first class to make-frame-on-display.
6186a4a0 11946
8a4f36cc
GM
11947 Closing the display is reported to lead to a bus error on
11948 OpenWindows in certain situations. I suspect that is a bug
11949 in OpenWindows. I don't know how to cicumvent it here. */
11950
f613a4c8 11951#ifdef USE_X_TOOLKIT
ae24cb3b
GM
11952 /* If DPYINFO is null, this means we didn't open the display
11953 in the first place, so don't try to close it. */
11954 if (dpyinfo)
f0e299de
GM
11955 {
11956 extern void (*fatal_error_signal_hook) P_ ((void));
11957 fatal_error_signal_hook = x_fatal_error_signal;
11958 XtCloseDisplay (dpy);
11959 fatal_error_signal_hook = NULL;
11960 }
f613a4c8 11961#endif
adabc3a9 11962
8a4f36cc 11963 /* Indicate that this display is dead. */
9e80b57d
KR
11964 if (dpyinfo)
11965 dpyinfo->display = 0;
6186a4a0 11966
06a2c219 11967 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
11968 that are on the dead display. */
11969 FOR_EACH_FRAME (tail, frame)
11970 {
11971 Lisp_Object minibuf_frame;
11972 minibuf_frame
11973 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
11974 if (FRAME_X_P (XFRAME (frame))
11975 && FRAME_X_P (XFRAME (minibuf_frame))
11976 && ! EQ (frame, minibuf_frame)
11977 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
11978 Fdelete_frame (frame, Qt);
11979 }
11980
11981 /* Now delete all remaining frames on the dead display.
06a2c219 11982 We are now sure none of these is used as the mini-buffer
7a13e894
RS
11983 for another frame that we need to delete. */
11984 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
11985 if (FRAME_X_P (XFRAME (frame))
11986 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
11987 {
11988 /* Set this to t so that Fdelete_frame won't get confused
11989 trying to find a replacement. */
11990 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
11991 Fdelete_frame (frame, Qt);
11992 }
7a13e894 11993
482a1bd2
KH
11994 if (dpyinfo)
11995 x_delete_display (dpyinfo);
7a13e894 11996
0da1ab50
GM
11997 x_uncatch_errors (dpy, count);
11998
7a13e894
RS
11999 if (x_display_list == 0)
12000 {
f0e299de 12001 fprintf (stderr, "%s\n", error_msg);
7a13e894
RS
12002 shut_down_emacs (0, 0, Qnil);
12003 exit (70);
12004 }
12ba150f 12005
7a13e894
RS
12006 /* Ordinary stack unwind doesn't deal with these. */
12007#ifdef SIGIO
12008 sigunblock (sigmask (SIGIO));
12009#endif
12010 sigunblock (sigmask (SIGALRM));
12011 TOTALLY_UNBLOCK_INPUT;
12012
aa4d9a9e 12013 clear_waiting_for_input ();
f0e299de 12014 error ("%s", error_msg);
4746118a
JB
12015}
12016
0da1ab50 12017
7a13e894
RS
12018/* This is the usual handler for X protocol errors.
12019 It kills all frames on the display that we got the error for.
12020 If that was the only one, it prints an error message and kills Emacs. */
12021
06a2c219 12022static void
c118dd06
JB
12023x_error_quitter (display, error)
12024 Display *display;
12025 XErrorEvent *error;
12026{
7a13e894 12027 char buf[256], buf1[356];
dc6f92b8 12028
58769bee 12029 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 12030 original error handler. */
dc6f92b8 12031
c118dd06 12032 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 12033 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 12034 buf, error->request_code);
7a13e894 12035 x_connection_closed (display, buf1);
dc6f92b8
JB
12036}
12037
0da1ab50 12038
e99db5a1
RS
12039/* This is the first-level handler for X protocol errors.
12040 It calls x_error_quitter or x_error_catcher. */
7a13e894 12041
8922af5f 12042static int
e99db5a1 12043x_error_handler (display, error)
8922af5f 12044 Display *display;
e99db5a1 12045 XErrorEvent *error;
8922af5f 12046{
e99db5a1
RS
12047 if (! NILP (x_error_message_string))
12048 x_error_catcher (display, error);
12049 else
12050 x_error_quitter (display, error);
06a2c219 12051 return 0;
f9e24cb9 12052}
c118dd06 12053
e99db5a1
RS
12054/* This is the handler for X IO errors, always.
12055 It kills all frames on the display that we lost touch with.
12056 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 12057
c118dd06 12058static int
e99db5a1 12059x_io_error_quitter (display)
c118dd06 12060 Display *display;
c118dd06 12061{
e99db5a1 12062 char buf[256];
dc6f92b8 12063
e99db5a1
RS
12064 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
12065 x_connection_closed (display, buf);
06a2c219 12066 return 0;
dc6f92b8 12067}
dc6f92b8 12068\f
f451eb13
JB
12069/* Changing the font of the frame. */
12070
76bcdf39
RS
12071/* Give frame F the font named FONTNAME as its default font, and
12072 return the full name of that font. FONTNAME may be a wildcard
12073 pattern; in that case, we choose some font that fits the pattern.
12074 The return value shows which font we chose. */
12075
b5cf7a0e 12076Lisp_Object
f676886a
JB
12077x_new_font (f, fontname)
12078 struct frame *f;
dc6f92b8
JB
12079 register char *fontname;
12080{
dc43ef94 12081 struct font_info *fontp
ee569018 12082 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 12083
dc43ef94
KH
12084 if (!fontp)
12085 return Qnil;
2224a5fc 12086
dc43ef94 12087 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 12088 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
12089 f->output_data.x->fontset = -1;
12090
b2cad826
KH
12091 /* Compute the scroll bar width in character columns. */
12092 if (f->scroll_bar_pixel_width > 0)
12093 {
7556890b 12094 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
12095 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
12096 }
12097 else
4e61bddf
RS
12098 {
12099 int wid = FONT_WIDTH (f->output_data.x->font);
12100 f->scroll_bar_cols = (14 + wid - 1) / wid;
12101 }
b2cad826 12102
f676886a 12103 /* Now make the frame display the given font. */
c118dd06 12104 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 12105 {
7556890b
RS
12106 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
12107 f->output_data.x->font->fid);
12108 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
12109 f->output_data.x->font->fid);
12110 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
12111 f->output_data.x->font->fid);
f676886a 12112
a27f9f86 12113 frame_update_line_height (f);
3497f73e
GM
12114
12115 /* Don't change the size of a tip frame; there's no point in
12116 doing it because it's done in Fx_show_tip, and it leads to
12117 problems because the tip frame has no widget. */
12118 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
12119 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 12120 }
a27f9f86
RS
12121 else
12122 /* If we are setting a new frame's font for the first time,
12123 there are no faces yet, so this font's height is the line height. */
7556890b 12124 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 12125
dc43ef94
KH
12126 return build_string (fontp->full_name);
12127}
12128
12129/* Give frame F the fontset named FONTSETNAME as its default font, and
12130 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
12131 pattern; in that case, we choose some fontset that fits the pattern.
12132 The return value shows which fontset we chose. */
b5cf7a0e 12133
dc43ef94
KH
12134Lisp_Object
12135x_new_fontset (f, fontsetname)
12136 struct frame *f;
12137 char *fontsetname;
12138{
ee569018 12139 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 12140 Lisp_Object result;
b5cf7a0e 12141
dc43ef94
KH
12142 if (fontset < 0)
12143 return Qnil;
b5cf7a0e 12144
2da424f1
KH
12145 if (f->output_data.x->fontset == fontset)
12146 /* This fontset is already set in frame F. There's nothing more
12147 to do. */
ee569018 12148 return fontset_name (fontset);
dc43ef94 12149
ee569018 12150 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
12151
12152 if (!STRINGP (result))
12153 /* Can't load ASCII font. */
12154 return Qnil;
12155
12156 /* Since x_new_font doesn't update any fontset information, do it now. */
12157 f->output_data.x->fontset = fontset;
dc43ef94 12158
f5d11644
GM
12159#ifdef HAVE_X_I18N
12160 if (FRAME_XIC (f)
12161 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 12162 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
12163#endif
12164
dc43ef94 12165 return build_string (fontsetname);
dc6f92b8 12166}
f5d11644
GM
12167
12168\f
12169/***********************************************************************
12170 X Input Methods
12171 ***********************************************************************/
12172
12173#ifdef HAVE_X_I18N
12174
12175#ifdef HAVE_X11R6
12176
12177/* XIM destroy callback function, which is called whenever the
12178 connection to input method XIM dies. CLIENT_DATA contains a
12179 pointer to the x_display_info structure corresponding to XIM. */
12180
12181static void
12182xim_destroy_callback (xim, client_data, call_data)
12183 XIM xim;
12184 XPointer client_data;
12185 XPointer call_data;
12186{
12187 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
12188 Lisp_Object frame, tail;
12189
12190 BLOCK_INPUT;
12191
12192 /* No need to call XDestroyIC.. */
12193 FOR_EACH_FRAME (tail, frame)
12194 {
12195 struct frame *f = XFRAME (frame);
12196 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
12197 {
12198 FRAME_XIC (f) = NULL;
12199 if (FRAME_XIC_FONTSET (f))
12200 {
12201 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
12202 FRAME_XIC_FONTSET (f) = NULL;
12203 }
12204 }
12205 }
12206
12207 /* No need to call XCloseIM. */
12208 dpyinfo->xim = NULL;
12209 XFree (dpyinfo->xim_styles);
12210 UNBLOCK_INPUT;
12211}
12212
12213#endif /* HAVE_X11R6 */
12214
12215/* Open the connection to the XIM server on display DPYINFO.
12216 RESOURCE_NAME is the resource name Emacs uses. */
12217
12218static void
12219xim_open_dpy (dpyinfo, resource_name)
12220 struct x_display_info *dpyinfo;
12221 char *resource_name;
12222{
287f7dd6 12223#ifdef USE_XIM
f5d11644
GM
12224 XIM xim;
12225
12226 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
12227 dpyinfo->xim = xim;
12228
12229 if (xim)
12230 {
f5d11644
GM
12231#ifdef HAVE_X11R6
12232 XIMCallback destroy;
12233#endif
12234
12235 /* Get supported styles and XIM values. */
12236 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
12237
12238#ifdef HAVE_X11R6
12239 destroy.callback = xim_destroy_callback;
12240 destroy.client_data = (XPointer)dpyinfo;
cea2ad76 12241 /* This isn't prototyped in OSF 5.0. */
f5d11644
GM
12242 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
12243#endif
12244 }
287f7dd6
GM
12245
12246#else /* not USE_XIM */
12247 dpyinfo->xim = NULL;
12248#endif /* not USE_XIM */
f5d11644
GM
12249}
12250
12251
b9de836c 12252#ifdef HAVE_X11R6_XIM
f5d11644
GM
12253
12254struct xim_inst_t
12255{
12256 struct x_display_info *dpyinfo;
12257 char *resource_name;
12258};
12259
12260/* XIM instantiate callback function, which is called whenever an XIM
12261 server is available. DISPLAY is teh display of the XIM.
12262 CLIENT_DATA contains a pointer to an xim_inst_t structure created
12263 when the callback was registered. */
12264
12265static void
12266xim_instantiate_callback (display, client_data, call_data)
12267 Display *display;
12268 XPointer client_data;
12269 XPointer call_data;
12270{
12271 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
12272 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
12273
12274 /* We don't support multiple XIM connections. */
12275 if (dpyinfo->xim)
12276 return;
12277
12278 xim_open_dpy (dpyinfo, xim_inst->resource_name);
12279
12280 /* Create XIC for the existing frames on the same display, as long
12281 as they have no XIC. */
12282 if (dpyinfo->xim && dpyinfo->reference_count > 0)
12283 {
12284 Lisp_Object tail, frame;
12285
12286 BLOCK_INPUT;
12287 FOR_EACH_FRAME (tail, frame)
12288 {
12289 struct frame *f = XFRAME (frame);
12290
12291 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
12292 if (FRAME_XIC (f) == NULL)
12293 {
12294 create_frame_xic (f);
12295 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
12296 xic_set_statusarea (f);
12297 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
12298 {
12299 struct window *w = XWINDOW (f->selected_window);
12300 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
12301 }
12302 }
12303 }
12304
12305 UNBLOCK_INPUT;
12306 }
12307}
12308
b9de836c 12309#endif /* HAVE_X11R6_XIM */
f5d11644
GM
12310
12311
12312/* Open a connection to the XIM server on display DPYINFO.
12313 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
12314 connection only at the first time. On X11R6, open the connection
12315 in the XIM instantiate callback function. */
12316
12317static void
12318xim_initialize (dpyinfo, resource_name)
12319 struct x_display_info *dpyinfo;
12320 char *resource_name;
12321{
287f7dd6 12322#ifdef USE_XIM
b9de836c 12323#ifdef HAVE_X11R6_XIM
f5d11644
GM
12324 struct xim_inst_t *xim_inst;
12325 int len;
12326
12327 dpyinfo->xim = NULL;
12328 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
12329 xim_inst->dpyinfo = dpyinfo;
12330 len = strlen (resource_name);
12331 xim_inst->resource_name = (char *) xmalloc (len + 1);
12332 bcopy (resource_name, xim_inst->resource_name, len + 1);
12333 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12334 resource_name, EMACS_CLASS,
12335 xim_instantiate_callback,
2ebb2f8b
DL
12336 /* Fixme: This is XPointer in
12337 XFree86 but (XPointer *) on
12338 Tru64, at least. */
12339 (XPointer) xim_inst);
b9de836c 12340#else /* not HAVE_X11R6_XIM */
f5d11644
GM
12341 dpyinfo->xim = NULL;
12342 xim_open_dpy (dpyinfo, resource_name);
b9de836c 12343#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
12344
12345#else /* not USE_XIM */
12346 dpyinfo->xim = NULL;
12347#endif /* not USE_XIM */
f5d11644
GM
12348}
12349
12350
12351/* Close the connection to the XIM server on display DPYINFO. */
12352
12353static void
12354xim_close_dpy (dpyinfo)
12355 struct x_display_info *dpyinfo;
12356{
287f7dd6 12357#ifdef USE_XIM
b9de836c 12358#ifdef HAVE_X11R6_XIM
8a4f36cc
GM
12359 if (dpyinfo->display)
12360 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12361 NULL, EMACS_CLASS,
12362 xim_instantiate_callback, NULL);
b9de836c 12363#endif /* not HAVE_X11R6_XIM */
8a4f36cc
GM
12364 if (dpyinfo->display)
12365 XCloseIM (dpyinfo->xim);
f5d11644
GM
12366 dpyinfo->xim = NULL;
12367 XFree (dpyinfo->xim_styles);
287f7dd6 12368#endif /* USE_XIM */
f5d11644
GM
12369}
12370
b9de836c 12371#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
12372
12373
dc6f92b8 12374\f
2e365682
RS
12375/* Calculate the absolute position in frame F
12376 from its current recorded position values and gravity. */
12377
dfcf069d 12378void
43bca5d5 12379x_calc_absolute_position (f)
f676886a 12380 struct frame *f;
dc6f92b8 12381{
06a2c219 12382 Window child;
6dba1858 12383 int win_x = 0, win_y = 0;
7556890b 12384 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
12385 int this_window;
12386
9829ddba
RS
12387 /* We have nothing to do if the current position
12388 is already for the top-left corner. */
12389 if (! ((flags & XNegative) || (flags & YNegative)))
12390 return;
12391
c81412a0 12392#ifdef USE_X_TOOLKIT
7556890b 12393 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
12394#else
12395 this_window = FRAME_X_WINDOW (f);
12396#endif
6dba1858
RS
12397
12398 /* Find the position of the outside upper-left corner of
9829ddba
RS
12399 the inner window, with respect to the outer window.
12400 But do this only if we will need the results. */
7556890b 12401 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 12402 {
9829ddba
RS
12403 int count;
12404
6dba1858 12405 BLOCK_INPUT;
9829ddba
RS
12406 count = x_catch_errors (FRAME_X_DISPLAY (f));
12407 while (1)
12408 {
12409 x_clear_errors (FRAME_X_DISPLAY (f));
12410 XTranslateCoordinates (FRAME_X_DISPLAY (f),
12411
12412 /* From-window, to-window. */
12413 this_window,
12414 f->output_data.x->parent_desc,
12415
12416 /* From-position, to-position. */
12417 0, 0, &win_x, &win_y,
12418
12419 /* Child of win. */
12420 &child);
12421 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12422 {
12423 Window newroot, newparent = 0xdeadbeef;
12424 Window *newchildren;
2ebb2f8b 12425 unsigned int nchildren;
9829ddba
RS
12426
12427 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
12428 &newparent, &newchildren, &nchildren))
12429 break;
58769bee 12430
7c3c78a3 12431 XFree ((char *) newchildren);
6dba1858 12432
9829ddba
RS
12433 f->output_data.x->parent_desc = newparent;
12434 }
12435 else
12436 break;
12437 }
6dba1858 12438
9829ddba 12439 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
12440 UNBLOCK_INPUT;
12441 }
12442
12443 /* Treat negative positions as relative to the leftmost bottommost
12444 position that fits on the screen. */
20f55f9a 12445 if (flags & XNegative)
7556890b 12446 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
12447 - 2 * f->output_data.x->border_width - win_x
12448 - PIXEL_WIDTH (f)
12449 + f->output_data.x->left_pos);
dc6f92b8 12450
7708ced0
GM
12451 {
12452 int height = PIXEL_HEIGHT (f);
06a2c219 12453
7708ced0
GM
12454#if defined USE_X_TOOLKIT && defined USE_MOTIF
12455 /* Something is fishy here. When using Motif, starting Emacs with
12456 `-g -0-0', the frame appears too low by a few pixels.
12457
12458 This seems to be so because initially, while Emacs is starting,
12459 the column widget's height and the frame's pixel height are
12460 different. The column widget's height is the right one. In
12461 later invocations, when Emacs is up, the frame's pixel height
12462 is right, though.
12463
12464 It's not obvious where the initial small difference comes from.
12465 2000-12-01, gerd. */
12466
12467 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
06a2c219 12468#endif
2e365682 12469
7708ced0
GM
12470 if (flags & YNegative)
12471 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
12472 - 2 * f->output_data.x->border_width
12473 - win_y
12474 - height
12475 + f->output_data.x->top_pos);
12476 }
12477
3a35ab44
RS
12478 /* The left_pos and top_pos
12479 are now relative to the top and left screen edges,
12480 so the flags should correspond. */
7556890b 12481 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
12482}
12483
3a35ab44
RS
12484/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
12485 to really change the position, and 0 when calling from
12486 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
12487 position values). It is -1 when calling from x_set_frame_parameters,
12488 which means, do adjust for borders but don't change the gravity. */
3a35ab44 12489
dfcf069d 12490void
dc05a16b 12491x_set_offset (f, xoff, yoff, change_gravity)
f676886a 12492 struct frame *f;
dc6f92b8 12493 register int xoff, yoff;
dc05a16b 12494 int change_gravity;
dc6f92b8 12495{
4a4cbdd5
KH
12496 int modified_top, modified_left;
12497
aa3ff7c9 12498 if (change_gravity > 0)
3a35ab44 12499 {
7556890b
RS
12500 f->output_data.x->top_pos = yoff;
12501 f->output_data.x->left_pos = xoff;
12502 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 12503 if (xoff < 0)
7556890b 12504 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 12505 if (yoff < 0)
7556890b
RS
12506 f->output_data.x->size_hint_flags |= YNegative;
12507 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 12508 }
43bca5d5 12509 x_calc_absolute_position (f);
dc6f92b8
JB
12510
12511 BLOCK_INPUT;
c32cdd9a 12512 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 12513
7556890b
RS
12514 modified_left = f->output_data.x->left_pos;
12515 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
12516#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
12517 this seems to be unnecessary and incorrect. rms, 4/17/97. */
12518 /* It is a mystery why we need to add the border_width here
12519 when the frame is already visible, but experiment says we do. */
aa3ff7c9 12520 if (change_gravity != 0)
4a4cbdd5 12521 {
7556890b
RS
12522 modified_left += f->output_data.x->border_width;
12523 modified_top += f->output_data.x->border_width;
4a4cbdd5 12524 }
e73ec6fa 12525#endif
4a4cbdd5 12526
3afe33e7 12527#ifdef USE_X_TOOLKIT
7556890b 12528 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 12529 modified_left, modified_top);
3afe33e7 12530#else /* not USE_X_TOOLKIT */
334208b7 12531 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 12532 modified_left, modified_top);
3afe33e7 12533#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12534 UNBLOCK_INPUT;
12535}
12536
dc6f92b8 12537
499b1844
GM
12538/* Change the size of frame F's X window to COLS/ROWS in the case F
12539 doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
12540 top-left-corner window gravity for this size change and subsequent
12541 size changes. Otherwise we leave the window gravity unchanged. */
12542
12543static void
12544x_set_window_size_1 (f, change_gravity, cols, rows)
f676886a 12545 struct frame *f;
bc20ebbf 12546 int change_gravity;
b1c884c3 12547 int cols, rows;
dc6f92b8
JB
12548{
12549 int pixelwidth, pixelheight;
80fd1fe2 12550
b1c884c3 12551 check_frame_size (f, &rows, &cols);
7556890b 12552 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
12553 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
12554 ? 0
12555 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 12556 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 12557 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 12558 f->output_data.x->flags_areas_extra
110859fc 12559 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
12560 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
12561 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 12562
7556890b 12563 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 12564 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 12565
334208b7
RS
12566 XSync (FRAME_X_DISPLAY (f), False);
12567 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12568 pixelwidth, pixelheight);
b1c884c3
JB
12569
12570 /* Now, strictly speaking, we can't be sure that this is accurate,
12571 but the window manager will get around to dealing with the size
12572 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
12573 ConfigureNotify event gets here.
12574
12575 We could just not bother storing any of this information here,
12576 and let the ConfigureNotify event set everything up, but that
fddd5ceb 12577 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 12578 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
12579 point in the future when the ConfigureNotify event arrives.
12580
12581 We pass 1 for DELAY since we can't run Lisp code inside of
12582 a BLOCK_INPUT. */
7d1e984f 12583 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
12584 PIXEL_WIDTH (f) = pixelwidth;
12585 PIXEL_HEIGHT (f) = pixelheight;
12586
aee9a898
RS
12587 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
12588 receive in the ConfigureNotify event; if we get what we asked
12589 for, then the event won't cause the screen to become garbaged, so
12590 we have to make sure to do it here. */
12591 SET_FRAME_GARBAGED (f);
12592
12593 XFlush (FRAME_X_DISPLAY (f));
499b1844
GM
12594}
12595
12596
12597/* Call this to change the size of frame F's x-window.
12598 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
12599 for this size change and subsequent size changes.
12600 Otherwise we leave the window gravity unchanged. */
aee9a898 12601
499b1844
GM
12602void
12603x_set_window_size (f, change_gravity, cols, rows)
12604 struct frame *f;
12605 int change_gravity;
12606 int cols, rows;
12607{
12608 BLOCK_INPUT;
12609
12610#ifdef USE_X_TOOLKIT
12611
f1f4d345 12612 if (f->output_data.x->widget != NULL)
499b1844
GM
12613 {
12614 /* The x and y position of the widget is clobbered by the
12615 call to XtSetValues within EmacsFrameSetCharSize.
12616 This is a real kludge, but I don't understand Xt so I can't
12617 figure out a correct fix. Can anyone else tell me? -- rms. */
12618 int xpos = f->output_data.x->widget->core.x;
12619 int ypos = f->output_data.x->widget->core.y;
12620 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
12621 f->output_data.x->widget->core.x = xpos;
12622 f->output_data.x->widget->core.y = ypos;
12623 }
12624 else
12625 x_set_window_size_1 (f, change_gravity, cols, rows);
12626
12627#else /* not USE_X_TOOLKIT */
12628
12629 x_set_window_size_1 (f, change_gravity, cols, rows);
12630
aee9a898
RS
12631#endif /* not USE_X_TOOLKIT */
12632
4d73d038 12633 /* If cursor was outside the new size, mark it as off. */
06a2c219 12634 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 12635
aee9a898
RS
12636 /* Clear out any recollection of where the mouse highlighting was,
12637 since it might be in a place that's outside the new frame size.
12638 Actually checking whether it is outside is a pain in the neck,
12639 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 12640 cancel_mouse_face (f);
dbc4e1c1 12641
dc6f92b8
JB
12642 UNBLOCK_INPUT;
12643}
dc6f92b8 12644\f
d047c4eb 12645/* Mouse warping. */
dc6f92b8 12646
9b378208 12647void
f676886a
JB
12648x_set_mouse_position (f, x, y)
12649 struct frame *f;
dc6f92b8
JB
12650 int x, y;
12651{
12652 int pix_x, pix_y;
12653
7556890b
RS
12654 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
12655 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
12656
12657 if (pix_x < 0) pix_x = 0;
12658 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
12659
12660 if (pix_y < 0) pix_y = 0;
12661 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
12662
12663 BLOCK_INPUT;
dc6f92b8 12664
334208b7
RS
12665 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12666 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
12667 UNBLOCK_INPUT;
12668}
12669
9b378208
RS
12670/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
12671
12672void
12673x_set_mouse_pixel_position (f, pix_x, pix_y)
12674 struct frame *f;
12675 int pix_x, pix_y;
12676{
12677 BLOCK_INPUT;
12678
334208b7
RS
12679 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12680 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
12681 UNBLOCK_INPUT;
12682}
d047c4eb
KH
12683\f
12684/* focus shifting, raising and lowering. */
9b378208 12685
dfcf069d 12686void
f676886a
JB
12687x_focus_on_frame (f)
12688 struct frame *f;
dc6f92b8 12689{
1fb20991 12690#if 0 /* This proves to be unpleasant. */
f676886a 12691 x_raise_frame (f);
1fb20991 12692#endif
6d4238f3
JB
12693#if 0
12694 /* I don't think that the ICCCM allows programs to do things like this
12695 without the interaction of the window manager. Whatever you end up
f676886a 12696 doing with this code, do it to x_unfocus_frame too. */
334208b7 12697 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 12698 RevertToPointerRoot, CurrentTime);
c118dd06 12699#endif /* ! 0 */
dc6f92b8
JB
12700}
12701
dfcf069d 12702void
f676886a
JB
12703x_unfocus_frame (f)
12704 struct frame *f;
dc6f92b8 12705{
6d4238f3 12706#if 0
f676886a 12707 /* Look at the remarks in x_focus_on_frame. */
0f941935 12708 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 12709 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 12710 RevertToPointerRoot, CurrentTime);
c118dd06 12711#endif /* ! 0 */
dc6f92b8
JB
12712}
12713
f676886a 12714/* Raise frame F. */
dc6f92b8 12715
dfcf069d 12716void
f676886a
JB
12717x_raise_frame (f)
12718 struct frame *f;
dc6f92b8 12719{
3a88c238 12720 if (f->async_visible)
dc6f92b8
JB
12721 {
12722 BLOCK_INPUT;
3afe33e7 12723#ifdef USE_X_TOOLKIT
7556890b 12724 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12725#else /* not USE_X_TOOLKIT */
334208b7 12726 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12727#endif /* not USE_X_TOOLKIT */
334208b7 12728 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12729 UNBLOCK_INPUT;
12730 }
12731}
12732
f676886a 12733/* Lower frame F. */
dc6f92b8 12734
dfcf069d 12735void
f676886a
JB
12736x_lower_frame (f)
12737 struct frame *f;
dc6f92b8 12738{
3a88c238 12739 if (f->async_visible)
dc6f92b8
JB
12740 {
12741 BLOCK_INPUT;
3afe33e7 12742#ifdef USE_X_TOOLKIT
7556890b 12743 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12744#else /* not USE_X_TOOLKIT */
334208b7 12745 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12746#endif /* not USE_X_TOOLKIT */
334208b7 12747 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12748 UNBLOCK_INPUT;
12749 }
12750}
12751
dbc4e1c1 12752static void
6b0442dc 12753XTframe_raise_lower (f, raise_flag)
dbc4e1c1 12754 FRAME_PTR f;
6b0442dc 12755 int raise_flag;
dbc4e1c1 12756{
6b0442dc 12757 if (raise_flag)
dbc4e1c1
JB
12758 x_raise_frame (f);
12759 else
12760 x_lower_frame (f);
12761}
d047c4eb
KH
12762\f
12763/* Change of visibility. */
dc6f92b8 12764
9382638d
KH
12765/* This tries to wait until the frame is really visible.
12766 However, if the window manager asks the user where to position
12767 the frame, this will return before the user finishes doing that.
12768 The frame will not actually be visible at that time,
12769 but it will become visible later when the window manager
12770 finishes with it. */
12771
dfcf069d 12772void
f676886a
JB
12773x_make_frame_visible (f)
12774 struct frame *f;
dc6f92b8 12775{
990ba854 12776 Lisp_Object type;
1aa6072f 12777 int original_top, original_left;
31be9251
GM
12778 int retry_count = 2;
12779
12780 retry:
dc6f92b8 12781
dc6f92b8 12782 BLOCK_INPUT;
dc6f92b8 12783
990ba854
RS
12784 type = x_icon_type (f);
12785 if (!NILP (type))
12786 x_bitmap_icon (f, type);
bdcd49ba 12787
f676886a 12788 if (! FRAME_VISIBLE_P (f))
90e65f07 12789 {
1aa6072f
RS
12790 /* We test FRAME_GARBAGED_P here to make sure we don't
12791 call x_set_offset a second time
12792 if we get to x_make_frame_visible a second time
12793 before the window gets really visible. */
12794 if (! FRAME_ICONIFIED_P (f)
12795 && ! f->output_data.x->asked_for_visible)
12796 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
12797
12798 f->output_data.x->asked_for_visible = 1;
12799
90e65f07 12800 if (! EQ (Vx_no_window_manager, Qt))
f676886a 12801 x_wm_set_window_state (f, NormalState);
3afe33e7 12802#ifdef USE_X_TOOLKIT
d7a38a2e 12803 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 12804 XtMapWidget (f->output_data.x->widget);
3afe33e7 12805#else /* not USE_X_TOOLKIT */
7f9c7f94 12806 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12807#endif /* not USE_X_TOOLKIT */
0134a210
RS
12808#if 0 /* This seems to bring back scroll bars in the wrong places
12809 if the window configuration has changed. They seem
12810 to come back ok without this. */
ab648270 12811 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 12812 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 12813#endif
90e65f07 12814 }
dc6f92b8 12815
334208b7 12816 XFlush (FRAME_X_DISPLAY (f));
90e65f07 12817
0dacf791
RS
12818 /* Synchronize to ensure Emacs knows the frame is visible
12819 before we do anything else. We do this loop with input not blocked
12820 so that incoming events are handled. */
12821 {
12822 Lisp_Object frame;
12ce2351 12823 int count;
28c01ffe
RS
12824 /* This must be before UNBLOCK_INPUT
12825 since events that arrive in response to the actions above
12826 will set it when they are handled. */
12827 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
12828
12829 original_left = f->output_data.x->left_pos;
12830 original_top = f->output_data.x->top_pos;
c0a04927
RS
12831
12832 /* This must come after we set COUNT. */
12833 UNBLOCK_INPUT;
12834
2745e6c4 12835 /* We unblock here so that arriving X events are processed. */
1aa6072f 12836
dcb07ae9
RS
12837 /* Now move the window back to where it was "supposed to be".
12838 But don't do it if the gravity is negative.
12839 When the gravity is negative, this uses a position
28c01ffe
RS
12840 that is 3 pixels too low. Perhaps that's really the border width.
12841
12842 Don't do this if the window has never been visible before,
12843 because the window manager may choose the position
12844 and we don't want to override it. */
1aa6072f 12845
4d3f5d9a 12846 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 12847 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 12848 && previously_visible)
1aa6072f 12849 {
2745e6c4
RS
12850 Drawable rootw;
12851 int x, y;
12852 unsigned int width, height, border, depth;
06a2c219 12853
1aa6072f 12854 BLOCK_INPUT;
9829ddba 12855
06a2c219
GM
12856 /* On some window managers (such as FVWM) moving an existing
12857 window, even to the same place, causes the window manager
12858 to introduce an offset. This can cause the window to move
12859 to an unexpected location. Check the geometry (a little
12860 slow here) and then verify that the window is in the right
12861 place. If the window is not in the right place, move it
12862 there, and take the potential window manager hit. */
2745e6c4
RS
12863 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12864 &rootw, &x, &y, &width, &height, &border, &depth);
12865
12866 if (original_left != x || original_top != y)
12867 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12868 original_left, original_top);
12869
1aa6072f
RS
12870 UNBLOCK_INPUT;
12871 }
9829ddba 12872
e0c1aef2 12873 XSETFRAME (frame, f);
c0a04927 12874
12ce2351
GM
12875 /* Wait until the frame is visible. Process X events until a
12876 MapNotify event has been seen, or until we think we won't get a
12877 MapNotify at all.. */
12878 for (count = input_signal_count + 10;
12879 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 12880 {
12ce2351 12881 /* Force processing of queued events. */
334208b7 12882 x_sync (f);
12ce2351
GM
12883
12884 /* Machines that do polling rather than SIGIO have been
12885 observed to go into a busy-wait here. So we'll fake an
12886 alarm signal to let the handler know that there's something
12887 to be read. We used to raise a real alarm, but it seems
12888 that the handler isn't always enabled here. This is
12889 probably a bug. */
8b2f8d4e 12890 if (input_polling_used ())
3b2fa4e6 12891 {
12ce2351
GM
12892 /* It could be confusing if a real alarm arrives while
12893 processing the fake one. Turn it off and let the
12894 handler reset it. */
3e71d8f2 12895 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
12896 int old_poll_suppress_count = poll_suppress_count;
12897 poll_suppress_count = 1;
12898 poll_for_input_1 ();
12899 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 12900 }
12ce2351
GM
12901
12902 /* See if a MapNotify event has been processed. */
12903 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 12904 }
31be9251
GM
12905
12906 /* 2000-09-28: In
12907
12908 (let ((f (selected-frame)))
12909 (iconify-frame f)
12910 (raise-frame f))
12911
12912 the frame is not raised with various window managers on
12913 FreeBSD, Linux and Solaris. It turns out that, for some
12914 unknown reason, the call to XtMapWidget is completely ignored.
12915 Mapping the widget a second time works. */
12916
12917 if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
12918 goto retry;
0dacf791 12919 }
dc6f92b8
JB
12920}
12921
06a2c219 12922/* Change from mapped state to withdrawn state. */
dc6f92b8 12923
d047c4eb
KH
12924/* Make the frame visible (mapped and not iconified). */
12925
dfcf069d 12926void
f676886a
JB
12927x_make_frame_invisible (f)
12928 struct frame *f;
dc6f92b8 12929{
546e6d5b
RS
12930 Window window;
12931
12932#ifdef USE_X_TOOLKIT
12933 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 12934 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
12935#else /* not USE_X_TOOLKIT */
12936 window = FRAME_X_WINDOW (f);
12937#endif /* not USE_X_TOOLKIT */
dc6f92b8 12938
9319ae23 12939 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
12940 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
12941 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 12942
5627c40e 12943#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 12944 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 12945 return;
5627c40e 12946#endif
dc6f92b8
JB
12947
12948 BLOCK_INPUT;
c118dd06 12949
af31d76f
RS
12950 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
12951 that the current position of the window is user-specified, rather than
12952 program-specified, so that when the window is mapped again, it will be
12953 placed at the same location, without forcing the user to position it
12954 by hand again (they have already done that once for this window.) */
c32cdd9a 12955 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 12956
c118dd06
JB
12957#ifdef HAVE_X11R4
12958
334208b7
RS
12959 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
12960 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
12961 {
12962 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12963 error ("Can't notify window manager of window withdrawal");
c118dd06 12964 }
c118dd06 12965#else /* ! defined (HAVE_X11R4) */
16bd92ea 12966
c118dd06 12967 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
12968 if (! EQ (Vx_no_window_manager, Qt))
12969 {
16bd92ea 12970 XEvent unmap;
dc6f92b8 12971
16bd92ea 12972 unmap.xunmap.type = UnmapNotify;
546e6d5b 12973 unmap.xunmap.window = window;
334208b7 12974 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 12975 unmap.xunmap.from_configure = False;
334208b7
RS
12976 if (! XSendEvent (FRAME_X_DISPLAY (f),
12977 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 12978 False,
06a2c219 12979 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
12980 &unmap))
12981 {
12982 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12983 error ("Can't notify window manager of withdrawal");
16bd92ea 12984 }
dc6f92b8
JB
12985 }
12986
16bd92ea 12987 /* Unmap the window ourselves. Cheeky! */
334208b7 12988 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 12989#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 12990
5627c40e
RS
12991 /* We can't distinguish this from iconification
12992 just by the event that we get from the server.
12993 So we can't win using the usual strategy of letting
12994 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
12995 and synchronize with the server to make sure we agree. */
12996 f->visible = 0;
12997 FRAME_ICONIFIED_P (f) = 0;
12998 f->async_visible = 0;
12999 f->async_iconified = 0;
13000
334208b7 13001 x_sync (f);
5627c40e 13002
dc6f92b8
JB
13003 UNBLOCK_INPUT;
13004}
13005
06a2c219 13006/* Change window state from mapped to iconified. */
dc6f92b8 13007
dfcf069d 13008void
f676886a
JB
13009x_iconify_frame (f)
13010 struct frame *f;
dc6f92b8 13011{
3afe33e7 13012 int result;
990ba854 13013 Lisp_Object type;
dc6f92b8 13014
9319ae23 13015 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
13016 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
13017 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 13018
3a88c238 13019 if (f->async_iconified)
dc6f92b8
JB
13020 return;
13021
3afe33e7 13022 BLOCK_INPUT;
546e6d5b 13023
9af3143a
RS
13024 FRAME_SAMPLE_VISIBILITY (f);
13025
990ba854
RS
13026 type = x_icon_type (f);
13027 if (!NILP (type))
13028 x_bitmap_icon (f, type);
bdcd49ba
RS
13029
13030#ifdef USE_X_TOOLKIT
13031
546e6d5b
RS
13032 if (! FRAME_VISIBLE_P (f))
13033 {
13034 if (! EQ (Vx_no_window_manager, Qt))
13035 x_wm_set_window_state (f, IconicState);
13036 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 13037 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
13038 /* The server won't give us any event to indicate
13039 that an invisible frame was changed to an icon,
13040 so we have to record it here. */
13041 f->iconified = 1;
1e6bc770 13042 f->visible = 1;
9cf30a30 13043 f->async_iconified = 1;
1e6bc770 13044 f->async_visible = 0;
546e6d5b
RS
13045 UNBLOCK_INPUT;
13046 return;
13047 }
13048
334208b7 13049 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 13050 XtWindow (f->output_data.x->widget),
334208b7 13051 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
13052 UNBLOCK_INPUT;
13053
13054 if (!result)
546e6d5b 13055 error ("Can't notify window manager of iconification");
3afe33e7
RS
13056
13057 f->async_iconified = 1;
1e6bc770
RS
13058 f->async_visible = 0;
13059
8c002a25
KH
13060
13061 BLOCK_INPUT;
334208b7 13062 XFlush (FRAME_X_DISPLAY (f));
8c002a25 13063 UNBLOCK_INPUT;
3afe33e7
RS
13064#else /* not USE_X_TOOLKIT */
13065
fd13dbb2
RS
13066 /* Make sure the X server knows where the window should be positioned,
13067 in case the user deiconifies with the window manager. */
13068 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 13069 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 13070
16bd92ea
JB
13071 /* Since we don't know which revision of X we're running, we'll use both
13072 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
13073
13074 /* X11R4: send a ClientMessage to the window manager using the
13075 WM_CHANGE_STATE type. */
13076 {
13077 XEvent message;
58769bee 13078
c118dd06 13079 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 13080 message.xclient.type = ClientMessage;
334208b7 13081 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
13082 message.xclient.format = 32;
13083 message.xclient.data.l[0] = IconicState;
13084
334208b7
RS
13085 if (! XSendEvent (FRAME_X_DISPLAY (f),
13086 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
13087 False,
13088 SubstructureRedirectMask | SubstructureNotifyMask,
13089 &message))
dc6f92b8
JB
13090 {
13091 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13092 error ("Can't notify window manager of iconification");
dc6f92b8 13093 }
16bd92ea 13094 }
dc6f92b8 13095
58769bee 13096 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
13097 IconicState. */
13098 x_wm_set_window_state (f, IconicState);
dc6f92b8 13099
a9c00105
RS
13100 if (!FRAME_VISIBLE_P (f))
13101 {
13102 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 13103 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
13104 }
13105
3a88c238 13106 f->async_iconified = 1;
1e6bc770 13107 f->async_visible = 0;
dc6f92b8 13108
334208b7 13109 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 13110 UNBLOCK_INPUT;
8c002a25 13111#endif /* not USE_X_TOOLKIT */
dc6f92b8 13112}
19f71add 13113
d047c4eb 13114\f
19f71add 13115/* Free X resources of frame F. */
dc6f92b8 13116
dfcf069d 13117void
19f71add 13118x_free_frame_resources (f)
f676886a 13119 struct frame *f;
dc6f92b8 13120{
7f9c7f94
RS
13121 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13122
dc6f92b8 13123 BLOCK_INPUT;
c0ff3fab 13124
6186a4a0
RS
13125 /* If a display connection is dead, don't try sending more
13126 commands to the X server. */
19f71add 13127 if (dpyinfo->display)
6186a4a0 13128 {
19f71add 13129 if (f->output_data.x->icon_desc)
6186a4a0 13130 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
19f71add 13131
31f41daf 13132#ifdef HAVE_X_I18N
f5d11644
GM
13133 if (FRAME_XIC (f))
13134 free_frame_xic (f);
31f41daf 13135#endif
19f71add 13136
2662734b 13137 if (FRAME_X_WINDOW (f))
19f71add
GM
13138 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13139
3afe33e7 13140#ifdef USE_X_TOOLKIT
06a2c219 13141 if (f->output_data.x->widget)
30ca89f5
GM
13142 {
13143 XtDestroyWidget (f->output_data.x->widget);
13144 f->output_data.x->widget = NULL;
13145 }
6186a4a0 13146 free_frame_menubar (f);
3afe33e7
RS
13147#endif /* USE_X_TOOLKIT */
13148
3e71d8f2
GM
13149 unload_color (f, f->output_data.x->foreground_pixel);
13150 unload_color (f, f->output_data.x->background_pixel);
13151 unload_color (f, f->output_data.x->cursor_pixel);
13152 unload_color (f, f->output_data.x->cursor_foreground_pixel);
13153 unload_color (f, f->output_data.x->border_pixel);
13154 unload_color (f, f->output_data.x->mouse_pixel);
19f71add 13155
3e71d8f2
GM
13156 if (f->output_data.x->scroll_bar_background_pixel != -1)
13157 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
13158 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
13159 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
7c1bef7a
MB
13160#ifdef USE_TOOLKIT_SCROLL_BARS
13161 /* Scrollbar shadow colors. */
13162 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
13163 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
13164 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
13165 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
13166#endif /* USE_TOOLKIT_SCROLL_BARS */
3e71d8f2
GM
13167 if (f->output_data.x->white_relief.allocated_p)
13168 unload_color (f, f->output_data.x->white_relief.pixel);
13169 if (f->output_data.x->black_relief.allocated_p)
13170 unload_color (f, f->output_data.x->black_relief.pixel);
4ca78676 13171
19f71add
GM
13172 if (FRAME_FACE_CACHE (f))
13173 free_frame_faces (f);
13174
4ca78676 13175 x_free_gcs (f);
6186a4a0
RS
13176 XFlush (FRAME_X_DISPLAY (f));
13177 }
dc6f92b8 13178
df89d8a4 13179 if (f->output_data.x->saved_menu_event)
06a2c219 13180 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 13181
7556890b 13182 xfree (f->output_data.x);
19f71add
GM
13183 f->output_data.x = NULL;
13184
0f941935
KH
13185 if (f == dpyinfo->x_focus_frame)
13186 dpyinfo->x_focus_frame = 0;
13187 if (f == dpyinfo->x_focus_event_frame)
13188 dpyinfo->x_focus_event_frame = 0;
13189 if (f == dpyinfo->x_highlight_frame)
13190 dpyinfo->x_highlight_frame = 0;
c0ff3fab 13191
7f9c7f94 13192 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 13193 {
7f9c7f94
RS
13194 dpyinfo->mouse_face_beg_row
13195 = dpyinfo->mouse_face_beg_col = -1;
13196 dpyinfo->mouse_face_end_row
13197 = dpyinfo->mouse_face_end_col = -1;
13198 dpyinfo->mouse_face_window = Qnil;
21323706
RS
13199 dpyinfo->mouse_face_deferred_gc = 0;
13200 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 13201 }
0134a210 13202
c0ff3fab 13203 UNBLOCK_INPUT;
dc6f92b8 13204}
19f71add
GM
13205
13206
13207/* Destroy the X window of frame F. */
13208
13209void
13210x_destroy_window (f)
13211 struct frame *f;
13212{
13213 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13214
13215 /* If a display connection is dead, don't try sending more
13216 commands to the X server. */
13217 if (dpyinfo->display != 0)
13218 x_free_frame_resources (f);
13219
13220 dpyinfo->reference_count--;
13221}
13222
dc6f92b8 13223\f
f451eb13
JB
13224/* Setting window manager hints. */
13225
af31d76f
RS
13226/* Set the normal size hints for the window manager, for frame F.
13227 FLAGS is the flags word to use--or 0 meaning preserve the flags
13228 that the window now has.
13229 If USER_POSITION is nonzero, we set the USPosition
13230 flag (this is useful when FLAGS is 0). */
6dba1858 13231
dfcf069d 13232void
af31d76f 13233x_wm_set_size_hint (f, flags, user_position)
f676886a 13234 struct frame *f;
af31d76f
RS
13235 long flags;
13236 int user_position;
dc6f92b8
JB
13237{
13238 XSizeHints size_hints;
3afe33e7
RS
13239
13240#ifdef USE_X_TOOLKIT
7e4f2521
FP
13241 Arg al[2];
13242 int ac = 0;
13243 Dimension widget_width, widget_height;
7556890b 13244 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 13245#else /* not USE_X_TOOLKIT */
c118dd06 13246 Window window = FRAME_X_WINDOW (f);
3afe33e7 13247#endif /* not USE_X_TOOLKIT */
dc6f92b8 13248
b72a58fd
RS
13249 /* Setting PMaxSize caused various problems. */
13250 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 13251
7556890b
RS
13252 size_hints.x = f->output_data.x->left_pos;
13253 size_hints.y = f->output_data.x->top_pos;
7553a6b7 13254
7e4f2521
FP
13255#ifdef USE_X_TOOLKIT
13256 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
13257 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 13258 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
13259 size_hints.height = widget_height;
13260 size_hints.width = widget_width;
13261#else /* not USE_X_TOOLKIT */
f676886a
JB
13262 size_hints.height = PIXEL_HEIGHT (f);
13263 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 13264#endif /* not USE_X_TOOLKIT */
7553a6b7 13265
7556890b
RS
13266 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
13267 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
13268 size_hints.max_width
13269 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
13270 size_hints.max_height
13271 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 13272
d067ea8b
KH
13273 /* Calculate the base and minimum sizes.
13274
13275 (When we use the X toolkit, we don't do it here.
13276 Instead we copy the values that the widgets are using, below.) */
13277#ifndef USE_X_TOOLKIT
b1c884c3 13278 {
b0342f17 13279 int base_width, base_height;
0134a210 13280 int min_rows = 0, min_cols = 0;
b0342f17 13281
f451eb13
JB
13282 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
13283 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 13284
0134a210 13285 check_frame_size (f, &min_rows, &min_cols);
b0342f17 13286
0134a210
RS
13287 /* The window manager uses the base width hints to calculate the
13288 current number of rows and columns in the frame while
13289 resizing; min_width and min_height aren't useful for this
13290 purpose, since they might not give the dimensions for a
13291 zero-row, zero-column frame.
58769bee 13292
0134a210
RS
13293 We use the base_width and base_height members if we have
13294 them; otherwise, we set the min_width and min_height members
13295 to the size for a zero x zero frame. */
b0342f17
JB
13296
13297#ifdef HAVE_X11R4
0134a210
RS
13298 size_hints.flags |= PBaseSize;
13299 size_hints.base_width = base_width;
13300 size_hints.base_height = base_height;
13301 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
13302 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 13303#else
0134a210
RS
13304 size_hints.min_width = base_width;
13305 size_hints.min_height = base_height;
b0342f17 13306#endif
b1c884c3 13307 }
dc6f92b8 13308
d067ea8b 13309 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 13310 if (flags)
dc6f92b8 13311 {
d067ea8b
KH
13312 size_hints.flags |= flags;
13313 goto no_read;
13314 }
13315#endif /* not USE_X_TOOLKIT */
13316
13317 {
13318 XSizeHints hints; /* Sometimes I hate X Windows... */
13319 long supplied_return;
13320 int value;
af31d76f
RS
13321
13322#ifdef HAVE_X11R4
d067ea8b
KH
13323 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
13324 &supplied_return);
af31d76f 13325#else
d067ea8b 13326 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 13327#endif
58769bee 13328
d067ea8b
KH
13329#ifdef USE_X_TOOLKIT
13330 size_hints.base_height = hints.base_height;
13331 size_hints.base_width = hints.base_width;
13332 size_hints.min_height = hints.min_height;
13333 size_hints.min_width = hints.min_width;
13334#endif
13335
13336 if (flags)
13337 size_hints.flags |= flags;
13338 else
13339 {
13340 if (value == 0)
13341 hints.flags = 0;
13342 if (hints.flags & PSize)
13343 size_hints.flags |= PSize;
13344 if (hints.flags & PPosition)
13345 size_hints.flags |= PPosition;
13346 if (hints.flags & USPosition)
13347 size_hints.flags |= USPosition;
13348 if (hints.flags & USSize)
13349 size_hints.flags |= USSize;
13350 }
13351 }
13352
06a2c219 13353#ifndef USE_X_TOOLKIT
d067ea8b 13354 no_read:
06a2c219 13355#endif
0134a210 13356
af31d76f 13357#ifdef PWinGravity
7556890b 13358 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 13359 size_hints.flags |= PWinGravity;
dc05a16b 13360
af31d76f 13361 if (user_position)
6dba1858 13362 {
af31d76f
RS
13363 size_hints.flags &= ~ PPosition;
13364 size_hints.flags |= USPosition;
6dba1858 13365 }
2554751d 13366#endif /* PWinGravity */
6dba1858 13367
b0342f17 13368#ifdef HAVE_X11R4
334208b7 13369 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13370#else
334208b7 13371 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13372#endif
dc6f92b8
JB
13373}
13374
13375/* Used for IconicState or NormalState */
06a2c219 13376
dfcf069d 13377void
f676886a
JB
13378x_wm_set_window_state (f, state)
13379 struct frame *f;
dc6f92b8
JB
13380 int state;
13381{
3afe33e7 13382#ifdef USE_X_TOOLKIT
546e6d5b
RS
13383 Arg al[1];
13384
13385 XtSetArg (al[0], XtNinitialState, state);
7556890b 13386 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 13387#else /* not USE_X_TOOLKIT */
c118dd06 13388 Window window = FRAME_X_WINDOW (f);
dc6f92b8 13389
7556890b
RS
13390 f->output_data.x->wm_hints.flags |= StateHint;
13391 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 13392
7556890b 13393 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 13394#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13395}
13396
dfcf069d 13397void
7f2ae036 13398x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 13399 struct frame *f;
7f2ae036 13400 int pixmap_id;
dc6f92b8 13401{
d2bd6bc4
RS
13402 Pixmap icon_pixmap;
13403
06a2c219 13404#ifndef USE_X_TOOLKIT
c118dd06 13405 Window window = FRAME_X_WINDOW (f);
75231bad 13406#endif
dc6f92b8 13407
7f2ae036 13408 if (pixmap_id > 0)
dbc4e1c1 13409 {
d2bd6bc4 13410 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 13411 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
13412 }
13413 else
68568555
RS
13414 {
13415 /* It seems there is no way to turn off use of an icon pixmap.
13416 The following line does it, only if no icon has yet been created,
13417 for some window managers. But with mwm it crashes.
13418 Some people say it should clear the IconPixmapHint bit in this case,
13419 but that doesn't work, and the X consortium said it isn't the
13420 right thing at all. Since there is no way to win,
13421 best to explicitly give up. */
13422#if 0
13423 f->output_data.x->wm_hints.icon_pixmap = None;
13424#else
13425 return;
13426#endif
13427 }
b1c884c3 13428
d2bd6bc4
RS
13429#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
13430
13431 {
13432 Arg al[1];
13433 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
13434 XtSetValues (f->output_data.x->widget, al, 1);
13435 }
13436
13437#else /* not USE_X_TOOLKIT */
13438
7556890b
RS
13439 f->output_data.x->wm_hints.flags |= IconPixmapHint;
13440 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
13441
13442#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13443}
13444
dfcf069d 13445void
f676886a
JB
13446x_wm_set_icon_position (f, icon_x, icon_y)
13447 struct frame *f;
dc6f92b8
JB
13448 int icon_x, icon_y;
13449{
75231bad 13450#ifdef USE_X_TOOLKIT
7556890b 13451 Window window = XtWindow (f->output_data.x->widget);
75231bad 13452#else
c118dd06 13453 Window window = FRAME_X_WINDOW (f);
75231bad 13454#endif
dc6f92b8 13455
7556890b
RS
13456 f->output_data.x->wm_hints.flags |= IconPositionHint;
13457 f->output_data.x->wm_hints.icon_x = icon_x;
13458 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 13459
7556890b 13460 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
13461}
13462
13463\f
06a2c219
GM
13464/***********************************************************************
13465 Fonts
13466 ***********************************************************************/
dc43ef94
KH
13467
13468/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 13469
dc43ef94
KH
13470struct font_info *
13471x_get_font_info (f, font_idx)
13472 FRAME_PTR f;
13473 int font_idx;
13474{
13475 return (FRAME_X_FONT_TABLE (f) + font_idx);
13476}
13477
13478
9c11f79e
GM
13479/* Return a list of names of available fonts matching PATTERN on frame F.
13480
13481 If SIZE is > 0, it is the size (maximum bounds width) of fonts
13482 to be listed.
13483
13484 SIZE < 0 means include scalable fonts.
13485
13486 Frame F null means we have not yet created any frame on X, and
13487 consult the first display in x_display_list. MAXNAMES sets a limit
13488 on how many fonts to match. */
dc43ef94
KH
13489
13490Lisp_Object
13491x_list_fonts (f, pattern, size, maxnames)
9c11f79e 13492 struct frame *f;
dc43ef94
KH
13493 Lisp_Object pattern;
13494 int size;
13495 int maxnames;
13496{
06a2c219
GM
13497 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
13498 Lisp_Object tem, second_best;
9c11f79e
GM
13499 struct x_display_info *dpyinfo
13500 = f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
13501 Display *dpy = dpyinfo->display;
09c6077f 13502 int try_XLoadQueryFont = 0;
53ca4657 13503 int count;
9c11f79e
GM
13504 int allow_scalable_fonts_p = 0;
13505
13506 if (size < 0)
13507 {
13508 allow_scalable_fonts_p = 1;
13509 size = 0;
13510 }
dc43ef94 13511
6b0efe73 13512 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
13513 if (NILP (patterns))
13514 patterns = Fcons (pattern, Qnil);
81ba44e5 13515
09c6077f
KH
13516 if (maxnames == 1 && !size)
13517 /* We can return any single font matching PATTERN. */
13518 try_XLoadQueryFont = 1;
9a32686f 13519
8e713be6 13520 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 13521 {
dc43ef94 13522 int num_fonts;
3e71d8f2 13523 char **names = NULL;
dc43ef94 13524
8e713be6 13525 pattern = XCAR (patterns);
536f4067
RS
13526 /* See if we cached the result for this particular query.
13527 The cache is an alist of the form:
9c11f79e
GM
13528 ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */
13529 tem = XCDR (dpyinfo->name_list_element);
13530 key = Fcons (Fcons (pattern, make_number (maxnames)),
13531 allow_scalable_fonts_p ? Qt : Qnil);
13532 list = Fassoc (key, tem);
13533 if (!NILP (list))
b5210ea7
KH
13534 {
13535 list = Fcdr_safe (list);
13536 /* We have a cashed list. Don't have to get the list again. */
13537 goto label_cached;
13538 }
13539
13540 /* At first, put PATTERN in the cache. */
09c6077f 13541
dc43ef94 13542 BLOCK_INPUT;
17d85edc
KH
13543 count = x_catch_errors (dpy);
13544
09c6077f
KH
13545 if (try_XLoadQueryFont)
13546 {
13547 XFontStruct *font;
13548 unsigned long value;
13549
13550 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
13551 if (x_had_errors_p (dpy))
13552 {
13553 /* This error is perhaps due to insufficient memory on X
13554 server. Let's just ignore it. */
13555 font = NULL;
13556 x_clear_errors (dpy);
13557 }
13558
09c6077f
KH
13559 if (font
13560 && XGetFontProperty (font, XA_FONT, &value))
13561 {
13562 char *name = (char *) XGetAtomName (dpy, (Atom) value);
13563 int len = strlen (name);
01c752b5 13564 char *tmp;
09c6077f 13565
6f6512e8
KH
13566 /* If DXPC (a Differential X Protocol Compressor)
13567 Ver.3.7 is running, XGetAtomName will return null
13568 string. We must avoid such a name. */
13569 if (len == 0)
13570 try_XLoadQueryFont = 0;
13571 else
13572 {
13573 num_fonts = 1;
13574 names = (char **) alloca (sizeof (char *));
13575 /* Some systems only allow alloca assigned to a
13576 simple var. */
13577 tmp = (char *) alloca (len + 1); names[0] = tmp;
13578 bcopy (name, names[0], len + 1);
13579 XFree (name);
13580 }
09c6077f
KH
13581 }
13582 else
13583 try_XLoadQueryFont = 0;
a083fd23
RS
13584
13585 if (font)
13586 XFreeFont (dpy, font);
09c6077f
KH
13587 }
13588
13589 if (!try_XLoadQueryFont)
17d85edc
KH
13590 {
13591 /* We try at least 10 fonts because XListFonts will return
13592 auto-scaled fonts at the head. */
13593 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
13594 &num_fonts);
13595 if (x_had_errors_p (dpy))
13596 {
13597 /* This error is perhaps due to insufficient memory on X
13598 server. Let's just ignore it. */
13599 names = NULL;
13600 x_clear_errors (dpy);
13601 }
13602 }
13603
13604 x_uncatch_errors (dpy, count);
dc43ef94
KH
13605 UNBLOCK_INPUT;
13606
13607 if (names)
13608 {
13609 int i;
dc43ef94
KH
13610
13611 /* Make a list of all the fonts we got back.
13612 Store that in the font cache for the display. */
13613 for (i = 0; i < num_fonts; i++)
13614 {
06a2c219 13615 int width = 0;
dc43ef94 13616 char *p = names[i];
06a2c219
GM
13617 int average_width = -1, dashes = 0;
13618
dc43ef94 13619 /* Count the number of dashes in NAMES[I]. If there are
9c11f79e
GM
13620 14 dashes, and the field value following 12th dash
13621 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
13622 is usually too ugly to be used for editing. Let's
13623 ignore it. */
dc43ef94
KH
13624 while (*p)
13625 if (*p++ == '-')
13626 {
13627 dashes++;
13628 if (dashes == 7) /* PIXEL_SIZE field */
13629 width = atoi (p);
13630 else if (dashes == 12) /* AVERAGE_WIDTH field */
13631 average_width = atoi (p);
13632 }
9c11f79e
GM
13633
13634 if (allow_scalable_fonts_p
13635 || dashes < 14 || average_width != 0)
dc43ef94
KH
13636 {
13637 tem = build_string (names[i]);
13638 if (NILP (Fassoc (tem, list)))
13639 {
13640 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
13641 && ((fast_c_string_match_ignore_case
13642 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
13643 >= 0))
13644 /* We can set the value of PIXEL_SIZE to the
b5210ea7 13645 width of this font. */
dc43ef94
KH
13646 list = Fcons (Fcons (tem, make_number (width)), list);
13647 else
13648 /* For the moment, width is not known. */
13649 list = Fcons (Fcons (tem, Qnil), list);
13650 }
13651 }
13652 }
e38f4136 13653
09c6077f 13654 if (!try_XLoadQueryFont)
e38f4136
GM
13655 {
13656 BLOCK_INPUT;
13657 XFreeFontNames (names);
13658 UNBLOCK_INPUT;
13659 }
dc43ef94
KH
13660 }
13661
b5210ea7 13662 /* Now store the result in the cache. */
f3fbd155
KR
13663 XSETCDR (dpyinfo->name_list_element,
13664 Fcons (Fcons (key, list), XCDR (dpyinfo->name_list_element)));
dc43ef94 13665
b5210ea7
KH
13666 label_cached:
13667 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 13668
b5210ea7
KH
13669 newlist = second_best = Qnil;
13670 /* Make a list of the fonts that have the right width. */
8e713be6 13671 for (; CONSP (list); list = XCDR (list))
b5210ea7 13672 {
536f4067
RS
13673 int found_size;
13674
8e713be6 13675 tem = XCAR (list);
dc43ef94 13676
8e713be6 13677 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
13678 continue;
13679 if (!size)
13680 {
8e713be6 13681 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
13682 continue;
13683 }
dc43ef94 13684
8e713be6 13685 if (!INTEGERP (XCDR (tem)))
dc43ef94 13686 {
b5210ea7 13687 /* Since we have not yet known the size of this font, we
9c11f79e 13688 must try slow function call XLoadQueryFont. */
dc43ef94
KH
13689 XFontStruct *thisinfo;
13690
13691 BLOCK_INPUT;
17d85edc 13692 count = x_catch_errors (dpy);
dc43ef94 13693 thisinfo = XLoadQueryFont (dpy,
8e713be6 13694 XSTRING (XCAR (tem))->data);
17d85edc
KH
13695 if (x_had_errors_p (dpy))
13696 {
13697 /* This error is perhaps due to insufficient memory on X
13698 server. Let's just ignore it. */
13699 thisinfo = NULL;
13700 x_clear_errors (dpy);
13701 }
13702 x_uncatch_errors (dpy, count);
dc43ef94
KH
13703 UNBLOCK_INPUT;
13704
13705 if (thisinfo)
13706 {
f3fbd155
KR
13707 XSETCDR (tem,
13708 (thisinfo->min_bounds.width == 0
13709 ? make_number (0)
13710 : make_number (thisinfo->max_bounds.width)));
e38f4136 13711 BLOCK_INPUT;
dc43ef94 13712 XFreeFont (dpy, thisinfo);
e38f4136 13713 UNBLOCK_INPUT;
dc43ef94
KH
13714 }
13715 else
b5210ea7 13716 /* For unknown reason, the previous call of XListFont had
06a2c219 13717 returned a font which can't be opened. Record the size
b5210ea7 13718 as 0 not to try to open it again. */
f3fbd155 13719 XSETCDR (tem, make_number (0));
dc43ef94 13720 }
536f4067 13721
8e713be6 13722 found_size = XINT (XCDR (tem));
536f4067 13723 if (found_size == size)
8e713be6 13724 newlist = Fcons (XCAR (tem), newlist);
536f4067 13725 else if (found_size > 0)
b5210ea7 13726 {
536f4067 13727 if (NILP (second_best))
b5210ea7 13728 second_best = tem;
536f4067
RS
13729 else if (found_size < size)
13730 {
8e713be6
KR
13731 if (XINT (XCDR (second_best)) > size
13732 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
13733 second_best = tem;
13734 }
13735 else
13736 {
8e713be6
KR
13737 if (XINT (XCDR (second_best)) > size
13738 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
13739 second_best = tem;
13740 }
b5210ea7
KH
13741 }
13742 }
13743 if (!NILP (newlist))
13744 break;
13745 else if (!NILP (second_best))
13746 {
8e713be6 13747 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 13748 break;
dc43ef94 13749 }
dc43ef94
KH
13750 }
13751
13752 return newlist;
13753}
13754
06a2c219
GM
13755
13756#if GLYPH_DEBUG
13757
13758/* Check that FONT is valid on frame F. It is if it can be found in F's
13759 font table. */
13760
13761static void
13762x_check_font (f, font)
13763 struct frame *f;
13764 XFontStruct *font;
13765{
13766 int i;
13767 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13768
13769 xassert (font != NULL);
13770
13771 for (i = 0; i < dpyinfo->n_fonts; i++)
13772 if (dpyinfo->font_table[i].name
13773 && font == dpyinfo->font_table[i].font)
13774 break;
13775
13776 xassert (i < dpyinfo->n_fonts);
13777}
13778
13779#endif /* GLYPH_DEBUG != 0 */
13780
13781/* Set *W to the minimum width, *H to the minimum font height of FONT.
13782 Note: There are (broken) X fonts out there with invalid XFontStruct
13783 min_bounds contents. For example, handa@etl.go.jp reports that
13784 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
13785 have font->min_bounds.width == 0. */
13786
13787static INLINE void
13788x_font_min_bounds (font, w, h)
13789 XFontStruct *font;
13790 int *w, *h;
13791{
13792 *h = FONT_HEIGHT (font);
13793 *w = font->min_bounds.width;
13794
13795 /* Try to handle the case where FONT->min_bounds has invalid
13796 contents. Since the only font known to have invalid min_bounds
13797 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
13798 if (*w <= 0)
13799 *w = font->max_bounds.width;
13800}
13801
13802
13803/* Compute the smallest character width and smallest font height over
13804 all fonts available on frame F. Set the members smallest_char_width
13805 and smallest_font_height in F's x_display_info structure to
13806 the values computed. Value is non-zero if smallest_font_height or
13807 smallest_char_width become smaller than they were before. */
13808
13809static int
13810x_compute_min_glyph_bounds (f)
13811 struct frame *f;
13812{
13813 int i;
13814 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13815 XFontStruct *font;
13816 int old_width = dpyinfo->smallest_char_width;
13817 int old_height = dpyinfo->smallest_font_height;
13818
13819 dpyinfo->smallest_font_height = 100000;
13820 dpyinfo->smallest_char_width = 100000;
13821
13822 for (i = 0; i < dpyinfo->n_fonts; ++i)
13823 if (dpyinfo->font_table[i].name)
13824 {
13825 struct font_info *fontp = dpyinfo->font_table + i;
13826 int w, h;
13827
13828 font = (XFontStruct *) fontp->font;
13829 xassert (font != (XFontStruct *) ~0);
13830 x_font_min_bounds (font, &w, &h);
13831
13832 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
13833 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
13834 }
13835
13836 xassert (dpyinfo->smallest_char_width > 0
13837 && dpyinfo->smallest_font_height > 0);
13838
13839 return (dpyinfo->n_fonts == 1
13840 || dpyinfo->smallest_char_width < old_width
13841 || dpyinfo->smallest_font_height < old_height);
13842}
13843
13844
dc43ef94
KH
13845/* Load font named FONTNAME of the size SIZE for frame F, and return a
13846 pointer to the structure font_info while allocating it dynamically.
13847 If SIZE is 0, load any size of font.
13848 If loading is failed, return NULL. */
13849
13850struct font_info *
13851x_load_font (f, fontname, size)
13852 struct frame *f;
13853 register char *fontname;
13854 int size;
13855{
13856 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13857 Lisp_Object font_names;
d645aaa4 13858 int count;
dc43ef94
KH
13859
13860 /* Get a list of all the fonts that match this name. Once we
13861 have a list of matching fonts, we compare them against the fonts
13862 we already have by comparing names. */
09c6077f 13863 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
13864
13865 if (!NILP (font_names))
13866 {
13867 Lisp_Object tail;
13868 int i;
13869
13870 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 13871 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
13872 if (dpyinfo->font_table[i].name
13873 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 13874 XSTRING (XCAR (tail))->data)
06a2c219 13875 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 13876 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
13877 return (dpyinfo->font_table + i);
13878 }
13879
13880 /* Load the font and add it to the table. */
13881 {
13882 char *full_name;
13883 XFontStruct *font;
13884 struct font_info *fontp;
13885 unsigned long value;
06a2c219 13886 int i;
dc43ef94 13887
2da424f1
KH
13888 /* If we have found fonts by x_list_font, load one of them. If
13889 not, we still try to load a font by the name given as FONTNAME
13890 because XListFonts (called in x_list_font) of some X server has
13891 a bug of not finding a font even if the font surely exists and
13892 is loadable by XLoadQueryFont. */
e1d6d5b9 13893 if (size > 0 && !NILP (font_names))
8e713be6 13894 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
13895
13896 BLOCK_INPUT;
d645aaa4 13897 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 13898 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
13899 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
13900 {
13901 /* This error is perhaps due to insufficient memory on X
13902 server. Let's just ignore it. */
13903 font = NULL;
13904 x_clear_errors (FRAME_X_DISPLAY (f));
13905 }
13906 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 13907 UNBLOCK_INPUT;
b5210ea7 13908 if (!font)
dc43ef94
KH
13909 return NULL;
13910
06a2c219
GM
13911 /* Find a free slot in the font table. */
13912 for (i = 0; i < dpyinfo->n_fonts; ++i)
13913 if (dpyinfo->font_table[i].name == NULL)
13914 break;
13915
13916 /* If no free slot found, maybe enlarge the font table. */
13917 if (i == dpyinfo->n_fonts
13918 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 13919 {
06a2c219
GM
13920 int sz;
13921 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
13922 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 13923 dpyinfo->font_table
06a2c219 13924 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
13925 }
13926
06a2c219
GM
13927 fontp = dpyinfo->font_table + i;
13928 if (i == dpyinfo->n_fonts)
13929 ++dpyinfo->n_fonts;
dc43ef94
KH
13930
13931 /* Now fill in the slots of *FONTP. */
13932 BLOCK_INPUT;
13933 fontp->font = font;
06a2c219 13934 fontp->font_idx = i;
dc43ef94
KH
13935 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
13936 bcopy (fontname, fontp->name, strlen (fontname) + 1);
13937
13938 /* Try to get the full name of FONT. Put it in FULL_NAME. */
13939 full_name = 0;
13940 if (XGetFontProperty (font, XA_FONT, &value))
13941 {
13942 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
13943 char *p = name;
13944 int dashes = 0;
13945
13946 /* Count the number of dashes in the "full name".
13947 If it is too few, this isn't really the font's full name,
13948 so don't use it.
13949 In X11R4, the fonts did not come with their canonical names
13950 stored in them. */
13951 while (*p)
13952 {
13953 if (*p == '-')
13954 dashes++;
13955 p++;
13956 }
13957
13958 if (dashes >= 13)
13959 {
13960 full_name = (char *) xmalloc (p - name + 1);
13961 bcopy (name, full_name, p - name + 1);
13962 }
13963
13964 XFree (name);
13965 }
13966
13967 if (full_name != 0)
13968 fontp->full_name = full_name;
13969 else
13970 fontp->full_name = fontp->name;
13971
13972 fontp->size = font->max_bounds.width;
d5749adb 13973 fontp->height = FONT_HEIGHT (font);
dc43ef94 13974
2da424f1
KH
13975 if (NILP (font_names))
13976 {
13977 /* We come here because of a bug of XListFonts mentioned at
13978 the head of this block. Let's store this information in
13979 the cache for x_list_fonts. */
13980 Lisp_Object lispy_name = build_string (fontname);
13981 Lisp_Object lispy_full_name = build_string (fontp->full_name);
9c11f79e
GM
13982 Lisp_Object key = Fcons (Fcons (lispy_name, make_number (256)),
13983 Qnil);
2da424f1 13984
f3fbd155
KR
13985 XSETCDR (dpyinfo->name_list_element,
13986 Fcons (Fcons (key,
13987 Fcons (Fcons (lispy_full_name,
13988 make_number (fontp->size)),
13989 Qnil)),
13990 XCDR (dpyinfo->name_list_element)));
2da424f1 13991 if (full_name)
9c11f79e
GM
13992 {
13993 key = Fcons (Fcons (lispy_full_name, make_number (256)),
13994 Qnil);
f3fbd155
KR
13995 XSETCDR (dpyinfo->name_list_element,
13996 Fcons (Fcons (key,
13997 Fcons (Fcons (lispy_full_name,
13998 make_number (fontp->size)),
13999 Qnil)),
14000 XCDR (dpyinfo->name_list_element)));
9c11f79e 14001 }
2da424f1
KH
14002 }
14003
dc43ef94
KH
14004 /* The slot `encoding' specifies how to map a character
14005 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
14006 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
14007 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 14008 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 14009 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
14010 which is never used by any charset. If mapping can't be
14011 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
14012 fontp->encoding[1]
14013 = (font->max_byte1 == 0
14014 /* 1-byte font */
14015 ? (font->min_char_or_byte2 < 0x80
14016 ? (font->max_char_or_byte2 < 0x80
14017 ? 0 /* 0x20..0x7F */
8ff102bd 14018 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
14019 : 1) /* 0xA0..0xFF */
14020 /* 2-byte font */
14021 : (font->min_byte1 < 0x80
14022 ? (font->max_byte1 < 0x80
14023 ? (font->min_char_or_byte2 < 0x80
14024 ? (font->max_char_or_byte2 < 0x80
14025 ? 0 /* 0x2020..0x7F7F */
8ff102bd 14026 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 14027 : 3) /* 0x20A0..0x7FFF */
8ff102bd 14028 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
14029 : (font->min_char_or_byte2 < 0x80
14030 ? (font->max_char_or_byte2 < 0x80
14031 ? 2 /* 0xA020..0xFF7F */
8ff102bd 14032 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
14033 : 1))); /* 0xA0A0..0xFFFF */
14034
14035 fontp->baseline_offset
14036 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
14037 ? (long) value : 0);
14038 fontp->relative_compose
14039 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
14040 ? (long) value : 0);
f78798df
KH
14041 fontp->default_ascent
14042 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
14043 ? (long) value : 0);
dc43ef94 14044
06a2c219
GM
14045 /* Set global flag fonts_changed_p to non-zero if the font loaded
14046 has a character with a smaller width than any other character
14047 before, or if the font loaded has a smalle>r height than any
14048 other font loaded before. If this happens, it will make a
14049 glyph matrix reallocation necessary. */
14050 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 14051 UNBLOCK_INPUT;
dc43ef94
KH
14052 return fontp;
14053 }
14054}
14055
06a2c219
GM
14056
14057/* Return a pointer to struct font_info of a font named FONTNAME for
14058 frame F. If no such font is loaded, return NULL. */
14059
dc43ef94
KH
14060struct font_info *
14061x_query_font (f, fontname)
14062 struct frame *f;
14063 register char *fontname;
14064{
14065 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14066 int i;
14067
14068 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
14069 if (dpyinfo->font_table[i].name
14070 && (!strcmp (dpyinfo->font_table[i].name, fontname)
14071 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
14072 return (dpyinfo->font_table + i);
14073 return NULL;
14074}
14075
06a2c219
GM
14076
14077/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
14078 `encoder' of the structure. */
14079
14080void
14081x_find_ccl_program (fontp)
14082 struct font_info *fontp;
14083{
a42f54e6 14084 Lisp_Object list, elt;
a6582676 14085
f9b5db02 14086 elt = Qnil;
8e713be6 14087 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 14088 {
8e713be6 14089 elt = XCAR (list);
a6582676 14090 if (CONSP (elt)
8e713be6 14091 && STRINGP (XCAR (elt))
9f2feff6
KH
14092 && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
14093 >= 0)
14094 || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
14095 >= 0)))
a42f54e6
KH
14096 break;
14097 }
f9b5db02 14098
a42f54e6
KH
14099 if (! NILP (list))
14100 {
d27f8ca7
KH
14101 struct ccl_program *ccl
14102 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 14103
8e713be6 14104 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
14105 xfree (ccl);
14106 else
14107 fontp->font_encoder = ccl;
a6582676
KH
14108 }
14109}
14110
06a2c219 14111
dc43ef94 14112\f
06a2c219
GM
14113/***********************************************************************
14114 Initialization
14115 ***********************************************************************/
f451eb13 14116
3afe33e7
RS
14117#ifdef USE_X_TOOLKIT
14118static XrmOptionDescRec emacs_options[] = {
14119 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
14120 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
14121
14122 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
14123 XrmoptionSepArg, NULL},
14124 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
14125
14126 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14127 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14128 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14129 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14130 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14131 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
14132 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
14133};
14134#endif /* USE_X_TOOLKIT */
14135
7a13e894
RS
14136static int x_initialized;
14137
29b38361
KH
14138#ifdef MULTI_KBOARD
14139/* Test whether two display-name strings agree up to the dot that separates
14140 the screen number from the server number. */
14141static int
14142same_x_server (name1, name2)
14143 char *name1, *name2;
14144{
14145 int seen_colon = 0;
cf591cc1
RS
14146 unsigned char *system_name = XSTRING (Vsystem_name)->data;
14147 int system_name_length = strlen (system_name);
14148 int length_until_period = 0;
14149
14150 while (system_name[length_until_period] != 0
14151 && system_name[length_until_period] != '.')
14152 length_until_period++;
14153
14154 /* Treat `unix' like an empty host name. */
14155 if (! strncmp (name1, "unix:", 5))
14156 name1 += 4;
14157 if (! strncmp (name2, "unix:", 5))
14158 name2 += 4;
14159 /* Treat this host's name like an empty host name. */
14160 if (! strncmp (name1, system_name, system_name_length)
14161 && name1[system_name_length] == ':')
14162 name1 += system_name_length;
14163 if (! strncmp (name2, system_name, system_name_length)
14164 && name2[system_name_length] == ':')
14165 name2 += system_name_length;
14166 /* Treat this host's domainless name like an empty host name. */
14167 if (! strncmp (name1, system_name, length_until_period)
14168 && name1[length_until_period] == ':')
14169 name1 += length_until_period;
14170 if (! strncmp (name2, system_name, length_until_period)
14171 && name2[length_until_period] == ':')
14172 name2 += length_until_period;
14173
29b38361
KH
14174 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
14175 {
14176 if (*name1 == ':')
14177 seen_colon++;
14178 if (seen_colon && *name1 == '.')
14179 return 1;
14180 }
14181 return (seen_colon
14182 && (*name1 == '.' || *name1 == '\0')
14183 && (*name2 == '.' || *name2 == '\0'));
14184}
14185#endif
14186
334208b7 14187struct x_display_info *
1f8255f2 14188x_term_init (display_name, xrm_option, resource_name)
334208b7 14189 Lisp_Object display_name;
1f8255f2
RS
14190 char *xrm_option;
14191 char *resource_name;
dc6f92b8 14192{
334208b7 14193 int connection;
7a13e894 14194 Display *dpy;
334208b7
RS
14195 struct x_display_info *dpyinfo;
14196 XrmDatabase xrdb;
14197
60439948
KH
14198 BLOCK_INPUT;
14199
7a13e894
RS
14200 if (!x_initialized)
14201 {
14202 x_initialize ();
14203 x_initialized = 1;
14204 }
dc6f92b8 14205
3afe33e7 14206#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
14207 /* weiner@footloose.sps.mot.com reports that this causes
14208 errors with X11R5:
14209 X protocol error: BadAtom (invalid Atom parameter)
14210 on protocol request 18skiloaf.
14211 So let's not use it until R6. */
14212#ifdef HAVE_X11XTR6
bdcd49ba
RS
14213 XtSetLanguageProc (NULL, NULL, NULL);
14214#endif
14215
7f9c7f94
RS
14216 {
14217 int argc = 0;
14218 char *argv[3];
14219
14220 argv[0] = "";
14221 argc = 1;
14222 if (xrm_option)
14223 {
14224 argv[argc++] = "-xrm";
14225 argv[argc++] = xrm_option;
14226 }
14227 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
14228 resource_name, EMACS_CLASS,
14229 emacs_options, XtNumber (emacs_options),
14230 &argc, argv);
39d8bb4d
KH
14231
14232#ifdef HAVE_X11XTR6
10537cb1 14233 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 14234 fixup_locale ();
39d8bb4d 14235#endif
7f9c7f94 14236 }
3afe33e7
RS
14237
14238#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
14239#ifdef HAVE_X11R5
14240 XSetLocaleModifiers ("");
14241#endif
7a13e894 14242 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 14243#endif /* not USE_X_TOOLKIT */
334208b7 14244
7a13e894
RS
14245 /* Detect failure. */
14246 if (dpy == 0)
60439948
KH
14247 {
14248 UNBLOCK_INPUT;
14249 return 0;
14250 }
7a13e894
RS
14251
14252 /* We have definitely succeeded. Record the new connection. */
14253
14254 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
f04e1297 14255 bzero (dpyinfo, sizeof *dpyinfo);
7a13e894 14256
29b38361
KH
14257#ifdef MULTI_KBOARD
14258 {
14259 struct x_display_info *share;
14260 Lisp_Object tail;
14261
14262 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
14263 share = share->next, tail = XCDR (tail))
14264 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
14265 XSTRING (display_name)->data))
14266 break;
14267 if (share)
14268 dpyinfo->kboard = share->kboard;
14269 else
14270 {
14271 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
14272 init_kboard (dpyinfo->kboard);
59e755be
KH
14273 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
14274 {
14275 char *vendor = ServerVendor (dpy);
9b6ed9f3 14276 UNBLOCK_INPUT;
59e755be
KH
14277 dpyinfo->kboard->Vsystem_key_alist
14278 = call1 (Qvendor_specific_keysyms,
14279 build_string (vendor ? vendor : ""));
9b6ed9f3 14280 BLOCK_INPUT;
59e755be
KH
14281 }
14282
29b38361
KH
14283 dpyinfo->kboard->next_kboard = all_kboards;
14284 all_kboards = dpyinfo->kboard;
0ad5446c
KH
14285 /* Don't let the initial kboard remain current longer than necessary.
14286 That would cause problems if a file loaded on startup tries to
06a2c219 14287 prompt in the mini-buffer. */
0ad5446c
KH
14288 if (current_kboard == initial_kboard)
14289 current_kboard = dpyinfo->kboard;
29b38361
KH
14290 }
14291 dpyinfo->kboard->reference_count++;
14292 }
b9737ad3
KH
14293#endif
14294
7a13e894
RS
14295 /* Put this display on the chain. */
14296 dpyinfo->next = x_display_list;
14297 x_display_list = dpyinfo;
14298
14299 /* Put it on x_display_name_list as well, to keep them parallel. */
14300 x_display_name_list = Fcons (Fcons (display_name, Qnil),
14301 x_display_name_list);
8e713be6 14302 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
14303
14304 dpyinfo->display = dpy;
dc6f92b8 14305
dc6f92b8 14306#if 0
7a13e894 14307 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 14308#endif /* ! 0 */
7a13e894
RS
14309
14310 dpyinfo->x_id_name
fc932ac6
RS
14311 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
14312 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
14313 + 2);
14314 sprintf (dpyinfo->x_id_name, "%s@%s",
14315 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
14316
14317 /* Figure out which modifier bits mean what. */
334208b7 14318 x_find_modifier_meanings (dpyinfo);
f451eb13 14319
ab648270 14320 /* Get the scroll bar cursor. */
7a13e894 14321 dpyinfo->vertical_scroll_bar_cursor
334208b7 14322 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 14323
334208b7
RS
14324 xrdb = x_load_resources (dpyinfo->display, xrm_option,
14325 resource_name, EMACS_CLASS);
14326#ifdef HAVE_XRMSETDATABASE
14327 XrmSetDatabase (dpyinfo->display, xrdb);
14328#else
14329 dpyinfo->display->db = xrdb;
14330#endif
547d9db8 14331 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
14332 all versions. */
14333 dpyinfo->xrdb = xrdb;
334208b7
RS
14334
14335 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
14336 DefaultScreen (dpyinfo->display));
5ff67d81 14337 select_visual (dpyinfo);
43bd1b2b 14338 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
14339 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
14340 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
14341 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
14342 dpyinfo->grabbed = 0;
14343 dpyinfo->reference_count = 0;
14344 dpyinfo->icon_bitmap_id = -1;
06a2c219 14345 dpyinfo->font_table = NULL;
7a13e894
RS
14346 dpyinfo->n_fonts = 0;
14347 dpyinfo->font_table_size = 0;
14348 dpyinfo->bitmaps = 0;
14349 dpyinfo->bitmaps_size = 0;
14350 dpyinfo->bitmaps_last = 0;
14351 dpyinfo->scratch_cursor_gc = 0;
14352 dpyinfo->mouse_face_mouse_frame = 0;
14353 dpyinfo->mouse_face_deferred_gc = 0;
14354 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
14355 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 14356 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894 14357 dpyinfo->mouse_face_window = Qnil;
0a61c667 14358 dpyinfo->mouse_face_overlay = Qnil;
7a13e894
RS
14359 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
14360 dpyinfo->mouse_face_defer = 0;
0f941935
KH
14361 dpyinfo->x_focus_frame = 0;
14362 dpyinfo->x_focus_event_frame = 0;
14363 dpyinfo->x_highlight_frame = 0;
06a2c219 14364 dpyinfo->image_cache = make_image_cache ();
334208b7 14365
43bd1b2b 14366 /* See if a private colormap is requested. */
5ff67d81
GM
14367 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
14368 {
14369 if (dpyinfo->visual->class == PseudoColor)
14370 {
14371 Lisp_Object value;
14372 value = display_x_get_resource (dpyinfo,
14373 build_string ("privateColormap"),
14374 build_string ("PrivateColormap"),
14375 Qnil, Qnil);
14376 if (STRINGP (value)
14377 && (!strcmp (XSTRING (value)->data, "true")
14378 || !strcmp (XSTRING (value)->data, "on")))
14379 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
14380 }
43bd1b2b 14381 }
5ff67d81
GM
14382 else
14383 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
14384 dpyinfo->visual, AllocNone);
43bd1b2b 14385
06a2c219
GM
14386 {
14387 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
14388 double pixels = DisplayHeight (dpyinfo->display, screen_number);
14389 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
14390 dpyinfo->resy = pixels * 25.4 / mm;
14391 pixels = DisplayWidth (dpyinfo->display, screen_number);
14392 mm = DisplayWidthMM (dpyinfo->display, screen_number);
14393 dpyinfo->resx = pixels * 25.4 / mm;
14394 }
14395
334208b7
RS
14396 dpyinfo->Xatom_wm_protocols
14397 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
14398 dpyinfo->Xatom_wm_take_focus
14399 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
14400 dpyinfo->Xatom_wm_save_yourself
14401 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
14402 dpyinfo->Xatom_wm_delete_window
14403 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
14404 dpyinfo->Xatom_wm_change_state
14405 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
14406 dpyinfo->Xatom_wm_configure_denied
14407 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
14408 dpyinfo->Xatom_wm_window_moved
14409 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
14410 dpyinfo->Xatom_editres
14411 = XInternAtom (dpyinfo->display, "Editres", False);
14412 dpyinfo->Xatom_CLIPBOARD
14413 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
14414 dpyinfo->Xatom_TIMESTAMP
14415 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
14416 dpyinfo->Xatom_TEXT
14417 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
14418 dpyinfo->Xatom_COMPOUND_TEXT
14419 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
14420 dpyinfo->Xatom_DELETE
14421 = XInternAtom (dpyinfo->display, "DELETE", False);
14422 dpyinfo->Xatom_MULTIPLE
14423 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
14424 dpyinfo->Xatom_INCR
14425 = XInternAtom (dpyinfo->display, "INCR", False);
14426 dpyinfo->Xatom_EMACS_TMP
14427 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
14428 dpyinfo->Xatom_TARGETS
14429 = XInternAtom (dpyinfo->display, "TARGETS", False);
14430 dpyinfo->Xatom_NULL
14431 = XInternAtom (dpyinfo->display, "NULL", False);
14432 dpyinfo->Xatom_ATOM_PAIR
14433 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
14434 /* For properties of font. */
14435 dpyinfo->Xatom_PIXEL_SIZE
14436 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
14437 dpyinfo->Xatom_MULE_BASELINE_OFFSET
14438 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
14439 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
14440 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
14441 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
14442 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 14443
06a2c219
GM
14444 /* Ghostscript support. */
14445 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
14446 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
14447
14448 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
14449 False);
14450
547d9db8
KH
14451 dpyinfo->cut_buffers_initialized = 0;
14452
334208b7
RS
14453 connection = ConnectionNumber (dpyinfo->display);
14454 dpyinfo->connection = connection;
14455
dc43ef94 14456 {
5d7cc324
RS
14457 char null_bits[1];
14458
14459 null_bits[0] = 0x00;
dc43ef94
KH
14460
14461 dpyinfo->null_pixel
14462 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14463 null_bits, 1, 1, (long) 0, (long) 0,
14464 1);
14465 }
14466
06a2c219
GM
14467 {
14468 extern int gray_bitmap_width, gray_bitmap_height;
10659c77 14469 extern char *gray_bitmap_bits;
06a2c219
GM
14470 dpyinfo->gray
14471 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14472 gray_bitmap_bits,
14473 gray_bitmap_width, gray_bitmap_height,
14474 (unsigned long) 1, (unsigned long) 0, 1);
14475 }
14476
f5d11644
GM
14477#ifdef HAVE_X_I18N
14478 xim_initialize (dpyinfo, resource_name);
14479#endif
14480
87485d6f
MW
14481#ifdef subprocesses
14482 /* This is only needed for distinguishing keyboard and process input. */
334208b7 14483 if (connection != 0)
7a13e894 14484 add_keyboard_wait_descriptor (connection);
87485d6f 14485#endif
6d4238f3 14486
041b69ac 14487#ifndef F_SETOWN_BUG
dc6f92b8 14488#ifdef F_SETOWN
dc6f92b8 14489#ifdef F_SETOWN_SOCK_NEG
61c3ce62 14490 /* stdin is a socket here */
334208b7 14491 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 14492#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 14493 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
14494#endif /* ! defined (F_SETOWN_SOCK_NEG) */
14495#endif /* ! defined (F_SETOWN) */
041b69ac 14496#endif /* F_SETOWN_BUG */
dc6f92b8
JB
14497
14498#ifdef SIGIO
eee20f6a
KH
14499 if (interrupt_input)
14500 init_sigio (connection);
c118dd06 14501#endif /* ! defined (SIGIO) */
dc6f92b8 14502
51b592fb 14503#ifdef USE_LUCID
f8c39f51 14504#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
14505 /* Make sure that we have a valid font for dialog boxes
14506 so that Xt does not crash. */
14507 {
14508 Display *dpy = dpyinfo->display;
14509 XrmValue d, fr, to;
14510 Font font;
e99db5a1 14511 int count;
51b592fb
RS
14512
14513 d.addr = (XPointer)&dpy;
14514 d.size = sizeof (Display *);
14515 fr.addr = XtDefaultFont;
14516 fr.size = sizeof (XtDefaultFont);
14517 to.size = sizeof (Font *);
14518 to.addr = (XPointer)&font;
e99db5a1 14519 count = x_catch_errors (dpy);
51b592fb
RS
14520 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
14521 abort ();
14522 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
14523 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 14524 x_uncatch_errors (dpy, count);
51b592fb
RS
14525 }
14526#endif
f8c39f51 14527#endif
51b592fb 14528
34e23e5a
GM
14529 /* See if we should run in synchronous mode. This is useful
14530 for debugging X code. */
14531 {
14532 Lisp_Object value;
14533 value = display_x_get_resource (dpyinfo,
14534 build_string ("synchronous"),
14535 build_string ("Synchronous"),
14536 Qnil, Qnil);
14537 if (STRINGP (value)
14538 && (!strcmp (XSTRING (value)->data, "true")
14539 || !strcmp (XSTRING (value)->data, "on")))
14540 XSynchronize (dpyinfo->display, True);
14541 }
14542
60439948
KH
14543 UNBLOCK_INPUT;
14544
7a13e894
RS
14545 return dpyinfo;
14546}
14547\f
14548/* Get rid of display DPYINFO, assuming all frames are already gone,
14549 and without sending any more commands to the X server. */
dc6f92b8 14550
7a13e894
RS
14551void
14552x_delete_display (dpyinfo)
14553 struct x_display_info *dpyinfo;
14554{
14555 delete_keyboard_wait_descriptor (dpyinfo->connection);
14556
14557 /* Discard this display from x_display_name_list and x_display_list.
14558 We can't use Fdelq because that can quit. */
14559 if (! NILP (x_display_name_list)
8e713be6
KR
14560 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
14561 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
14562 else
14563 {
14564 Lisp_Object tail;
14565
14566 tail = x_display_name_list;
8e713be6 14567 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 14568 {
bffcfca9 14569 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 14570 {
f3fbd155 14571 XSETCDR (tail, XCDR (XCDR (tail)));
7a13e894
RS
14572 break;
14573 }
8e713be6 14574 tail = XCDR (tail);
7a13e894
RS
14575 }
14576 }
14577
9bda743f
GM
14578 if (next_noop_dpyinfo == dpyinfo)
14579 next_noop_dpyinfo = dpyinfo->next;
14580
7a13e894
RS
14581 if (x_display_list == dpyinfo)
14582 x_display_list = dpyinfo->next;
7f9c7f94
RS
14583 else
14584 {
14585 struct x_display_info *tail;
7a13e894 14586
7f9c7f94
RS
14587 for (tail = x_display_list; tail; tail = tail->next)
14588 if (tail->next == dpyinfo)
14589 tail->next = tail->next->next;
14590 }
7a13e894 14591
0d777288
RS
14592#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
14593#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
14594 XrmDestroyDatabase (dpyinfo->xrdb);
14595#endif
0d777288 14596#endif
29b38361
KH
14597#ifdef MULTI_KBOARD
14598 if (--dpyinfo->kboard->reference_count == 0)
39f79001 14599 delete_kboard (dpyinfo->kboard);
b9737ad3 14600#endif
f5d11644
GM
14601#ifdef HAVE_X_I18N
14602 if (dpyinfo->xim)
14603 xim_close_dpy (dpyinfo);
14604#endif
14605
b9737ad3
KH
14606 xfree (dpyinfo->font_table);
14607 xfree (dpyinfo->x_id_name);
f04e1297 14608 xfree (dpyinfo->color_cells);
b9737ad3 14609 xfree (dpyinfo);
7a13e894 14610}
f04e1297 14611
7a13e894
RS
14612\f
14613/* Set up use of X before we make the first connection. */
14614
06a2c219
GM
14615static struct redisplay_interface x_redisplay_interface =
14616{
14617 x_produce_glyphs,
14618 x_write_glyphs,
14619 x_insert_glyphs,
14620 x_clear_end_of_line,
14621 x_scroll_run,
14622 x_after_update_window_line,
14623 x_update_window_begin,
14624 x_update_window_end,
14625 XTcursor_to,
14626 x_flush,
71b8321e 14627 x_clear_mouse_face,
66ac4b0e
GM
14628 x_get_glyph_overhangs,
14629 x_fix_overlapping_area
06a2c219
GM
14630};
14631
dfcf069d 14632void
7a13e894
RS
14633x_initialize ()
14634{
06a2c219
GM
14635 rif = &x_redisplay_interface;
14636
14637 clear_frame_hook = x_clear_frame;
14638 ins_del_lines_hook = x_ins_del_lines;
06a2c219 14639 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
14640 ring_bell_hook = XTring_bell;
14641 reset_terminal_modes_hook = XTreset_terminal_modes;
14642 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
14643 update_begin_hook = x_update_begin;
14644 update_end_hook = x_update_end;
dc6f92b8
JB
14645 set_terminal_window_hook = XTset_terminal_window;
14646 read_socket_hook = XTread_socket;
b8009dd1 14647 frame_up_to_date_hook = XTframe_up_to_date;
90e65f07 14648 mouse_position_hook = XTmouse_position;
f451eb13 14649 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 14650 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
14651 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
14652 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
14653 redeem_scroll_bar_hook = XTredeem_scroll_bar;
14654 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 14655 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 14656
f676886a 14657 scroll_region_ok = 1; /* we'll scroll partial frames */
9017309f 14658 char_ins_del_ok = 1;
dc6f92b8
JB
14659 line_ins_del_ok = 1; /* we'll just blt 'em */
14660 fast_clear_end_of_line = 1; /* X does this well */
58769bee 14661 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
14662 off the bottom */
14663 baud_rate = 19200;
14664
7a13e894 14665 x_noop_count = 0;
9ea173e8 14666 last_tool_bar_item = -1;
06a2c219
GM
14667 any_help_event_p = 0;
14668
b30b24cb
RS
14669 /* Try to use interrupt input; if we can't, then start polling. */
14670 Fset_input_mode (Qt, Qnil, Qt, Qnil);
14671
7f9c7f94
RS
14672#ifdef USE_X_TOOLKIT
14673 XtToolkitInitialize ();
651f03b6 14674
7f9c7f94 14675 Xt_app_con = XtCreateApplicationContext ();
651f03b6
GM
14676
14677 /* Register a converter from strings to pixels, which uses
14678 Emacs' color allocation infrastructure. */
14679 XtAppSetTypeConverter (Xt_app_con,
14680 XtRString, XtRPixel, cvt_string_to_pixel,
14681 cvt_string_to_pixel_args,
14682 XtNumber (cvt_string_to_pixel_args),
14683 XtCacheByDisplay, cvt_pixel_dtor);
14684
665881ad 14685 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
14686
14687 /* Install an asynchronous timer that processes Xt timeout events
14688 every 0.1s. This is necessary because some widget sets use
14689 timeouts internally, for example the LessTif menu bar, or the
14690 Xaw3d scroll bar. When Xt timouts aren't processed, these
14691 widgets don't behave normally. */
14692 {
14693 EMACS_TIME interval;
14694 EMACS_SET_SECS_USECS (interval, 0, 100000);
14695 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
14696 }
db74249b 14697#endif
bffcfca9 14698
eccc05db 14699#ifdef USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
14700 xaw3d_arrow_scroll = False;
14701 xaw3d_pick_top = True;
7f9c7f94
RS
14702#endif
14703
58769bee 14704 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 14705 original error handler. */
e99db5a1 14706 XSetErrorHandler (x_error_handler);
334208b7 14707 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 14708
06a2c219 14709 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
14710#ifdef SIGWINCH
14711 signal (SIGWINCH, SIG_DFL);
c118dd06 14712#endif /* ! defined (SIGWINCH) */
dc6f92b8 14713
92e2441b 14714 signal (SIGPIPE, x_connection_signal);
dc6f92b8 14715}
55123275 14716
06a2c219 14717
55123275
JB
14718void
14719syms_of_xterm ()
14720{
e99db5a1
RS
14721 staticpro (&x_error_message_string);
14722 x_error_message_string = Qnil;
14723
7a13e894
RS
14724 staticpro (&x_display_name_list);
14725 x_display_name_list = Qnil;
334208b7 14726
ab648270 14727 staticpro (&last_mouse_scroll_bar);
e53cb100 14728 last_mouse_scroll_bar = Qnil;
59e755be
KH
14729
14730 staticpro (&Qvendor_specific_keysyms);
14731 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
14732
14733 staticpro (&last_mouse_press_frame);
14734 last_mouse_press_frame = Qnil;
06a2c219 14735
06a2c219 14736 help_echo = Qnil;
be010514
GM
14737 staticpro (&help_echo);
14738 help_echo_object = Qnil;
14739 staticpro (&help_echo_object);
7cea38bc
GM
14740 help_echo_window = Qnil;
14741 staticpro (&help_echo_window);
06a2c219 14742 previous_help_echo = Qnil;
be010514
GM
14743 staticpro (&previous_help_echo);
14744 help_echo_pos = -1;
06a2c219 14745
7ee72033
MB
14746 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
14747 doc: /* *Non-nil means draw block cursor as wide as the glyph under it.
228299fa
GM
14748For example, if a block cursor is over a tab, it will be drawn as
14749wide as that tab on the display. */);
06a2c219
GM
14750 x_stretch_cursor_p = 0;
14751
a72d5ce5 14752 DEFVAR_BOOL ("x-use-underline-position-properties",
7ee72033
MB
14753 &x_use_underline_position_properties,
14754 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
228299fa
GM
14755Nil means ignore them. If you encounter fonts with bogus
14756UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
14757to 4.1, set this to nil. */);
a72d5ce5
GM
14758 x_use_underline_position_properties = 1;
14759
7ee72033
MB
14760 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
14761 doc: /* What X toolkit scroll bars Emacs uses.
228299fa
GM
14762A value of nil means Emacs doesn't use X toolkit scroll bars.
14763Otherwise, value is a symbol describing the X toolkit. */);
eccc05db 14764#ifdef USE_TOOLKIT_SCROLL_BARS
5bf04520
GM
14765#ifdef USE_MOTIF
14766 Vx_toolkit_scroll_bars = intern ("motif");
14767#elif defined HAVE_XAW3D
14768 Vx_toolkit_scroll_bars = intern ("xaw3d");
14769#else
14770 Vx_toolkit_scroll_bars = intern ("xaw");
14771#endif
06a2c219 14772#else
5bf04520 14773 Vx_toolkit_scroll_bars = Qnil;
06a2c219
GM
14774#endif
14775
06a2c219
GM
14776 staticpro (&last_mouse_motion_frame);
14777 last_mouse_motion_frame = Qnil;
55123275 14778}
6cf0ae86 14779
1d6c120a 14780#endif /* HAVE_X_WINDOWS */