(sql-mysql): Doc change by RMS.
[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;
772
773 xassert (w);
774
775 if (!desired_row->mode_line_p && !w->pseudo_window_p)
776 {
c5e6e06b
GM
777 struct frame *f;
778 int width;
779
06a2c219
GM
780 BLOCK_INPUT;
781 x_draw_row_bitmaps (w, desired_row);
782
783 /* When a window has disappeared, make sure that no rest of
784 full-width rows stays visible in the internal border. */
c5e6e06b
GM
785 if (windows_or_buffers_changed
786 && (f = XFRAME (w->frame),
787 width = FRAME_INTERNAL_BORDER_WIDTH (f),
788 width != 0))
06a2c219 789 {
06a2c219 790 int height = desired_row->visible_height;
110859fc
GM
791 int x = (window_box_right (w, -1)
792 + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
793 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
794
c5e6e06b
GM
795 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
796 x, y, width, height, False);
06a2c219
GM
797 }
798
799 UNBLOCK_INPUT;
800 }
801}
802
803
804/* Draw the bitmap WHICH in one of the areas to the left or right of
805 window W. ROW is the glyph row for which to display the bitmap; it
806 determines the vertical position at which the bitmap has to be
807 drawn. */
808
809static void
810x_draw_bitmap (w, row, which)
811 struct window *w;
812 struct glyph_row *row;
813 enum bitmap_type which;
814{
815 struct frame *f = XFRAME (WINDOW_FRAME (w));
816 Display *display = FRAME_X_DISPLAY (f);
817 Window window = FRAME_X_WINDOW (f);
818 int x, y, wd, h, dy;
819 unsigned char *bits;
820 Pixmap pixmap;
821 GC gc = f->output_data.x->normal_gc;
822 struct face *face;
823 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
824
825 /* Must clip because of partially visible lines. */
826 x_clip_to_row (w, row, gc, 1);
827
828 switch (which)
829 {
830 case LEFT_TRUNCATION_BITMAP:
831 wd = left_width;
832 h = left_height;
833 bits = left_bits;
834 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
835 - wd
110859fc 836 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
837 break;
838
839 case OVERLAY_ARROW_BITMAP:
840 wd = left_width;
841 h = left_height;
842 bits = ov_bits;
843 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
844 - wd
110859fc 845 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
846 break;
847
848 case RIGHT_TRUNCATION_BITMAP:
849 wd = right_width;
850 h = right_height;
851 bits = right_bits;
852 x = window_box_right (w, -1);
110859fc 853 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
854 break;
855
856 case CONTINUED_LINE_BITMAP:
857 wd = right_width;
858 h = right_height;
859 bits = continued_bits;
860 x = window_box_right (w, -1);
110859fc 861 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
862 break;
863
864 case CONTINUATION_LINE_BITMAP:
865 wd = continuation_width;
866 h = continuation_height;
867 bits = continuation_bits;
868 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
869 - wd
110859fc 870 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
871 break;
872
873 case ZV_LINE_BITMAP:
874 wd = zv_width;
875 h = zv_height;
876 bits = zv_bits;
877 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
878 - wd
110859fc 879 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
880 break;
881
882 default:
883 abort ();
884 }
885
886 /* Convert to frame coordinates. Set dy to the offset in the row to
887 start drawing the bitmap. */
888 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
889 dy = (row->height - h) / 2;
890
891 /* Draw the bitmap. I believe these small pixmaps can be cached
892 by the server. */
893 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
894 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
895 face->foreground,
896 face->background, depth);
897 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
898 XFreePixmap (display, pixmap);
899 XSetClipMask (display, gc, None);
900}
901
902
903/* Draw flags bitmaps for glyph row ROW on window W. Call this
904 function with input blocked. */
905
906static void
907x_draw_row_bitmaps (w, row)
908 struct window *w;
909 struct glyph_row *row;
910{
911 struct frame *f = XFRAME (w->frame);
912 enum bitmap_type bitmap;
913 struct face *face;
045dee35 914 int header_line_height = -1;
06a2c219
GM
915
916 xassert (interrupt_input_blocked);
917
918 /* If row is completely invisible, because of vscrolling, we
919 don't have to draw anything. */
920 if (row->visible_height <= 0)
921 return;
922
923 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
924 PREPARE_FACE_FOR_DISPLAY (f, face);
925
926 /* Decide which bitmap to draw at the left side. */
927 if (row->overlay_arrow_p)
928 bitmap = OVERLAY_ARROW_BITMAP;
929 else if (row->truncated_on_left_p)
930 bitmap = LEFT_TRUNCATION_BITMAP;
931 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
932 bitmap = CONTINUATION_LINE_BITMAP;
933 else if (row->indicate_empty_line_p)
934 bitmap = ZV_LINE_BITMAP;
935 else
936 bitmap = NO_BITMAP;
937
938 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
939 the flags area. */
940 if (bitmap == NO_BITMAP
110859fc 941 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
942 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
943 {
944 /* If W has a vertical border to its left, don't draw over it. */
945 int border = ((XFASTINT (w->left) > 0
946 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
947 ? 1 : 0);
948 int left = window_box_left (w, -1);
949
045dee35
GM
950 if (header_line_height < 0)
951 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
952
953 /* In case the same realized face is used for bitmap areas and
954 for something displayed in the text (e.g. face `region' on
955 mono-displays, the fill style may have been changed to
956 FillSolid in x_draw_glyph_string_background. */
957 if (face->stipple)
958 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
959 else
960 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
961
06a2c219
GM
962 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
963 face->gc,
964 (left
110859fc 965 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219 966 + border),
045dee35 967 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 968 row->y)),
110859fc 969 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
06a2c219 970 row->visible_height);
dcd08bfb
GM
971 if (!face->stipple)
972 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
973 }
974
975 /* Draw the left bitmap. */
976 if (bitmap != NO_BITMAP)
977 x_draw_bitmap (w, row, bitmap);
978
979 /* Decide which bitmap to draw at the right side. */
980 if (row->truncated_on_right_p)
981 bitmap = RIGHT_TRUNCATION_BITMAP;
982 else if (row->continued_p)
983 bitmap = CONTINUED_LINE_BITMAP;
984 else
985 bitmap = NO_BITMAP;
986
987 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
988 the flags area. */
989 if (bitmap == NO_BITMAP
110859fc 990 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
991 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
992 {
993 int right = window_box_right (w, -1);
994
045dee35
GM
995 if (header_line_height < 0)
996 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
997
998 /* In case the same realized face is used for bitmap areas and
999 for something displayed in the text (e.g. face `region' on
1000 mono-displays, the fill style may have been changed to
1001 FillSolid in x_draw_glyph_string_background. */
1002 if (face->stipple)
1003 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
1004 else
1005 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
1006 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1007 face->gc,
1008 right,
045dee35 1009 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 1010 row->y)),
110859fc 1011 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
06a2c219 1012 row->visible_height);
dcd08bfb
GM
1013 if (!face->stipple)
1014 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
1015 }
1016
1017 /* Draw the right bitmap. */
1018 if (bitmap != NO_BITMAP)
1019 x_draw_bitmap (w, row, bitmap);
1020}
1021
dc6f92b8 1022\f
06a2c219
GM
1023
1024/* This is called when starting Emacs and when restarting after
1025 suspend. When starting Emacs, no X window is mapped. And nothing
1026 must be done to Emacs's own window if it is suspended (though that
1027 rarely happens). */
dc6f92b8 1028
dfcf069d 1029static void
dc6f92b8
JB
1030XTset_terminal_modes ()
1031{
1032}
1033
06a2c219
GM
1034/* This is called when exiting or suspending Emacs. Exiting will make
1035 the X-windows go away, and suspending requires no action. */
dc6f92b8 1036
dfcf069d 1037static void
dc6f92b8
JB
1038XTreset_terminal_modes ()
1039{
dc6f92b8 1040}
06a2c219
GM
1041
1042
dc6f92b8 1043\f
06a2c219
GM
1044/***********************************************************************
1045 Output Cursor
1046 ***********************************************************************/
1047
1048/* Set the global variable output_cursor to CURSOR. All cursor
1049 positions are relative to updated_window. */
dc6f92b8 1050
dfcf069d 1051static void
06a2c219
GM
1052set_output_cursor (cursor)
1053 struct cursor_pos *cursor;
dc6f92b8 1054{
06a2c219
GM
1055 output_cursor.hpos = cursor->hpos;
1056 output_cursor.vpos = cursor->vpos;
1057 output_cursor.x = cursor->x;
1058 output_cursor.y = cursor->y;
1059}
1060
1061
1062/* Set a nominal cursor position.
dc6f92b8 1063
06a2c219
GM
1064 HPOS and VPOS are column/row positions in a window glyph matrix. X
1065 and Y are window text area relative pixel positions.
1066
1067 If this is done during an update, updated_window will contain the
1068 window that is being updated and the position is the future output
1069 cursor position for that window. If updated_window is null, use
1070 selected_window and display the cursor at the given position. */
1071
1072static void
1073XTcursor_to (vpos, hpos, y, x)
1074 int vpos, hpos, y, x;
1075{
1076 struct window *w;
1077
1078 /* If updated_window is not set, work on selected_window. */
1079 if (updated_window)
1080 w = updated_window;
1081 else
1082 w = XWINDOW (selected_window);
dbcb258a 1083
06a2c219
GM
1084 /* Set the output cursor. */
1085 output_cursor.hpos = hpos;
1086 output_cursor.vpos = vpos;
1087 output_cursor.x = x;
1088 output_cursor.y = y;
dc6f92b8 1089
06a2c219
GM
1090 /* If not called as part of an update, really display the cursor.
1091 This will also set the cursor position of W. */
1092 if (updated_window == NULL)
dc6f92b8
JB
1093 {
1094 BLOCK_INPUT;
06a2c219 1095 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1096 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1097 UNBLOCK_INPUT;
1098 }
1099}
dc43ef94 1100
06a2c219
GM
1101
1102\f
1103/***********************************************************************
1104 Display Iterator
1105 ***********************************************************************/
1106
1107/* Function prototypes of this page. */
1108
1109static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1110 struct glyph *,
ee569018
KH
1111 XChar2b *,
1112 int *));
06a2c219
GM
1113static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1114 int, XChar2b *, int));
1115static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1116static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1117static void x_append_glyph P_ ((struct it *));
b4192550 1118static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1119static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1120 int, int, double));
1121static void x_produce_glyphs P_ ((struct it *));
06a2c219 1122static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1123
1124
e2ef8ee6
GM
1125/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1126 is not contained in the font. */
dc43ef94 1127
06a2c219 1128static INLINE XCharStruct *
ee569018 1129x_per_char_metric (font, char2b)
06a2c219
GM
1130 XFontStruct *font;
1131 XChar2b *char2b;
1132{
1133 /* The result metric information. */
1134 XCharStruct *pcm = NULL;
dc6f92b8 1135
06a2c219 1136 xassert (font && char2b);
dc6f92b8 1137
06a2c219 1138 if (font->per_char != NULL)
dc6f92b8 1139 {
06a2c219 1140 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1141 {
06a2c219
GM
1142 /* min_char_or_byte2 specifies the linear character index
1143 corresponding to the first element of the per_char array,
1144 max_char_or_byte2 is the index of the last character. A
1145 character with non-zero CHAR2B->byte1 is not in the font.
1146 A character with byte2 less than min_char_or_byte2 or
1147 greater max_char_or_byte2 is not in the font. */
1148 if (char2b->byte1 == 0
1149 && char2b->byte2 >= font->min_char_or_byte2
1150 && char2b->byte2 <= font->max_char_or_byte2)
1151 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1152 }
06a2c219 1153 else
dc6f92b8 1154 {
06a2c219
GM
1155 /* If either min_byte1 or max_byte1 are nonzero, both
1156 min_char_or_byte2 and max_char_or_byte2 are less than
1157 256, and the 2-byte character index values corresponding
1158 to the per_char array element N (counting from 0) are:
1159
1160 byte1 = N/D + min_byte1
1161 byte2 = N\D + min_char_or_byte2
1162
1163 where:
1164
1165 D = max_char_or_byte2 - min_char_or_byte2 + 1
1166 / = integer division
1167 \ = integer modulus */
1168 if (char2b->byte1 >= font->min_byte1
1169 && char2b->byte1 <= font->max_byte1
1170 && char2b->byte2 >= font->min_char_or_byte2
1171 && char2b->byte2 <= font->max_char_or_byte2)
1172 {
1173 pcm = (font->per_char
1174 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1175 * (char2b->byte1 - font->min_byte1))
1176 + (char2b->byte2 - font->min_char_or_byte2));
1177 }
dc6f92b8 1178 }
06a2c219
GM
1179 }
1180 else
1181 {
1182 /* If the per_char pointer is null, all glyphs between the first
1183 and last character indexes inclusive have the same
1184 information, as given by both min_bounds and max_bounds. */
1185 if (char2b->byte2 >= font->min_char_or_byte2
1186 && char2b->byte2 <= font->max_char_or_byte2)
1187 pcm = &font->max_bounds;
1188 }
dc6f92b8 1189
ee569018 1190 return ((pcm == NULL
3e71d8f2 1191 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1192 ? NULL : pcm);
06a2c219 1193}
b73b6aaf 1194
57b03282 1195
06a2c219
GM
1196/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1197 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1198
06a2c219
GM
1199static INLINE void
1200x_encode_char (c, char2b, font_info)
1201 int c;
1202 XChar2b *char2b;
1203 struct font_info *font_info;
1204{
1205 int charset = CHAR_CHARSET (c);
1206 XFontStruct *font = font_info->font;
1207
1208 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1209 This may be either a program in a special encoder language or a
1210 fixed encoding. */
1211 if (font_info->font_encoder)
1212 {
1213 /* It's a program. */
1214 struct ccl_program *ccl = font_info->font_encoder;
1215
1216 if (CHARSET_DIMENSION (charset) == 1)
1217 {
1218 ccl->reg[0] = charset;
1219 ccl->reg[1] = char2b->byte2;
1220 }
1221 else
1222 {
1223 ccl->reg[0] = charset;
1224 ccl->reg[1] = char2b->byte1;
1225 ccl->reg[2] = char2b->byte2;
1226 }
1227
1228 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1229
1230 /* We assume that MSBs are appropriately set/reset by CCL
1231 program. */
1232 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1233 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1234 else
1235 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1236 }
1237 else if (font_info->encoding[charset])
1238 {
1239 /* Fixed encoding scheme. See fontset.h for the meaning of the
1240 encoding numbers. */
1241 int enc = font_info->encoding[charset];
1242
1243 if ((enc == 1 || enc == 2)
1244 && CHARSET_DIMENSION (charset) == 2)
1245 char2b->byte1 |= 0x80;
1246
1247 if (enc == 1 || enc == 3)
1248 char2b->byte2 |= 0x80;
1249 }
1250}
1251
1252
1253/* Get face and two-byte form of character C in face FACE_ID on frame
1254 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1255 means we want to display multibyte text. Value is a pointer to a
1256 realized face that is ready for display. */
1257
1258static INLINE struct face *
1259x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1260 struct frame *f;
1261 int c, face_id;
1262 XChar2b *char2b;
1263 int multibyte_p;
1264{
1265 struct face *face = FACE_FROM_ID (f, face_id);
1266
1267 if (!multibyte_p)
1268 {
1269 /* Unibyte case. We don't have to encode, but we have to make
1270 sure to use a face suitable for unibyte. */
1271 char2b->byte1 = 0;
1272 char2b->byte2 = c;
ee569018
KH
1273 face_id = FACE_FOR_CHAR (f, face, c);
1274 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1275 }
1276 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1277 {
1278 /* Case of ASCII in a face known to fit ASCII. */
1279 char2b->byte1 = 0;
1280 char2b->byte2 = c;
1281 }
1282 else
1283 {
1284 int c1, c2, charset;
1285
1286 /* Split characters into bytes. If c2 is -1 afterwards, C is
1287 really a one-byte character so that byte1 is zero. */
1288 SPLIT_CHAR (c, charset, c1, c2);
1289 if (c2 > 0)
1290 char2b->byte1 = c1, char2b->byte2 = c2;
1291 else
1292 char2b->byte1 = 0, char2b->byte2 = c1;
1293
06a2c219 1294 /* Maybe encode the character in *CHAR2B. */
ee569018 1295 if (face->font != NULL)
06a2c219
GM
1296 {
1297 struct font_info *font_info
1298 = FONT_INFO_FROM_ID (f, face->font_info_id);
1299 if (font_info)
ee569018 1300 x_encode_char (c, char2b, font_info);
06a2c219
GM
1301 }
1302 }
1303
1304 /* Make sure X resources of the face are allocated. */
1305 xassert (face != NULL);
1306 PREPARE_FACE_FOR_DISPLAY (f, face);
1307
1308 return face;
1309}
1310
1311
1312/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1313 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1314 a pointer to a realized face that is ready for display. */
1315
1316static INLINE struct face *
ee569018 1317x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1318 struct frame *f;
1319 struct glyph *glyph;
1320 XChar2b *char2b;
ee569018 1321 int *two_byte_p;
06a2c219
GM
1322{
1323 struct face *face;
1324
1325 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1326 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1327
ee569018
KH
1328 if (two_byte_p)
1329 *two_byte_p = 0;
1330
06a2c219
GM
1331 if (!glyph->multibyte_p)
1332 {
1333 /* Unibyte case. We don't have to encode, but we have to make
1334 sure to use a face suitable for unibyte. */
1335 char2b->byte1 = 0;
43d120d8 1336 char2b->byte2 = glyph->u.ch;
06a2c219 1337 }
43d120d8
KH
1338 else if (glyph->u.ch < 128
1339 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1340 {
1341 /* Case of ASCII in a face known to fit ASCII. */
1342 char2b->byte1 = 0;
43d120d8 1343 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1344 }
1345 else
1346 {
1347 int c1, c2, charset;
1348
1349 /* Split characters into bytes. If c2 is -1 afterwards, C is
1350 really a one-byte character so that byte1 is zero. */
43d120d8 1351 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1352 if (c2 > 0)
1353 char2b->byte1 = c1, char2b->byte2 = c2;
1354 else
1355 char2b->byte1 = 0, char2b->byte2 = c1;
1356
1357 /* Maybe encode the character in *CHAR2B. */
1358 if (charset != CHARSET_ASCII)
1359 {
1360 struct font_info *font_info
1361 = FONT_INFO_FROM_ID (f, face->font_info_id);
1362 if (font_info)
1363 {
43d120d8 1364 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1365 if (two_byte_p)
1366 *two_byte_p
1367 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1368 }
1369 }
1370 }
1371
1372 /* Make sure X resources of the face are allocated. */
1373 xassert (face != NULL);
1374 PREPARE_FACE_FOR_DISPLAY (f, face);
1375 return face;
1376}
1377
1378
1379/* Store one glyph for IT->char_to_display in IT->glyph_row.
1380 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1381
1382static INLINE void
1383x_append_glyph (it)
1384 struct it *it;
1385{
1386 struct glyph *glyph;
1387 enum glyph_row_area area = it->area;
1388
1389 xassert (it->glyph_row);
1390 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1391
1392 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1393 if (glyph < it->glyph_row->glyphs[area + 1])
1394 {
06a2c219
GM
1395 glyph->charpos = CHARPOS (it->position);
1396 glyph->object = it->object;
88d75730 1397 glyph->pixel_width = it->pixel_width;
06a2c219 1398 glyph->voffset = it->voffset;
88d75730 1399 glyph->type = CHAR_GLYPH;
06a2c219 1400 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1401 glyph->left_box_line_p = it->start_of_box_run_p;
1402 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1403 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1404 || it->phys_descent > it->descent);
88d75730 1405 glyph->padding_p = 0;
ee569018 1406 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1407 glyph->face_id = it->face_id;
1408 glyph->u.ch = it->char_to_display;
06a2c219
GM
1409 ++it->glyph_row->used[area];
1410 }
1411}
1412
b4192550
KH
1413/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1414 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1415
1416static INLINE void
1417x_append_composite_glyph (it)
1418 struct it *it;
1419{
1420 struct glyph *glyph;
1421 enum glyph_row_area area = it->area;
1422
1423 xassert (it->glyph_row);
1424
1425 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1426 if (glyph < it->glyph_row->glyphs[area + 1])
1427 {
b4192550
KH
1428 glyph->charpos = CHARPOS (it->position);
1429 glyph->object = it->object;
88d75730 1430 glyph->pixel_width = it->pixel_width;
b4192550 1431 glyph->voffset = it->voffset;
88d75730 1432 glyph->type = COMPOSITE_GLYPH;
b4192550 1433 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1434 glyph->left_box_line_p = it->start_of_box_run_p;
1435 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1436 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1437 || it->phys_descent > it->descent);
88d75730
GM
1438 glyph->padding_p = 0;
1439 glyph->glyph_not_available_p = 0;
1440 glyph->face_id = it->face_id;
1441 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1442 ++it->glyph_row->used[area];
1443 }
1444}
1445
06a2c219
GM
1446
1447/* Change IT->ascent and IT->height according to the setting of
1448 IT->voffset. */
1449
1450static INLINE void
1451take_vertical_position_into_account (it)
1452 struct it *it;
1453{
1454 if (it->voffset)
1455 {
1456 if (it->voffset < 0)
1457 /* Increase the ascent so that we can display the text higher
1458 in the line. */
1459 it->ascent += abs (it->voffset);
1460 else
1461 /* Increase the descent so that we can display the text lower
1462 in the line. */
1463 it->descent += it->voffset;
1464 }
1465}
1466
1467
1468/* Produce glyphs/get display metrics for the image IT is loaded with.
1469 See the description of struct display_iterator in dispextern.h for
1470 an overview of struct display_iterator. */
1471
1472static void
1473x_produce_image_glyph (it)
1474 struct it *it;
1475{
1476 struct image *img;
1477 struct face *face;
1478
1479 xassert (it->what == IT_IMAGE);
1480
1481 face = FACE_FROM_ID (it->f, it->face_id);
1482 img = IMAGE_FROM_ID (it->f, it->image_id);
1483 xassert (img);
1484
1485 /* Make sure X resources of the face and image are loaded. */
1486 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1487 prepare_image_for_display (it->f, img);
1488
95af8492 1489 it->ascent = it->phys_ascent = image_ascent (img, face);
22d650b8
GM
1490 it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
1491 it->pixel_width = img->width + 2 * img->hmargin;
06a2c219
GM
1492
1493 it->nglyphs = 1;
1494
1495 if (face->box != FACE_NO_BOX)
1496 {
ea2ba0d4
KH
1497 if (face->box_line_width > 0)
1498 {
1499 it->ascent += face->box_line_width;
1500 it->descent += face->box_line_width;
1501 }
06a2c219
GM
1502
1503 if (it->start_of_box_run_p)
ea2ba0d4 1504 it->pixel_width += abs (face->box_line_width);
06a2c219 1505 if (it->end_of_box_run_p)
ea2ba0d4 1506 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1507 }
1508
1509 take_vertical_position_into_account (it);
1510
1511 if (it->glyph_row)
1512 {
1513 struct glyph *glyph;
1514 enum glyph_row_area area = it->area;
1515
1516 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1517 if (glyph < it->glyph_row->glyphs[area + 1])
1518 {
06a2c219
GM
1519 glyph->charpos = CHARPOS (it->position);
1520 glyph->object = it->object;
88d75730 1521 glyph->pixel_width = it->pixel_width;
06a2c219 1522 glyph->voffset = it->voffset;
88d75730 1523 glyph->type = IMAGE_GLYPH;
06a2c219 1524 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1525 glyph->left_box_line_p = it->start_of_box_run_p;
1526 glyph->right_box_line_p = it->end_of_box_run_p;
1527 glyph->overlaps_vertically_p = 0;
1528 glyph->padding_p = 0;
1529 glyph->glyph_not_available_p = 0;
1530 glyph->face_id = it->face_id;
1531 glyph->u.img_id = img->id;
06a2c219
GM
1532 ++it->glyph_row->used[area];
1533 }
1534 }
1535}
1536
1537
1538/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1539 of the glyph, WIDTH and HEIGHT are the width and height of the
1540 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1541 ascent of the glyph (0 <= ASCENT <= 1). */
1542
1543static void
1544x_append_stretch_glyph (it, object, width, height, ascent)
1545 struct it *it;
1546 Lisp_Object object;
1547 int width, height;
1548 double ascent;
1549{
1550 struct glyph *glyph;
1551 enum glyph_row_area area = it->area;
1552
1553 xassert (ascent >= 0 && ascent <= 1);
1554
1555 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1556 if (glyph < it->glyph_row->glyphs[area + 1])
1557 {
06a2c219
GM
1558 glyph->charpos = CHARPOS (it->position);
1559 glyph->object = object;
88d75730 1560 glyph->pixel_width = width;
06a2c219 1561 glyph->voffset = it->voffset;
88d75730 1562 glyph->type = STRETCH_GLYPH;
06a2c219 1563 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1564 glyph->left_box_line_p = it->start_of_box_run_p;
1565 glyph->right_box_line_p = it->end_of_box_run_p;
1566 glyph->overlaps_vertically_p = 0;
1567 glyph->padding_p = 0;
1568 glyph->glyph_not_available_p = 0;
1569 glyph->face_id = it->face_id;
1570 glyph->u.stretch.ascent = height * ascent;
1571 glyph->u.stretch.height = height;
06a2c219
GM
1572 ++it->glyph_row->used[area];
1573 }
1574}
1575
1576
1577/* Produce a stretch glyph for iterator IT. IT->object is the value
1578 of the glyph property displayed. The value must be a list
1579 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1580 being recognized:
1581
1582 1. `:width WIDTH' specifies that the space should be WIDTH *
1583 canonical char width wide. WIDTH may be an integer or floating
1584 point number.
1585
1586 2. `:relative-width FACTOR' specifies that the width of the stretch
1587 should be computed from the width of the first character having the
1588 `glyph' property, and should be FACTOR times that width.
1589
1590 3. `:align-to HPOS' specifies that the space should be wide enough
1591 to reach HPOS, a value in canonical character units.
1592
1593 Exactly one of the above pairs must be present.
1594
1595 4. `:height HEIGHT' specifies that the height of the stretch produced
1596 should be HEIGHT, measured in canonical character units.
1597
1598 5. `:relative-height FACTOR' specifies that the height of the the
1599 stretch should be FACTOR times the height of the characters having
1600 the glyph property.
1601
1602 Either none or exactly one of 4 or 5 must be present.
1603
1604 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1605 of the stretch should be used for the ascent of the stretch.
1606 ASCENT must be in the range 0 <= ASCENT <= 100. */
1607
1608#define NUMVAL(X) \
1609 ((INTEGERP (X) || FLOATP (X)) \
1610 ? XFLOATINT (X) \
1611 : - 1)
1612
1613
1614static void
1615x_produce_stretch_glyph (it)
1616 struct it *it;
1617{
1618 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1619#if GLYPH_DEBUG
1620 extern Lisp_Object Qspace;
1621#endif
1622 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1623 extern Lisp_Object QCrelative_width, QCrelative_height;
1624 extern Lisp_Object QCalign_to;
1625 Lisp_Object prop, plist;
1626 double width = 0, height = 0, ascent = 0;
1627 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1628 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1629
1630 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1631
1632 /* List should start with `space'. */
1633 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1634 plist = XCDR (it->object);
1635
1636 /* Compute the width of the stretch. */
1637 if (prop = Fplist_get (plist, QCwidth),
1638 NUMVAL (prop) > 0)
1639 /* Absolute width `:width WIDTH' specified and valid. */
1640 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1641 else if (prop = Fplist_get (plist, QCrelative_width),
1642 NUMVAL (prop) > 0)
1643 {
1644 /* Relative width `:relative-width FACTOR' specified and valid.
1645 Compute the width of the characters having the `glyph'
1646 property. */
1647 struct it it2;
1648 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1649
1650 it2 = *it;
1651 if (it->multibyte_p)
1652 {
1653 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1654 - IT_BYTEPOS (*it));
1655 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1656 }
1657 else
1658 it2.c = *p, it2.len = 1;
1659
1660 it2.glyph_row = NULL;
1661 it2.what = IT_CHARACTER;
1662 x_produce_glyphs (&it2);
1663 width = NUMVAL (prop) * it2.pixel_width;
1664 }
1665 else if (prop = Fplist_get (plist, QCalign_to),
1666 NUMVAL (prop) > 0)
1667 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1668 else
1669 /* Nothing specified -> width defaults to canonical char width. */
1670 width = CANON_X_UNIT (it->f);
1671
1672 /* Compute height. */
1673 if (prop = Fplist_get (plist, QCheight),
1674 NUMVAL (prop) > 0)
1675 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1676 else if (prop = Fplist_get (plist, QCrelative_height),
1677 NUMVAL (prop) > 0)
1678 height = FONT_HEIGHT (font) * NUMVAL (prop);
1679 else
1680 height = FONT_HEIGHT (font);
1681
1682 /* Compute percentage of height used for ascent. If
1683 `:ascent ASCENT' is present and valid, use that. Otherwise,
1684 derive the ascent from the font in use. */
1685 if (prop = Fplist_get (plist, QCascent),
1686 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1687 ascent = NUMVAL (prop) / 100.0;
1688 else
1689 ascent = (double) font->ascent / FONT_HEIGHT (font);
1690
1691 if (width <= 0)
1692 width = 1;
1693 if (height <= 0)
1694 height = 1;
1695
1696 if (it->glyph_row)
1697 {
1698 Lisp_Object object = it->stack[it->sp - 1].string;
1699 if (!STRINGP (object))
1700 object = it->w->buffer;
1701 x_append_stretch_glyph (it, object, width, height, ascent);
1702 }
1703
1704 it->pixel_width = width;
66ac4b0e
GM
1705 it->ascent = it->phys_ascent = height * ascent;
1706 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1707 it->nglyphs = 1;
1708
1709 if (face->box != FACE_NO_BOX)
1710 {
ea2ba0d4
KH
1711 if (face->box_line_width > 0)
1712 {
1713 it->ascent += face->box_line_width;
1714 it->descent += face->box_line_width;
1715 }
06a2c219
GM
1716
1717 if (it->start_of_box_run_p)
ea2ba0d4 1718 it->pixel_width += abs (face->box_line_width);
06a2c219 1719 if (it->end_of_box_run_p)
ea2ba0d4 1720 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1721 }
1722
1723 take_vertical_position_into_account (it);
1724}
1725
b4192550
KH
1726/* Return proper value to be used as baseline offset of font that has
1727 ASCENT and DESCENT to draw characters by the font at the vertical
1728 center of the line of frame F.
1729
1730 Here, out task is to find the value of BOFF in the following figure;
1731
1732 -------------------------+-----------+-
1733 -+-+---------+-+ | |
1734 | | | | | |
1735 | | | | F_ASCENT F_HEIGHT
1736 | | | ASCENT | |
1737 HEIGHT | | | | |
1738 | | |-|-+------+-----------|------- baseline
1739 | | | | BOFF | |
1740 | |---------|-+-+ | |
1741 | | | DESCENT | |
1742 -+-+---------+-+ F_DESCENT |
1743 -------------------------+-----------+-
1744
1745 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1746 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1747 DESCENT = FONT->descent
1748 HEIGHT = FONT_HEIGHT (FONT)
1749 F_DESCENT = (F->output_data.x->font->descent
1750 - F->output_data.x->baseline_offset)
1751 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1752*/
1753
458f45fa
KH
1754#define VCENTER_BASELINE_OFFSET(FONT, F) \
1755 ((FONT)->descent \
1756 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT)) \
1757 + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \
1758 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1759
1760/* Produce glyphs/get display metrics for the display element IT is
1761 loaded with. See the description of struct display_iterator in
1762 dispextern.h for an overview of struct display_iterator. */
1763
1764static void
1765x_produce_glyphs (it)
1766 struct it *it;
1767{
ee569018
KH
1768 it->glyph_not_available_p = 0;
1769
06a2c219
GM
1770 if (it->what == IT_CHARACTER)
1771 {
1772 XChar2b char2b;
1773 XFontStruct *font;
ee569018 1774 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1775 XCharStruct *pcm;
06a2c219 1776 int font_not_found_p;
b4192550
KH
1777 struct font_info *font_info;
1778 int boff; /* baseline offset */
a4249304
KH
1779 /* We may change it->multibyte_p upon unibyte<->multibyte
1780 conversion. So, save the current value now and restore it
1781 later.
1782
1783 Note: It seems that we don't have to record multibyte_p in
1784 struct glyph because the character code itself tells if or
1785 not the character is multibyte. Thus, in the future, we must
1786 consider eliminating the field `multibyte_p' in the struct
c347a1c3 1787 glyph. */
a4249304 1788 int saved_multibyte_p = it->multibyte_p;
06a2c219 1789
ee569018
KH
1790 /* Maybe translate single-byte characters to multibyte, or the
1791 other way. */
06a2c219 1792 it->char_to_display = it->c;
ee569018 1793 if (!ASCII_BYTE_P (it->c))
06a2c219 1794 {
ee569018
KH
1795 if (unibyte_display_via_language_environment
1796 && SINGLE_BYTE_CHAR_P (it->c)
1797 && (it->c >= 0240
1798 || !NILP (Vnonascii_translation_table)))
1799 {
1800 it->char_to_display = unibyte_char_to_multibyte (it->c);
a4249304 1801 it->multibyte_p = 1;
ee569018
KH
1802 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1803 face = FACE_FROM_ID (it->f, it->face_id);
1804 }
1805 else if (!SINGLE_BYTE_CHAR_P (it->c)
1806 && !it->multibyte_p)
1807 {
c347a1c3 1808 it->multibyte_p = 1;
ee569018
KH
1809 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1810 face = FACE_FROM_ID (it->f, it->face_id);
1811 }
06a2c219
GM
1812 }
1813
ee569018
KH
1814 /* Get font to use. Encode IT->char_to_display. */
1815 x_get_char_face_and_encoding (it->f, it->char_to_display,
1816 it->face_id, &char2b,
1817 it->multibyte_p);
06a2c219
GM
1818 font = face->font;
1819
1820 /* When no suitable font found, use the default font. */
1821 font_not_found_p = font == NULL;
1822 if (font_not_found_p)
b4192550
KH
1823 {
1824 font = FRAME_FONT (it->f);
1825 boff = it->f->output_data.x->baseline_offset;
1826 font_info = NULL;
1827 }
1828 else
1829 {
1830 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1831 boff = font_info->baseline_offset;
1832 if (font_info->vertical_centering)
1833 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1834 }
06a2c219
GM
1835
1836 if (it->char_to_display >= ' '
1837 && (!it->multibyte_p || it->char_to_display < 128))
1838 {
1839 /* Either unibyte or ASCII. */
1840 int stretched_p;
1841
1842 it->nglyphs = 1;
06a2c219
GM
1843
1844 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1845 it->ascent = font->ascent + boff;
1846 it->descent = font->descent - boff;
474848ac
GM
1847
1848 if (pcm)
1849 {
1850 it->phys_ascent = pcm->ascent + boff;
1851 it->phys_descent = pcm->descent - boff;
1852 it->pixel_width = pcm->width;
1853 }
1854 else
1855 {
1856 it->glyph_not_available_p = 1;
1857 it->phys_ascent = font->ascent + boff;
1858 it->phys_descent = font->descent - boff;
1859 it->pixel_width = FONT_WIDTH (font);
1860 }
06a2c219
GM
1861
1862 /* If this is a space inside a region of text with
1863 `space-width' property, change its width. */
1864 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1865 if (stretched_p)
1866 it->pixel_width *= XFLOATINT (it->space_width);
1867
1868 /* If face has a box, add the box thickness to the character
1869 height. If character has a box line to the left and/or
1870 right, add the box line width to the character's width. */
1871 if (face->box != FACE_NO_BOX)
1872 {
1873 int thick = face->box_line_width;
1874
ea2ba0d4
KH
1875 if (thick > 0)
1876 {
1877 it->ascent += thick;
1878 it->descent += thick;
1879 }
1880 else
1881 thick = -thick;
1882
06a2c219
GM
1883 if (it->start_of_box_run_p)
1884 it->pixel_width += thick;
1885 if (it->end_of_box_run_p)
1886 it->pixel_width += thick;
1887 }
1888
1889 /* If face has an overline, add the height of the overline
1890 (1 pixel) and a 1 pixel margin to the character height. */
1891 if (face->overline_p)
1892 it->ascent += 2;
1893
1894 take_vertical_position_into_account (it);
1895
1896 /* If we have to actually produce glyphs, do it. */
1897 if (it->glyph_row)
1898 {
1899 if (stretched_p)
1900 {
1901 /* Translate a space with a `space-width' property
1902 into a stretch glyph. */
1903 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1904 x_append_stretch_glyph (it, it->object, it->pixel_width,
1905 it->ascent + it->descent, ascent);
1906 }
1907 else
1908 x_append_glyph (it);
1909
1910 /* If characters with lbearing or rbearing are displayed
1911 in this line, record that fact in a flag of the
1912 glyph row. This is used to optimize X output code. */
1c7e22fd 1913 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1914 it->glyph_row->contains_overlapping_glyphs_p = 1;
1915 }
1916 }
1917 else if (it->char_to_display == '\n')
1918 {
1919 /* A newline has no width but we need the height of the line. */
1920 it->pixel_width = 0;
1921 it->nglyphs = 0;
b4192550
KH
1922 it->ascent = it->phys_ascent = font->ascent + boff;
1923 it->descent = it->phys_descent = font->descent - boff;
06a2c219 1924
ea2ba0d4
KH
1925 if (face->box != FACE_NO_BOX
1926 && face->box_line_width > 0)
06a2c219 1927 {
ea2ba0d4
KH
1928 it->ascent += face->box_line_width;
1929 it->descent += face->box_line_width;
06a2c219
GM
1930 }
1931 }
1932 else if (it->char_to_display == '\t')
1933 {
1934 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1935 int x = it->current_x + it->continuation_lines_width;
06a2c219 1936 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
2a32b5ea
GM
1937
1938 /* If the distance from the current position to the next tab
1939 stop is less than a canonical character width, use the
1940 tab stop after that. */
1941 if (next_tab_x - x < CANON_X_UNIT (it->f))
1942 next_tab_x += tab_width;
06a2c219
GM
1943
1944 it->pixel_width = next_tab_x - x;
1945 it->nglyphs = 1;
b4192550
KH
1946 it->ascent = it->phys_ascent = font->ascent + boff;
1947 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1948
1949 if (it->glyph_row)
1950 {
1951 double ascent = (double) it->ascent / (it->ascent + it->descent);
1952 x_append_stretch_glyph (it, it->object, it->pixel_width,
1953 it->ascent + it->descent, ascent);
1954 }
1955 }
1956 else
1957 {
1958 /* A multi-byte character. Assume that the display width of the
1959 character is the width of the character multiplied by the
b4192550 1960 width of the font. */
06a2c219 1961
b4192550
KH
1962 /* If we found a font, this font should give us the right
1963 metrics. If we didn't find a font, use the frame's
1964 default font and calculate the width of the character
1965 from the charset width; this is what old redisplay code
1966 did. */
1967 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
1968 if (font_not_found_p || !pcm)
1969 {
1970 int charset = CHAR_CHARSET (it->char_to_display);
1971
1972 it->glyph_not_available_p = 1;
1973 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
1974 * CHARSET_WIDTH (charset));
1975 it->phys_ascent = font->ascent + boff;
1976 it->phys_descent = font->descent - boff;
1977 }
1978 else
1979 {
1980 it->pixel_width = pcm->width;
1981 it->phys_ascent = pcm->ascent + boff;
1982 it->phys_descent = pcm->descent - boff;
1983 if (it->glyph_row
1984 && (pcm->lbearing < 0
1985 || pcm->rbearing > pcm->width))
1986 it->glyph_row->contains_overlapping_glyphs_p = 1;
1987 }
b4192550
KH
1988 it->nglyphs = 1;
1989 it->ascent = font->ascent + boff;
1990 it->descent = font->descent - boff;
06a2c219
GM
1991 if (face->box != FACE_NO_BOX)
1992 {
1993 int thick = face->box_line_width;
ea2ba0d4
KH
1994
1995 if (thick > 0)
1996 {
1997 it->ascent += thick;
1998 it->descent += thick;
1999 }
2000 else
2001 thick = - thick;
06a2c219
GM
2002
2003 if (it->start_of_box_run_p)
2004 it->pixel_width += thick;
2005 if (it->end_of_box_run_p)
2006 it->pixel_width += thick;
2007 }
2008
2009 /* If face has an overline, add the height of the overline
2010 (1 pixel) and a 1 pixel margin to the character height. */
2011 if (face->overline_p)
2012 it->ascent += 2;
2013
2014 take_vertical_position_into_account (it);
2015
2016 if (it->glyph_row)
2017 x_append_glyph (it);
2018 }
a4249304 2019 it->multibyte_p = saved_multibyte_p;
06a2c219 2020 }
b4192550
KH
2021 else if (it->what == IT_COMPOSITION)
2022 {
2023 /* Note: A composition is represented as one glyph in the
2024 glyph matrix. There are no padding glyphs. */
2025 XChar2b char2b;
2026 XFontStruct *font;
ee569018 2027 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2028 XCharStruct *pcm;
2029 int font_not_found_p;
2030 struct font_info *font_info;
2031 int boff; /* baseline offset */
2032 struct composition *cmp = composition_table[it->cmp_id];
2033
2034 /* Maybe translate single-byte characters to multibyte. */
2035 it->char_to_display = it->c;
2036 if (unibyte_display_via_language_environment
2037 && SINGLE_BYTE_CHAR_P (it->c)
2038 && (it->c >= 0240
2039 || (it->c >= 0200
2040 && !NILP (Vnonascii_translation_table))))
2041 {
2042 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2043 }
2044
2045 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2046 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2047 face = FACE_FROM_ID (it->f, it->face_id);
2048 x_get_char_face_and_encoding (it->f, it->char_to_display,
2049 it->face_id, &char2b, it->multibyte_p);
b4192550
KH
2050 font = face->font;
2051
2052 /* When no suitable font found, use the default font. */
2053 font_not_found_p = font == NULL;
2054 if (font_not_found_p)
2055 {
2056 font = FRAME_FONT (it->f);
2057 boff = it->f->output_data.x->baseline_offset;
2058 font_info = NULL;
2059 }
2060 else
2061 {
2062 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2063 boff = font_info->baseline_offset;
2064 if (font_info->vertical_centering)
2065 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2066 }
2067
2068 /* There are no padding glyphs, so there is only one glyph to
2069 produce for the composition. Important is that pixel_width,
2070 ascent and descent are the values of what is drawn by
2071 draw_glyphs (i.e. the values of the overall glyphs composed). */
2072 it->nglyphs = 1;
2073
2074 /* If we have not yet calculated pixel size data of glyphs of
2075 the composition for the current face font, calculate them
2076 now. Theoretically, we have to check all fonts for the
2077 glyphs, but that requires much time and memory space. So,
2078 here we check only the font of the first glyph. This leads
2079 to incorrect display very rarely, and C-l (recenter) can
2080 correct the display anyway. */
2081 if (cmp->font != (void *) font)
2082 {
2083 /* Ascent and descent of the font of the first character of
2084 this composition (adjusted by baseline offset). Ascent
2085 and descent of overall glyphs should not be less than
2086 them respectively. */
2087 int font_ascent = font->ascent + boff;
2088 int font_descent = font->descent - boff;
2089 /* Bounding box of the overall glyphs. */
2090 int leftmost, rightmost, lowest, highest;
329bed06 2091 int i, width, ascent, descent;
b4192550
KH
2092
2093 cmp->font = (void *) font;
2094
2095 /* Initialize the bounding box. */
1bdeec2e
KH
2096 if (font_info
2097 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2098 {
2099 width = pcm->width;
2100 ascent = pcm->ascent;
2101 descent = pcm->descent;
2102 }
2103 else
2104 {
2105 width = FONT_WIDTH (font);
2106 ascent = font->ascent;
2107 descent = font->descent;
2108 }
2109
2110 rightmost = width;
2111 lowest = - descent + boff;
2112 highest = ascent + boff;
b4192550 2113 leftmost = 0;
329bed06 2114
b4192550
KH
2115 if (font_info
2116 && font_info->default_ascent
2117 && CHAR_TABLE_P (Vuse_default_ascent)
2118 && !NILP (Faref (Vuse_default_ascent,
2119 make_number (it->char_to_display))))
2120 highest = font_info->default_ascent + boff;
2121
2122 /* Draw the first glyph at the normal position. It may be
2123 shifted to right later if some other glyphs are drawn at
2124 the left. */
2125 cmp->offsets[0] = 0;
2126 cmp->offsets[1] = boff;
2127
2128 /* Set cmp->offsets for the remaining glyphs. */
2129 for (i = 1; i < cmp->glyph_len; i++)
2130 {
2131 int left, right, btm, top;
2132 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2133 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2134
2135 face = FACE_FROM_ID (it->f, face_id);
2136 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2137 it->multibyte_p);
b4192550
KH
2138 font = face->font;
2139 if (font == NULL)
2140 {
2141 font = FRAME_FONT (it->f);
2142 boff = it->f->output_data.x->baseline_offset;
2143 font_info = NULL;
2144 }
2145 else
2146 {
2147 font_info
2148 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2149 boff = font_info->baseline_offset;
2150 if (font_info->vertical_centering)
2151 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2152 }
2153
1bdeec2e
KH
2154 if (font_info
2155 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2156 {
2157 width = pcm->width;
2158 ascent = pcm->ascent;
2159 descent = pcm->descent;
2160 }
2161 else
2162 {
2163 width = FONT_WIDTH (font);
1bdeec2e
KH
2164 ascent = 1;
2165 descent = 0;
329bed06 2166 }
b4192550
KH
2167
2168 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2169 {
2170 /* Relative composition with or without
2171 alternate chars. */
329bed06
GM
2172 left = (leftmost + rightmost - width) / 2;
2173 btm = - descent + boff;
b4192550
KH
2174 if (font_info && font_info->relative_compose
2175 && (! CHAR_TABLE_P (Vignore_relative_composition)
2176 || NILP (Faref (Vignore_relative_composition,
2177 make_number (ch)))))
2178 {
2179
329bed06 2180 if (- descent >= font_info->relative_compose)
b4192550
KH
2181 /* One extra pixel between two glyphs. */
2182 btm = highest + 1;
329bed06 2183 else if (ascent <= 0)
b4192550 2184 /* One extra pixel between two glyphs. */
329bed06 2185 btm = lowest - 1 - ascent - descent;
b4192550
KH
2186 }
2187 }
2188 else
2189 {
2190 /* A composition rule is specified by an integer
2191 value that encodes global and new reference
2192 points (GREF and NREF). GREF and NREF are
2193 specified by numbers as below:
2194
2195 0---1---2 -- ascent
2196 | |
2197 | |
2198 | |
2199 9--10--11 -- center
2200 | |
2201 ---3---4---5--- baseline
2202 | |
2203 6---7---8 -- descent
2204 */
2205 int rule = COMPOSITION_RULE (cmp, i);
2206 int gref, nref, grefx, grefy, nrefx, nrefy;
2207
2208 COMPOSITION_DECODE_RULE (rule, gref, nref);
2209 grefx = gref % 3, nrefx = nref % 3;
2210 grefy = gref / 3, nrefy = nref / 3;
2211
2212 left = (leftmost
2213 + grefx * (rightmost - leftmost) / 2
329bed06 2214 - nrefx * width / 2);
b4192550
KH
2215 btm = ((grefy == 0 ? highest
2216 : grefy == 1 ? 0
2217 : grefy == 2 ? lowest
2218 : (highest + lowest) / 2)
329bed06
GM
2219 - (nrefy == 0 ? ascent + descent
2220 : nrefy == 1 ? descent - boff
b4192550 2221 : nrefy == 2 ? 0
329bed06 2222 : (ascent + descent) / 2));
b4192550
KH
2223 }
2224
2225 cmp->offsets[i * 2] = left;
329bed06 2226 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2227
2228 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2229 right = left + width;
2230 top = btm + descent + ascent;
b4192550
KH
2231 if (left < leftmost)
2232 leftmost = left;
2233 if (right > rightmost)
2234 rightmost = right;
2235 if (top > highest)
2236 highest = top;
2237 if (btm < lowest)
2238 lowest = btm;
2239 }
2240
2241 /* If there are glyphs whose x-offsets are negative,
2242 shift all glyphs to the right and make all x-offsets
2243 non-negative. */
2244 if (leftmost < 0)
2245 {
2246 for (i = 0; i < cmp->glyph_len; i++)
2247 cmp->offsets[i * 2] -= leftmost;
2248 rightmost -= leftmost;
2249 }
2250
2251 cmp->pixel_width = rightmost;
2252 cmp->ascent = highest;
2253 cmp->descent = - lowest;
2254 if (cmp->ascent < font_ascent)
2255 cmp->ascent = font_ascent;
2256 if (cmp->descent < font_descent)
2257 cmp->descent = font_descent;
2258 }
2259
2260 it->pixel_width = cmp->pixel_width;
2261 it->ascent = it->phys_ascent = cmp->ascent;
2262 it->descent = it->phys_descent = cmp->descent;
2263
2264 if (face->box != FACE_NO_BOX)
2265 {
2266 int thick = face->box_line_width;
ea2ba0d4
KH
2267
2268 if (thick > 0)
2269 {
2270 it->ascent += thick;
2271 it->descent += thick;
2272 }
2273 else
2274 thick = - thick;
b4192550
KH
2275
2276 if (it->start_of_box_run_p)
2277 it->pixel_width += thick;
2278 if (it->end_of_box_run_p)
2279 it->pixel_width += thick;
2280 }
2281
2282 /* If face has an overline, add the height of the overline
2283 (1 pixel) and a 1 pixel margin to the character height. */
2284 if (face->overline_p)
2285 it->ascent += 2;
2286
2287 take_vertical_position_into_account (it);
2288
2289 if (it->glyph_row)
2290 x_append_composite_glyph (it);
2291 }
06a2c219
GM
2292 else if (it->what == IT_IMAGE)
2293 x_produce_image_glyph (it);
2294 else if (it->what == IT_STRETCH)
2295 x_produce_stretch_glyph (it);
2296
3017fdd1
GM
2297 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2298 because this isn't true for images with `:ascent 100'. */
2299 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2300 if (it->area == TEXT_AREA)
2301 it->current_x += it->pixel_width;
66ac4b0e 2302
d365f5bb
GM
2303 it->descent += it->extra_line_spacing;
2304
06a2c219
GM
2305 it->max_ascent = max (it->max_ascent, it->ascent);
2306 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2307 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2308 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2309}
2310
2311
2312/* Estimate the pixel height of the mode or top line on frame F.
2313 FACE_ID specifies what line's height to estimate. */
2314
2315int
2316x_estimate_mode_line_height (f, face_id)
2317 struct frame *f;
2318 enum face_id face_id;
2319{
43281ee3 2320 int height = FONT_HEIGHT (FRAME_FONT (f));
06a2c219
GM
2321
2322 /* This function is called so early when Emacs starts that the face
2323 cache and mode line face are not yet initialized. */
2324 if (FRAME_FACE_CACHE (f))
2325 {
2326 struct face *face = FACE_FROM_ID (f, face_id);
2327 if (face)
43281ee3
GM
2328 {
2329 if (face->font)
2330 height = FONT_HEIGHT (face->font);
ea2ba0d4
KH
2331 if (face->box_line_width > 0)
2332 height += 2 * face->box_line_width;
43281ee3 2333 }
06a2c219
GM
2334 }
2335
2336 return height;
2337}
2338
2339\f
2340/***********************************************************************
2341 Glyph display
2342 ***********************************************************************/
2343
2344/* A sequence of glyphs to be drawn in the same face.
2345
2346 This data structure is not really completely X specific, so it
2347 could possibly, at least partially, be useful for other systems. It
2348 is currently not part of the external redisplay interface because
2349 it's not clear what other systems will need. */
2350
2351struct glyph_string
2352{
2353 /* X-origin of the string. */
2354 int x;
2355
2356 /* Y-origin and y-position of the base line of this string. */
2357 int y, ybase;
2358
2359 /* The width of the string, not including a face extension. */
2360 int width;
2361
2362 /* The width of the string, including a face extension. */
2363 int background_width;
2364
2365 /* The height of this string. This is the height of the line this
2366 string is drawn in, and can be different from the height of the
2367 font the string is drawn in. */
2368 int height;
2369
2370 /* Number of pixels this string overwrites in front of its x-origin.
2371 This number is zero if the string has an lbearing >= 0; it is
2372 -lbearing, if the string has an lbearing < 0. */
2373 int left_overhang;
2374
2375 /* Number of pixels this string overwrites past its right-most
2376 nominal x-position, i.e. x + width. Zero if the string's
2377 rbearing is <= its nominal width, rbearing - width otherwise. */
2378 int right_overhang;
2379
2380 /* The frame on which the glyph string is drawn. */
2381 struct frame *f;
2382
2383 /* The window on which the glyph string is drawn. */
2384 struct window *w;
2385
2386 /* X display and window for convenience. */
2387 Display *display;
2388 Window window;
2389
2390 /* The glyph row for which this string was built. It determines the
2391 y-origin and height of the string. */
2392 struct glyph_row *row;
2393
2394 /* The area within row. */
2395 enum glyph_row_area area;
2396
2397 /* Characters to be drawn, and number of characters. */
2398 XChar2b *char2b;
2399 int nchars;
2400
06a2c219
GM
2401 /* A face-override for drawing cursors, mouse face and similar. */
2402 enum draw_glyphs_face hl;
2403
2404 /* Face in which this string is to be drawn. */
2405 struct face *face;
2406
2407 /* Font in which this string is to be drawn. */
2408 XFontStruct *font;
2409
2410 /* Font info for this string. */
2411 struct font_info *font_info;
2412
b4192550
KH
2413 /* Non-null means this string describes (part of) a composition.
2414 All characters from char2b are drawn composed. */
2415 struct composition *cmp;
06a2c219
GM
2416
2417 /* Index of this glyph string's first character in the glyph
b4192550
KH
2418 definition of CMP. If this is zero, this glyph string describes
2419 the first character of a composition. */
06a2c219
GM
2420 int gidx;
2421
2422 /* 1 means this glyph strings face has to be drawn to the right end
2423 of the window's drawing area. */
2424 unsigned extends_to_end_of_line_p : 1;
2425
2426 /* 1 means the background of this string has been drawn. */
2427 unsigned background_filled_p : 1;
2428
2429 /* 1 means glyph string must be drawn with 16-bit functions. */
2430 unsigned two_byte_p : 1;
2431
2432 /* 1 means that the original font determined for drawing this glyph
2433 string could not be loaded. The member `font' has been set to
2434 the frame's default font in this case. */
2435 unsigned font_not_found_p : 1;
2436
2437 /* 1 means that the face in which this glyph string is drawn has a
2438 stipple pattern. */
2439 unsigned stippled_p : 1;
2440
66ac4b0e
GM
2441 /* 1 means only the foreground of this glyph string must be drawn,
2442 and we should use the physical height of the line this glyph
2443 string appears in as clip rect. */
2444 unsigned for_overlaps_p : 1;
2445
06a2c219
GM
2446 /* The GC to use for drawing this glyph string. */
2447 GC gc;
2448
2449 /* A pointer to the first glyph in the string. This glyph
2450 corresponds to char2b[0]. Needed to draw rectangles if
2451 font_not_found_p is 1. */
2452 struct glyph *first_glyph;
2453
2454 /* Image, if any. */
2455 struct image *img;
2456
2457 struct glyph_string *next, *prev;
2458};
2459
2460
61869b99 2461#if GLYPH_DEBUG
06a2c219
GM
2462
2463static void
2464x_dump_glyph_string (s)
2465 struct glyph_string *s;
2466{
2467 fprintf (stderr, "glyph string\n");
2468 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2469 s->x, s->y, s->width, s->height);
2470 fprintf (stderr, " ybase = %d\n", s->ybase);
2471 fprintf (stderr, " hl = %d\n", s->hl);
2472 fprintf (stderr, " left overhang = %d, right = %d\n",
2473 s->left_overhang, s->right_overhang);
2474 fprintf (stderr, " nchars = %d\n", s->nchars);
2475 fprintf (stderr, " extends to end of line = %d\n",
2476 s->extends_to_end_of_line_p);
2477 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2478 fprintf (stderr, " bg width = %d\n", s->background_width);
2479}
2480
2481#endif /* GLYPH_DEBUG */
2482
2483
2484
2485static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2486 struct glyph_string **,
2487 struct glyph_string *,
2488 struct glyph_string *));
2489static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2490 struct glyph_string **,
2491 struct glyph_string *,
2492 struct glyph_string *));
2493static void x_append_glyph_string P_ ((struct glyph_string **,
2494 struct glyph_string **,
2495 struct glyph_string *));
2496static int x_left_overwritten P_ ((struct glyph_string *));
2497static int x_left_overwriting P_ ((struct glyph_string *));
2498static int x_right_overwritten P_ ((struct glyph_string *));
2499static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2500static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2501 int));
06a2c219
GM
2502static void x_init_glyph_string P_ ((struct glyph_string *,
2503 XChar2b *, struct window *,
2504 struct glyph_row *,
2505 enum glyph_row_area, int,
2506 enum draw_glyphs_face));
2507static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2508 enum glyph_row_area, int, int,
f0a48a01 2509 enum draw_glyphs_face, int));
06a2c219
GM
2510static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2511static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2512static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2513 int));
2514static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2515static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2516static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2517static void x_draw_glyph_string P_ ((struct glyph_string *));
2518static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2519static void x_set_cursor_gc P_ ((struct glyph_string *));
2520static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2521static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2522static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2523 int *, int *));
2524static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2525static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2526 unsigned long *, double, int));
06a2c219 2527static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2528 double, int, unsigned long));
06a2c219
GM
2529static void x_setup_relief_colors P_ ((struct glyph_string *));
2530static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2531static void x_draw_image_relief P_ ((struct glyph_string *));
2532static void x_draw_image_foreground P_ ((struct glyph_string *));
2533static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2534static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2535static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2536 int, int, int));
2537static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2538 int, int, int, int, XRectangle *));
2539static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2540 int, int, int, XRectangle *));
66ac4b0e
GM
2541static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2542 enum glyph_row_area));
209f68d9
GM
2543static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2544 struct glyph_row *,
2545 enum glyph_row_area, int, int));
06a2c219 2546
163dcff3
GM
2547#if GLYPH_DEBUG
2548static void x_check_font P_ ((struct frame *, XFontStruct *));
2549#endif
2550
06a2c219 2551
06a2c219
GM
2552/* Append the list of glyph strings with head H and tail T to the list
2553 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2554
2555static INLINE void
2556x_append_glyph_string_lists (head, tail, h, t)
2557 struct glyph_string **head, **tail;
2558 struct glyph_string *h, *t;
2559{
2560 if (h)
2561 {
2562 if (*head)
2563 (*tail)->next = h;
2564 else
2565 *head = h;
2566 h->prev = *tail;
2567 *tail = t;
2568 }
2569}
2570
2571
2572/* Prepend the list of glyph strings with head H and tail T to the
2573 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2574 result. */
2575
2576static INLINE void
2577x_prepend_glyph_string_lists (head, tail, h, t)
2578 struct glyph_string **head, **tail;
2579 struct glyph_string *h, *t;
2580{
2581 if (h)
2582 {
2583 if (*head)
2584 (*head)->prev = t;
2585 else
2586 *tail = t;
2587 t->next = *head;
2588 *head = h;
2589 }
2590}
2591
2592
2593/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2594 Set *HEAD and *TAIL to the resulting list. */
2595
2596static INLINE void
2597x_append_glyph_string (head, tail, s)
2598 struct glyph_string **head, **tail;
2599 struct glyph_string *s;
2600{
2601 s->next = s->prev = NULL;
2602 x_append_glyph_string_lists (head, tail, s, s);
2603}
2604
2605
2606/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2607 face. */
2608
2609static void
2610x_set_cursor_gc (s)
2611 struct glyph_string *s;
2612{
2613 if (s->font == FRAME_FONT (s->f)
2614 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2615 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2616 && !s->cmp)
06a2c219
GM
2617 s->gc = s->f->output_data.x->cursor_gc;
2618 else
2619 {
2620 /* Cursor on non-default face: must merge. */
2621 XGCValues xgcv;
2622 unsigned long mask;
2623
2624 xgcv.background = s->f->output_data.x->cursor_pixel;
2625 xgcv.foreground = s->face->background;
2626
2627 /* If the glyph would be invisible, try a different foreground. */
2628 if (xgcv.foreground == xgcv.background)
2629 xgcv.foreground = s->face->foreground;
2630 if (xgcv.foreground == xgcv.background)
2631 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2632 if (xgcv.foreground == xgcv.background)
2633 xgcv.foreground = s->face->foreground;
2634
2635 /* Make sure the cursor is distinct from text in this face. */
2636 if (xgcv.background == s->face->background
2637 && xgcv.foreground == s->face->foreground)
2638 {
2639 xgcv.background = s->face->foreground;
2640 xgcv.foreground = s->face->background;
2641 }
2642
2643 IF_DEBUG (x_check_font (s->f, s->font));
2644 xgcv.font = s->font->fid;
2645 xgcv.graphics_exposures = False;
2646 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2647
2648 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2649 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2650 mask, &xgcv);
2651 else
2652 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2653 = XCreateGC (s->display, s->window, mask, &xgcv);
2654
2655 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2656 }
2657}
2658
2659
2660/* Set up S->gc of glyph string S for drawing text in mouse face. */
2661
2662static void
2663x_set_mouse_face_gc (s)
2664 struct glyph_string *s;
2665{
2666 int face_id;
ee569018 2667 struct face *face;
06a2c219 2668
e4ded23c 2669 /* What face has to be used last for the mouse face? */
06a2c219 2670 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2671 face = FACE_FROM_ID (s->f, face_id);
e4ded23c
GM
2672 if (face == NULL)
2673 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2674
033e3e18
GM
2675 if (s->first_glyph->type == CHAR_GLYPH)
2676 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2677 else
2678 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2679 s->face = FACE_FROM_ID (s->f, face_id);
2680 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2681
2682 /* If font in this face is same as S->font, use it. */
2683 if (s->font == s->face->font)
2684 s->gc = s->face->gc;
2685 else
2686 {
2687 /* Otherwise construct scratch_cursor_gc with values from FACE
2688 but font FONT. */
2689 XGCValues xgcv;
2690 unsigned long mask;
2691
2692 xgcv.background = s->face->background;
2693 xgcv.foreground = s->face->foreground;
2694 IF_DEBUG (x_check_font (s->f, s->font));
2695 xgcv.font = s->font->fid;
2696 xgcv.graphics_exposures = False;
2697 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2698
2699 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2700 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2701 mask, &xgcv);
2702 else
2703 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2704 = XCreateGC (s->display, s->window, mask, &xgcv);
2705
2706 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2707 }
2708
2709 xassert (s->gc != 0);
2710}
2711
2712
2713/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2714 Faces to use in the mode line have already been computed when the
2715 matrix was built, so there isn't much to do, here. */
2716
2717static INLINE void
2718x_set_mode_line_face_gc (s)
2719 struct glyph_string *s;
2720{
2721 s->gc = s->face->gc;
06a2c219
GM
2722}
2723
2724
2725/* Set S->gc of glyph string S for drawing that glyph string. Set
2726 S->stippled_p to a non-zero value if the face of S has a stipple
2727 pattern. */
2728
2729static INLINE void
2730x_set_glyph_string_gc (s)
2731 struct glyph_string *s;
2732{
209f68d9
GM
2733 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2734
06a2c219
GM
2735 if (s->hl == DRAW_NORMAL_TEXT)
2736 {
2737 s->gc = s->face->gc;
2738 s->stippled_p = s->face->stipple != 0;
2739 }
2740 else if (s->hl == DRAW_INVERSE_VIDEO)
2741 {
2742 x_set_mode_line_face_gc (s);
2743 s->stippled_p = s->face->stipple != 0;
2744 }
2745 else if (s->hl == DRAW_CURSOR)
2746 {
2747 x_set_cursor_gc (s);
2748 s->stippled_p = 0;
2749 }
2750 else if (s->hl == DRAW_MOUSE_FACE)
2751 {
2752 x_set_mouse_face_gc (s);
2753 s->stippled_p = s->face->stipple != 0;
2754 }
2755 else if (s->hl == DRAW_IMAGE_RAISED
2756 || s->hl == DRAW_IMAGE_SUNKEN)
2757 {
2758 s->gc = s->face->gc;
2759 s->stippled_p = s->face->stipple != 0;
2760 }
2761 else
2762 {
2763 s->gc = s->face->gc;
2764 s->stippled_p = s->face->stipple != 0;
2765 }
2766
2767 /* GC must have been set. */
2768 xassert (s->gc != 0);
2769}
2770
2771
2772/* Return in *R the clipping rectangle for glyph string S. */
2773
2774static void
2775x_get_glyph_string_clip_rect (s, r)
2776 struct glyph_string *s;
2777 XRectangle *r;
2778{
2779 if (s->row->full_width_p)
2780 {
2781 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2782 int canon_x = CANON_X_UNIT (s->f);
2783
2784 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2785 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2786
2787 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2788 {
1da3fd71 2789 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2790 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2791 r->x -= width;
2792 }
2793
b9432a85 2794 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2795
06a2c219
GM
2796 /* Unless displaying a mode or menu bar line, which are always
2797 fully visible, clip to the visible part of the row. */
2798 if (s->w->pseudo_window_p)
2799 r->height = s->row->visible_height;
2800 else
2801 r->height = s->height;
2802 }
2803 else
2804 {
2805 /* This is a text line that may be partially visible. */
2806 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2807 r->width = window_box_width (s->w, s->area);
2808 r->height = s->row->visible_height;
2809 }
2810
66ac4b0e
GM
2811 /* If S draws overlapping rows, it's sufficient to use the top and
2812 bottom of the window for clipping because this glyph string
2813 intentionally draws over other lines. */
2814 if (s->for_overlaps_p)
2815 {
045dee35 2816 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2817 r->height = window_text_bottom_y (s->w) - r->y;
2818 }
98b8a90f
GM
2819 else
2820 {
2821 /* Don't use S->y for clipping because it doesn't take partially
2822 visible lines into account. For example, it can be negative for
2823 partially visible lines at the top of a window. */
2824 if (!s->row->full_width_p
2825 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
2826 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
2827 else
2828 r->y = max (0, s->row->y);
2829
2830 /* If drawing a tool-bar window, draw it over the internal border
2831 at the top of the window. */
2832 if (s->w == XWINDOW (s->f->tool_bar_window))
2833 r->y -= s->f->output_data.x->internal_border_width;
2834 }
2835
66ac4b0e 2836 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2837}
2838
2839
2840/* Set clipping for output of glyph string S. S may be part of a mode
2841 line or menu if we don't have X toolkit support. */
2842
2843static INLINE void
2844x_set_glyph_string_clipping (s)
2845 struct glyph_string *s;
2846{
2847 XRectangle r;
2848 x_get_glyph_string_clip_rect (s, &r);
2849 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2850}
2851
2852
2853/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2854 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2855
2856static INLINE void
2857x_compute_glyph_string_overhangs (s)
2858 struct glyph_string *s;
2859{
b4192550 2860 if (s->cmp == NULL
06a2c219
GM
2861 && s->first_glyph->type == CHAR_GLYPH)
2862 {
2863 XCharStruct cs;
2864 int direction, font_ascent, font_descent;
2865 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2866 &font_ascent, &font_descent, &cs);
2867 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2868 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2869 }
2870}
2871
2872
2873/* Compute overhangs and x-positions for glyph string S and its
2874 predecessors, or successors. X is the starting x-position for S.
2875 BACKWARD_P non-zero means process predecessors. */
2876
2877static void
2878x_compute_overhangs_and_x (s, x, backward_p)
2879 struct glyph_string *s;
2880 int x;
2881 int backward_p;
2882{
2883 if (backward_p)
2884 {
2885 while (s)
2886 {
2887 x_compute_glyph_string_overhangs (s);
2888 x -= s->width;
2889 s->x = x;
2890 s = s->prev;
2891 }
2892 }
2893 else
2894 {
2895 while (s)
2896 {
2897 x_compute_glyph_string_overhangs (s);
2898 s->x = x;
2899 x += s->width;
2900 s = s->next;
2901 }
2902 }
2903}
2904
2905
2906/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2907 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2908 assumed to be zero. */
06a2c219
GM
2909
2910static void
2911x_get_glyph_overhangs (glyph, f, left, right)
2912 struct glyph *glyph;
2913 struct frame *f;
2914 int *left, *right;
2915{
06a2c219
GM
2916 *left = *right = 0;
2917
b4192550 2918 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2919 {
2920 XFontStruct *font;
2921 struct face *face;
2922 struct font_info *font_info;
2923 XChar2b char2b;
ee569018
KH
2924 XCharStruct *pcm;
2925
2926 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2927 font = face->font;
2928 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2929 if (font
2930 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2931 {
06a2c219
GM
2932 if (pcm->rbearing > pcm->width)
2933 *right = pcm->rbearing - pcm->width;
2934 if (pcm->lbearing < 0)
2935 *left = -pcm->lbearing;
2936 }
2937 }
2938}
2939
2940
2941/* Return the index of the first glyph preceding glyph string S that
2942 is overwritten by S because of S's left overhang. Value is -1
2943 if no glyphs are overwritten. */
2944
2945static int
2946x_left_overwritten (s)
2947 struct glyph_string *s;
2948{
2949 int k;
2950
2951 if (s->left_overhang)
2952 {
2953 int x = 0, i;
2954 struct glyph *glyphs = s->row->glyphs[s->area];
2955 int first = s->first_glyph - glyphs;
2956
2957 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2958 x -= glyphs[i].pixel_width;
2959
2960 k = i + 1;
2961 }
2962 else
2963 k = -1;
2964
2965 return k;
2966}
2967
2968
2969/* Return the index of the first glyph preceding glyph string S that
2970 is overwriting S because of its right overhang. Value is -1 if no
2971 glyph in front of S overwrites S. */
2972
2973static int
2974x_left_overwriting (s)
2975 struct glyph_string *s;
2976{
2977 int i, k, x;
2978 struct glyph *glyphs = s->row->glyphs[s->area];
2979 int first = s->first_glyph - glyphs;
2980
2981 k = -1;
2982 x = 0;
2983 for (i = first - 1; i >= 0; --i)
2984 {
2985 int left, right;
2986 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2987 if (x + right > 0)
2988 k = i;
2989 x -= glyphs[i].pixel_width;
2990 }
2991
2992 return k;
2993}
2994
2995
2996/* Return the index of the last glyph following glyph string S that is
2997 not overwritten by S because of S's right overhang. Value is -1 if
2998 no such glyph is found. */
2999
3000static int
3001x_right_overwritten (s)
3002 struct glyph_string *s;
3003{
3004 int k = -1;
3005
3006 if (s->right_overhang)
3007 {
3008 int x = 0, i;
3009 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3010 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3011 int end = s->row->used[s->area];
3012
3013 for (i = first; i < end && s->right_overhang > x; ++i)
3014 x += glyphs[i].pixel_width;
3015
3016 k = i;
3017 }
3018
3019 return k;
3020}
3021
3022
3023/* Return the index of the last glyph following glyph string S that
3024 overwrites S because of its left overhang. Value is negative
3025 if no such glyph is found. */
3026
3027static int
3028x_right_overwriting (s)
3029 struct glyph_string *s;
3030{
3031 int i, k, x;
3032 int end = s->row->used[s->area];
3033 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3034 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3035
3036 k = -1;
3037 x = 0;
3038 for (i = first; i < end; ++i)
3039 {
3040 int left, right;
3041 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3042 if (x - left < 0)
3043 k = i;
3044 x += glyphs[i].pixel_width;
3045 }
3046
3047 return k;
3048}
3049
3050
3051/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3052
3053static INLINE void
3054x_clear_glyph_string_rect (s, x, y, w, h)
3055 struct glyph_string *s;
3056 int x, y, w, h;
3057{
3058 XGCValues xgcv;
3059 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3060 XSetForeground (s->display, s->gc, xgcv.background);
3061 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3062 XSetForeground (s->display, s->gc, xgcv.foreground);
3063}
3064
3065
3066/* Draw the background of glyph_string S. If S->background_filled_p
3067 is non-zero don't draw it. FORCE_P non-zero means draw the
3068 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3069 when a string preceding S draws into the background of S, or S
3070 contains the first component of a composition. */
06a2c219
GM
3071
3072static void
3073x_draw_glyph_string_background (s, force_p)
3074 struct glyph_string *s;
3075 int force_p;
3076{
3077 /* Nothing to do if background has already been drawn or if it
3078 shouldn't be drawn in the first place. */
3079 if (!s->background_filled_p)
3080 {
ea2ba0d4
KH
3081 int box_line_width = max (s->face->box_line_width, 0);
3082
b4192550 3083 if (s->stippled_p)
06a2c219
GM
3084 {
3085 /* Fill background with a stipple pattern. */
3086 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3087 XFillRectangle (s->display, s->window, s->gc, s->x,
ea2ba0d4 3088 s->y + box_line_width,
06a2c219 3089 s->background_width,
ea2ba0d4 3090 s->height - 2 * box_line_width);
06a2c219
GM
3091 XSetFillStyle (s->display, s->gc, FillSolid);
3092 s->background_filled_p = 1;
3093 }
ea2ba0d4 3094 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
06a2c219
GM
3095 || s->font_not_found_p
3096 || s->extends_to_end_of_line_p
06a2c219
GM
3097 || force_p)
3098 {
ea2ba0d4 3099 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
06a2c219 3100 s->background_width,
ea2ba0d4 3101 s->height - 2 * box_line_width);
06a2c219
GM
3102 s->background_filled_p = 1;
3103 }
3104 }
3105}
3106
3107
3108/* Draw the foreground of glyph string S. */
3109
3110static void
3111x_draw_glyph_string_foreground (s)
3112 struct glyph_string *s;
3113{
3114 int i, x;
3115
3116 /* If first glyph of S has a left box line, start drawing the text
3117 of S to the right of that box line. */
3118 if (s->face->box != FACE_NO_BOX
3119 && s->first_glyph->left_box_line_p)
ea2ba0d4 3120 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
3121 else
3122 x = s->x;
3123
b4192550
KH
3124 /* Draw characters of S as rectangles if S's font could not be
3125 loaded. */
3126 if (s->font_not_found_p)
06a2c219 3127 {
b4192550 3128 for (i = 0; i < s->nchars; ++i)
06a2c219 3129 {
b4192550
KH
3130 struct glyph *g = s->first_glyph + i;
3131 XDrawRectangle (s->display, s->window,
3132 s->gc, x, s->y, g->pixel_width - 1,
3133 s->height - 1);
3134 x += g->pixel_width;
06a2c219
GM
3135 }
3136 }
3137 else
3138 {
b4192550
KH
3139 char *char1b = (char *) s->char2b;
3140 int boff = s->font_info->baseline_offset;
06a2c219 3141
b4192550
KH
3142 if (s->font_info->vertical_centering)
3143 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3144
3145 /* If we can use 8-bit functions, condense S->char2b. */
3146 if (!s->two_byte_p)
3147 for (i = 0; i < s->nchars; ++i)
3148 char1b[i] = s->char2b[i].byte2;
3149
3150 /* Draw text with XDrawString if background has already been
3151 filled. Otherwise, use XDrawImageString. (Note that
3152 XDrawImageString is usually faster than XDrawString.) Always
3153 use XDrawImageString when drawing the cursor so that there is
3154 no chance that characters under a box cursor are invisible. */
3155 if (s->for_overlaps_p
3156 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3157 {
3158 /* Draw characters with 16-bit or 8-bit functions. */
3159 if (s->two_byte_p)
3160 XDrawString16 (s->display, s->window, s->gc, x,
3161 s->ybase - boff, s->char2b, s->nchars);
3162 else
3163 XDrawString (s->display, s->window, s->gc, x,
3164 s->ybase - boff, char1b, s->nchars);
3165 }
06a2c219
GM
3166 else
3167 {
b4192550
KH
3168 if (s->two_byte_p)
3169 XDrawImageString16 (s->display, s->window, s->gc, x,
3170 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3171 else
b4192550
KH
3172 XDrawImageString (s->display, s->window, s->gc, x,
3173 s->ybase - boff, char1b, s->nchars);
3174 }
3175 }
3176}
06a2c219 3177
b4192550 3178/* Draw the foreground of composite glyph string S. */
06a2c219 3179
b4192550
KH
3180static void
3181x_draw_composite_glyph_string_foreground (s)
3182 struct glyph_string *s;
3183{
3184 int i, x;
06a2c219 3185
b4192550
KH
3186 /* If first glyph of S has a left box line, start drawing the text
3187 of S to the right of that box line. */
3188 if (s->face->box != FACE_NO_BOX
3189 && s->first_glyph->left_box_line_p)
ea2ba0d4 3190 x = s->x + abs (s->face->box_line_width);
b4192550
KH
3191 else
3192 x = s->x;
06a2c219 3193
b4192550
KH
3194 /* S is a glyph string for a composition. S->gidx is the index of
3195 the first character drawn for glyphs of this composition.
3196 S->gidx == 0 means we are drawing the very first character of
3197 this composition. */
06a2c219 3198
b4192550
KH
3199 /* Draw a rectangle for the composition if the font for the very
3200 first character of the composition could not be loaded. */
3201 if (s->font_not_found_p)
3202 {
3203 if (s->gidx == 0)
3204 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3205 s->width - 1, s->height - 1);
3206 }
3207 else
3208 {
3209 for (i = 0; i < s->nchars; i++, ++s->gidx)
3210 XDrawString16 (s->display, s->window, s->gc,
3211 x + s->cmp->offsets[s->gidx * 2],
3212 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3213 s->char2b + i, 1);
06a2c219
GM
3214 }
3215}
3216
3217
80c32bcc
GM
3218#ifdef USE_X_TOOLKIT
3219
3e71d8f2 3220static struct frame *x_frame_of_widget P_ ((Widget));
651f03b6
GM
3221static Boolean cvt_string_to_pixel P_ ((Display *, XrmValue *, Cardinal *,
3222 XrmValue *, XrmValue *, XtPointer *));
3223static void cvt_pixel_dtor P_ ((XtAppContext, XrmValue *, XtPointer,
3224 XrmValue *, Cardinal *));
80c32bcc 3225
3e71d8f2
GM
3226
3227/* Return the frame on which widget WIDGET is used.. Abort if frame
3228 cannot be determined. */
3229
e851c833 3230static struct frame *
3e71d8f2 3231x_frame_of_widget (widget)
80c32bcc 3232 Widget widget;
80c32bcc 3233{
80c32bcc 3234 struct x_display_info *dpyinfo;
5c187dee 3235 Lisp_Object tail;
3e71d8f2
GM
3236 struct frame *f;
3237
80c32bcc
GM
3238 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3239
3240 /* Find the top-level shell of the widget. Note that this function
3241 can be called when the widget is not yet realized, so XtWindow
3242 (widget) == 0. That's the reason we can't simply use
3243 x_any_window_to_frame. */
3244 while (!XtIsTopLevelShell (widget))
3245 widget = XtParent (widget);
3246
3247 /* Look for a frame with that top-level widget. Allocate the color
3248 on that frame to get the right gamma correction value. */
3249 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3250 if (GC_FRAMEP (XCAR (tail))
3251 && (f = XFRAME (XCAR (tail)),
3252 (f->output_data.nothing != 1
3253 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3254 && f->output_data.x->widget == widget)
3e71d8f2 3255 return f;
80c32bcc
GM
3256
3257 abort ();
3258}
3259
3e71d8f2
GM
3260
3261/* Allocate the color COLOR->pixel on the screen and display of
3262 widget WIDGET in colormap CMAP. If an exact match cannot be
3263 allocated, try the nearest color available. Value is non-zero
3264 if successful. This is called from lwlib. */
3265
3266int
3267x_alloc_nearest_color_for_widget (widget, cmap, color)
3268 Widget widget;
3269 Colormap cmap;
3270 XColor *color;
3271{
3272 struct frame *f = x_frame_of_widget (widget);
3273 return x_alloc_nearest_color (f, cmap, color);
3274}
3275
3276
46d516e5
MB
3277/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3278 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3279 If this produces the same color as PIXEL, try a color where all RGB
3280 values have DELTA added. Return the allocated color in *PIXEL.
3281 DISPLAY is the X display, CMAP is the colormap to operate on.
3282 Value is non-zero if successful. */
3283
3284int
3285x_alloc_lighter_color_for_widget (widget, display, cmap, pixel, factor, delta)
3286 Widget widget;
3287 Display *display;
3288 Colormap cmap;
3289 unsigned long *pixel;
3290 double factor;
3291 int delta;
3292{
3293 struct frame *f = x_frame_of_widget (widget);
3294 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
3295}
3296
3297
651f03b6
GM
3298/* Structure specifying which arguments should be passed by Xt to
3299 cvt_string_to_pixel. We want the widget's screen and colormap. */
3300
3301static XtConvertArgRec cvt_string_to_pixel_args[] =
3302 {
3303 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.screen),
3304 sizeof (Screen *)},
3305 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.colormap),
3306 sizeof (Colormap)}
3307 };
3308
3309
3310/* The address of this variable is returned by
3311 cvt_string_to_pixel. */
3312
3313static Pixel cvt_string_to_pixel_value;
3314
3315
3316/* Convert a color name to a pixel color.
3317
3318 DPY is the display we are working on.
3319
3320 ARGS is an array of *NARGS XrmValue structures holding additional
3321 information about the widget for which the conversion takes place.
3322 The contents of this array are determined by the specification
3323 in cvt_string_to_pixel_args.
3324
3325 FROM is a pointer to an XrmValue which points to the color name to
3326 convert. TO is an XrmValue in which to return the pixel color.
3327
3328 CLOSURE_RET is a pointer to user-data, in which we record if
3329 we allocated the color or not.
3330
3331 Value is True if successful, False otherwise. */
3332
3333static Boolean
3334cvt_string_to_pixel (dpy, args, nargs, from, to, closure_ret)
3335 Display *dpy;
3336 XrmValue *args;
3337 Cardinal *nargs;
3338 XrmValue *from, *to;
3339 XtPointer *closure_ret;
3340{
3341 Screen *screen;
3342 Colormap cmap;
3343 Pixel pixel;
3344 String color_name;
3345 XColor color;
3346
3347 if (*nargs != 2)
3348 {
3349 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3350 "wrongParameters", "cvt_string_to_pixel",
3351 "XtToolkitError",
3352 "Screen and colormap args required", NULL, NULL);
3353 return False;
3354 }
3355
3356 screen = *(Screen **) args[0].addr;
3357 cmap = *(Colormap *) args[1].addr;
3358 color_name = (String) from->addr;
3359
3360 if (strcmp (color_name, XtDefaultBackground) == 0)
3361 {
3362 *closure_ret = (XtPointer) False;
3363 pixel = WhitePixelOfScreen (screen);
3364 }
3365 else if (strcmp (color_name, XtDefaultForeground) == 0)
3366 {
3367 *closure_ret = (XtPointer) False;
3368 pixel = BlackPixelOfScreen (screen);
3369 }
3370 else if (XParseColor (dpy, cmap, color_name, &color)
3371 && x_alloc_nearest_color_1 (dpy, cmap, &color))
3372 {
3373 pixel = color.pixel;
3374 *closure_ret = (XtPointer) True;
3375 }
3376 else
3377 {
3378 String params[1];
3379 Cardinal nparams = 1;
3380
3381 params[0] = color_name;
3382 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3383 "badValue", "cvt_string_to_pixel",
3384 "XtToolkitError", "Invalid color `%s'",
3385 params, &nparams);
3386 return False;
3387 }
3388
3389 if (to->addr != NULL)
3390 {
3391 if (to->size < sizeof (Pixel))
3392 {
3393 to->size = sizeof (Pixel);
3394 return False;
3395 }
3396
3397 *(Pixel *) to->addr = pixel;
3398 }
3399 else
3400 {
3401 cvt_string_to_pixel_value = pixel;
3402 to->addr = (XtPointer) &cvt_string_to_pixel_value;
3403 }
3404
3405 to->size = sizeof (Pixel);
3406 return True;
3407}
3408
3409
3410/* Free a pixel color which was previously allocated via
3411 cvt_string_to_pixel. This is registered as the destructor
3412 for this type of resource via XtSetTypeConverter.
3413
3414 APP is the application context in which we work.
3415
3416 TO is a pointer to an XrmValue holding the color to free.
3417 CLOSURE is the value we stored in CLOSURE_RET for this color
3418 in cvt_string_to_pixel.
3419
3420 ARGS and NARGS are like for cvt_string_to_pixel. */
3421
3422static void
3423cvt_pixel_dtor (app, to, closure, args, nargs)
3424 XtAppContext app;
3425 XrmValuePtr to;
3426 XtPointer closure;
3427 XrmValuePtr args;
3428 Cardinal *nargs;
3429{
3430 if (*nargs != 2)
3431 {
3432 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
3433 "XtToolkitError",
3434 "Screen and colormap arguments required",
3435 NULL, NULL);
3436 }
3437 else if (closure != NULL)
3438 {
3439 /* We did allocate the pixel, so free it. */
3440 Screen *screen = *(Screen **) args[0].addr;
3441 Colormap cmap = *(Colormap *) args[1].addr;
3442 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
97762eb7 3443 (Pixel *) to->addr, 1);
651f03b6
GM
3444 }
3445}
3446
3447
80c32bcc
GM
3448#endif /* USE_X_TOOLKIT */
3449
3450
f04e1297 3451/* Value is an array of XColor structures for the contents of the
651f03b6 3452 color map of display DPY. Set *NCELLS to the size of the array.
f04e1297
GM
3453 Note that this probably shouldn't be called for large color maps,
3454 say a 24-bit TrueColor map. */
3455
3456static const XColor *
651f03b6
GM
3457x_color_cells (dpy, ncells)
3458 Display *dpy;
f04e1297
GM
3459 int *ncells;
3460{
651f03b6 3461 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
f04e1297
GM
3462
3463 if (dpyinfo->color_cells == NULL)
3464 {
651f03b6 3465 Screen *screen = dpyinfo->screen;
f04e1297
GM
3466 int i;
3467
3468 dpyinfo->ncolor_cells
651f03b6 3469 = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
f04e1297
GM
3470 dpyinfo->color_cells
3471 = (XColor *) xmalloc (dpyinfo->ncolor_cells
3472 * sizeof *dpyinfo->color_cells);
3473
3474 for (i = 0; i < dpyinfo->ncolor_cells; ++i)
3475 dpyinfo->color_cells[i].pixel = i;
3476
651f03b6 3477 XQueryColors (dpy, dpyinfo->cmap,
f04e1297
GM
3478 dpyinfo->color_cells, dpyinfo->ncolor_cells);
3479 }
3480
3481 *ncells = dpyinfo->ncolor_cells;
3482 return dpyinfo->color_cells;
3483}
3484
3485
3486/* On frame F, translate pixel colors to RGB values for the NCOLORS
3487 colors in COLORS. Use cached information, if available. */
3488
3489void
3490x_query_colors (f, colors, ncolors)
3491 struct frame *f;
3492 XColor *colors;
3493 int ncolors;
3494{
3495 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3496
3497 if (dpyinfo->color_cells)
3498 {
3499 int i;
3500 for (i = 0; i < ncolors; ++i)
3501 {
3502 unsigned long pixel = colors[i].pixel;
3503 xassert (pixel < dpyinfo->ncolor_cells);
3504 xassert (dpyinfo->color_cells[pixel].pixel == pixel);
3505 colors[i] = dpyinfo->color_cells[pixel];
3506 }
3507 }
3508 else
3509 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
3510}
3511
3512
3513/* On frame F, translate pixel color to RGB values for the color in
3514 COLOR. Use cached information, if available. */
3515
3516void
3517x_query_color (f, color)
3518 struct frame *f;
3519 XColor *color;
3520{
3521 x_query_colors (f, color, 1);
3522}
3523
3524
651f03b6
GM
3525/* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
3526 exact match can't be allocated, try the nearest color available.
3527 Value is non-zero if successful. Set *COLOR to the color
3528 allocated. */
06a2c219 3529
651f03b6
GM
3530static int
3531x_alloc_nearest_color_1 (dpy, cmap, color)
3532 Display *dpy;
06a2c219
GM
3533 Colormap cmap;
3534 XColor *color;
3535{
80c32bcc
GM
3536 int rc;
3537
651f03b6 3538 rc = XAllocColor (dpy, cmap, color);
06a2c219
GM
3539 if (rc == 0)
3540 {
3541 /* If we got to this point, the colormap is full, so we're going
3542 to try to get the next closest color. The algorithm used is
3543 a least-squares matching, which is what X uses for closest
3544 color matching with StaticColor visuals. */
3545 int nearest, i;
3546 unsigned long nearest_delta = ~0;
f04e1297 3547 int ncells;
651f03b6 3548 const XColor *cells = x_color_cells (dpy, &ncells);
06a2c219
GM
3549
3550 for (nearest = i = 0; i < ncells; ++i)
3551 {
3552 long dred = (color->red >> 8) - (cells[i].red >> 8);
3553 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3554 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3555 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3556
3557 if (delta < nearest_delta)
3558 {
3559 nearest = i;
3560 nearest_delta = delta;
3561 }
3562 }
3563
3564 color->red = cells[nearest].red;
3565 color->green = cells[nearest].green;
3566 color->blue = cells[nearest].blue;
651f03b6 3567 rc = XAllocColor (dpy, cmap, color);
06a2c219 3568 }
35efe0a1
GM
3569 else
3570 {
3571 /* If allocation succeeded, and the allocated pixel color is not
3572 equal to a cached pixel color recorded earlier, there was a
3573 change in the colormap, so clear the color cache. */
651f03b6 3574 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
35efe0a1
GM
3575 XColor *cached_color;
3576
3577 if (dpyinfo->color_cells
3578 && (cached_color = &dpyinfo->color_cells[color->pixel],
cae71efe
GM
3579 (cached_color->red != color->red
3580 || cached_color->blue != color->blue
3581 || cached_color->green != color->green)))
35efe0a1
GM
3582 {
3583 xfree (dpyinfo->color_cells);
3584 dpyinfo->color_cells = NULL;
3585 dpyinfo->ncolor_cells = 0;
3586 }
3587 }
06a2c219 3588
d9c545da
GM
3589#ifdef DEBUG_X_COLORS
3590 if (rc)
3591 register_color (color->pixel);
3592#endif /* DEBUG_X_COLORS */
3593
06a2c219
GM
3594 return rc;
3595}
3596
3597
651f03b6
GM
3598/* Allocate the color COLOR->pixel on frame F, colormap CMAP. If an
3599 exact match can't be allocated, try the nearest color available.
3600 Value is non-zero if successful. Set *COLOR to the color
3601 allocated. */
3602
3603int
3604x_alloc_nearest_color (f, cmap, color)
3605 struct frame *f;
3606 Colormap cmap;
3607 XColor *color;
3608{
3609 gamma_correct (f, color);
3610 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
3611}
3612
3613
d9c545da
GM
3614/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3615 It's necessary to do this instead of just using PIXEL directly to
3616 get color reference counts right. */
3617
3618unsigned long
3619x_copy_color (f, pixel)
3620 struct frame *f;
3621 unsigned long pixel;
3622{
3623 XColor color;
3624
3625 color.pixel = pixel;
3626 BLOCK_INPUT;
f04e1297 3627 x_query_color (f, &color);
d9c545da
GM
3628 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3629 UNBLOCK_INPUT;
3630#ifdef DEBUG_X_COLORS
3631 register_color (pixel);
3632#endif
3633 return color.pixel;
3634}
3635
3636
3e71d8f2
GM
3637/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3638 It's necessary to do this instead of just using PIXEL directly to
3639 get color reference counts right. */
3640
3641unsigned long
3642x_copy_dpy_color (dpy, cmap, pixel)
3643 Display *dpy;
3644 Colormap cmap;
3645 unsigned long pixel;
3646{
3647 XColor color;
3648
3649 color.pixel = pixel;
3650 BLOCK_INPUT;
3651 XQueryColor (dpy, cmap, &color);
3652 XAllocColor (dpy, cmap, &color);
3653 UNBLOCK_INPUT;
3654#ifdef DEBUG_X_COLORS
3655 register_color (pixel);
3656#endif
3657 return color.pixel;
3658}
3659
3660
6d8b0acd 3661/* Brightness beyond which a color won't have its highlight brightness
d7361edf 3662 boosted.
6d8b0acd 3663
d7361edf
MB
3664 Nominally, highlight colors for `3d' faces are calculated by
3665 brightening an object's color by a constant scale factor, but this
3666 doesn't yield good results for dark colors, so for colors who's
3667 brightness is less than this value (on a scale of 0-65535) have an
3668 use an additional additive factor.
6d8b0acd
MB
3669
3670 The value here is set so that the default menu-bar/mode-line color
3671 (grey75) will not have its highlights changed at all. */
3672#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
3673
3674
06a2c219
GM
3675/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3676 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3677 If this produces the same color as PIXEL, try a color where all RGB
3678 values have DELTA added. Return the allocated color in *PIXEL.
3679 DISPLAY is the X display, CMAP is the colormap to operate on.
3680 Value is non-zero if successful. */
3681
3682static int
3683x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3684 struct frame *f;
3685 Display *display;
3686 Colormap cmap;
3687 unsigned long *pixel;
68c45bf0 3688 double factor;
06a2c219
GM
3689 int delta;
3690{
3691 XColor color, new;
6d8b0acd 3692 long bright;
06a2c219
GM
3693 int success_p;
3694
3695 /* Get RGB color values. */
3696 color.pixel = *pixel;
f04e1297 3697 x_query_color (f, &color);
06a2c219
GM
3698
3699 /* Change RGB values by specified FACTOR. Avoid overflow! */
3700 xassert (factor >= 0);
3701 new.red = min (0xffff, factor * color.red);
3702 new.green = min (0xffff, factor * color.green);
3703 new.blue = min (0xffff, factor * color.blue);
3704
d7361edf
MB
3705 /* Calculate brightness of COLOR. */
3706 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
6d8b0acd
MB
3707
3708 /* We only boost colors that are darker than
3709 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3710 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3711 /* Make an additive adjustment to NEW, because it's dark enough so
3712 that scaling by FACTOR alone isn't enough. */
3713 {
3714 /* How far below the limit this color is (0 - 1, 1 being darker). */
3715 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3716 /* The additive adjustment. */
d7361edf 3717 int min_delta = delta * dimness * factor / 2;
6d8b0acd
MB
3718
3719 if (factor < 1)
3720 {
6d8b0acd
MB
3721 new.red = max (0, new.red - min_delta);
3722 new.green = max (0, new.green - min_delta);
3723 new.blue = max (0, new.blue - min_delta);
3724 }
3725 else
3726 {
3727 new.red = min (0xffff, min_delta + new.red);
3728 new.green = min (0xffff, min_delta + new.green);
3729 new.blue = min (0xffff, min_delta + new.blue);
3730 }
3731 }
3732
06a2c219 3733 /* Try to allocate the color. */
80c32bcc 3734 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3735 if (success_p)
3736 {
3737 if (new.pixel == *pixel)
3738 {
3739 /* If we end up with the same color as before, try adding
3740 delta to the RGB values. */
0d605c67 3741 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3742
3743 new.red = min (0xffff, delta + color.red);
3744 new.green = min (0xffff, delta + color.green);
3745 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3746 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3747 }
3748 else
3749 success_p = 1;
3750 *pixel = new.pixel;
3751 }
3752
3753 return success_p;
3754}
3755
3756
3757/* Set up the foreground color for drawing relief lines of glyph
3758 string S. RELIEF is a pointer to a struct relief containing the GC
3759 with which lines will be drawn. Use a color that is FACTOR or
3760 DELTA lighter or darker than the relief's background which is found
3761 in S->f->output_data.x->relief_background. If such a color cannot
3762 be allocated, use DEFAULT_PIXEL, instead. */
3763
3764static void
3765x_setup_relief_color (f, relief, factor, delta, default_pixel)
3766 struct frame *f;
3767 struct relief *relief;
68c45bf0 3768 double factor;
06a2c219
GM
3769 int delta;
3770 unsigned long default_pixel;
3771{
3772 XGCValues xgcv;
3773 struct x_output *di = f->output_data.x;
3774 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3775 unsigned long pixel;
3776 unsigned long background = di->relief_background;
43bd1b2b 3777 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3778 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3779 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3780
3781 xgcv.graphics_exposures = False;
3782 xgcv.line_width = 1;
3783
3784 /* Free previously allocated color. The color cell will be reused
3785 when it has been freed as many times as it was allocated, so this
3786 doesn't affect faces using the same colors. */
3787 if (relief->gc
3788 && relief->allocated_p)
3789 {
0d605c67 3790 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3791 relief->allocated_p = 0;
3792 }
3793
3794 /* Allocate new color. */
3795 xgcv.foreground = default_pixel;
3796 pixel = background;
dcd08bfb
GM
3797 if (dpyinfo->n_planes != 1
3798 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3799 {
3800 relief->allocated_p = 1;
3801 xgcv.foreground = relief->pixel = pixel;
3802 }
3803
3804 if (relief->gc == 0)
3805 {
dcd08bfb 3806 xgcv.stipple = dpyinfo->gray;
06a2c219 3807 mask |= GCStipple;
dcd08bfb 3808 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3809 }
3810 else
dcd08bfb 3811 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3812}
3813
3814
3815/* Set up colors for the relief lines around glyph string S. */
3816
3817static void
3818x_setup_relief_colors (s)
3819 struct glyph_string *s;
3820{
3821 struct x_output *di = s->f->output_data.x;
3822 unsigned long color;
3823
3824 if (s->face->use_box_color_for_shadows_p)
3825 color = s->face->box_color;
e2a57b34
MB
3826 else if (s->first_glyph->type == IMAGE_GLYPH
3827 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3828 color = IMAGE_BACKGROUND (s->img, s->f, 0);
06a2c219
GM
3829 else
3830 {
3831 XGCValues xgcv;
3832
3833 /* Get the background color of the face. */
3834 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3835 color = xgcv.background;
3836 }
3837
3838 if (di->white_relief.gc == 0
3839 || color != di->relief_background)
3840 {
3841 di->relief_background = color;
3842 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3843 WHITE_PIX_DEFAULT (s->f));
3844 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3845 BLACK_PIX_DEFAULT (s->f));
3846 }
3847}
3848
3849
3850/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3851 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3852 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3853 relief. LEFT_P non-zero means draw a relief on the left side of
3854 the rectangle. RIGHT_P non-zero means draw a relief on the right
3855 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3856 when drawing. */
3857
3858static void
3859x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3860 raised_p, left_p, right_p, clip_rect)
3861 struct frame *f;
3862 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3863 XRectangle *clip_rect;
3864{
de507556
GM
3865 Display *dpy = FRAME_X_DISPLAY (f);
3866 Window window = FRAME_X_WINDOW (f);
06a2c219
GM
3867 int i;
3868 GC gc;
3869
3870 if (raised_p)
3871 gc = f->output_data.x->white_relief.gc;
3872 else
3873 gc = f->output_data.x->black_relief.gc;
de507556 3874 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3875
3876 /* Top. */
3877 for (i = 0; i < width; ++i)
de507556 3878 XDrawLine (dpy, window, gc,
06a2c219
GM
3879 left_x + i * left_p, top_y + i,
3880 right_x + 1 - i * right_p, top_y + i);
3881
3882 /* Left. */
3883 if (left_p)
3884 for (i = 0; i < width; ++i)
de507556 3885 XDrawLine (dpy, window, gc,
44655e77 3886 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
06a2c219 3887
de507556 3888 XSetClipMask (dpy, gc, None);
06a2c219
GM
3889 if (raised_p)
3890 gc = f->output_data.x->black_relief.gc;
3891 else
3892 gc = f->output_data.x->white_relief.gc;
de507556 3893 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3894
3895 /* Bottom. */
3896 for (i = 0; i < width; ++i)
de507556
GM
3897 XDrawLine (dpy, window, gc,
3898 left_x + i * left_p, bottom_y - i,
3899 right_x + 2 - i * right_p, bottom_y - i);
06a2c219
GM
3900
3901 /* Right. */
3902 if (right_p)
3903 for (i = 0; i < width; ++i)
de507556 3904 XDrawLine (dpy, window, gc,
06a2c219
GM
3905 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3906
de507556 3907 XSetClipMask (dpy, gc, None);
06a2c219
GM
3908}
3909
3910
3911/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3912 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3913 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3914 left side of the rectangle. RIGHT_P non-zero means draw a line
3915 on the right side of the rectangle. CLIP_RECT is the clipping
3916 rectangle to use when drawing. */
3917
3918static void
3919x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3920 left_p, right_p, clip_rect)
3921 struct glyph_string *s;
3922 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3923 XRectangle *clip_rect;
3924{
3925 XGCValues xgcv;
3926
3927 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3928 XSetForeground (s->display, s->gc, s->face->box_color);
3929 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3930
3931 /* Top. */
3932 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3933 left_x, top_y, right_x - left_x + 1, width);
06a2c219
GM
3934
3935 /* Left. */
3936 if (left_p)
3937 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3938 left_x, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3939
3940 /* Bottom. */
3941 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3942 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
06a2c219
GM
3943
3944 /* Right. */
3945 if (right_p)
3946 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3947 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3948
3949 XSetForeground (s->display, s->gc, xgcv.foreground);
3950 XSetClipMask (s->display, s->gc, None);
3951}
3952
3953
3954/* Draw a box around glyph string S. */
3955
3956static void
3957x_draw_glyph_string_box (s)
3958 struct glyph_string *s;
3959{
3960 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3961 int left_p, right_p;
3962 struct glyph *last_glyph;
3963 XRectangle clip_rect;
3964
3965 last_x = window_box_right (s->w, s->area);
3966 if (s->row->full_width_p
3967 && !s->w->pseudo_window_p)
3968 {
110859fc 3969 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
06a2c219
GM
3970 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3971 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3972 }
3973
3974 /* The glyph that may have a right box line. */
b4192550 3975 last_glyph = (s->cmp || s->img
06a2c219
GM
3976 ? s->first_glyph
3977 : s->first_glyph + s->nchars - 1);
3978
ea2ba0d4 3979 width = abs (s->face->box_line_width);
06a2c219
GM
3980 raised_p = s->face->box == FACE_RAISED_BOX;
3981 left_x = s->x;
57ac7c81
GM
3982 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
3983 ? last_x - 1
3984 : min (last_x, s->x + s->background_width) - 1);
06a2c219
GM
3985 top_y = s->y;
3986 bottom_y = top_y + s->height - 1;
3987
3988 left_p = (s->first_glyph->left_box_line_p
3989 || (s->hl == DRAW_MOUSE_FACE
3990 && (s->prev == NULL
3991 || s->prev->hl != s->hl)));
3992 right_p = (last_glyph->right_box_line_p
3993 || (s->hl == DRAW_MOUSE_FACE
3994 && (s->next == NULL
3995 || s->next->hl != s->hl)));
3996
3997 x_get_glyph_string_clip_rect (s, &clip_rect);
3998
3999 if (s->face->box == FACE_SIMPLE_BOX)
4000 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4001 left_p, right_p, &clip_rect);
4002 else
4003 {
4004 x_setup_relief_colors (s);
4005 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
4006 width, raised_p, left_p, right_p, &clip_rect);
4007 }
4008}
4009
4010
4011/* Draw foreground of image glyph string S. */
4012
4013static void
4014x_draw_image_foreground (s)
4015 struct glyph_string *s;
4016{
4017 int x;
95af8492 4018 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4019
4020 /* If first glyph of S has a left box line, start drawing it to the
4021 right of that line. */
4022 if (s->face->box != FACE_NO_BOX
4023 && s->first_glyph->left_box_line_p)
ea2ba0d4 4024 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4025 else
4026 x = s->x;
4027
4028 /* If there is a margin around the image, adjust x- and y-position
4029 by that margin. */
22d650b8
GM
4030 x += s->img->hmargin;
4031 y += s->img->vmargin;
06a2c219
GM
4032
4033 if (s->img->pixmap)
4034 {
4035 if (s->img->mask)
4036 {
4037 /* We can't set both a clip mask and use XSetClipRectangles
4038 because the latter also sets a clip mask. We also can't
4039 trust on the shape extension to be available
4040 (XShapeCombineRegion). So, compute the rectangle to draw
4041 manually. */
4042 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4043 | GCFunction);
4044 XGCValues xgcv;
4045 XRectangle clip_rect, image_rect, r;
4046
4047 xgcv.clip_mask = s->img->mask;
4048 xgcv.clip_x_origin = x;
4049 xgcv.clip_y_origin = y;
4050 xgcv.function = GXcopy;
4051 XChangeGC (s->display, s->gc, mask, &xgcv);
4052
4053 x_get_glyph_string_clip_rect (s, &clip_rect);
4054 image_rect.x = x;
4055 image_rect.y = y;
4056 image_rect.width = s->img->width;
4057 image_rect.height = s->img->height;
4058 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4059 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4060 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
4061 }
4062 else
4063 {
49ad1d99
GM
4064 XRectangle clip_rect, image_rect, r;
4065
4066 x_get_glyph_string_clip_rect (s, &clip_rect);
4067 image_rect.x = x;
4068 image_rect.y = y;
4069 image_rect.width = s->img->width;
4070 image_rect.height = s->img->height;
4071 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4072 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4073 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
06a2c219
GM
4074
4075 /* When the image has a mask, we can expect that at
4076 least part of a mouse highlight or a block cursor will
4077 be visible. If the image doesn't have a mask, make
4078 a block cursor visible by drawing a rectangle around
4079 the image. I believe it's looking better if we do
4080 nothing here for mouse-face. */
4081 if (s->hl == DRAW_CURSOR)
4082 XDrawRectangle (s->display, s->window, s->gc, x, y,
4083 s->img->width - 1, s->img->height - 1);
4084 }
4085 }
4086 else
4087 /* Draw a rectangle if image could not be loaded. */
4088 XDrawRectangle (s->display, s->window, s->gc, x, y,
4089 s->img->width - 1, s->img->height - 1);
4090}
4091
4092
4093/* Draw a relief around the image glyph string S. */
4094
4095static void
4096x_draw_image_relief (s)
4097 struct glyph_string *s;
4098{
4099 int x0, y0, x1, y1, thick, raised_p;
4100 XRectangle r;
4101 int x;
95af8492 4102 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4103
4104 /* If first glyph of S has a left box line, start drawing it to the
4105 right of that line. */
4106 if (s->face->box != FACE_NO_BOX
4107 && s->first_glyph->left_box_line_p)
ea2ba0d4 4108 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4109 else
4110 x = s->x;
4111
4112 /* If there is a margin around the image, adjust x- and y-position
4113 by that margin. */
22d650b8
GM
4114 x += s->img->hmargin;
4115 y += s->img->vmargin;
06a2c219
GM
4116
4117 if (s->hl == DRAW_IMAGE_SUNKEN
4118 || s->hl == DRAW_IMAGE_RAISED)
4119 {
9ea173e8 4120 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
06a2c219
GM
4121 raised_p = s->hl == DRAW_IMAGE_RAISED;
4122 }
4123 else
4124 {
4125 thick = abs (s->img->relief);
4126 raised_p = s->img->relief > 0;
4127 }
4128
4129 x0 = x - thick;
4130 y0 = y - thick;
4131 x1 = x + s->img->width + thick - 1;
4132 y1 = y + s->img->height + thick - 1;
4133
4134 x_setup_relief_colors (s);
4135 x_get_glyph_string_clip_rect (s, &r);
4136 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
4137}
4138
4139
4140/* Draw the foreground of image glyph string S to PIXMAP. */
4141
4142static void
4143x_draw_image_foreground_1 (s, pixmap)
4144 struct glyph_string *s;
4145 Pixmap pixmap;
4146{
4147 int x;
95af8492 4148 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
4149
4150 /* If first glyph of S has a left box line, start drawing it to the
4151 right of that line. */
4152 if (s->face->box != FACE_NO_BOX
4153 && s->first_glyph->left_box_line_p)
ea2ba0d4 4154 x = abs (s->face->box_line_width);
06a2c219
GM
4155 else
4156 x = 0;
4157
4158 /* If there is a margin around the image, adjust x- and y-position
4159 by that margin. */
22d650b8
GM
4160 x += s->img->hmargin;
4161 y += s->img->vmargin;
dc43ef94 4162
06a2c219
GM
4163 if (s->img->pixmap)
4164 {
4165 if (s->img->mask)
4166 {
4167 /* We can't set both a clip mask and use XSetClipRectangles
4168 because the latter also sets a clip mask. We also can't
4169 trust on the shape extension to be available
4170 (XShapeCombineRegion). So, compute the rectangle to draw
4171 manually. */
4172 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4173 | GCFunction);
4174 XGCValues xgcv;
4175
4176 xgcv.clip_mask = s->img->mask;
4177 xgcv.clip_x_origin = x;
4178 xgcv.clip_y_origin = y;
4179 xgcv.function = GXcopy;
4180 XChangeGC (s->display, s->gc, mask, &xgcv);
4181
4182 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4183 0, 0, s->img->width, s->img->height, x, y);
4184 XSetClipMask (s->display, s->gc, None);
4185 }
4186 else
4187 {
4188 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4189 0, 0, s->img->width, s->img->height, x, y);
4190
4191 /* When the image has a mask, we can expect that at
4192 least part of a mouse highlight or a block cursor will
4193 be visible. If the image doesn't have a mask, make
4194 a block cursor visible by drawing a rectangle around
4195 the image. I believe it's looking better if we do
4196 nothing here for mouse-face. */
4197 if (s->hl == DRAW_CURSOR)
4198 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4199 s->img->width - 1, s->img->height - 1);
4200 }
4201 }
4202 else
4203 /* Draw a rectangle if image could not be loaded. */
4204 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4205 s->img->width - 1, s->img->height - 1);
4206}
dc43ef94 4207
990ba854 4208
06a2c219
GM
4209/* Draw part of the background of glyph string S. X, Y, W, and H
4210 give the rectangle to draw. */
a9a5b0a5 4211
06a2c219
GM
4212static void
4213x_draw_glyph_string_bg_rect (s, x, y, w, h)
4214 struct glyph_string *s;
4215 int x, y, w, h;
4216{
4217 if (s->stippled_p)
4218 {
4219 /* Fill background with a stipple pattern. */
4220 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4221 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4222 XSetFillStyle (s->display, s->gc, FillSolid);
4223 }
4224 else
4225 x_clear_glyph_string_rect (s, x, y, w, h);
4226}
07e34cb0 4227
b5210ea7 4228
06a2c219 4229/* Draw image glyph string S.
dc43ef94 4230
06a2c219
GM
4231 s->y
4232 s->x +-------------------------
4233 | s->face->box
4234 |
4235 | +-------------------------
4236 | | s->img->margin
4237 | |
4238 | | +-------------------
4239 | | | the image
dc43ef94 4240
06a2c219 4241 */
dc43ef94 4242
06a2c219
GM
4243static void
4244x_draw_image_glyph_string (s)
4245 struct glyph_string *s;
4246{
4247 int x, y;
ea2ba0d4
KH
4248 int box_line_hwidth = abs (s->face->box_line_width);
4249 int box_line_vwidth = max (s->face->box_line_width, 0);
06a2c219
GM
4250 int height;
4251 Pixmap pixmap = None;
4252
ea2ba0d4 4253 height = s->height - 2 * box_line_vwidth;
06a2c219
GM
4254
4255 /* Fill background with face under the image. Do it only if row is
4256 taller than image or if image has a clip mask to reduce
4257 flickering. */
4258 s->stippled_p = s->face->stipple != 0;
4259 if (height > s->img->height
22d650b8
GM
4260 || s->img->hmargin
4261 || s->img->vmargin
06a2c219
GM
4262 || s->img->mask
4263 || s->img->pixmap == 0
4264 || s->width != s->background_width)
4265 {
ea2ba0d4
KH
4266 if (box_line_hwidth && s->first_glyph->left_box_line_p)
4267 x = s->x + box_line_hwidth;
06a2c219
GM
4268 else
4269 x = s->x;
4270
ea2ba0d4 4271 y = s->y + box_line_vwidth;
06a2c219
GM
4272
4273 if (s->img->mask)
4274 {
f9b5db02
GM
4275 /* Create a pixmap as large as the glyph string. Fill it
4276 with the background color. Copy the image to it, using
4277 its mask. Copy the temporary pixmap to the display. */
06a2c219
GM
4278 Screen *screen = FRAME_X_SCREEN (s->f);
4279 int depth = DefaultDepthOfScreen (screen);
4280
4281 /* Create a pixmap as large as the glyph string. */
4282 pixmap = XCreatePixmap (s->display, s->window,
4283 s->background_width,
4284 s->height, depth);
4285
4286 /* Don't clip in the following because we're working on the
4287 pixmap. */
4288 XSetClipMask (s->display, s->gc, None);
4289
4290 /* Fill the pixmap with the background color/stipple. */
4291 if (s->stippled_p)
4292 {
4293 /* Fill background with a stipple pattern. */
4294 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4295 XFillRectangle (s->display, pixmap, s->gc,
4296 0, 0, s->background_width, s->height);
4297 XSetFillStyle (s->display, s->gc, FillSolid);
4298 }
4299 else
4300 {
4301 XGCValues xgcv;
4302 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4303 &xgcv);
4304 XSetForeground (s->display, s->gc, xgcv.background);
4305 XFillRectangle (s->display, pixmap, s->gc,
4306 0, 0, s->background_width, s->height);
4307 XSetForeground (s->display, s->gc, xgcv.foreground);
4308 }
4309 }
4310 else
06a2c219
GM
4311 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
4312
4313 s->background_filled_p = 1;
4314 }
dc43ef94 4315
06a2c219
GM
4316 /* Draw the foreground. */
4317 if (pixmap != None)
4318 {
4319 x_draw_image_foreground_1 (s, pixmap);
4320 x_set_glyph_string_clipping (s);
4321 XCopyArea (s->display, pixmap, s->window, s->gc,
4322 0, 0, s->background_width, s->height, s->x, s->y);
4323 XFreePixmap (s->display, pixmap);
4324 }
4325 else
4326 x_draw_image_foreground (s);
b5210ea7 4327
06a2c219
GM
4328 /* If we must draw a relief around the image, do it. */
4329 if (s->img->relief
4330 || s->hl == DRAW_IMAGE_RAISED
4331 || s->hl == DRAW_IMAGE_SUNKEN)
4332 x_draw_image_relief (s);
4333}
8c1a6a84 4334
990ba854 4335
06a2c219 4336/* Draw stretch glyph string S. */
dc43ef94 4337
06a2c219
GM
4338static void
4339x_draw_stretch_glyph_string (s)
4340 struct glyph_string *s;
4341{
4342 xassert (s->first_glyph->type == STRETCH_GLYPH);
4343 s->stippled_p = s->face->stipple != 0;
990ba854 4344
06a2c219
GM
4345 if (s->hl == DRAW_CURSOR
4346 && !x_stretch_cursor_p)
4347 {
4348 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4349 as wide as the stretch glyph. */
4350 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4351
06a2c219
GM
4352 /* Draw cursor. */
4353 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4354
06a2c219
GM
4355 /* Clear rest using the GC of the original non-cursor face. */
4356 if (width < s->background_width)
4357 {
06a2c219
GM
4358 int x = s->x + width, y = s->y;
4359 int w = s->background_width - width, h = s->height;
4360 XRectangle r;
b7f83f9e 4361 GC gc;
dc43ef94 4362
b7f83f9e
GM
4363 if (s->row->mouse_face_p
4364 && cursor_in_mouse_face_p (s->w))
4365 {
4366 x_set_mouse_face_gc (s);
4367 gc = s->gc;
4368 }
4369 else
4370 gc = s->face->gc;
4371
06a2c219
GM
4372 x_get_glyph_string_clip_rect (s, &r);
4373 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
b7f83f9e 4374
06a2c219
GM
4375 if (s->face->stipple)
4376 {
4377 /* Fill background with a stipple pattern. */
4378 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4379 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4380 XSetFillStyle (s->display, gc, FillSolid);
4381 }
4382 else
4383 {
4384 XGCValues xgcv;
4385 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4386 XSetForeground (s->display, gc, xgcv.background);
4387 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4388 XSetForeground (s->display, gc, xgcv.foreground);
4389 }
4390 }
4391 }
61e9f9f3 4392 else if (!s->background_filled_p)
06a2c219
GM
4393 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4394 s->height);
4395
4396 s->background_filled_p = 1;
4397}
4398
4399
4400/* Draw glyph string S. */
4401
4402static void
4403x_draw_glyph_string (s)
4404 struct glyph_string *s;
4405{
4458cf11
KH
4406 int relief_drawn_p = 0;
4407
06a2c219
GM
4408 /* If S draws into the background of its successor, draw the
4409 background of the successor first so that S can draw into it.
4410 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4411 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4412 {
4413 xassert (s->next->img == NULL);
4414 x_set_glyph_string_gc (s->next);
4415 x_set_glyph_string_clipping (s->next);
4416 x_draw_glyph_string_background (s->next, 1);
4417 }
97210f4e 4418
06a2c219
GM
4419 /* Set up S->gc, set clipping and draw S. */
4420 x_set_glyph_string_gc (s);
06a2c219 4421
4458cf11
KH
4422 /* Draw relief (if any) in advance for char/composition so that the
4423 glyph string can be drawn over it. */
4424 if (!s->for_overlaps_p
4425 && s->face->box != FACE_NO_BOX
4426 && (s->first_glyph->type == CHAR_GLYPH
4427 || s->first_glyph->type == COMPOSITE_GLYPH))
4428
4429 {
e6269cbb 4430 x_set_glyph_string_clipping (s);
4458cf11
KH
4431 x_draw_glyph_string_background (s, 1);
4432 x_draw_glyph_string_box (s);
e6269cbb 4433 x_set_glyph_string_clipping (s);
4458cf11
KH
4434 relief_drawn_p = 1;
4435 }
e6269cbb
GM
4436 else
4437 x_set_glyph_string_clipping (s);
4458cf11 4438
06a2c219
GM
4439 switch (s->first_glyph->type)
4440 {
4441 case IMAGE_GLYPH:
4442 x_draw_image_glyph_string (s);
4443 break;
4444
4445 case STRETCH_GLYPH:
4446 x_draw_stretch_glyph_string (s);
4447 break;
4448
4449 case CHAR_GLYPH:
66ac4b0e
GM
4450 if (s->for_overlaps_p)
4451 s->background_filled_p = 1;
4452 else
4453 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4454 x_draw_glyph_string_foreground (s);
4455 break;
4456
b4192550
KH
4457 case COMPOSITE_GLYPH:
4458 if (s->for_overlaps_p || s->gidx > 0)
4459 s->background_filled_p = 1;
4460 else
4461 x_draw_glyph_string_background (s, 1);
4462 x_draw_composite_glyph_string_foreground (s);
4463 break;
4464
06a2c219
GM
4465 default:
4466 abort ();
4467 }
4468
66ac4b0e 4469 if (!s->for_overlaps_p)
06a2c219 4470 {
66ac4b0e
GM
4471 /* Draw underline. */
4472 if (s->face->underline_p)
4473 {
e24e84cc
GM
4474 unsigned long tem, h;
4475 int y;
06a2c219 4476
e24e84cc 4477 /* Get the underline thickness. Default is 1 pixel. */
66ac4b0e
GM
4478 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4479 h = 1;
e24e84cc
GM
4480
4481 /* Get the underline position. This is the recommended
4482 vertical offset in pixels from the baseline to the top of
4483 the underline. This is a signed value according to the
4484 specs, and its default is
4485
4486 ROUND ((maximum descent) / 2), with
4487 ROUND(x) = floor (x + 0.5) */
4488
a72d5ce5
GM
4489 if (x_use_underline_position_properties
4490 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
e24e84cc
GM
4491 y = s->ybase + (long) tem;
4492 else if (s->face->font)
4493 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4494 else
a02f1be0 4495 y = s->y + s->height - h;
06a2c219 4496
66ac4b0e 4497 if (s->face->underline_defaulted_p)
e24e84cc
GM
4498 XFillRectangle (s->display, s->window, s->gc,
4499 s->x, y, s->width, h);
66ac4b0e
GM
4500 else
4501 {
4502 XGCValues xgcv;
4503 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4504 XSetForeground (s->display, s->gc, s->face->underline_color);
e24e84cc
GM
4505 XFillRectangle (s->display, s->window, s->gc,
4506 s->x, y, s->width, h);
66ac4b0e
GM
4507 XSetForeground (s->display, s->gc, xgcv.foreground);
4508 }
dc6f92b8 4509 }
07e34cb0 4510
66ac4b0e
GM
4511 /* Draw overline. */
4512 if (s->face->overline_p)
06a2c219 4513 {
66ac4b0e
GM
4514 unsigned long dy = 0, h = 1;
4515
4516 if (s->face->overline_color_defaulted_p)
4517 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4518 s->width, h);
4519 else
4520 {
4521 XGCValues xgcv;
4522 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4523 XSetForeground (s->display, s->gc, s->face->overline_color);
4524 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4525 s->width, h);
4526 XSetForeground (s->display, s->gc, xgcv.foreground);
4527 }
06a2c219 4528 }
06a2c219 4529
66ac4b0e
GM
4530 /* Draw strike-through. */
4531 if (s->face->strike_through_p)
06a2c219 4532 {
66ac4b0e
GM
4533 unsigned long h = 1;
4534 unsigned long dy = (s->height - h) / 2;
4535
4536 if (s->face->strike_through_color_defaulted_p)
4537 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4538 s->width, h);
4539 else
4540 {
4541 XGCValues xgcv;
4542 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4543 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4544 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4545 s->width, h);
4546 XSetForeground (s->display, s->gc, xgcv.foreground);
4547 }
06a2c219 4548 }
06a2c219 4549
4458cf11
KH
4550 /* Draw relief if not yet drawn. */
4551 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
66ac4b0e
GM
4552 x_draw_glyph_string_box (s);
4553 }
06a2c219
GM
4554
4555 /* Reset clipping. */
4556 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4557}
07e34cb0 4558
06a2c219 4559
b4192550
KH
4560static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4561 struct face **, int));
06a2c219 4562
06a2c219 4563
209f68d9
GM
4564/* Fill glyph string S with composition components specified by S->cmp.
4565
b4192550
KH
4566 FACES is an array of faces for all components of this composition.
4567 S->gidx is the index of the first component for S.
4568 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4569 use its physical height for clipping.
06a2c219 4570
b4192550 4571 Value is the index of a component not in S. */
07e34cb0 4572
b4192550
KH
4573static int
4574x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4575 struct glyph_string *s;
b4192550 4576 struct face **faces;
66ac4b0e 4577 int overlaps_p;
07e34cb0 4578{
b4192550 4579 int i;
06a2c219 4580
b4192550 4581 xassert (s);
06a2c219 4582
b4192550 4583 s->for_overlaps_p = overlaps_p;
06a2c219 4584
b4192550
KH
4585 s->face = faces[s->gidx];
4586 s->font = s->face->font;
4587 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4588
b4192550
KH
4589 /* For all glyphs of this composition, starting at the offset
4590 S->gidx, until we reach the end of the definition or encounter a
4591 glyph that requires the different face, add it to S. */
4592 ++s->nchars;
4593 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4594 ++s->nchars;
06a2c219 4595
b4192550
KH
4596 /* All glyph strings for the same composition has the same width,
4597 i.e. the width set for the first component of the composition. */
06a2c219 4598
06a2c219
GM
4599 s->width = s->first_glyph->pixel_width;
4600
4601 /* If the specified font could not be loaded, use the frame's
4602 default font, but record the fact that we couldn't load it in
4603 the glyph string so that we can draw rectangles for the
4604 characters of the glyph string. */
4605 if (s->font == NULL)
4606 {
4607 s->font_not_found_p = 1;
4608 s->font = FRAME_FONT (s->f);
4609 }
4610
4611 /* Adjust base line for subscript/superscript text. */
4612 s->ybase += s->first_glyph->voffset;
4613
4614 xassert (s->face && s->face->gc);
4615
4616 /* This glyph string must always be drawn with 16-bit functions. */
4617 s->two_byte_p = 1;
b4192550
KH
4618
4619 return s->gidx + s->nchars;
06a2c219
GM
4620}
4621
4622
209f68d9
GM
4623/* Fill glyph string S from a sequence of character glyphs.
4624
06a2c219 4625 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4626 first glyph to consider, END is the index of the last + 1.
4627 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4628 use its physical height for clipping.
66ac4b0e
GM
4629
4630 Value is the index of the first glyph not in S. */
06a2c219
GM
4631
4632static int
66ac4b0e 4633x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4634 struct glyph_string *s;
4635 int face_id;
66ac4b0e 4636 int start, end, overlaps_p;
06a2c219
GM
4637{
4638 struct glyph *glyph, *last;
4639 int voffset;
ee569018 4640 int glyph_not_available_p;
06a2c219 4641
06a2c219
GM
4642 xassert (s->f == XFRAME (s->w->frame));
4643 xassert (s->nchars == 0);
4644 xassert (start >= 0 && end > start);
4645
66ac4b0e 4646 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4647 glyph = s->row->glyphs[s->area] + start;
4648 last = s->row->glyphs[s->area] + end;
4649 voffset = glyph->voffset;
4650
ee569018
KH
4651 glyph_not_available_p = glyph->glyph_not_available_p;
4652
06a2c219
GM
4653 while (glyph < last
4654 && glyph->type == CHAR_GLYPH
4655 && glyph->voffset == voffset
ee569018
KH
4656 /* Same face id implies same font, nowadays. */
4657 && glyph->face_id == face_id
4658 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4659 {
ee569018
KH
4660 int two_byte_p;
4661
06a2c219 4662 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4663 s->char2b + s->nchars,
4664 &two_byte_p);
4665 s->two_byte_p = two_byte_p;
06a2c219
GM
4666 ++s->nchars;
4667 xassert (s->nchars <= end - start);
4668 s->width += glyph->pixel_width;
4669 ++glyph;
4670 }
4671
4672 s->font = s->face->font;
4673 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4674
4675 /* If the specified font could not be loaded, use the frame's font,
4676 but record the fact that we couldn't load it in
4677 S->font_not_found_p so that we can draw rectangles for the
4678 characters of the glyph string. */
ee569018 4679 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4680 {
4681 s->font_not_found_p = 1;
4682 s->font = FRAME_FONT (s->f);
4683 }
4684
4685 /* Adjust base line for subscript/superscript text. */
4686 s->ybase += voffset;
66ac4b0e 4687
06a2c219
GM
4688 xassert (s->face && s->face->gc);
4689 return glyph - s->row->glyphs[s->area];
07e34cb0 4690}
dc6f92b8 4691
06a2c219
GM
4692
4693/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4694
dfcf069d 4695static void
06a2c219
GM
4696x_fill_image_glyph_string (s)
4697 struct glyph_string *s;
4698{
4699 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4700 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4701 xassert (s->img);
43d120d8 4702 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4703 s->font = s->face->font;
4704 s->width = s->first_glyph->pixel_width;
4705
4706 /* Adjust base line for subscript/superscript text. */
4707 s->ybase += s->first_glyph->voffset;
4708}
4709
4710
209f68d9 4711/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4712
209f68d9
GM
4713 ROW is the glyph row in which the glyphs are found, AREA is the
4714 area within the row. START is the index of the first glyph to
4715 consider, END is the index of the last + 1.
4716
4717 Value is the index of the first glyph not in S. */
4718
4719static int
4720x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4721 struct glyph_string *s;
209f68d9
GM
4722 struct glyph_row *row;
4723 enum glyph_row_area area;
4724 int start, end;
06a2c219 4725{
209f68d9
GM
4726 struct glyph *glyph, *last;
4727 int voffset, face_id;
4728
06a2c219 4729 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4730
4731 glyph = s->row->glyphs[s->area] + start;
4732 last = s->row->glyphs[s->area] + end;
4733 face_id = glyph->face_id;
4734 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4735 s->font = s->face->font;
209f68d9
GM
4736 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4737 s->width = glyph->pixel_width;
4738 voffset = glyph->voffset;
4739
4740 for (++glyph;
4741 (glyph < last
4742 && glyph->type == STRETCH_GLYPH
4743 && glyph->voffset == voffset
4744 && glyph->face_id == face_id);
4745 ++glyph)
4746 s->width += glyph->pixel_width;
06a2c219
GM
4747
4748 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4749 s->ybase += voffset;
4750
c296fc01
GM
4751 /* The case that face->gc == 0 is handled when drawing the glyph
4752 string by calling PREPARE_FACE_FOR_DISPLAY. */
4753 xassert (s->face);
209f68d9 4754 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4755}
4756
4757
4758/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4759 of XChar2b structures for S; it can't be allocated in
4760 x_init_glyph_string because it must be allocated via `alloca'. W
4761 is the window on which S is drawn. ROW and AREA are the glyph row
4762 and area within the row from which S is constructed. START is the
4763 index of the first glyph structure covered by S. HL is a
4764 face-override for drawing S. */
4765
4766static void
4767x_init_glyph_string (s, char2b, w, row, area, start, hl)
4768 struct glyph_string *s;
4769 XChar2b *char2b;
4770 struct window *w;
4771 struct glyph_row *row;
4772 enum glyph_row_area area;
4773 int start;
4774 enum draw_glyphs_face hl;
4775{
4776 bzero (s, sizeof *s);
4777 s->w = w;
4778 s->f = XFRAME (w->frame);
4779 s->display = FRAME_X_DISPLAY (s->f);
4780 s->window = FRAME_X_WINDOW (s->f);
4781 s->char2b = char2b;
4782 s->hl = hl;
4783 s->row = row;
4784 s->area = area;
4785 s->first_glyph = row->glyphs[area] + start;
4786 s->height = row->height;
4787 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4788
9ea173e8
GM
4789 /* Display the internal border below the tool-bar window. */
4790 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4791 s->y -= s->f->output_data.x->internal_border_width;
4792
4793 s->ybase = s->y + row->ascent;
4794}
4795
4796
4797/* Set background width of glyph string S. START is the index of the
4798 first glyph following S. LAST_X is the right-most x-position + 1
4799 in the drawing area. */
4800
4801static INLINE void
4802x_set_glyph_string_background_width (s, start, last_x)
4803 struct glyph_string *s;
4804 int start;
4805 int last_x;
4806{
4807 /* If the face of this glyph string has to be drawn to the end of
4808 the drawing area, set S->extends_to_end_of_line_p. */
4809 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4810
4811 if (start == s->row->used[s->area]
eb79f5cc 4812 && s->area == TEXT_AREA
7b0870b2
GM
4813 && ((s->hl == DRAW_NORMAL_TEXT
4814 && (s->row->fill_line_p
4815 || s->face->background != default_face->background
4816 || s->face->stipple != default_face->stipple
4817 || s->row->mouse_face_p))
4818 || s->hl == DRAW_MOUSE_FACE))
4819 s->extends_to_end_of_line_p = 1;
06a2c219
GM
4820
4821 /* If S extends its face to the end of the line, set its
4822 background_width to the distance to the right edge of the drawing
4823 area. */
4824 if (s->extends_to_end_of_line_p)
1da3fd71 4825 s->background_width = last_x - s->x + 1;
06a2c219
GM
4826 else
4827 s->background_width = s->width;
4828}
4829
4830
4831/* Add a glyph string for a stretch glyph to the list of strings
4832 between HEAD and TAIL. START is the index of the stretch glyph in
4833 row area AREA of glyph row ROW. END is the index of the last glyph
4834 in that glyph row area. X is the current output position assigned
4835 to the new glyph string constructed. HL overrides that face of the
4836 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4837 is the right-most x-position of the drawing area. */
4838
8abee2e1
DL
4839/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4840 and below -- keep them on one line. */
4841#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4842 do \
4843 { \
4844 s = (struct glyph_string *) alloca (sizeof *s); \
4845 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4846 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4847 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4848 s->x = (X); \
4849 } \
4850 while (0)
4851
4852
4853/* Add a glyph string for an image glyph to the list of strings
4854 between HEAD and TAIL. START is the index of the image glyph in
4855 row area AREA of glyph row ROW. END is the index of the last glyph
4856 in that glyph row area. X is the current output position assigned
4857 to the new glyph string constructed. HL overrides that face of the
4858 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4859 is the right-most x-position of the drawing area. */
4860
8abee2e1 4861#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4862 do \
4863 { \
4864 s = (struct glyph_string *) alloca (sizeof *s); \
4865 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4866 x_fill_image_glyph_string (s); \
4867 x_append_glyph_string (&HEAD, &TAIL, s); \
4868 ++START; \
4869 s->x = (X); \
4870 } \
4871 while (0)
4872
4873
4874/* Add a glyph string for a sequence of character glyphs to the list
4875 of strings between HEAD and TAIL. START is the index of the first
4876 glyph in row area AREA of glyph row ROW that is part of the new
4877 glyph string. END is the index of the last glyph in that glyph row
4878 area. X is the current output position assigned to the new glyph
4879 string constructed. HL overrides that face of the glyph; e.g. it
4880 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4881 right-most x-position of the drawing area. */
4882
8abee2e1 4883#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4884 do \
4885 { \
3e71d8f2 4886 int c, face_id; \
06a2c219
GM
4887 XChar2b *char2b; \
4888 \
43d120d8 4889 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4890 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4891 \
b4192550
KH
4892 s = (struct glyph_string *) alloca (sizeof *s); \
4893 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4894 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4895 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4896 s->x = (X); \
4897 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4898 OVERLAPS_P); \
06a2c219
GM
4899 } \
4900 while (0)
4901
4902
b4192550
KH
4903/* Add a glyph string for a composite sequence to the list of strings
4904 between HEAD and TAIL. START is the index of the first glyph in
4905 row area AREA of glyph row ROW that is part of the new glyph
4906 string. END is the index of the last glyph in that glyph row area.
4907 X is the current output position assigned to the new glyph string
4908 constructed. HL overrides that face of the glyph; e.g. it is
4909 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4910 x-position of the drawing area. */
4911
6c27ec25 4912#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4913 do { \
43d120d8
KH
4914 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4915 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4916 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4917 struct composition *cmp = composition_table[cmp_id]; \
4918 int glyph_len = cmp->glyph_len; \
4919 XChar2b *char2b; \
4920 struct face **faces; \
4921 struct glyph_string *first_s = NULL; \
4922 int n; \
4923 \
ee569018 4924 base_face = base_face->ascii_face; \
b4192550
KH
4925 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4926 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4927 /* At first, fill in `char2b' and `faces'. */ \
4928 for (n = 0; n < glyph_len; n++) \
4929 { \
43d120d8 4930 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4931 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4932 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4933 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4934 this_face_id, char2b + n, 1); \
b4192550
KH
4935 } \
4936 \
4937 /* Make glyph_strings for each glyph sequence that is drawable by \
4938 the same face, and append them to HEAD/TAIL. */ \
4939 for (n = 0; n < cmp->glyph_len;) \
4940 { \
4941 s = (struct glyph_string *) alloca (sizeof *s); \
4942 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4943 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4944 s->cmp = cmp; \
4945 s->gidx = n; \
b4192550
KH
4946 s->x = (X); \
4947 \
4948 if (n == 0) \
4949 first_s = s; \
4950 \
4951 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4952 } \
4953 \
4954 ++START; \
4955 s = first_s; \
4956 } while (0)
4957
4958
06a2c219
GM
4959/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4960 of AREA of glyph row ROW on window W between indices START and END.
4961 HL overrides the face for drawing glyph strings, e.g. it is
4962 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4963 x-positions of the drawing area.
4964
4965 This is an ugly monster macro construct because we must use alloca
4966 to allocate glyph strings (because x_draw_glyphs can be called
4967 asynchronously). */
4968
8abee2e1 4969#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4970 do \
4971 { \
4972 HEAD = TAIL = NULL; \
4973 while (START < END) \
4974 { \
4975 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4976 switch (first_glyph->type) \
4977 { \
4978 case CHAR_GLYPH: \
4979 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
4980 TAIL, HL, X, LAST_X, \
4981 OVERLAPS_P); \
06a2c219
GM
4982 break; \
4983 \
b4192550
KH
4984 case COMPOSITE_GLYPH: \
4985 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
4986 HEAD, TAIL, HL, X, LAST_X,\
4987 OVERLAPS_P); \
4988 break; \
4989 \
06a2c219
GM
4990 case STRETCH_GLYPH: \
4991 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
4992 HEAD, TAIL, HL, X, LAST_X); \
4993 break; \
4994 \
4995 case IMAGE_GLYPH: \
4996 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
4997 TAIL, HL, X, LAST_X); \
4998 break; \
4999 \
5000 default: \
5001 abort (); \
5002 } \
5003 \
5004 x_set_glyph_string_background_width (s, START, LAST_X); \
5005 (X) += s->width; \
5006 } \
5007 } \
5008 while (0)
5009
5010
5011/* Draw glyphs between START and END in AREA of ROW on window W,
5012 starting at x-position X. X is relative to AREA in W. HL is a
5013 face-override with the following meaning:
5014
5015 DRAW_NORMAL_TEXT draw normally
5016 DRAW_CURSOR draw in cursor face
5017 DRAW_MOUSE_FACE draw in mouse face.
5018 DRAW_INVERSE_VIDEO draw in mode line face
5019 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
5020 DRAW_IMAGE_RAISED draw an image with a raised relief around it
5021
66ac4b0e
GM
5022 If OVERLAPS_P is non-zero, draw only the foreground of characters
5023 and clip to the physical height of ROW.
5024
06a2c219
GM
5025 Value is the x-position reached, relative to AREA of W. */
5026
5027static int
f0a48a01 5028x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
06a2c219
GM
5029 struct window *w;
5030 int x;
5031 struct glyph_row *row;
5032 enum glyph_row_area area;
5033 int start, end;
5034 enum draw_glyphs_face hl;
66ac4b0e 5035 int overlaps_p;
dc6f92b8 5036{
06a2c219
GM
5037 struct glyph_string *head, *tail;
5038 struct glyph_string *s;
5039 int last_x, area_width;
5040 int x_reached;
5041 int i, j;
5042
5043 /* Let's rather be paranoid than getting a SEGV. */
06a2c219 5044 end = min (end, row->used[area]);
a8710abf
GM
5045 start = max (0, start);
5046 start = min (end, start);
06a2c219
GM
5047
5048 /* Translate X to frame coordinates. Set last_x to the right
5049 end of the drawing area. */
5050 if (row->full_width_p)
5051 {
5052 /* X is relative to the left edge of W, without scroll bars
5053 or flag areas. */
5054 struct frame *f = XFRAME (w->frame);
110859fc 5055 /* int width = FRAME_FLAGS_AREA_WIDTH (f); */
06a2c219 5056 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 5057
06a2c219
GM
5058 x += window_left_x;
5059 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
5060 last_x = window_left_x + area_width;
5061
5062 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5063 {
110859fc 5064 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
5065 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
5066 last_x += width;
5067 else
5068 x -= width;
5069 }
dc6f92b8 5070
b9432a85 5071 x += FRAME_INTERNAL_BORDER_WIDTH (f);
98fedd97 5072 last_x += FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
5073 }
5074 else
dc6f92b8 5075 {
06a2c219
GM
5076 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
5077 area_width = window_box_width (w, area);
5078 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
5079 }
5080
06a2c219
GM
5081 /* Build a doubly-linked list of glyph_string structures between
5082 head and tail from what we have to draw. Note that the macro
5083 BUILD_GLYPH_STRINGS will modify its start parameter. That's
5084 the reason we use a separate variable `i'. */
5085 i = start;
66ac4b0e
GM
5086 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
5087 overlaps_p);
06a2c219
GM
5088 if (tail)
5089 x_reached = tail->x + tail->background_width;
5090 else
5091 x_reached = x;
90e65f07 5092
06a2c219
GM
5093 /* If there are any glyphs with lbearing < 0 or rbearing > width in
5094 the row, redraw some glyphs in front or following the glyph
5095 strings built above. */
a8710abf 5096 if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
5097 {
5098 int dummy_x = 0;
5099 struct glyph_string *h, *t;
5100
5101 /* Compute overhangs for all glyph strings. */
5102 for (s = head; s; s = s->next)
5103 x_compute_glyph_string_overhangs (s);
5104
5105 /* Prepend glyph strings for glyphs in front of the first glyph
5106 string that are overwritten because of the first glyph
5107 string's left overhang. The background of all strings
5108 prepended must be drawn because the first glyph string
5109 draws over it. */
5110 i = x_left_overwritten (head);
5111 if (i >= 0)
5112 {
5113 j = i;
5114 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
5115 DRAW_NORMAL_TEXT, dummy_x, last_x,
5116 overlaps_p);
06a2c219 5117 start = i;
06a2c219
GM
5118 x_compute_overhangs_and_x (t, head->x, 1);
5119 x_prepend_glyph_string_lists (&head, &tail, h, t);
5120 }
58769bee 5121
06a2c219
GM
5122 /* Prepend glyph strings for glyphs in front of the first glyph
5123 string that overwrite that glyph string because of their
5124 right overhang. For these strings, only the foreground must
5125 be drawn, because it draws over the glyph string at `head'.
5126 The background must not be drawn because this would overwrite
5127 right overhangs of preceding glyphs for which no glyph
5128 strings exist. */
5129 i = x_left_overwriting (head);
5130 if (i >= 0)
5131 {
5132 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
5133 DRAW_NORMAL_TEXT, dummy_x, last_x,
5134 overlaps_p);
06a2c219
GM
5135 for (s = h; s; s = s->next)
5136 s->background_filled_p = 1;
06a2c219
GM
5137 x_compute_overhangs_and_x (t, head->x, 1);
5138 x_prepend_glyph_string_lists (&head, &tail, h, t);
5139 }
dbcb258a 5140
06a2c219
GM
5141 /* Append glyphs strings for glyphs following the last glyph
5142 string tail that are overwritten by tail. The background of
5143 these strings has to be drawn because tail's foreground draws
5144 over it. */
5145 i = x_right_overwritten (tail);
5146 if (i >= 0)
5147 {
5148 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5149 DRAW_NORMAL_TEXT, x, last_x,
5150 overlaps_p);
06a2c219
GM
5151 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5152 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219 5153 }
dc6f92b8 5154
06a2c219
GM
5155 /* Append glyph strings for glyphs following the last glyph
5156 string tail that overwrite tail. The foreground of such
5157 glyphs has to be drawn because it writes into the background
5158 of tail. The background must not be drawn because it could
5159 paint over the foreground of following glyphs. */
5160 i = x_right_overwriting (tail);
5161 if (i >= 0)
5162 {
5163 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5164 DRAW_NORMAL_TEXT, x, last_x,
5165 overlaps_p);
06a2c219
GM
5166 for (s = h; s; s = s->next)
5167 s->background_filled_p = 1;
5168 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5169 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219
GM
5170 }
5171 }
58769bee 5172
06a2c219
GM
5173 /* Draw all strings. */
5174 for (s = head; s; s = s->next)
5175 x_draw_glyph_string (s);
dc6f92b8 5176
d9e3b8c6 5177 if (area == TEXT_AREA && !row->full_width_p)
f0a48a01
GM
5178 {
5179 int x0 = head ? head->x : x;
5180 int x1 = tail ? tail->x + tail->background_width : x;
5181
5182 x0 = FRAME_TO_WINDOW_PIXEL_X (w, x0);
5183 x1 = FRAME_TO_WINDOW_PIXEL_X (w, x1);
5184
5185 if (!row->full_width_p && XFASTINT (w->left_margin_width) != 0)
5186 {
5187 int left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
5188 x0 -= left_area_width;
5189 x1 -= left_area_width;
5190 }
5191
5192 notice_overwritten_cursor (w, x0, x1);
5193 }
5194
06a2c219
GM
5195 /* Value is the x-position up to which drawn, relative to AREA of W.
5196 This doesn't include parts drawn because of overhangs. */
5197 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
5198 if (!row->full_width_p)
5199 {
f0a48a01 5200 if (area > LEFT_MARGIN_AREA && XFASTINT (w->left_margin_width) != 0)
06a2c219
GM
5201 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
5202 if (area > TEXT_AREA)
5203 x_reached -= window_box_width (w, TEXT_AREA);
5204 }
a8710abf 5205
06a2c219
GM
5206 return x_reached;
5207}
dc6f92b8 5208
dc6f92b8 5209
66ac4b0e
GM
5210/* Fix the display of area AREA of overlapping row ROW in window W. */
5211
5212static void
5213x_fix_overlapping_area (w, row, area)
5214 struct window *w;
5215 struct glyph_row *row;
5216 enum glyph_row_area area;
5217{
5218 int i, x;
5219
5220 BLOCK_INPUT;
5221
5222 if (area == LEFT_MARGIN_AREA)
5223 x = 0;
5224 else if (area == TEXT_AREA)
5225 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5226 else
5227 x = (window_box_width (w, LEFT_MARGIN_AREA)
5228 + window_box_width (w, TEXT_AREA));
5229
5230 for (i = 0; i < row->used[area];)
5231 {
5232 if (row->glyphs[area][i].overlaps_vertically_p)
5233 {
5234 int start = i, start_x = x;
5235
5236 do
5237 {
5238 x += row->glyphs[area][i].pixel_width;
5239 ++i;
5240 }
5241 while (i < row->used[area]
5242 && row->glyphs[area][i].overlaps_vertically_p);
5243
5244 x_draw_glyphs (w, start_x, row, area, start, i,
f0a48a01 5245 DRAW_NORMAL_TEXT, 1);
66ac4b0e
GM
5246 }
5247 else
5248 {
5249 x += row->glyphs[area][i].pixel_width;
5250 ++i;
5251 }
5252 }
5253
5254 UNBLOCK_INPUT;
5255}
5256
5257
06a2c219
GM
5258/* Output LEN glyphs starting at START at the nominal cursor position.
5259 Advance the nominal cursor over the text. The global variable
5260 updated_window contains the window being updated, updated_row is
5261 the glyph row being updated, and updated_area is the area of that
5262 row being updated. */
dc6f92b8 5263
06a2c219
GM
5264static void
5265x_write_glyphs (start, len)
5266 struct glyph *start;
5267 int len;
5268{
f0a48a01 5269 int x, hpos;
d9cdbb3d 5270
06a2c219 5271 xassert (updated_window && updated_row);
dc6f92b8 5272 BLOCK_INPUT;
06a2c219
GM
5273
5274 /* Write glyphs. */
dc6f92b8 5275
06a2c219
GM
5276 hpos = start - updated_row->glyphs[updated_area];
5277 x = x_draw_glyphs (updated_window, output_cursor.x,
5278 updated_row, updated_area,
5279 hpos, hpos + len,
f0a48a01 5280 DRAW_NORMAL_TEXT, 0);
dc6f92b8
JB
5281
5282 UNBLOCK_INPUT;
06a2c219
GM
5283
5284 /* Advance the output cursor. */
5285 output_cursor.hpos += len;
5286 output_cursor.x = x;
dc6f92b8
JB
5287}
5288
0cdd0c9f 5289
06a2c219 5290/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 5291
06a2c219
GM
5292static void
5293x_insert_glyphs (start, len)
5294 struct glyph *start;
5295 register int len;
5296{
5297 struct frame *f;
5298 struct window *w;
5299 int line_height, shift_by_width, shifted_region_width;
5300 struct glyph_row *row;
5301 struct glyph *glyph;
2beb36f9 5302 int frame_x, frame_y, hpos;
58769bee 5303
06a2c219 5304 xassert (updated_window && updated_row);
0cdd0c9f 5305 BLOCK_INPUT;
06a2c219
GM
5306 w = updated_window;
5307 f = XFRAME (WINDOW_FRAME (w));
5308
5309 /* Get the height of the line we are in. */
5310 row = updated_row;
5311 line_height = row->height;
5312
5313 /* Get the width of the glyphs to insert. */
5314 shift_by_width = 0;
5315 for (glyph = start; glyph < start + len; ++glyph)
5316 shift_by_width += glyph->pixel_width;
5317
5318 /* Get the width of the region to shift right. */
5319 shifted_region_width = (window_box_width (w, updated_area)
5320 - output_cursor.x
5321 - shift_by_width);
5322
5323 /* Shift right. */
bf0ab8a2 5324 frame_x = window_box_left (w, updated_area) + output_cursor.x;
06a2c219
GM
5325 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
5326 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5327 f->output_data.x->normal_gc,
5328 frame_x, frame_y,
5329 shifted_region_width, line_height,
5330 frame_x + shift_by_width, frame_y);
5331
5332 /* Write the glyphs. */
5333 hpos = start - row->glyphs[updated_area];
5334 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
f0a48a01 5335 DRAW_NORMAL_TEXT, 0);
06a2c219
GM
5336
5337 /* Advance the output cursor. */
5338 output_cursor.hpos += len;
5339 output_cursor.x += shift_by_width;
0cdd0c9f
RS
5340 UNBLOCK_INPUT;
5341}
0cdd0c9f 5342
0cdd0c9f 5343
06a2c219
GM
5344/* Delete N glyphs at the nominal cursor position. Not implemented
5345 for X frames. */
c83febd7
RS
5346
5347static void
06a2c219
GM
5348x_delete_glyphs (n)
5349 register int n;
c83febd7 5350{
06a2c219 5351 abort ();
c83febd7
RS
5352}
5353
0cdd0c9f 5354
c5e6e06b
GM
5355/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
5356 If they are <= 0, this is probably an error. */
5357
5358void
5359x_clear_area (dpy, window, x, y, width, height, exposures)
5360 Display *dpy;
5361 Window window;
5362 int x, y;
5363 int width, height;
5364 int exposures;
5365{
5366 xassert (width > 0 && height > 0);
5367 XClearArea (dpy, window, x, y, width, height, exposures);
5368}
5369
5370
06a2c219
GM
5371/* Erase the current text line from the nominal cursor position
5372 (inclusive) to pixel column TO_X (exclusive). The idea is that
5373 everything from TO_X onward is already erased.
5374
5375 TO_X is a pixel position relative to updated_area of
5376 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 5377
06a2c219
GM
5378static void
5379x_clear_end_of_line (to_x)
5380 int to_x;
5381{
5382 struct frame *f;
5383 struct window *w = updated_window;
5384 int max_x, min_y, max_y;
5385 int from_x, from_y, to_y;
5386
5387 xassert (updated_window && updated_row);
5388 f = XFRAME (w->frame);
5389
5390 if (updated_row->full_width_p)
5391 {
5392 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
5393 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5394 && !w->pseudo_window_p)
5395 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 5396 }
06a2c219
GM
5397 else
5398 max_x = window_box_width (w, updated_area);
5399 max_y = window_text_bottom_y (w);
dc6f92b8 5400
06a2c219
GM
5401 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5402 of window. For TO_X > 0, truncate to end of drawing area. */
5403 if (to_x == 0)
5404 return;
5405 else if (to_x < 0)
5406 to_x = max_x;
5407 else
5408 to_x = min (to_x, max_x);
dbc4e1c1 5409
06a2c219
GM
5410 to_y = min (max_y, output_cursor.y + updated_row->height);
5411
5412 /* Notice if the cursor will be cleared by this operation. */
5413 if (!updated_row->full_width_p)
f0a48a01 5414 notice_overwritten_cursor (w, output_cursor.x, -1);
dbc4e1c1 5415
06a2c219
GM
5416 from_x = output_cursor.x;
5417
5418 /* Translate to frame coordinates. */
5419 if (updated_row->full_width_p)
5420 {
5421 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5422 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5423 }
0cdd0c9f
RS
5424 else
5425 {
06a2c219
GM
5426 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5427 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5428 }
5429
045dee35 5430 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5431 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5432 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5433
5434 /* Prevent inadvertently clearing to end of the X window. */
5435 if (to_x > from_x && to_y > from_y)
5436 {
5437 BLOCK_INPUT;
c5e6e06b
GM
5438 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5439 from_x, from_y, to_x - from_x, to_y - from_y,
5440 False);
06a2c219 5441 UNBLOCK_INPUT;
0cdd0c9f 5442 }
0cdd0c9f 5443}
dbc4e1c1 5444
0cdd0c9f 5445
06a2c219 5446/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5447 frame. Otherwise clear the selected frame. */
06a2c219
GM
5448
5449static void
5450x_clear_frame ()
0cdd0c9f 5451{
06a2c219 5452 struct frame *f;
0cdd0c9f 5453
06a2c219
GM
5454 if (updating_frame)
5455 f = updating_frame;
0cdd0c9f 5456 else
b86bd3dd 5457 f = SELECTED_FRAME ();
58769bee 5458
06a2c219
GM
5459 /* Clearing the frame will erase any cursor, so mark them all as no
5460 longer visible. */
5461 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5462 output_cursor.hpos = output_cursor.vpos = 0;
5463 output_cursor.x = -1;
5464
5465 /* We don't set the output cursor here because there will always
5466 follow an explicit cursor_to. */
5467 BLOCK_INPUT;
5468 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5469
5470 /* We have to clear the scroll bars, too. If we have changed
5471 colors or something like that, then they should be notified. */
5472 x_scroll_bar_clear (f);
0cdd0c9f 5473
06a2c219
GM
5474 XFlush (FRAME_X_DISPLAY (f));
5475 UNBLOCK_INPUT;
dc6f92b8 5476}
06a2c219
GM
5477
5478
dc6f92b8 5479\f
dbc4e1c1
JB
5480/* Invert the middle quarter of the frame for .15 sec. */
5481
06a2c219
GM
5482/* We use the select system call to do the waiting, so we have to make
5483 sure it's available. If it isn't, we just won't do visual bells. */
5484
dbc4e1c1
JB
5485#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5486
06a2c219
GM
5487
5488/* Subtract the `struct timeval' values X and Y, storing the result in
5489 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5490
5491static int
5492timeval_subtract (result, x, y)
5493 struct timeval *result, x, y;
5494{
06a2c219
GM
5495 /* Perform the carry for the later subtraction by updating y. This
5496 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5497 if (x.tv_usec < y.tv_usec)
5498 {
5499 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5500 y.tv_usec -= 1000000 * nsec;
5501 y.tv_sec += nsec;
5502 }
06a2c219 5503
dbc4e1c1
JB
5504 if (x.tv_usec - y.tv_usec > 1000000)
5505 {
5506 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5507 y.tv_usec += 1000000 * nsec;
5508 y.tv_sec -= nsec;
5509 }
5510
06a2c219
GM
5511 /* Compute the time remaining to wait. tv_usec is certainly
5512 positive. */
dbc4e1c1
JB
5513 result->tv_sec = x.tv_sec - y.tv_sec;
5514 result->tv_usec = x.tv_usec - y.tv_usec;
5515
06a2c219
GM
5516 /* Return indication of whether the result should be considered
5517 negative. */
dbc4e1c1
JB
5518 return x.tv_sec < y.tv_sec;
5519}
dc6f92b8 5520
dfcf069d 5521void
f676886a
JB
5522XTflash (f)
5523 struct frame *f;
dc6f92b8 5524{
dbc4e1c1 5525 BLOCK_INPUT;
dc6f92b8 5526
dbc4e1c1
JB
5527 {
5528 GC gc;
dc6f92b8 5529
06a2c219
GM
5530 /* Create a GC that will use the GXxor function to flip foreground
5531 pixels into background pixels. */
dbc4e1c1
JB
5532 {
5533 XGCValues values;
dc6f92b8 5534
dbc4e1c1 5535 values.function = GXxor;
7556890b
RS
5536 values.foreground = (f->output_data.x->foreground_pixel
5537 ^ f->output_data.x->background_pixel);
58769bee 5538
334208b7 5539 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5540 GCFunction | GCForeground, &values);
5541 }
dc6f92b8 5542
dbc4e1c1 5543 {
e84e14c3
RS
5544 /* Get the height not including a menu bar widget. */
5545 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5546 /* Height of each line to flash. */
5547 int flash_height = FRAME_LINE_HEIGHT (f);
5548 /* These will be the left and right margins of the rectangles. */
5549 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5550 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5551
5552 int width;
5553
5554 /* Don't flash the area between a scroll bar and the frame
5555 edge it is next to. */
5556 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5557 {
5558 case vertical_scroll_bar_left:
5559 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5560 break;
5561
5562 case vertical_scroll_bar_right:
5563 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5564 break;
06a2c219
GM
5565
5566 default:
5567 break;
e84e14c3
RS
5568 }
5569
5570 width = flash_right - flash_left;
5571
5572 /* If window is tall, flash top and bottom line. */
5573 if (height > 3 * FRAME_LINE_HEIGHT (f))
5574 {
5575 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5576 flash_left,
5577 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5578 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5579 width, flash_height);
5580 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5581 flash_left,
5582 (height - flash_height
5583 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5584 width, flash_height);
5585 }
5586 else
5587 /* If it is short, flash it all. */
5588 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5589 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5590 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5591
06a2c219 5592 x_flush (f);
dc6f92b8 5593
dbc4e1c1 5594 {
06a2c219 5595 struct timeval wakeup;
dc6f92b8 5596
66c30ea1 5597 EMACS_GET_TIME (wakeup);
dc6f92b8 5598
dbc4e1c1
JB
5599 /* Compute time to wait until, propagating carry from usecs. */
5600 wakeup.tv_usec += 150000;
5601 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5602 wakeup.tv_usec %= 1000000;
5603
101922c3
GM
5604 /* Keep waiting until past the time wakeup or any input gets
5605 available. */
5606 while (! detect_input_pending ())
dbc4e1c1 5607 {
101922c3 5608 struct timeval current;
dbc4e1c1
JB
5609 struct timeval timeout;
5610
101922c3 5611 EMACS_GET_TIME (current);
dbc4e1c1 5612
101922c3
GM
5613 /* Break if result would be negative. */
5614 if (timeval_subtract (&current, wakeup, current))
dbc4e1c1
JB
5615 break;
5616
101922c3
GM
5617 /* How long `select' should wait. */
5618 timeout.tv_sec = 0;
5619 timeout.tv_usec = 10000;
5620
dbc4e1c1 5621 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5622 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5623 }
5624 }
58769bee 5625
e84e14c3
RS
5626 /* If window is tall, flash top and bottom line. */
5627 if (height > 3 * FRAME_LINE_HEIGHT (f))
5628 {
5629 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5630 flash_left,
5631 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5632 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5633 width, flash_height);
5634 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5635 flash_left,
5636 (height - flash_height
5637 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5638 width, flash_height);
5639 }
5640 else
5641 /* If it is short, flash it all. */
5642 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5643 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5644 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5645
334208b7 5646 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5647 x_flush (f);
dc6f92b8 5648 }
dbc4e1c1
JB
5649 }
5650
5651 UNBLOCK_INPUT;
dc6f92b8
JB
5652}
5653
06a2c219 5654#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5655
5656
dc6f92b8
JB
5657/* Make audible bell. */
5658
dfcf069d 5659void
dc6f92b8
JB
5660XTring_bell ()
5661{
b86bd3dd
GM
5662 struct frame *f = SELECTED_FRAME ();
5663
5664 if (FRAME_X_DISPLAY (f))
5665 {
dbc4e1c1 5666#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5667 if (visible_bell)
5668 XTflash (f);
5669 else
dbc4e1c1 5670#endif
b86bd3dd
GM
5671 {
5672 BLOCK_INPUT;
5673 XBell (FRAME_X_DISPLAY (f), 0);
5674 XFlush (FRAME_X_DISPLAY (f));
5675 UNBLOCK_INPUT;
5676 }
dc6f92b8
JB
5677 }
5678}
06a2c219 5679
dc6f92b8 5680\f
06a2c219
GM
5681/* Specify how many text lines, from the top of the window,
5682 should be affected by insert-lines and delete-lines operations.
5683 This, and those operations, are used only within an update
5684 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5685
dfcf069d 5686static void
06a2c219
GM
5687XTset_terminal_window (n)
5688 register int n;
dc6f92b8 5689{
06a2c219 5690 /* This function intentionally left blank. */
dc6f92b8
JB
5691}
5692
06a2c219
GM
5693
5694\f
5695/***********************************************************************
5696 Line Dance
5697 ***********************************************************************/
5698
5699/* Perform an insert-lines or delete-lines operation, inserting N
5700 lines or deleting -N lines at vertical position VPOS. */
5701
dfcf069d 5702static void
06a2c219
GM
5703x_ins_del_lines (vpos, n)
5704 int vpos, n;
dc6f92b8
JB
5705{
5706 abort ();
5707}
06a2c219
GM
5708
5709
5710/* Scroll part of the display as described by RUN. */
dc6f92b8 5711
dfcf069d 5712static void
06a2c219
GM
5713x_scroll_run (w, run)
5714 struct window *w;
5715 struct run *run;
dc6f92b8 5716{
06a2c219
GM
5717 struct frame *f = XFRAME (w->frame);
5718 int x, y, width, height, from_y, to_y, bottom_y;
5719
5720 /* Get frame-relative bounding box of the text display area of W,
5721 without mode lines. Include in this box the flags areas to the
5722 left and right of W. */
5723 window_box (w, -1, &x, &y, &width, &height);
110859fc
GM
5724 width += FRAME_X_FLAGS_AREA_WIDTH (f);
5725 x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
5726
5727 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5728 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5729 bottom_y = y + height;
dc6f92b8 5730
06a2c219
GM
5731 if (to_y < from_y)
5732 {
5733 /* Scrolling up. Make sure we don't copy part of the mode
5734 line at the bottom. */
5735 if (from_y + run->height > bottom_y)
5736 height = bottom_y - from_y;
5737 else
5738 height = run->height;
5739 }
dc6f92b8 5740 else
06a2c219
GM
5741 {
5742 /* Scolling down. Make sure we don't copy over the mode line.
5743 at the bottom. */
5744 if (to_y + run->height > bottom_y)
5745 height = bottom_y - to_y;
5746 else
5747 height = run->height;
5748 }
7a13e894 5749
06a2c219
GM
5750 BLOCK_INPUT;
5751
5752 /* Cursor off. Will be switched on again in x_update_window_end. */
5753 updated_window = w;
5754 x_clear_cursor (w);
5755
5756 XCopyArea (FRAME_X_DISPLAY (f),
5757 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5758 f->output_data.x->normal_gc,
5759 x, from_y,
5760 width, height,
5761 x, to_y);
5762
5763 UNBLOCK_INPUT;
5764}
dc6f92b8 5765
dc6f92b8 5766
06a2c219
GM
5767\f
5768/***********************************************************************
5769 Exposure Events
5770 ***********************************************************************/
5771
5772/* Redisplay an exposed area of frame F. X and Y are the upper-left
5773 corner of the exposed rectangle. W and H are width and height of
5774 the exposed area. All are pixel values. W or H zero means redraw
5775 the entire frame. */
dc6f92b8 5776
06a2c219
GM
5777static void
5778expose_frame (f, x, y, w, h)
5779 struct frame *f;
5780 int x, y, w, h;
dc6f92b8 5781{
06a2c219 5782 XRectangle r;
82f053ab 5783 int mouse_face_overwritten_p = 0;
dc6f92b8 5784
06a2c219 5785 TRACE ((stderr, "expose_frame "));
dc6f92b8 5786
06a2c219
GM
5787 /* No need to redraw if frame will be redrawn soon. */
5788 if (FRAME_GARBAGED_P (f))
dc6f92b8 5789 {
06a2c219
GM
5790 TRACE ((stderr, " garbaged\n"));
5791 return;
5792 }
5793
5794 /* If basic faces haven't been realized yet, there is no point in
5795 trying to redraw anything. This can happen when we get an expose
5796 event while Emacs is starting, e.g. by moving another window. */
5797 if (FRAME_FACE_CACHE (f) == NULL
5798 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5799 {
5800 TRACE ((stderr, " no faces\n"));
5801 return;
58769bee 5802 }
06a2c219
GM
5803
5804 if (w == 0 || h == 0)
58769bee 5805 {
06a2c219
GM
5806 r.x = r.y = 0;
5807 r.width = CANON_X_UNIT (f) * f->width;
5808 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5809 }
5810 else
5811 {
06a2c219
GM
5812 r.x = x;
5813 r.y = y;
5814 r.width = w;
5815 r.height = h;
5816 }
5817
5818 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
82f053ab 5819 mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
06a2c219 5820
9ea173e8 5821 if (WINDOWP (f->tool_bar_window))
82f053ab
GM
5822 mouse_face_overwritten_p
5823 |= expose_window (XWINDOW (f->tool_bar_window), &r);
06a2c219
GM
5824
5825#ifndef USE_X_TOOLKIT
5826 if (WINDOWP (f->menu_bar_window))
82f053ab
GM
5827 mouse_face_overwritten_p
5828 |= expose_window (XWINDOW (f->menu_bar_window), &r);
06a2c219 5829#endif /* not USE_X_TOOLKIT */
82f053ab
GM
5830
5831 /* Some window managers support a focus-follows-mouse style with
5832 delayed raising of frames. Imagine a partially obscured frame,
5833 and moving the mouse into partially obscured mouse-face on that
5834 frame. The visible part of the mouse-face will be highlighted,
5835 then the WM raises the obscured frame. With at least one WM, KDE
5836 2.1, Emacs is not getting any event for the raising of the frame
5837 (even tried with SubstructureRedirectMask), only Expose events.
5838 These expose events will draw text normally, i.e. not
5839 highlighted. Which means we must redo the highlight here.
5840 Subsume it under ``we love X''. --gerd 2001-08-15 */
5841 if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
5842 {
5843 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5844 if (f == dpyinfo->mouse_face_mouse_frame)
5845 {
5846 int x = dpyinfo->mouse_face_mouse_x;
5847 int y = dpyinfo->mouse_face_mouse_y;
5848 clear_mouse_face (dpyinfo);
5849 note_mouse_highlight (f, x, y);
5850 }
5851 }
dc6f92b8
JB
5852}
5853
06a2c219
GM
5854
5855/* Redraw (parts) of all windows in the window tree rooted at W that
82f053ab
GM
5856 intersect R. R contains frame pixel coordinates. Value is
5857 non-zero if the exposure overwrites mouse-face. */
06a2c219 5858
82f053ab 5859static int
06a2c219
GM
5860expose_window_tree (w, r)
5861 struct window *w;
5862 XRectangle *r;
dc6f92b8 5863{
82f053ab
GM
5864 struct frame *f = XFRAME (w->frame);
5865 int mouse_face_overwritten_p = 0;
5866
5867 while (w && !FRAME_GARBAGED_P (f))
06a2c219
GM
5868 {
5869 if (!NILP (w->hchild))
82f053ab
GM
5870 mouse_face_overwritten_p
5871 |= expose_window_tree (XWINDOW (w->hchild), r);
06a2c219 5872 else if (!NILP (w->vchild))
82f053ab
GM
5873 mouse_face_overwritten_p
5874 |= expose_window_tree (XWINDOW (w->vchild), r);
5875 else
5876 mouse_face_overwritten_p |= expose_window (w, r);
5877
a02f1be0 5878 w = NILP (w->next) ? NULL : XWINDOW (w->next);
06a2c219 5879 }
82f053ab
GM
5880
5881 return mouse_face_overwritten_p;
06a2c219 5882}
58769bee 5883
dc6f92b8 5884
06a2c219
GM
5885/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5886 which intersects rectangle R. R is in window-relative coordinates. */
5887
5888static void
5889expose_area (w, row, r, area)
5890 struct window *w;
5891 struct glyph_row *row;
5892 XRectangle *r;
5893 enum glyph_row_area area;
5894{
06a2c219
GM
5895 struct glyph *first = row->glyphs[area];
5896 struct glyph *end = row->glyphs[area] + row->used[area];
5897 struct glyph *last;
4bc6dcc7 5898 int first_x, start_x, x;
06a2c219 5899
6fb13182
GM
5900 if (area == TEXT_AREA && row->fill_line_p)
5901 /* If row extends face to end of line write the whole line. */
153f5ed7 5902 x_draw_glyphs (w, 0, row, area, 0, row->used[area],
f0a48a01 5903 DRAW_NORMAL_TEXT, 0);
6fb13182
GM
5904 else
5905 {
4bc6dcc7
GM
5906 /* Set START_X to the window-relative start position for drawing glyphs of
5907 AREA. The first glyph of the text area can be partially visible.
5908 The first glyphs of other areas cannot. */
5909 if (area == LEFT_MARGIN_AREA)
5910 start_x = 0;
5911 else if (area == TEXT_AREA)
5912 start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5913 else
5914 start_x = (window_box_width (w, LEFT_MARGIN_AREA)
5915 + window_box_width (w, TEXT_AREA));
5916 x = start_x;
5917
6fb13182
GM
5918 /* Find the first glyph that must be redrawn. */
5919 while (first < end
5920 && x + first->pixel_width < r->x)
5921 {
5922 x += first->pixel_width;
5923 ++first;
5924 }
5925
5926 /* Find the last one. */
5927 last = first;
5928 first_x = x;
5929 while (last < end
5930 && x < r->x + r->width)
5931 {
5932 x += last->pixel_width;
5933 ++last;
5934 }
5935
5936 /* Repaint. */
5937 if (last > first)
4bc6dcc7 5938 x_draw_glyphs (w, first_x - start_x, row, area,
6fb13182
GM
5939 first - row->glyphs[area],
5940 last - row->glyphs[area],
f0a48a01 5941 DRAW_NORMAL_TEXT, 0);
6fb13182 5942 }
06a2c219
GM
5943}
5944
58769bee 5945
06a2c219 5946/* Redraw the parts of the glyph row ROW on window W intersecting
82f053ab
GM
5947 rectangle R. R is in window-relative coordinates. Value is
5948 non-zero if mouse-face was overwritten. */
dc6f92b8 5949
82f053ab 5950static int
06a2c219
GM
5951expose_line (w, row, r)
5952 struct window *w;
5953 struct glyph_row *row;
5954 XRectangle *r;
5955{
5956 xassert (row->enabled_p);
5957
5958 if (row->mode_line_p || w->pseudo_window_p)
5959 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
f0a48a01 5960 DRAW_NORMAL_TEXT, 0);
06a2c219
GM
5961 else
5962 {
5963 if (row->used[LEFT_MARGIN_AREA])
5964 expose_area (w, row, r, LEFT_MARGIN_AREA);
5965 if (row->used[TEXT_AREA])
5966 expose_area (w, row, r, TEXT_AREA);
5967 if (row->used[RIGHT_MARGIN_AREA])
5968 expose_area (w, row, r, RIGHT_MARGIN_AREA);
5969 x_draw_row_bitmaps (w, row);
5970 }
82f053ab
GM
5971
5972 return row->mouse_face_p;
06a2c219 5973}
dc6f92b8 5974
58769bee 5975
06a2c219
GM
5976/* Return non-zero if W's cursor intersects rectangle R. */
5977
5978static int
5979x_phys_cursor_in_rect_p (w, r)
5980 struct window *w;
5981 XRectangle *r;
5982{
5983 XRectangle cr, result;
5984 struct glyph *cursor_glyph;
5985
5986 cursor_glyph = get_phys_cursor_glyph (w);
5987 if (cursor_glyph)
5988 {
5989 cr.x = w->phys_cursor.x;
5990 cr.y = w->phys_cursor.y;
5991 cr.width = cursor_glyph->pixel_width;
5992 cr.height = w->phys_cursor_height;
5993 return x_intersect_rectangles (&cr, r, &result);
5994 }
5995 else
5996 return 0;
dc6f92b8 5997}
dc6f92b8 5998
06a2c219 5999
a02f1be0
GM
6000/* Redraw the part of window W intersection rectangle FR. Pixel
6001 coordinates in FR are frame-relative. Call this function with
82f053ab
GM
6002 input blocked. Value is non-zero if the exposure overwrites
6003 mouse-face. */
dc6f92b8 6004
a39202f6 6005static int
a02f1be0 6006expose_window (w, fr)
06a2c219 6007 struct window *w;
a02f1be0 6008 XRectangle *fr;
dc6f92b8 6009{
a02f1be0 6010 struct frame *f = XFRAME (w->frame);
a02f1be0 6011 XRectangle wr, r;
82f053ab 6012 int mouse_face_overwritten_p = 0;
dc6f92b8 6013
80c32bcc
GM
6014 /* If window is not yet fully initialized, do nothing. This can
6015 happen when toolkit scroll bars are used and a window is split.
6016 Reconfiguring the scroll bar will generate an expose for a newly
6017 created window. */
a39202f6 6018 if (w->current_matrix == NULL)
82f053ab 6019 return 0;
a39202f6
GM
6020
6021 /* When we're currently updating the window, display and current
6022 matrix usually don't agree. Arrange for a thorough display
6023 later. */
6024 if (w == updated_window)
6025 {
6026 SET_FRAME_GARBAGED (f);
6027 return 0;
6028 }
80c32bcc 6029
a39202f6 6030 /* Frame-relative pixel rectangle of W. */
a02f1be0
GM
6031 wr.x = XFASTINT (w->left) * CANON_X_UNIT (f);
6032 wr.y = XFASTINT (w->top) * CANON_Y_UNIT (f);
6033 wr.width = XFASTINT (w->width) * CANON_X_UNIT (f);
6034 wr.height = XFASTINT (w->height) * CANON_Y_UNIT (f);
6035
a39202f6
GM
6036 if (x_intersect_rectangles (fr, &wr, &r))
6037 {
6038 int yb = window_text_bottom_y (w);
6039 struct glyph_row *row;
6040 int cursor_cleared_p;
a02f1be0 6041
a39202f6
GM
6042 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
6043 r.x, r.y, r.width, r.height));
dc6f92b8 6044
a39202f6
GM
6045 /* Convert to window coordinates. */
6046 r.x = FRAME_TO_WINDOW_PIXEL_X (w, r.x);
6047 r.y = FRAME_TO_WINDOW_PIXEL_Y (w, r.y);
dc6f92b8 6048
a39202f6
GM
6049 /* Turn off the cursor. */
6050 if (!w->pseudo_window_p
6051 && x_phys_cursor_in_rect_p (w, &r))
6052 {
6053 x_clear_cursor (w);
6054 cursor_cleared_p = 1;
6055 }
6056 else
6057 cursor_cleared_p = 0;
06a2c219 6058
a39202f6
GM
6059 /* Find the first row intersecting the rectangle R. */
6060 for (row = w->current_matrix->rows;
6061 row->enabled_p;
6062 ++row)
6063 {
6064 int y0 = row->y;
6065 int y1 = MATRIX_ROW_BOTTOM_Y (row);
6066
6067 if ((y0 >= r.y && y0 < r.y + r.height)
6068 || (y1 > r.y && y1 < r.y + r.height)
6069 || (r.y >= y0 && r.y < y1)
6070 || (r.y + r.height > y0 && r.y + r.height < y1))
82f053ab
GM
6071 {
6072 if (expose_line (w, row, &r))
6073 mouse_face_overwritten_p = 1;
6074 }
6075
a39202f6
GM
6076 if (y1 >= yb)
6077 break;
6078 }
dc6f92b8 6079
a39202f6
GM
6080 /* Display the mode line if there is one. */
6081 if (WINDOW_WANTS_MODELINE_P (w)
6082 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
6083 row->enabled_p)
6084 && row->y < r.y + r.height)
82f053ab
GM
6085 {
6086 if (expose_line (w, row, &r))
6087 mouse_face_overwritten_p = 1;
6088 }
a39202f6
GM
6089
6090 if (!w->pseudo_window_p)
6091 {
6092 /* Draw border between windows. */
6093 x_draw_vertical_border (w);
06a2c219 6094
a39202f6
GM
6095 /* Turn the cursor on again. */
6096 if (cursor_cleared_p)
6097 x_update_window_cursor (w, 1);
6098 }
06a2c219 6099 }
82f053ab
GM
6100
6101 return mouse_face_overwritten_p;
06a2c219 6102}
dc6f92b8 6103
dc6f92b8 6104
06a2c219
GM
6105/* Determine the intersection of two rectangles R1 and R2. Return
6106 the intersection in *RESULT. Value is non-zero if RESULT is not
6107 empty. */
6108
6109static int
6110x_intersect_rectangles (r1, r2, result)
6111 XRectangle *r1, *r2, *result;
6112{
6113 XRectangle *left, *right;
6114 XRectangle *upper, *lower;
6115 int intersection_p = 0;
6116
6117 /* Rearrange so that R1 is the left-most rectangle. */
6118 if (r1->x < r2->x)
6119 left = r1, right = r2;
6120 else
6121 left = r2, right = r1;
6122
6123 /* X0 of the intersection is right.x0, if this is inside R1,
6124 otherwise there is no intersection. */
6125 if (right->x <= left->x + left->width)
6126 {
6127 result->x = right->x;
6128
6129 /* The right end of the intersection is the minimum of the
6130 the right ends of left and right. */
6131 result->width = (min (left->x + left->width, right->x + right->width)
6132 - result->x);
6133
6134 /* Same game for Y. */
6135 if (r1->y < r2->y)
6136 upper = r1, lower = r2;
6137 else
6138 upper = r2, lower = r1;
6139
6140 /* The upper end of the intersection is lower.y0, if this is inside
6141 of upper. Otherwise, there is no intersection. */
6142 if (lower->y <= upper->y + upper->height)
dc43ef94 6143 {
06a2c219
GM
6144 result->y = lower->y;
6145
6146 /* The lower end of the intersection is the minimum of the lower
6147 ends of upper and lower. */
6148 result->height = (min (lower->y + lower->height,
6149 upper->y + upper->height)
6150 - result->y);
6151 intersection_p = 1;
dc43ef94 6152 }
dc6f92b8
JB
6153 }
6154
06a2c219 6155 return intersection_p;
dc6f92b8 6156}
06a2c219
GM
6157
6158
6159
6160
dc6f92b8 6161\f
dc6f92b8 6162static void
334208b7
RS
6163frame_highlight (f)
6164 struct frame *f;
dc6f92b8 6165{
b3e1e05c
JB
6166 /* We used to only do this if Vx_no_window_manager was non-nil, but
6167 the ICCCM (section 4.1.6) says that the window's border pixmap
6168 and border pixel are window attributes which are "private to the
6169 client", so we can always change it to whatever we want. */
6170 BLOCK_INPUT;
334208b7 6171 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6172 f->output_data.x->border_pixel);
b3e1e05c 6173 UNBLOCK_INPUT;
5d46f928 6174 x_update_cursor (f, 1);
dc6f92b8
JB
6175}
6176
6177static void
334208b7
RS
6178frame_unhighlight (f)
6179 struct frame *f;
dc6f92b8 6180{
b3e1e05c
JB
6181 /* We used to only do this if Vx_no_window_manager was non-nil, but
6182 the ICCCM (section 4.1.6) says that the window's border pixmap
6183 and border pixel are window attributes which are "private to the
6184 client", so we can always change it to whatever we want. */
6185 BLOCK_INPUT;
334208b7 6186 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6187 f->output_data.x->border_tile);
b3e1e05c 6188 UNBLOCK_INPUT;
5d46f928 6189 x_update_cursor (f, 1);
dc6f92b8 6190}
dc6f92b8 6191
f676886a
JB
6192/* The focus has changed. Update the frames as necessary to reflect
6193 the new situation. Note that we can't change the selected frame
c5acd733 6194 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 6195 Each event gets marked with the frame in which it occurred, so the
c5acd733 6196 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 6197
6d4238f3 6198static void
0f941935
KH
6199x_new_focus_frame (dpyinfo, frame)
6200 struct x_display_info *dpyinfo;
f676886a 6201 struct frame *frame;
dc6f92b8 6202{
0f941935 6203 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 6204
0f941935 6205 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 6206 {
58769bee 6207 /* Set this before calling other routines, so that they see
f676886a 6208 the correct value of x_focus_frame. */
0f941935 6209 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
6210
6211 if (old_focus && old_focus->auto_lower)
f676886a 6212 x_lower_frame (old_focus);
dc6f92b8
JB
6213
6214#if 0
f676886a 6215 selected_frame = frame;
e0c1aef2
KH
6216 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6217 selected_frame);
f676886a
JB
6218 Fselect_window (selected_frame->selected_window);
6219 choose_minibuf_frame ();
c118dd06 6220#endif /* ! 0 */
dc6f92b8 6221
0f941935
KH
6222 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6223 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
6224 else
6225 pending_autoraise_frame = 0;
6d4238f3 6226 }
dc6f92b8 6227
0f941935 6228 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
6229}
6230
37c2c98b
RS
6231/* Handle an event saying the mouse has moved out of an Emacs frame. */
6232
6233void
0f941935
KH
6234x_mouse_leave (dpyinfo)
6235 struct x_display_info *dpyinfo;
37c2c98b 6236{
0f941935 6237 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 6238}
6d4238f3 6239
f451eb13
JB
6240/* The focus has changed, or we have redirected a frame's focus to
6241 another frame (this happens when a frame uses a surrogate
06a2c219 6242 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
6243
6244 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 6245 frame is being highlighted or un-highlighted; we only use it to find
0f941935 6246 the appropriate X display info. */
06a2c219 6247
6d4238f3 6248static void
0f941935
KH
6249XTframe_rehighlight (frame)
6250 struct frame *frame;
6d4238f3 6251{
0f941935
KH
6252 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6253}
6d4238f3 6254
0f941935
KH
6255static void
6256x_frame_rehighlight (dpyinfo)
6257 struct x_display_info *dpyinfo;
6258{
6259 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6260
6261 if (dpyinfo->x_focus_frame)
6d4238f3 6262 {
0f941935
KH
6263 dpyinfo->x_highlight_frame
6264 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6265 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6266 : dpyinfo->x_focus_frame);
6267 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 6268 {
0f941935
KH
6269 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6270 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 6271 }
dc6f92b8 6272 }
6d4238f3 6273 else
0f941935 6274 dpyinfo->x_highlight_frame = 0;
dc6f92b8 6275
0f941935 6276 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
6277 {
6278 if (old_highlight)
f676886a 6279 frame_unhighlight (old_highlight);
0f941935
KH
6280 if (dpyinfo->x_highlight_frame)
6281 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 6282 }
dc6f92b8 6283}
06a2c219
GM
6284
6285
dc6f92b8 6286\f
06a2c219 6287/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 6288
28430d3c
JB
6289/* Initialize mode_switch_bit and modifier_meaning. */
6290static void
334208b7
RS
6291x_find_modifier_meanings (dpyinfo)
6292 struct x_display_info *dpyinfo;
28430d3c 6293{
f689eb05 6294 int min_code, max_code;
28430d3c
JB
6295 KeySym *syms;
6296 int syms_per_code;
6297 XModifierKeymap *mods;
6298
334208b7
RS
6299 dpyinfo->meta_mod_mask = 0;
6300 dpyinfo->shift_lock_mask = 0;
6301 dpyinfo->alt_mod_mask = 0;
6302 dpyinfo->super_mod_mask = 0;
6303 dpyinfo->hyper_mod_mask = 0;
58769bee 6304
9658a521 6305#ifdef HAVE_X11R4
334208b7 6306 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 6307#else
4a60f8c5
RS
6308 min_code = dpyinfo->display->min_keycode;
6309 max_code = dpyinfo->display->max_keycode;
9658a521
JB
6310#endif
6311
334208b7 6312 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
6313 min_code, max_code - min_code + 1,
6314 &syms_per_code);
334208b7 6315 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 6316
58769bee 6317 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 6318 Alt keysyms are on. */
28430d3c 6319 {
06a2c219 6320 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
6321
6322 for (row = 3; row < 8; row++)
6323 for (col = 0; col < mods->max_keypermod; col++)
6324 {
0299d313
RS
6325 KeyCode code
6326 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 6327
af92970c
KH
6328 /* Zeroes are used for filler. Skip them. */
6329 if (code == 0)
6330 continue;
6331
28430d3c
JB
6332 /* Are any of this keycode's keysyms a meta key? */
6333 {
6334 int code_col;
6335
6336 for (code_col = 0; code_col < syms_per_code; code_col++)
6337 {
f689eb05 6338 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 6339
f689eb05 6340 switch (sym)
28430d3c 6341 {
f689eb05
JB
6342 case XK_Meta_L:
6343 case XK_Meta_R:
334208b7 6344 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 6345 break;
f689eb05
JB
6346
6347 case XK_Alt_L:
6348 case XK_Alt_R:
334208b7 6349 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
6350 break;
6351
6352 case XK_Hyper_L:
6353 case XK_Hyper_R:
334208b7 6354 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
6355 break;
6356
6357 case XK_Super_L:
6358 case XK_Super_R:
334208b7 6359 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 6360 break;
11edeb03
JB
6361
6362 case XK_Shift_Lock:
6363 /* Ignore this if it's not on the lock modifier. */
6364 if ((1 << row) == LockMask)
334208b7 6365 dpyinfo->shift_lock_mask = LockMask;
11edeb03 6366 break;
28430d3c
JB
6367 }
6368 }
6369 }
6370 }
6371 }
6372
f689eb05 6373 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 6374 if (! dpyinfo->meta_mod_mask)
a3c44b14 6375 {
334208b7
RS
6376 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6377 dpyinfo->alt_mod_mask = 0;
a3c44b14 6378 }
f689eb05 6379
148c4b70
RS
6380 /* If some keys are both alt and meta,
6381 make them just meta, not alt. */
334208b7 6382 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 6383 {
334208b7 6384 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 6385 }
58769bee 6386
28430d3c 6387 XFree ((char *) syms);
f689eb05 6388 XFreeModifiermap (mods);
28430d3c
JB
6389}
6390
dfeccd2d
JB
6391/* Convert between the modifier bits X uses and the modifier bits
6392 Emacs uses. */
06a2c219 6393
7c5283e4 6394static unsigned int
334208b7
RS
6395x_x_to_emacs_modifiers (dpyinfo, state)
6396 struct x_display_info *dpyinfo;
dc6f92b8
JB
6397 unsigned int state;
6398{
334208b7
RS
6399 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
6400 | ((state & ControlMask) ? ctrl_modifier : 0)
6401 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
6402 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
6403 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
6404 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
6405}
6406
dfeccd2d 6407static unsigned int
334208b7
RS
6408x_emacs_to_x_modifiers (dpyinfo, state)
6409 struct x_display_info *dpyinfo;
dfeccd2d
JB
6410 unsigned int state;
6411{
334208b7
RS
6412 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
6413 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6414 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6415 | ((state & shift_modifier) ? ShiftMask : 0)
6416 | ((state & ctrl_modifier) ? ControlMask : 0)
6417 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6418}
d047c4eb
KH
6419
6420/* Convert a keysym to its name. */
6421
6422char *
6423x_get_keysym_name (keysym)
6424 KeySym keysym;
6425{
6426 char *value;
6427
6428 BLOCK_INPUT;
6429 value = XKeysymToString (keysym);
6430 UNBLOCK_INPUT;
6431
6432 return value;
6433}
06a2c219
GM
6434
6435
e4571a43
JB
6436\f
6437/* Mouse clicks and mouse movement. Rah. */
e4571a43 6438
06a2c219
GM
6439/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6440 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6441 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6442 not force the value into range. */
69388238 6443
c8dba240 6444void
69388238 6445pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6446 FRAME_PTR f;
69388238 6447 register int pix_x, pix_y;
e4571a43
JB
6448 register int *x, *y;
6449 XRectangle *bounds;
69388238 6450 int noclip;
e4571a43 6451{
06a2c219 6452 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6453 even for negative values. */
6454 if (pix_x < 0)
7556890b 6455 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6456 if (pix_y < 0)
7556890b 6457 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6458
e4571a43
JB
6459 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6460 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6461
6462 if (bounds)
6463 {
7556890b
RS
6464 bounds->width = FONT_WIDTH (f->output_data.x->font);
6465 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6466 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6467 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6468 }
6469
69388238
RS
6470 if (!noclip)
6471 {
6472 if (pix_x < 0)
6473 pix_x = 0;
3cbd2e0b
RS
6474 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6475 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6476
6477 if (pix_y < 0)
6478 pix_y = 0;
6479 else if (pix_y > f->height)
6480 pix_y = f->height;
6481 }
e4571a43
JB
6482
6483 *x = pix_x;
6484 *y = pix_y;
6485}
6486
06a2c219
GM
6487
6488/* Given HPOS/VPOS in the current matrix of W, return corresponding
6489 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6490 can't tell the positions because W's display is not up to date,
6491 return 0. */
6492
6493int
6494glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6495 struct window *w;
6496 int hpos, vpos;
6497 int *frame_x, *frame_y;
2b5c9e71 6498{
06a2c219
GM
6499 int success_p;
6500
6501 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6502 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6503
6504 if (display_completed)
6505 {
6506 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6507 struct glyph *glyph = row->glyphs[TEXT_AREA];
6508 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6509
6510 *frame_y = row->y;
6511 *frame_x = row->x;
6512 while (glyph < end)
6513 {
6514 *frame_x += glyph->pixel_width;
6515 ++glyph;
6516 }
6517
6518 success_p = 1;
6519 }
6520 else
6521 {
6522 *frame_y = *frame_x = 0;
6523 success_p = 0;
6524 }
6525
6526 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6527 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6528 return success_p;
2b5c9e71
RS
6529}
6530
06a2c219 6531
dc6f92b8
JB
6532/* Prepare a mouse-event in *RESULT for placement in the input queue.
6533
6534 If the event is a button press, then note that we have grabbed
f451eb13 6535 the mouse. */
dc6f92b8
JB
6536
6537static Lisp_Object
f451eb13 6538construct_mouse_click (result, event, f)
dc6f92b8
JB
6539 struct input_event *result;
6540 XButtonEvent *event;
f676886a 6541 struct frame *f;
dc6f92b8 6542{
f451eb13 6543 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6544 otherwise. */
f451eb13 6545 result->kind = mouse_click;
69388238 6546 result->code = event->button - Button1;
1113d9db 6547 result->timestamp = event->time;
334208b7
RS
6548 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6549 event->state)
f689eb05 6550 | (event->type == ButtonRelease
58769bee 6551 ? up_modifier
f689eb05 6552 : down_modifier));
dc6f92b8 6553
06a2c219
GM
6554 XSETINT (result->x, event->x);
6555 XSETINT (result->y, event->y);
6556 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6557 result->arg = Qnil;
06a2c219 6558 return Qnil;
dc6f92b8 6559}
b849c413 6560
69388238 6561\f
90e65f07
JB
6562/* Function to report a mouse movement to the mainstream Emacs code.
6563 The input handler calls this.
6564
6565 We have received a mouse movement event, which is given in *event.
6566 If the mouse is over a different glyph than it was last time, tell
6567 the mainstream emacs code by setting mouse_moved. If not, ask for
6568 another motion event, so we can check again the next time it moves. */
b8009dd1 6569
06a2c219
GM
6570static XMotionEvent last_mouse_motion_event;
6571static Lisp_Object last_mouse_motion_frame;
6572
90e65f07 6573static void
12ba150f 6574note_mouse_movement (frame, event)
f676886a 6575 FRAME_PTR frame;
90e65f07 6576 XMotionEvent *event;
90e65f07 6577{
e5d77022 6578 last_mouse_movement_time = event->time;
06a2c219
GM
6579 last_mouse_motion_event = *event;
6580 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6581
27f338af
RS
6582 if (event->window != FRAME_X_WINDOW (frame))
6583 {
39d8bb4d 6584 frame->mouse_moved = 1;
27f338af 6585 last_mouse_scroll_bar = Qnil;
27f338af 6586 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6587 }
6588
90e65f07 6589 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6590 else if (event->x < last_mouse_glyph.x
6591 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6592 || event->y < last_mouse_glyph.y
6593 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6594 {
39d8bb4d 6595 frame->mouse_moved = 1;
ab648270 6596 last_mouse_scroll_bar = Qnil;
b8009dd1 6597 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6598 }
6599}
6600
bf1c0ba1 6601/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6602
06a2c219
GM
6603 int disable_mouse_highlight;
6604
6605
6606\f
6607/************************************************************************
6608 Mouse Face
6609 ************************************************************************/
6610
6611/* Find the glyph under window-relative coordinates X/Y in window W.
6612 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6613 strings. Return in *HPOS and *VPOS the row and column number of
6614 the glyph found. Return in *AREA the glyph area containing X.
6615 Value is a pointer to the glyph found or null if X/Y is not on
6616 text, or we can't tell because W's current matrix is not up to
6617 date. */
6618
6619static struct glyph *
f9db2310 6620x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
06a2c219
GM
6621 struct window *w;
6622 int x, y;
6623 int *hpos, *vpos, *area;
f9db2310 6624 int buffer_only_p;
06a2c219
GM
6625{
6626 struct glyph *glyph, *end;
3e71d8f2 6627 struct glyph_row *row = NULL;
06a2c219
GM
6628 int x0, i, left_area_width;
6629
6630 /* Find row containing Y. Give up if some row is not enabled. */
6631 for (i = 0; i < w->current_matrix->nrows; ++i)
6632 {
6633 row = MATRIX_ROW (w->current_matrix, i);
6634 if (!row->enabled_p)
6635 return NULL;
6636 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6637 break;
6638 }
6639
6640 *vpos = i;
6641 *hpos = 0;
6642
6643 /* Give up if Y is not in the window. */
6644 if (i == w->current_matrix->nrows)
6645 return NULL;
6646
6647 /* Get the glyph area containing X. */
6648 if (w->pseudo_window_p)
6649 {
6650 *area = TEXT_AREA;
6651 x0 = 0;
6652 }
6653 else
6654 {
6655 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6656 if (x < left_area_width)
6657 {
6658 *area = LEFT_MARGIN_AREA;
6659 x0 = 0;
6660 }
6661 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6662 {
6663 *area = TEXT_AREA;
6664 x0 = row->x + left_area_width;
6665 }
6666 else
6667 {
6668 *area = RIGHT_MARGIN_AREA;
6669 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6670 }
6671 }
6672
6673 /* Find glyph containing X. */
6674 glyph = row->glyphs[*area];
6675 end = glyph + row->used[*area];
6676 while (glyph < end)
6677 {
6678 if (x < x0 + glyph->pixel_width)
6679 {
6680 if (w->pseudo_window_p)
6681 break;
f9db2310 6682 else if (!buffer_only_p || BUFFERP (glyph->object))
06a2c219
GM
6683 break;
6684 }
6685
6686 x0 += glyph->pixel_width;
6687 ++glyph;
6688 }
6689
6690 if (glyph == end)
6691 return NULL;
6692
6693 *hpos = glyph - row->glyphs[*area];
6694 return glyph;
6695}
6696
6697
6698/* Convert frame-relative x/y to coordinates relative to window W.
6699 Takes pseudo-windows into account. */
6700
6701static void
6702frame_to_window_pixel_xy (w, x, y)
6703 struct window *w;
6704 int *x, *y;
6705{
6706 if (w->pseudo_window_p)
6707 {
6708 /* A pseudo-window is always full-width, and starts at the
6709 left edge of the frame, plus a frame border. */
6710 struct frame *f = XFRAME (w->frame);
6711 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6712 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6713 }
6714 else
6715 {
6716 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6717 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6718 }
6719}
6720
6721
e371a781 6722/* Take proper action when mouse has moved to the mode or header line of
06a2c219
GM
6723 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6724 mode line. X is relative to the start of the text display area of
6725 W, so the width of bitmap areas and scroll bars must be subtracted
6726 to get a position relative to the start of the mode line. */
6727
6728static void
6729note_mode_line_highlight (w, x, mode_line_p)
6730 struct window *w;
6731 int x, mode_line_p;
6732{
6733 struct frame *f = XFRAME (w->frame);
6734 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6735 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6736 struct glyph_row *row;
6737
6738 if (mode_line_p)
6739 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6740 else
045dee35 6741 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
e371a781 6742
06a2c219
GM
6743 if (row->enabled_p)
6744 {
6745 struct glyph *glyph, *end;
6746 Lisp_Object help, map;
6747 int x0;
6748
6749 /* Find the glyph under X. */
6750 glyph = row->glyphs[TEXT_AREA];
6751 end = glyph + row->used[TEXT_AREA];
6752 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
110859fc 6753 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
e371a781 6754
06a2c219
GM
6755 while (glyph < end
6756 && x >= x0 + glyph->pixel_width)
6757 {
6758 x0 += glyph->pixel_width;
6759 ++glyph;
6760 }
6761
6762 if (glyph < end
6763 && STRINGP (glyph->object)
6764 && XSTRING (glyph->object)->intervals
6765 && glyph->charpos >= 0
6766 && glyph->charpos < XSTRING (glyph->object)->size)
6767 {
6768 /* If we're on a string with `help-echo' text property,
6769 arrange for the help to be displayed. This is done by
6770 setting the global variable help_echo to the help string. */
6771 help = Fget_text_property (make_number (glyph->charpos),
6772 Qhelp_echo, glyph->object);
b7e80413 6773 if (!NILP (help))
be010514
GM
6774 {
6775 help_echo = help;
7cea38bc 6776 XSETWINDOW (help_echo_window, w);
be010514
GM
6777 help_echo_object = glyph->object;
6778 help_echo_pos = glyph->charpos;
6779 }
06a2c219
GM
6780
6781 /* Change the mouse pointer according to what is under X/Y. */
6782 map = Fget_text_property (make_number (glyph->charpos),
6783 Qlocal_map, glyph->object);
02067692 6784 if (KEYMAPP (map))
06a2c219 6785 cursor = f->output_data.x->nontext_cursor;
be010514
GM
6786 else
6787 {
6788 map = Fget_text_property (make_number (glyph->charpos),
6789 Qkeymap, glyph->object);
02067692 6790 if (KEYMAPP (map))
be010514
GM
6791 cursor = f->output_data.x->nontext_cursor;
6792 }
06a2c219
GM
6793 }
6794 }
6795
6796 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6797}
6798
6799
6800/* Take proper action when the mouse has moved to position X, Y on
6801 frame F as regards highlighting characters that have mouse-face
6802 properties. Also de-highlighting chars where the mouse was before.
27f338af 6803 X and Y can be negative or out of range. */
b8009dd1
RS
6804
6805static void
6806note_mouse_highlight (f, x, y)
06a2c219 6807 struct frame *f;
c32cdd9a 6808 int x, y;
b8009dd1 6809{
06a2c219
GM
6810 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6811 int portion;
b8009dd1
RS
6812 Lisp_Object window;
6813 struct window *w;
0d487c52
GM
6814 Cursor cursor = None;
6815 struct buffer *b;
b8009dd1 6816
06a2c219
GM
6817 /* When a menu is active, don't highlight because this looks odd. */
6818#ifdef USE_X_TOOLKIT
6819 if (popup_activated ())
6820 return;
6821#endif
6822
04fff9c0
GM
6823 if (disable_mouse_highlight
6824 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6825 return;
6826
06a2c219
GM
6827 dpyinfo->mouse_face_mouse_x = x;
6828 dpyinfo->mouse_face_mouse_y = y;
6829 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6830
06a2c219 6831 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6832 return;
6833
514e4681
RS
6834 if (gc_in_progress)
6835 {
06a2c219 6836 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6837 return;
6838 }
6839
b8009dd1 6840 /* Which window is that in? */
06a2c219 6841 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6842
6843 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6844 if (! EQ (window, dpyinfo->mouse_face_window))
6845 clear_mouse_face (dpyinfo);
6846
6847 /* Not on a window -> return. */
6848 if (!WINDOWP (window))
6849 return;
6850
6851 /* Convert to window-relative pixel coordinates. */
6852 w = XWINDOW (window);
6853 frame_to_window_pixel_xy (w, &x, &y);
6854
9ea173e8 6855 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6856 buffer. */
9ea173e8 6857 if (EQ (window, f->tool_bar_window))
06a2c219 6858 {
9ea173e8 6859 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6860 return;
6861 }
6862
0d487c52 6863 /* Mouse is on the mode or header line? */
06a2c219
GM
6864 if (portion == 1 || portion == 3)
6865 {
06a2c219
GM
6866 note_mode_line_highlight (w, x, portion == 1);
6867 return;
6868 }
0d487c52
GM
6869
6870 if (portion == 2)
6871 cursor = f->output_data.x->horizontal_drag_cursor;
06a2c219 6872 else
0d487c52 6873 cursor = f->output_data.x->text_cursor;
b8009dd1 6874
0cdd0c9f
RS
6875 /* Are we in a window whose display is up to date?
6876 And verify the buffer's text has not changed. */
0d487c52 6877 b = XBUFFER (w->buffer);
06a2c219
GM
6878 if (/* Within text portion of the window. */
6879 portion == 0
0cdd0c9f 6880 && EQ (w->window_end_valid, w->buffer)
0d487c52
GM
6881 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
6882 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
b8009dd1 6883 {
06a2c219
GM
6884 int hpos, vpos, pos, i, area;
6885 struct glyph *glyph;
f9db2310 6886 Lisp_Object object;
0d487c52
GM
6887 Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
6888 Lisp_Object *overlay_vec = NULL;
6889 int len, noverlays;
6890 struct buffer *obuf;
6891 int obegv, ozv, same_region;
b8009dd1 6892
06a2c219 6893 /* Find the glyph under X/Y. */
f9db2310 6894 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
06a2c219
GM
6895
6896 /* Clear mouse face if X/Y not over text. */
6897 if (glyph == NULL
6898 || area != TEXT_AREA
6899 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6900 {
fa262c07
GM
6901 if (clear_mouse_face (dpyinfo))
6902 cursor = None;
6903 goto set_cursor;
06a2c219
GM
6904 }
6905
6906 pos = glyph->charpos;
f9db2310
GM
6907 object = glyph->object;
6908 if (!STRINGP (object) && !BUFFERP (object))
fa262c07 6909 goto set_cursor;
06a2c219 6910
0d487c52
GM
6911 /* If we get an out-of-range value, return now; avoid an error. */
6912 if (BUFFERP (object) && pos > BUF_Z (b))
fa262c07 6913 goto set_cursor;
06a2c219 6914
0d487c52
GM
6915 /* Make the window's buffer temporarily current for
6916 overlays_at and compute_char_face. */
6917 obuf = current_buffer;
6918 current_buffer = b;
6919 obegv = BEGV;
6920 ozv = ZV;
6921 BEGV = BEG;
6922 ZV = Z;
06a2c219 6923
0d487c52
GM
6924 /* Is this char mouse-active or does it have help-echo? */
6925 position = make_number (pos);
f9db2310 6926
0d487c52
GM
6927 if (BUFFERP (object))
6928 {
6929 /* Put all the overlays we want in a vector in overlay_vec.
6930 Store the length in len. If there are more than 10, make
6931 enough space for all, and try again. */
6932 len = 10;
6933 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6934 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
6935 if (noverlays > len)
6936 {
6937 len = noverlays;
6938 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6939 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
6940 }
f8349001 6941
0d487c52
GM
6942 /* Sort overlays into increasing priority order. */
6943 noverlays = sort_overlays (overlay_vec, noverlays, w);
6944 }
6945 else
6946 noverlays = 0;
6947
6948 same_region = (EQ (window, dpyinfo->mouse_face_window)
6949 && vpos >= dpyinfo->mouse_face_beg_row
6950 && vpos <= dpyinfo->mouse_face_end_row
6951 && (vpos > dpyinfo->mouse_face_beg_row
6952 || hpos >= dpyinfo->mouse_face_beg_col)
6953 && (vpos < dpyinfo->mouse_face_end_row
6954 || hpos < dpyinfo->mouse_face_end_col
6955 || dpyinfo->mouse_face_past_end));
6956
6957 if (same_region)
6958 cursor = None;
6959
6960 /* Check mouse-face highlighting. */
6961 if (! same_region
6962 /* If there exists an overlay with mouse-face overlapping
6963 the one we are currently highlighting, we have to
6964 check if we enter the overlapping overlay, and then
6965 highlight only that. */
6966 || (OVERLAYP (dpyinfo->mouse_face_overlay)
6967 && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
6968 {
0d487c52
GM
6969 /* Find the highest priority overlay that has a mouse-face
6970 property. */
6971 overlay = Qnil;
6972 for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
6973 {
6974 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6975 if (!NILP (mouse_face))
6976 overlay = overlay_vec[i];
6977 }
8bd189fb
GM
6978
6979 /* If we're actually highlighting the same overlay as
6980 before, there's no need to do that again. */
6981 if (!NILP (overlay)
6982 && EQ (overlay, dpyinfo->mouse_face_overlay))
6983 goto check_help_echo;
f9db2310 6984
8bd189fb
GM
6985 dpyinfo->mouse_face_overlay = overlay;
6986
6987 /* Clear the display of the old active region, if any. */
6988 if (clear_mouse_face (dpyinfo))
6989 cursor = None;
6990
0d487c52
GM
6991 /* If no overlay applies, get a text property. */
6992 if (NILP (overlay))
6993 mouse_face = Fget_text_property (position, Qmouse_face, object);
06a2c219 6994
0d487c52
GM
6995 /* Handle the overlay case. */
6996 if (!NILP (overlay))
6997 {
6998 /* Find the range of text around this char that
6999 should be active. */
7000 Lisp_Object before, after;
7001 int ignore;
7002
7003 before = Foverlay_start (overlay);
7004 after = Foverlay_end (overlay);
7005 /* Record this as the current active region. */
7006 fast_find_position (w, XFASTINT (before),
7007 &dpyinfo->mouse_face_beg_col,
7008 &dpyinfo->mouse_face_beg_row,
7009 &dpyinfo->mouse_face_beg_x,
7e376260
GM
7010 &dpyinfo->mouse_face_beg_y, Qnil);
7011
0d487c52
GM
7012 dpyinfo->mouse_face_past_end
7013 = !fast_find_position (w, XFASTINT (after),
7014 &dpyinfo->mouse_face_end_col,
7015 &dpyinfo->mouse_face_end_row,
7016 &dpyinfo->mouse_face_end_x,
7e376260 7017 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7018 dpyinfo->mouse_face_window = window;
7019 dpyinfo->mouse_face_face_id
7020 = face_at_buffer_position (w, pos, 0, 0,
7021 &ignore, pos + 1, 1);
7022
7023 /* Display it as active. */
7024 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7025 cursor = None;
0d487c52
GM
7026 }
7027 /* Handle the text property case. */
7028 else if (!NILP (mouse_face) && BUFFERP (object))
7029 {
7030 /* Find the range of text around this char that
7031 should be active. */
7032 Lisp_Object before, after, beginning, end;
7033 int ignore;
7034
7035 beginning = Fmarker_position (w->start);
7036 end = make_number (BUF_Z (XBUFFER (object))
7037 - XFASTINT (w->window_end_pos));
7038 before
7039 = Fprevious_single_property_change (make_number (pos + 1),
7040 Qmouse_face,
7041 object, beginning);
7042 after
7043 = Fnext_single_property_change (position, Qmouse_face,
7044 object, end);
7045
7046 /* Record this as the current active region. */
7047 fast_find_position (w, XFASTINT (before),
7048 &dpyinfo->mouse_face_beg_col,
7049 &dpyinfo->mouse_face_beg_row,
7050 &dpyinfo->mouse_face_beg_x,
7e376260 7051 &dpyinfo->mouse_face_beg_y, Qnil);
0d487c52
GM
7052 dpyinfo->mouse_face_past_end
7053 = !fast_find_position (w, XFASTINT (after),
7054 &dpyinfo->mouse_face_end_col,
7055 &dpyinfo->mouse_face_end_row,
7056 &dpyinfo->mouse_face_end_x,
7e376260 7057 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7058 dpyinfo->mouse_face_window = window;
7059
7060 if (BUFFERP (object))
06a2c219
GM
7061 dpyinfo->mouse_face_face_id
7062 = face_at_buffer_position (w, pos, 0, 0,
7063 &ignore, pos + 1, 1);
7064
0d487c52
GM
7065 /* Display it as active. */
7066 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7067 cursor = None;
0d487c52
GM
7068 }
7069 else if (!NILP (mouse_face) && STRINGP (object))
7070 {
7071 Lisp_Object b, e;
7072 int ignore;
f9db2310 7073
0d487c52
GM
7074 b = Fprevious_single_property_change (make_number (pos + 1),
7075 Qmouse_face,
7076 object, Qnil);
7077 e = Fnext_single_property_change (position, Qmouse_face,
7078 object, Qnil);
7079 if (NILP (b))
7080 b = make_number (0);
7081 if (NILP (e))
7082 e = make_number (XSTRING (object)->size - 1);
7083 fast_find_string_pos (w, XINT (b), object,
06a2c219
GM
7084 &dpyinfo->mouse_face_beg_col,
7085 &dpyinfo->mouse_face_beg_row,
7086 &dpyinfo->mouse_face_beg_x,
0d487c52
GM
7087 &dpyinfo->mouse_face_beg_y, 0);
7088 fast_find_string_pos (w, XINT (e), object,
7089 &dpyinfo->mouse_face_end_col,
7090 &dpyinfo->mouse_face_end_row,
7091 &dpyinfo->mouse_face_end_x,
7092 &dpyinfo->mouse_face_end_y, 1);
7093 dpyinfo->mouse_face_past_end = 0;
7094 dpyinfo->mouse_face_window = window;
7095 dpyinfo->mouse_face_face_id
7096 = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
7097 glyph->face_id, 1);
7098 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7099 cursor = None;
0d487c52 7100 }
7e376260
GM
7101 else if (STRINGP (object) && NILP (mouse_face))
7102 {
7103 /* A string which doesn't have mouse-face, but
7104 the text ``under'' it might have. */
7105 struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
7106 int start = MATRIX_ROW_START_CHARPOS (r);
7107
7108 pos = string_buffer_position (w, object, start);
7109 if (pos > 0)
7110 mouse_face = get_char_property_and_overlay (make_number (pos),
7111 Qmouse_face,
7112 w->buffer,
7113 &overlay);
7114 if (!NILP (mouse_face) && !NILP (overlay))
7115 {
7116 Lisp_Object before = Foverlay_start (overlay);
7117 Lisp_Object after = Foverlay_end (overlay);
7118 Lisp_Object ignore;
7119
7120 /* Note that we might not be able to find position
7121 BEFORE in the glyph matrix if the overlay is
7122 entirely covered by a `display' property. In
7123 this case, we overshoot. So let's stop in
7124 the glyph matrix before glyphs for OBJECT. */
7125 fast_find_position (w, XFASTINT (before),
7126 &dpyinfo->mouse_face_beg_col,
7127 &dpyinfo->mouse_face_beg_row,
7128 &dpyinfo->mouse_face_beg_x,
7129 &dpyinfo->mouse_face_beg_y,
7130 object);
7131
7132 dpyinfo->mouse_face_past_end
7133 = !fast_find_position (w, XFASTINT (after),
7134 &dpyinfo->mouse_face_end_col,
7135 &dpyinfo->mouse_face_end_row,
7136 &dpyinfo->mouse_face_end_x,
7137 &dpyinfo->mouse_face_end_y,
7138 Qnil);
7139 dpyinfo->mouse_face_window = window;
7140 dpyinfo->mouse_face_face_id
7141 = face_at_buffer_position (w, pos, 0, 0,
7142 &ignore, pos + 1, 1);
7143
7144 /* Display it as active. */
7145 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
7146 cursor = None;
7147 }
7148 }
0d487c52 7149 }
06a2c219 7150
8bd189fb
GM
7151 check_help_echo:
7152
0d487c52
GM
7153 /* Look for a `help-echo' property. */
7154 {
7155 Lisp_Object help, overlay;
06a2c219 7156
0d487c52
GM
7157 /* Check overlays first. */
7158 help = overlay = Qnil;
7159 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
7160 {
7161 overlay = overlay_vec[i];
7162 help = Foverlay_get (overlay, Qhelp_echo);
7163 }
be010514 7164
0d487c52
GM
7165 if (!NILP (help))
7166 {
7167 help_echo = help;
7168 help_echo_window = window;
7169 help_echo_object = overlay;
7170 help_echo_pos = pos;
7171 }
7172 else
7173 {
7174 Lisp_Object object = glyph->object;
7175 int charpos = glyph->charpos;
7177d86b 7176
0d487c52
GM
7177 /* Try text properties. */
7178 if (STRINGP (object)
7179 && charpos >= 0
7180 && charpos < XSTRING (object)->size)
7181 {
7182 help = Fget_text_property (make_number (charpos),
7183 Qhelp_echo, object);
7184 if (NILP (help))
7185 {
7186 /* If the string itself doesn't specify a help-echo,
7187 see if the buffer text ``under'' it does. */
7188 struct glyph_row *r
7189 = MATRIX_ROW (w->current_matrix, vpos);
7190 int start = MATRIX_ROW_START_CHARPOS (r);
7191 int pos = string_buffer_position (w, object, start);
7192 if (pos > 0)
7193 {
7e376260 7194 help = Fget_char_property (make_number (pos),
0d487c52
GM
7195 Qhelp_echo, w->buffer);
7196 if (!NILP (help))
7197 {
7198 charpos = pos;
7199 object = w->buffer;
7200 }
7201 }
7202 }
7203 }
7204 else if (BUFFERP (object)
7205 && charpos >= BEGV
7206 && charpos < ZV)
7207 help = Fget_text_property (make_number (charpos), Qhelp_echo,
7208 object);
06a2c219 7209
0d487c52
GM
7210 if (!NILP (help))
7211 {
7212 help_echo = help;
7213 help_echo_window = window;
7214 help_echo_object = object;
7215 help_echo_pos = charpos;
7216 }
7217 }
06a2c219 7218 }
0d487c52
GM
7219
7220 BEGV = obegv;
7221 ZV = ozv;
7222 current_buffer = obuf;
06a2c219 7223 }
0d487c52 7224
fa262c07
GM
7225 set_cursor:
7226
0d487c52
GM
7227 if (cursor != None)
7228 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
06a2c219
GM
7229}
7230
7231static void
7232redo_mouse_highlight ()
7233{
7234 if (!NILP (last_mouse_motion_frame)
7235 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
7236 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
7237 last_mouse_motion_event.x,
7238 last_mouse_motion_event.y);
7239}
7240
7241
7242\f
7243/***********************************************************************
9ea173e8 7244 Tool-bars
06a2c219
GM
7245 ***********************************************************************/
7246
9ea173e8
GM
7247static int x_tool_bar_item P_ ((struct frame *, int, int,
7248 struct glyph **, int *, int *, int *));
06a2c219 7249
9ea173e8 7250/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
7251 or -1. */
7252
9ea173e8 7253static int last_tool_bar_item;
06a2c219
GM
7254
7255
9ea173e8
GM
7256/* Get information about the tool-bar item at position X/Y on frame F.
7257 Return in *GLYPH a pointer to the glyph of the tool-bar item in
7258 the current matrix of the tool-bar window of F, or NULL if not
7259 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
8daf1204 7260 item in F->tool_bar_items. Value is
06a2c219 7261
9ea173e8 7262 -1 if X/Y is not on a tool-bar item
06a2c219
GM
7263 0 if X/Y is on the same item that was highlighted before.
7264 1 otherwise. */
7265
7266static int
9ea173e8 7267x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
7268 struct frame *f;
7269 int x, y;
7270 struct glyph **glyph;
7271 int *hpos, *vpos, *prop_idx;
7272{
7273 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7274 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7275 int area;
7276
7277 /* Find the glyph under X/Y. */
f9db2310 7278 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
06a2c219
GM
7279 if (*glyph == NULL)
7280 return -1;
7281
9ea173e8 7282 /* Get the start of this tool-bar item's properties in
8daf1204 7283 f->tool_bar_items. */
9ea173e8 7284 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
7285 return -1;
7286
7287 /* Is mouse on the highlighted item? */
9ea173e8 7288 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
7289 && *vpos >= dpyinfo->mouse_face_beg_row
7290 && *vpos <= dpyinfo->mouse_face_end_row
7291 && (*vpos > dpyinfo->mouse_face_beg_row
7292 || *hpos >= dpyinfo->mouse_face_beg_col)
7293 && (*vpos < dpyinfo->mouse_face_end_row
7294 || *hpos < dpyinfo->mouse_face_end_col
7295 || dpyinfo->mouse_face_past_end))
7296 return 0;
7297
7298 return 1;
7299}
7300
7301
9ea173e8 7302/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
7303 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
7304 or ButtonRelase. */
7305
7306static void
9ea173e8 7307x_handle_tool_bar_click (f, button_event)
06a2c219
GM
7308 struct frame *f;
7309 XButtonEvent *button_event;
7310{
7311 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7312 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7313 int hpos, vpos, prop_idx;
7314 struct glyph *glyph;
7315 Lisp_Object enabled_p;
7316 int x = button_event->x;
7317 int y = button_event->y;
7318
9ea173e8 7319 /* If not on the highlighted tool-bar item, return. */
06a2c219 7320 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 7321 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
7322 return;
7323
7324 /* If item is disabled, do nothing. */
8daf1204 7325 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7326 if (NILP (enabled_p))
7327 return;
7328
7329 if (button_event->type == ButtonPress)
7330 {
7331 /* Show item in pressed state. */
7332 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
7333 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 7334 last_tool_bar_item = prop_idx;
06a2c219
GM
7335 }
7336 else
7337 {
7338 Lisp_Object key, frame;
7339 struct input_event event;
7340
7341 /* Show item in released state. */
7342 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
7343 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
7344
8daf1204 7345 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
06a2c219
GM
7346
7347 XSETFRAME (frame, f);
9ea173e8 7348 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7349 event.frame_or_window = frame;
7350 event.arg = frame;
06a2c219
GM
7351 kbd_buffer_store_event (&event);
7352
9ea173e8 7353 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7354 event.frame_or_window = frame;
7355 event.arg = key;
06a2c219
GM
7356 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7357 button_event->state);
7358 kbd_buffer_store_event (&event);
9ea173e8 7359 last_tool_bar_item = -1;
06a2c219
GM
7360 }
7361}
7362
7363
9ea173e8
GM
7364/* Possibly highlight a tool-bar item on frame F when mouse moves to
7365 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
7366 note_mouse_highlight. */
7367
7368static void
9ea173e8 7369note_tool_bar_highlight (f, x, y)
06a2c219
GM
7370 struct frame *f;
7371 int x, y;
7372{
9ea173e8 7373 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
7374 struct window *w = XWINDOW (window);
7375 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7376 int hpos, vpos;
7377 struct glyph *glyph;
7378 struct glyph_row *row;
5c187dee 7379 int i;
06a2c219
GM
7380 Lisp_Object enabled_p;
7381 int prop_idx;
140330de 7382 enum draw_glyphs_face draw;
5c187dee 7383 int mouse_down_p, rc;
06a2c219
GM
7384
7385 /* Function note_mouse_highlight is called with negative x(y
7386 values when mouse moves outside of the frame. */
7387 if (x <= 0 || y <= 0)
7388 {
7389 clear_mouse_face (dpyinfo);
7390 return;
7391 }
7392
9ea173e8 7393 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
7394 if (rc < 0)
7395 {
9ea173e8 7396 /* Not on tool-bar item. */
06a2c219
GM
7397 clear_mouse_face (dpyinfo);
7398 return;
7399 }
7400 else if (rc == 0)
06a2c219 7401 goto set_help_echo;
b8009dd1 7402
06a2c219
GM
7403 clear_mouse_face (dpyinfo);
7404
9ea173e8 7405 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
7406 mouse_down_p = (dpyinfo->grabbed
7407 && f == last_mouse_frame
7408 && FRAME_LIVE_P (f));
7409 if (mouse_down_p
9ea173e8 7410 && last_tool_bar_item != prop_idx)
06a2c219
GM
7411 return;
7412
7413 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7414 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7415
9ea173e8 7416 /* If tool-bar item is not enabled, don't highlight it. */
8daf1204 7417 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7418 if (!NILP (enabled_p))
7419 {
7420 /* Compute the x-position of the glyph. In front and past the
7421 image is a space. We include this is the highlighted area. */
7422 row = MATRIX_ROW (w->current_matrix, vpos);
7423 for (i = x = 0; i < hpos; ++i)
7424 x += row->glyphs[TEXT_AREA][i].pixel_width;
7425
7426 /* Record this as the current active region. */
7427 dpyinfo->mouse_face_beg_col = hpos;
7428 dpyinfo->mouse_face_beg_row = vpos;
7429 dpyinfo->mouse_face_beg_x = x;
7430 dpyinfo->mouse_face_beg_y = row->y;
7431 dpyinfo->mouse_face_past_end = 0;
7432
7433 dpyinfo->mouse_face_end_col = hpos + 1;
7434 dpyinfo->mouse_face_end_row = vpos;
7435 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7436 dpyinfo->mouse_face_end_y = row->y;
7437 dpyinfo->mouse_face_window = window;
9ea173e8 7438 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
7439
7440 /* Display it as active. */
7441 show_mouse_face (dpyinfo, draw);
7442 dpyinfo->mouse_face_image_state = draw;
b8009dd1 7443 }
06a2c219
GM
7444
7445 set_help_echo:
7446
9ea173e8 7447 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 7448 XTread_socket does the rest. */
7cea38bc 7449 help_echo_object = help_echo_window = Qnil;
be010514 7450 help_echo_pos = -1;
8daf1204 7451 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
b7e80413 7452 if (NILP (help_echo))
8daf1204 7453 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
b8009dd1 7454}
4d73d038 7455
06a2c219
GM
7456
7457\f
9f8531e5
GM
7458/* Find the glyph matrix position of buffer position CHARPOS in window
7459 *W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7460 current glyphs must be up to date. If CHARPOS is above window
7461 start return (0, 0, 0, 0). If CHARPOS is after end of W, return end
7462 of last line in W. In the row containing CHARPOS, stop before glyphs
7e376260 7463 having STOP as object. */
b8009dd1 7464
9f8531e5
GM
7465#if 0 /* This is a version of fast_find_position that's more correct
7466 in the presence of hscrolling, for example. I didn't install
7467 it right away because the problem fixed is minor, it failed
7468 in 20.x as well, and I think it's too risky to install
7469 so near the release of 21.1. 2001-09-25 gerd. */
7470
7471static int
7472fast_find_position (w, charpos, hpos, vpos, x, y, stop)
7473 struct window *w;
7474 int charpos;
7475 int *hpos, *vpos, *x, *y;
7476 Lisp_Object stop;
7477{
7478 struct glyph_row *row, *first;
7479 struct glyph *glyph, *end;
7480 int i, past_end = 0;
7481
7482 first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
62e33982 7483 row = row_containing_pos (w, charpos, first, NULL, 0);
9f8531e5
GM
7484 if (row == NULL)
7485 {
7486 if (charpos < MATRIX_ROW_START_CHARPOS (first))
7487 {
7488 *x = *y = *hpos = *vpos = 0;
7489 return 0;
7490 }
7491 else
7492 {
7493 row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
7494 past_end = 1;
7495 }
7496 }
7497
7498 *x = row->x;
7499 *y = row->y;
7500 *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7501
7502 glyph = row->glyphs[TEXT_AREA];
7503 end = glyph + row->used[TEXT_AREA];
7504
7505 /* Skip over glyphs not having an object at the start of the row.
7506 These are special glyphs like truncation marks on terminal
7507 frames. */
7508 if (row->displays_text_p)
7509 while (glyph < end
7510 && INTEGERP (glyph->object)
7511 && !EQ (stop, glyph->object)
7512 && glyph->charpos < 0)
7513 {
7514 *x += glyph->pixel_width;
7515 ++glyph;
7516 }
7517
7518 while (glyph < end
7519 && !INTEGERP (glyph->object)
7520 && !EQ (stop, glyph->object)
7521 && (!BUFFERP (glyph->object)
7522 || glyph->charpos < charpos))
7523 {
7524 *x += glyph->pixel_width;
7525 ++glyph;
7526 }
7527
7528 *hpos = glyph - row->glyphs[TEXT_AREA];
7529 return past_end;
7530}
7531
7532#else /* not 0 */
7533
b8009dd1 7534static int
7e376260 7535fast_find_position (w, pos, hpos, vpos, x, y, stop)
06a2c219 7536 struct window *w;
b8009dd1 7537 int pos;
06a2c219 7538 int *hpos, *vpos, *x, *y;
7e376260 7539 Lisp_Object stop;
b8009dd1 7540{
b8009dd1 7541 int i;
bf1c0ba1 7542 int lastcol;
06a2c219
GM
7543 int maybe_next_line_p = 0;
7544 int line_start_position;
7545 int yb = window_text_bottom_y (w);
03d1a189
GM
7546 struct glyph_row *row, *best_row;
7547 int row_vpos, best_row_vpos;
06a2c219
GM
7548 int current_x;
7549
03d1a189
GM
7550 row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7551 row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7552
06a2c219 7553 while (row->y < yb)
b8009dd1 7554 {
06a2c219
GM
7555 if (row->used[TEXT_AREA])
7556 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7557 else
7558 line_start_position = 0;
7559
7560 if (line_start_position > pos)
b8009dd1 7561 break;
77b68646
RS
7562 /* If the position sought is the end of the buffer,
7563 don't include the blank lines at the bottom of the window. */
06a2c219
GM
7564 else if (line_start_position == pos
7565 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 7566 {
06a2c219 7567 maybe_next_line_p = 1;
77b68646
RS
7568 break;
7569 }
06a2c219
GM
7570 else if (line_start_position > 0)
7571 {
7572 best_row = row;
7573 best_row_vpos = row_vpos;
7574 }
4b0bb6f3
GM
7575
7576 if (row->y + row->height >= yb)
7577 break;
06a2c219
GM
7578
7579 ++row;
7580 ++row_vpos;
b8009dd1 7581 }
06a2c219
GM
7582
7583 /* Find the right column within BEST_ROW. */
7584 lastcol = 0;
7585 current_x = best_row->x;
7586 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 7587 {
06a2c219 7588 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7e376260 7589 int charpos = glyph->charpos;
06a2c219 7590
7e376260 7591 if (BUFFERP (glyph->object))
bf1c0ba1 7592 {
7e376260
GM
7593 if (charpos == pos)
7594 {
7595 *hpos = i;
7596 *vpos = best_row_vpos;
7597 *x = current_x;
7598 *y = best_row->y;
7599 return 1;
7600 }
7601 else if (charpos > pos)
7602 break;
bf1c0ba1 7603 }
7e376260 7604 else if (EQ (glyph->object, stop))
4d73d038 7605 break;
06a2c219 7606
7e376260
GM
7607 if (charpos > 0)
7608 lastcol = i;
06a2c219 7609 current_x += glyph->pixel_width;
bf1c0ba1 7610 }
b8009dd1 7611
77b68646
RS
7612 /* If we're looking for the end of the buffer,
7613 and we didn't find it in the line we scanned,
7614 use the start of the following line. */
06a2c219 7615 if (maybe_next_line_p)
77b68646 7616 {
06a2c219
GM
7617 ++best_row;
7618 ++best_row_vpos;
7619 lastcol = 0;
7620 current_x = best_row->x;
77b68646
RS
7621 }
7622
06a2c219
GM
7623 *vpos = best_row_vpos;
7624 *hpos = lastcol + 1;
7625 *x = current_x;
7626 *y = best_row->y;
b8009dd1
RS
7627 return 0;
7628}
7629
9f8531e5
GM
7630#endif /* not 0 */
7631
06a2c219 7632
f9db2310
GM
7633/* Find the position of the the glyph for position POS in OBJECT in
7634 window W's current matrix, and return in *X/*Y the pixel
7635 coordinates, and return in *HPOS/*VPOS the column/row of the glyph.
7636
7637 RIGHT_P non-zero means return the position of the right edge of the
7638 glyph, RIGHT_P zero means return the left edge position.
7639
7640 If no glyph for POS exists in the matrix, return the position of
7641 the glyph with the next smaller position that is in the matrix, if
7642 RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS
7643 exists in the matrix, return the position of the glyph with the
7644 next larger position in OBJECT.
7645
7646 Value is non-zero if a glyph was found. */
7647
7648static int
7649fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
7650 struct window *w;
7651 int pos;
7652 Lisp_Object object;
7653 int *hpos, *vpos, *x, *y;
7654 int right_p;
7655{
7656 int yb = window_text_bottom_y (w);
7657 struct glyph_row *r;
7658 struct glyph *best_glyph = NULL;
7659 struct glyph_row *best_row = NULL;
7660 int best_x = 0;
7661
7662 for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7663 r->enabled_p && r->y < yb;
7664 ++r)
7665 {
7666 struct glyph *g = r->glyphs[TEXT_AREA];
7667 struct glyph *e = g + r->used[TEXT_AREA];
7668 int gx;
7669
7670 for (gx = r->x; g < e; gx += g->pixel_width, ++g)
7671 if (EQ (g->object, object))
7672 {
7673 if (g->charpos == pos)
7674 {
7675 best_glyph = g;
7676 best_x = gx;
7677 best_row = r;
7678 goto found;
7679 }
7680 else if (best_glyph == NULL
7681 || ((abs (g->charpos - pos)
7682 < abs (best_glyph->charpos - pos))
7683 && (right_p
7684 ? g->charpos < pos
7685 : g->charpos > pos)))
7686 {
7687 best_glyph = g;
7688 best_x = gx;
7689 best_row = r;
7690 }
7691 }
7692 }
7693
7694 found:
7695
7696 if (best_glyph)
7697 {
7698 *x = best_x;
7699 *hpos = best_glyph - best_row->glyphs[TEXT_AREA];
7700
7701 if (right_p)
7702 {
7703 *x += best_glyph->pixel_width;
7704 ++*hpos;
7705 }
7706
7707 *y = best_row->y;
7708 *vpos = best_row - w->current_matrix->rows;
7709 }
7710
7711 return best_glyph != NULL;
7712}
7713
7714
b8009dd1
RS
7715/* Display the active region described by mouse_face_*
7716 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7717
7718static void
06a2c219 7719show_mouse_face (dpyinfo, draw)
7a13e894 7720 struct x_display_info *dpyinfo;
06a2c219 7721 enum draw_glyphs_face draw;
b8009dd1 7722{
7a13e894 7723 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7724 struct frame *f = XFRAME (WINDOW_FRAME (w));
06a2c219 7725
b2bbd509
GM
7726 if (/* If window is in the process of being destroyed, don't bother
7727 to do anything. */
7728 w->current_matrix != NULL
7729 /* Recognize when we are called to operate on rows that don't exist
7730 anymore. This can happen when a window is split. */
7731 && dpyinfo->mouse_face_end_row < w->current_matrix->nrows)
06a2c219 7732 {
b2bbd509
GM
7733 int phys_cursor_on_p = w->phys_cursor_on_p;
7734 struct glyph_row *row, *first, *last;
06a2c219 7735
b2bbd509
GM
7736 first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row);
7737 last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row);
7738
7739 for (row = first; row <= last && row->enabled_p; ++row)
06a2c219 7740 {
b2bbd509 7741 int start_hpos, end_hpos, start_x;
06a2c219 7742
b2bbd509
GM
7743 /* For all but the first row, the highlight starts at column 0. */
7744 if (row == first)
7745 {
7746 start_hpos = dpyinfo->mouse_face_beg_col;
7747 start_x = dpyinfo->mouse_face_beg_x;
7748 }
7749 else
7750 {
7751 start_hpos = 0;
7752 start_x = 0;
7753 }
06a2c219 7754
b2bbd509
GM
7755 if (row == last)
7756 end_hpos = dpyinfo->mouse_face_end_col;
7757 else
7758 end_hpos = row->used[TEXT_AREA];
b8009dd1 7759
b2bbd509
GM
7760 if (end_hpos > start_hpos)
7761 {
7762 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7763 start_hpos, end_hpos, draw, 0);
b8009dd1 7764
b2bbd509
GM
7765 row->mouse_face_p = draw == DRAW_MOUSE_FACE || DRAW_IMAGE_RAISED;
7766 }
7767 }
2729a2b5 7768
b2bbd509
GM
7769 /* When we've written over the cursor, arrange for it to
7770 be displayed again. */
7771 if (phys_cursor_on_p && !w->phys_cursor_on_p)
7772 x_display_cursor (w, 1,
7773 w->phys_cursor.hpos, w->phys_cursor.vpos,
7774 w->phys_cursor.x, w->phys_cursor.y);
7775 }
fb3b7de5 7776
06a2c219
GM
7777 /* Change the mouse cursor. */
7778 if (draw == DRAW_NORMAL_TEXT)
7779 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7780 f->output_data.x->text_cursor);
7781 else if (draw == DRAW_MOUSE_FACE)
334208b7 7782 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7783 f->output_data.x->cross_cursor);
27ead1d5 7784 else
334208b7 7785 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7786 f->output_data.x->nontext_cursor);
b8009dd1
RS
7787}
7788
7789/* Clear out the mouse-highlighted active region.
fa262c07
GM
7790 Redraw it un-highlighted first. Value is non-zero if mouse
7791 face was actually drawn unhighlighted. */
b8009dd1 7792
fa262c07 7793static int
7a13e894
RS
7794clear_mouse_face (dpyinfo)
7795 struct x_display_info *dpyinfo;
b8009dd1 7796{
fa262c07 7797 int cleared = 0;
06a2c219 7798
fa262c07
GM
7799 if (!NILP (dpyinfo->mouse_face_window))
7800 {
7801 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
7802 cleared = 1;
7803 }
b8009dd1 7804
7a13e894
RS
7805 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7806 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7807 dpyinfo->mouse_face_window = Qnil;
1b85dc1c 7808 dpyinfo->mouse_face_overlay = Qnil;
fa262c07 7809 return cleared;
b8009dd1 7810}
e687d06e 7811
71b8321e
GM
7812
7813/* Clear any mouse-face on window W. This function is part of the
7814 redisplay interface, and is called from try_window_id and similar
7815 functions to ensure the mouse-highlight is off. */
7816
7817static void
7818x_clear_mouse_face (w)
7819 struct window *w;
7820{
7821 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7822 Lisp_Object window;
7823
2e636f9d 7824 BLOCK_INPUT;
71b8321e
GM
7825 XSETWINDOW (window, w);
7826 if (EQ (window, dpyinfo->mouse_face_window))
7827 clear_mouse_face (dpyinfo);
2e636f9d 7828 UNBLOCK_INPUT;
71b8321e
GM
7829}
7830
7831
e687d06e
RS
7832/* Just discard the mouse face information for frame F, if any.
7833 This is used when the size of F is changed. */
7834
dfcf069d 7835void
e687d06e
RS
7836cancel_mouse_face (f)
7837 FRAME_PTR f;
7838{
7839 Lisp_Object window;
7840 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7841
7842 window = dpyinfo->mouse_face_window;
7843 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7844 {
7845 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7846 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7847 dpyinfo->mouse_face_window = Qnil;
7848 }
7849}
b52b65bd 7850
b8009dd1 7851\f
b52b65bd
GM
7852static int glyph_rect P_ ((struct frame *f, int, int, XRectangle *));
7853
7854
7855/* Try to determine frame pixel position and size of the glyph under
7856 frame pixel coordinates X/Y on frame F . Return the position and
7857 size in *RECT. Value is non-zero if we could compute these
7858 values. */
7859
7860static int
7861glyph_rect (f, x, y, rect)
7862 struct frame *f;
7863 int x, y;
7864 XRectangle *rect;
7865{
7866 Lisp_Object window;
7867 int part, found = 0;
7868
7869 window = window_from_coordinates (f, x, y, &part, 0);
7870 if (!NILP (window))
7871 {
7872 struct window *w = XWINDOW (window);
7873 struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7874 struct glyph_row *end = r + w->current_matrix->nrows - 1;
b52b65bd
GM
7875
7876 frame_to_window_pixel_xy (w, &x, &y);
7877
7878 for (; !found && r < end && r->enabled_p; ++r)
7879 if (r->y >= y)
7880 {
7881 struct glyph *g = r->glyphs[TEXT_AREA];
7882 struct glyph *end = g + r->used[TEXT_AREA];
7883 int gx;
7884
7885 for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
7886 if (gx >= x)
7887 {
7888 rect->width = g->pixel_width;
7889 rect->height = r->height;
7890 rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
7891 rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
7892 found = 1;
7893 }
7894 }
7895 }
7896
7897 return found;
7898}
7899
12ba150f 7900
90e65f07 7901/* Return the current position of the mouse.
b52b65bd 7902 *FP should be a frame which indicates which display to ask about.
90e65f07 7903
b52b65bd
GM
7904 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
7905 and *PART to the frame, window, and scroll bar part that the mouse
7906 is over. Set *X and *Y to the portion and whole of the mouse's
ab648270 7907 position on the scroll bar.
12ba150f 7908
b52b65bd
GM
7909 If the mouse movement started elsewhere, set *FP to the frame the
7910 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
12ba150f
JB
7911 the mouse is over.
7912
b52b65bd 7913 Set *TIME to the server time-stamp for the time at which the mouse
12ba150f
JB
7914 was at this position.
7915
a135645a
RS
7916 Don't store anything if we don't have a valid set of values to report.
7917
90e65f07 7918 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7919 movement. */
90e65f07
JB
7920
7921static void
1cf412ec 7922XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7923 FRAME_PTR *fp;
1cf412ec 7924 int insist;
12ba150f 7925 Lisp_Object *bar_window;
ab648270 7926 enum scroll_bar_part *part;
90e65f07 7927 Lisp_Object *x, *y;
e5d77022 7928 unsigned long *time;
90e65f07 7929{
a135645a
RS
7930 FRAME_PTR f1;
7931
90e65f07
JB
7932 BLOCK_INPUT;
7933
8bcee03e 7934 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7935 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7936 else
7937 {
12ba150f
JB
7938 Window root;
7939 int root_x, root_y;
90e65f07 7940
12ba150f
JB
7941 Window dummy_window;
7942 int dummy;
7943
39d8bb4d
KH
7944 Lisp_Object frame, tail;
7945
7946 /* Clear the mouse-moved flag for every frame on this display. */
7947 FOR_EACH_FRAME (tail, frame)
7948 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7949 XFRAME (frame)->mouse_moved = 0;
7950
ab648270 7951 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7952
7953 /* Figure out which root window we're on. */
334208b7
RS
7954 XQueryPointer (FRAME_X_DISPLAY (*fp),
7955 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7956
7957 /* The root window which contains the pointer. */
7958 &root,
7959
7960 /* Trash which we can't trust if the pointer is on
7961 a different screen. */
7962 &dummy_window,
7963
7964 /* The position on that root window. */
58769bee 7965 &root_x, &root_y,
12ba150f
JB
7966
7967 /* More trash we can't trust. */
7968 &dummy, &dummy,
7969
7970 /* Modifier keys and pointer buttons, about which
7971 we don't care. */
7972 (unsigned int *) &dummy);
7973
7974 /* Now we have a position on the root; find the innermost window
7975 containing the pointer. */
7976 {
7977 Window win, child;
7978 int win_x, win_y;
06a2c219 7979 int parent_x = 0, parent_y = 0;
e99db5a1 7980 int count;
12ba150f
JB
7981
7982 win = root;
69388238 7983
2d7fc7e8
RS
7984 /* XTranslateCoordinates can get errors if the window
7985 structure is changing at the same time this function
7986 is running. So at least we must not crash from them. */
7987
e99db5a1 7988 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 7989
334208b7 7990 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 7991 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 7992 {
69388238
RS
7993 /* If mouse was grabbed on a frame, give coords for that frame
7994 even if the mouse is now outside it. */
334208b7 7995 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 7996
12ba150f 7997 /* From-window, to-window. */
69388238 7998 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
7999
8000 /* From-position, to-position. */
8001 root_x, root_y, &win_x, &win_y,
8002
8003 /* Child of win. */
8004 &child);
69388238
RS
8005 f1 = last_mouse_frame;
8006 }
8007 else
8008 {
8009 while (1)
8010 {
334208b7 8011 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 8012
69388238
RS
8013 /* From-window, to-window. */
8014 root, win,
12ba150f 8015
69388238
RS
8016 /* From-position, to-position. */
8017 root_x, root_y, &win_x, &win_y,
8018
8019 /* Child of win. */
8020 &child);
8021
9af3143a 8022 if (child == None || child == win)
69388238
RS
8023 break;
8024
8025 win = child;
8026 parent_x = win_x;
8027 parent_y = win_y;
8028 }
12ba150f 8029
69388238
RS
8030 /* Now we know that:
8031 win is the innermost window containing the pointer
8032 (XTC says it has no child containing the pointer),
8033 win_x and win_y are the pointer's position in it
8034 (XTC did this the last time through), and
8035 parent_x and parent_y are the pointer's position in win's parent.
8036 (They are what win_x and win_y were when win was child.
8037 If win is the root window, it has no parent, and
8038 parent_{x,y} are invalid, but that's okay, because we'll
8039 never use them in that case.) */
8040
8041 /* Is win one of our frames? */
19126e11 8042 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
aad0f6ab
GM
8043
8044#ifdef USE_X_TOOLKIT
8045 /* If we end up with the menu bar window, say it's not
8046 on the frame. */
8047 if (f1 != NULL
8048 && f1->output_data.x->menubar_widget
8049 && win == XtWindow (f1->output_data.x->menubar_widget))
8050 f1 = NULL;
8051#endif /* USE_X_TOOLKIT */
69388238 8052 }
58769bee 8053
2d7fc7e8
RS
8054 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
8055 f1 = 0;
8056
e99db5a1 8057 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 8058
ab648270 8059 /* If not, is it one of our scroll bars? */
a135645a 8060 if (! f1)
12ba150f 8061 {
ab648270 8062 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
8063
8064 if (bar)
8065 {
a135645a 8066 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
8067 win_x = parent_x;
8068 win_y = parent_y;
8069 }
8070 }
90e65f07 8071
8bcee03e 8072 if (f1 == 0 && insist > 0)
b86bd3dd 8073 f1 = SELECTED_FRAME ();
1cf412ec 8074
a135645a 8075 if (f1)
12ba150f 8076 {
06a2c219
GM
8077 /* Ok, we found a frame. Store all the values.
8078 last_mouse_glyph is a rectangle used to reduce the
8079 generation of mouse events. To not miss any motion
8080 events, we must divide the frame into rectangles of the
8081 size of the smallest character that could be displayed
8082 on it, i.e. into the same rectangles that matrices on
8083 the frame are divided into. */
8084
b52b65bd
GM
8085 int width, height, gx, gy;
8086 XRectangle rect;
8087
8088 if (glyph_rect (f1, win_x, win_y, &rect))
8089 last_mouse_glyph = rect;
8090 else
8091 {
8092 width = FRAME_SMALLEST_CHAR_WIDTH (f1);
8093 height = FRAME_SMALLEST_FONT_HEIGHT (f1);
8094 gx = win_x;
8095 gy = win_y;
06a2c219 8096
b52b65bd
GM
8097 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
8098 round down even for negative values. */
8099 if (gx < 0)
8100 gx -= width - 1;
4f00e84d 8101 if (gy < 0)
b52b65bd
GM
8102 gy -= height - 1;
8103 gx = (gx + width - 1) / width * width;
8104 gy = (gy + height - 1) / height * height;
8105
8106 last_mouse_glyph.width = width;
8107 last_mouse_glyph.height = height;
8108 last_mouse_glyph.x = gx;
8109 last_mouse_glyph.y = gy;
8110 }
12ba150f
JB
8111
8112 *bar_window = Qnil;
8113 *part = 0;
334208b7 8114 *fp = f1;
e0c1aef2
KH
8115 XSETINT (*x, win_x);
8116 XSETINT (*y, win_y);
12ba150f
JB
8117 *time = last_mouse_movement_time;
8118 }
8119 }
8120 }
90e65f07
JB
8121
8122 UNBLOCK_INPUT;
8123}
f451eb13 8124
06a2c219 8125
06a2c219 8126#ifdef USE_X_TOOLKIT
bffcfca9
GM
8127
8128/* Atimer callback function for TIMER. Called every 0.1s to process
8129 Xt timeouts, if needed. We must avoid calling XtAppPending as
8130 much as possible because that function does an implicit XFlush
8131 that slows us down. */
8132
8133static void
8134x_process_timeouts (timer)
8135 struct atimer *timer;
8136{
8137 if (toolkit_scroll_bar_interaction || popup_activated_flag)
8138 {
8139 BLOCK_INPUT;
8140 while (XtAppPending (Xt_app_con) & XtIMTimer)
8141 XtAppProcessEvent (Xt_app_con, XtIMTimer);
8142 UNBLOCK_INPUT;
8143 }
06a2c219
GM
8144}
8145
bffcfca9 8146#endif /* USE_X_TOOLKIT */
06a2c219
GM
8147
8148\f
8149/* Scroll bar support. */
8150
8151/* Given an X window ID, find the struct scroll_bar which manages it.
8152 This can be called in GC, so we have to make sure to strip off mark
8153 bits. */
bffcfca9 8154
06a2c219
GM
8155static struct scroll_bar *
8156x_window_to_scroll_bar (window_id)
8157 Window window_id;
8158{
8159 Lisp_Object tail;
8160
8161 for (tail = Vframe_list;
8162 XGCTYPE (tail) == Lisp_Cons;
8e713be6 8163 tail = XCDR (tail))
06a2c219
GM
8164 {
8165 Lisp_Object frame, bar, condemned;
8166
8e713be6 8167 frame = XCAR (tail);
06a2c219
GM
8168 /* All elements of Vframe_list should be frames. */
8169 if (! GC_FRAMEP (frame))
8170 abort ();
8171
8172 /* Scan this frame's scroll bar list for a scroll bar with the
8173 right window ID. */
8174 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
8175 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
8176 /* This trick allows us to search both the ordinary and
8177 condemned scroll bar lists with one loop. */
8178 ! GC_NILP (bar) || (bar = condemned,
8179 condemned = Qnil,
8180 ! GC_NILP (bar));
8181 bar = XSCROLL_BAR (bar)->next)
8182 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
8183 return XSCROLL_BAR (bar);
8184 }
8185
8186 return 0;
8187}
8188
8189
01f67d2c 8190#if defined USE_LUCID
c95fc5f1
GM
8191
8192/* Return the Lucid menu bar WINDOW is part of. Return null
8193 if WINDOW is not part of a menu bar. */
8194
8195static Widget
8196x_window_to_menu_bar (window)
8197 Window window;
8198{
8199 Lisp_Object tail;
8200
8201 for (tail = Vframe_list;
8202 XGCTYPE (tail) == Lisp_Cons;
8203 tail = XCDR (tail))
8204 {
8205 Lisp_Object frame = XCAR (tail);
8206 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
8207
8208 if (menu_bar && xlwmenu_window_p (menu_bar, window))
8209 return menu_bar;
8210 }
8211
8212 return NULL;
8213}
8214
01f67d2c 8215#endif /* USE_LUCID */
c95fc5f1 8216
06a2c219
GM
8217\f
8218/************************************************************************
8219 Toolkit scroll bars
8220 ************************************************************************/
8221
eccc05db 8222#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8223
8224static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
8225static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
8226static void x_create_toolkit_scroll_bar P_ ((struct frame *,
8227 struct scroll_bar *));
8228static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
8229 int, int, int));
8230
8231
8232/* Id of action hook installed for scroll bars. */
8233
8234static XtActionHookId action_hook_id;
8235
8236/* Lisp window being scrolled. Set when starting to interact with
8237 a toolkit scroll bar, reset to nil when ending the interaction. */
8238
8239static Lisp_Object window_being_scrolled;
8240
8241/* Last scroll bar part sent in xm_scroll_callback. */
8242
8243static int last_scroll_bar_part;
8244
ec18280f
SM
8245/* Whether this is an Xaw with arrow-scrollbars. This should imply
8246 that movements of 1/20 of the screen size are mapped to up/down. */
8247
8248static Boolean xaw3d_arrow_scroll;
8249
8250/* Whether the drag scrolling maintains the mouse at the top of the
8251 thumb. If not, resizing the thumb needs to be done more carefully
8252 to avoid jerkyness. */
8253
8254static Boolean xaw3d_pick_top;
8255
06a2c219
GM
8256
8257/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 8258 bars are used.. The hook is responsible for detecting when
06a2c219
GM
8259 the user ends an interaction with the scroll bar, and generates
8260 a `end-scroll' scroll_bar_click' event if so. */
8261
8262static void
8263xt_action_hook (widget, client_data, action_name, event, params,
8264 num_params)
8265 Widget widget;
8266 XtPointer client_data;
8267 String action_name;
8268 XEvent *event;
8269 String *params;
8270 Cardinal *num_params;
8271{
8272 int scroll_bar_p;
8273 char *end_action;
8274
8275#ifdef USE_MOTIF
8276 scroll_bar_p = XmIsScrollBar (widget);
8277 end_action = "Release";
ec18280f 8278#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8279 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
8280 end_action = "EndScroll";
ec18280f 8281#endif /* USE_MOTIF */
06a2c219 8282
06a2c219
GM
8283 if (scroll_bar_p
8284 && strcmp (action_name, end_action) == 0
8285 && WINDOWP (window_being_scrolled))
8286 {
8287 struct window *w;
8288
8289 x_send_scroll_bar_event (window_being_scrolled,
8290 scroll_bar_end_scroll, 0, 0);
8291 w = XWINDOW (window_being_scrolled);
8292 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
8293 window_being_scrolled = Qnil;
8294 last_scroll_bar_part = -1;
bffcfca9
GM
8295
8296 /* Xt timeouts no longer needed. */
8297 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
8298 }
8299}
8300
07b3d16e
GM
8301/* A vector of windows used for communication between
8302 x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
8303
8304static struct window **scroll_bar_windows;
8305static int scroll_bar_windows_size;
8306
06a2c219
GM
8307
8308/* Send a client message with message type Xatom_Scrollbar for a
8309 scroll action to the frame of WINDOW. PART is a value identifying
8310 the part of the scroll bar that was clicked on. PORTION is the
8311 amount to scroll of a whole of WHOLE. */
8312
8313static void
8314x_send_scroll_bar_event (window, part, portion, whole)
8315 Lisp_Object window;
8316 int part, portion, whole;
8317{
8318 XEvent event;
8319 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
07b3d16e
GM
8320 struct window *w = XWINDOW (window);
8321 struct frame *f = XFRAME (w->frame);
8322 int i;
06a2c219 8323
07b3d16e
GM
8324 BLOCK_INPUT;
8325
06a2c219
GM
8326 /* Construct a ClientMessage event to send to the frame. */
8327 ev->type = ClientMessage;
8328 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
8329 ev->display = FRAME_X_DISPLAY (f);
8330 ev->window = FRAME_X_WINDOW (f);
8331 ev->format = 32;
07b3d16e
GM
8332
8333 /* We can only transfer 32 bits in the XClientMessageEvent, which is
8334 not enough to store a pointer or Lisp_Object on a 64 bit system.
8335 So, store the window in scroll_bar_windows and pass the index
8336 into that array in the event. */
8337 for (i = 0; i < scroll_bar_windows_size; ++i)
8338 if (scroll_bar_windows[i] == NULL)
8339 break;
8340
8341 if (i == scroll_bar_windows_size)
8342 {
8343 int new_size = max (10, 2 * scroll_bar_windows_size);
8344 size_t nbytes = new_size * sizeof *scroll_bar_windows;
8345 size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows;
8346
8347 scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
8348 nbytes);
8349 bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
8350 scroll_bar_windows_size = new_size;
8351 }
8352
8353 scroll_bar_windows[i] = w;
8354 ev->data.l[0] = (long) i;
06a2c219
GM
8355 ev->data.l[1] = (long) part;
8356 ev->data.l[2] = (long) 0;
8357 ev->data.l[3] = (long) portion;
8358 ev->data.l[4] = (long) whole;
8359
bffcfca9
GM
8360 /* Make Xt timeouts work while the scroll bar is active. */
8361 toolkit_scroll_bar_interaction = 1;
8362
06a2c219
GM
8363 /* Setting the event mask to zero means that the message will
8364 be sent to the client that created the window, and if that
8365 window no longer exists, no event will be sent. */
06a2c219
GM
8366 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
8367 UNBLOCK_INPUT;
8368}
8369
8370
8371/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
8372 in *IEVENT. */
8373
8374static void
8375x_scroll_bar_to_input_event (event, ievent)
8376 XEvent *event;
8377 struct input_event *ievent;
8378{
8379 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
8380 Lisp_Object window;
8381 struct frame *f;
07b3d16e
GM
8382 struct window *w;
8383
8384 w = scroll_bar_windows[ev->data.l[0]];
8385 scroll_bar_windows[ev->data.l[0]] = NULL;
52e386c2 8386
07b3d16e
GM
8387 XSETWINDOW (window, w);
8388 f = XFRAME (w->frame);
06a2c219
GM
8389
8390 ievent->kind = scroll_bar_click;
8391 ievent->frame_or_window = window;
0f8aabe9 8392 ievent->arg = Qnil;
06a2c219
GM
8393 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
8394 ievent->part = ev->data.l[1];
8395 ievent->code = ev->data.l[2];
8396 ievent->x = make_number ((int) ev->data.l[3]);
8397 ievent->y = make_number ((int) ev->data.l[4]);
8398 ievent->modifiers = 0;
8399}
8400
8401
8402#ifdef USE_MOTIF
8403
8404/* Minimum and maximum values used for Motif scroll bars. */
8405
8406#define XM_SB_MIN 1
8407#define XM_SB_MAX 10000000
8408#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
8409
8410
8411/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
8412 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
8413 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
8414
8415static void
8416xm_scroll_callback (widget, client_data, call_data)
8417 Widget widget;
8418 XtPointer client_data, call_data;
8419{
8420 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8421 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
06a2c219
GM
8422 int part = -1, whole = 0, portion = 0;
8423
8424 switch (cs->reason)
8425 {
8426 case XmCR_DECREMENT:
8427 bar->dragging = Qnil;
8428 part = scroll_bar_up_arrow;
8429 break;
8430
8431 case XmCR_INCREMENT:
8432 bar->dragging = Qnil;
8433 part = scroll_bar_down_arrow;
8434 break;
8435
8436 case XmCR_PAGE_DECREMENT:
8437 bar->dragging = Qnil;
8438 part = scroll_bar_above_handle;
8439 break;
8440
8441 case XmCR_PAGE_INCREMENT:
8442 bar->dragging = Qnil;
8443 part = scroll_bar_below_handle;
8444 break;
8445
8446 case XmCR_TO_TOP:
8447 bar->dragging = Qnil;
8448 part = scroll_bar_to_top;
8449 break;
8450
8451 case XmCR_TO_BOTTOM:
8452 bar->dragging = Qnil;
8453 part = scroll_bar_to_bottom;
8454 break;
8455
8456 case XmCR_DRAG:
8457 {
8458 int slider_size;
8459 int dragging_down_p = (INTEGERP (bar->dragging)
8460 && XINT (bar->dragging) <= cs->value);
8461
8462 /* Get the slider size. */
8463 BLOCK_INPUT;
8464 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
8465 UNBLOCK_INPUT;
8466
8467 /* At the max position of the scroll bar, do a line-wise
23442ae4
GM
8468 movement. Without doing anything, we would be called with
8469 the same cs->value again and again. If we want to make
8470 sure that we can reach the end of the buffer, we have to do
8471 something.
06a2c219
GM
8472
8473 Implementation note: setting bar->dragging always to
8474 cs->value gives a smoother movement at the max position.
8475 Setting it to nil when doing line-wise movement gives
8476 a better slider behavior. */
8477
8478 if (cs->value + slider_size == XM_SB_MAX
8479 || (dragging_down_p
8480 && last_scroll_bar_part == scroll_bar_down_arrow))
8481 {
8482 part = scroll_bar_down_arrow;
8483 bar->dragging = Qnil;
8484 }
8485 else
8486 {
8487 whole = XM_SB_RANGE;
8488 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
8489 part = scroll_bar_handle;
8490 bar->dragging = make_number (cs->value);
8491 }
8492 }
8493 break;
8494
8495 case XmCR_VALUE_CHANGED:
8496 break;
8497 };
8498
8499 if (part >= 0)
8500 {
8501 window_being_scrolled = bar->window;
8502 last_scroll_bar_part = part;
8503 x_send_scroll_bar_event (bar->window, part, portion, whole);
8504 }
8505}
8506
8507
ec18280f 8508#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
8509
8510
ec18280f 8511/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
8512 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
8513 scroll bar struct. CALL_DATA is a pointer to a float saying where
8514 the thumb is. */
8515
8516static void
ec18280f 8517xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
8518 Widget widget;
8519 XtPointer client_data, call_data;
8520{
8521 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8522 float top = *(float *) call_data;
8523 float shown;
ec18280f
SM
8524 int whole, portion, height;
8525 int part;
06a2c219
GM
8526
8527 /* Get the size of the thumb, a value between 0 and 1. */
8528 BLOCK_INPUT;
ec18280f 8529 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
8530 UNBLOCK_INPUT;
8531
8532 whole = 10000000;
8533 portion = shown < 1 ? top * whole : 0;
06a2c219 8534
ec18280f
SM
8535 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
8536 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
8537 the bottom, so we force the scrolling whenever we see that we're
8538 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
8539 we try to ensure that we always stay two pixels away from the
8540 bottom). */
06a2c219
GM
8541 part = scroll_bar_down_arrow;
8542 else
8543 part = scroll_bar_handle;
8544
8545 window_being_scrolled = bar->window;
8546 bar->dragging = make_number (portion);
8547 last_scroll_bar_part = part;
8548 x_send_scroll_bar_event (bar->window, part, portion, whole);
8549}
8550
8551
ec18280f
SM
8552/* Xaw scroll bar callback. Invoked for incremental scrolling.,
8553 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
8554 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
8555 the scroll bar. CALL_DATA is an integer specifying the action that
8556 has taken place. It's magnitude is in the range 0..height of the
8557 scroll bar. Negative values mean scroll towards buffer start.
8558 Values < height of scroll bar mean line-wise movement. */
8559
8560static void
ec18280f 8561xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
8562 Widget widget;
8563 XtPointer client_data, call_data;
8564{
8565 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8566 int position = (int) call_data;
8567 Dimension height;
8568 int part;
8569
8570 /* Get the height of the scroll bar. */
8571 BLOCK_INPUT;
8572 XtVaGetValues (widget, XtNheight, &height, NULL);
8573 UNBLOCK_INPUT;
8574
ec18280f
SM
8575 if (abs (position) >= height)
8576 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
8577
8578 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
8579 it maps line-movement to call_data = max(5, height/20). */
8580 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
8581 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 8582 else
ec18280f 8583 part = scroll_bar_move_ratio;
06a2c219
GM
8584
8585 window_being_scrolled = bar->window;
8586 bar->dragging = Qnil;
8587 last_scroll_bar_part = part;
ec18280f 8588 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
8589}
8590
8591
8592#endif /* not USE_MOTIF */
8593
8594
8595/* Create the widget for scroll bar BAR on frame F. Record the widget
8596 and X window of the scroll bar in BAR. */
8597
8598static void
8599x_create_toolkit_scroll_bar (f, bar)
8600 struct frame *f;
8601 struct scroll_bar *bar;
8602{
8603 Window xwindow;
8604 Widget widget;
8605 Arg av[20];
8606 int ac = 0;
8607 char *scroll_bar_name = "verticalScrollBar";
8608 unsigned long pixel;
8609
8610 BLOCK_INPUT;
8611
8612#ifdef USE_MOTIF
06a2c219
GM
8613 /* Set resources. Create the widget. */
8614 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8615 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
8616 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
8617 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
8618 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
8619 XtSetArg (av[ac], XmNincrement, 1); ++ac;
8620 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
8621
8622 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8623 if (pixel != -1)
8624 {
8625 XtSetArg (av[ac], XmNforeground, pixel);
8626 ++ac;
8627 }
8628
8629 pixel = f->output_data.x->scroll_bar_background_pixel;
8630 if (pixel != -1)
8631 {
8632 XtSetArg (av[ac], XmNbackground, pixel);
8633 ++ac;
8634 }
8635
8636 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
8637 scroll_bar_name, av, ac);
8638
8639 /* Add one callback for everything that can happen. */
8640 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
8641 (XtPointer) bar);
8642 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
8643 (XtPointer) bar);
8644 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
8645 (XtPointer) bar);
8646 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
8647 (XtPointer) bar);
8648 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
8649 (XtPointer) bar);
8650 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
8651 (XtPointer) bar);
8652 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
8653 (XtPointer) bar);
8654
8655 /* Realize the widget. Only after that is the X window created. */
8656 XtRealizeWidget (widget);
8657
8658 /* Set the cursor to an arrow. I didn't find a resource to do that.
8659 And I'm wondering why it hasn't an arrow cursor by default. */
8660 XDefineCursor (XtDisplay (widget), XtWindow (widget),
8661 f->output_data.x->nontext_cursor);
8662
ec18280f 8663#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8664
8665 /* Set resources. Create the widget. The background of the
8666 Xaw3d scroll bar widget is a little bit light for my taste.
8667 We don't alter it here to let users change it according
8668 to their taste with `emacs*verticalScrollBar.background: xxx'. */
8669 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8670 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
8671 /* For smoother scrolling with Xaw3d -sm */
8672 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
06a2c219
GM
8673
8674 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8675 if (pixel != -1)
8676 {
8677 XtSetArg (av[ac], XtNforeground, pixel);
8678 ++ac;
8679 }
8680
8681 pixel = f->output_data.x->scroll_bar_background_pixel;
8682 if (pixel != -1)
8683 {
8684 XtSetArg (av[ac], XtNbackground, pixel);
8685 ++ac;
8686 }
7c1bef7a
MB
8687
8688 /* Top/bottom shadow colors. */
8689
8690 /* Allocate them, if necessary. */
8691 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
8692 {
8693 pixel = f->output_data.x->scroll_bar_background_pixel;
8694 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8695 &pixel, 1.2, 0x8000))
8696 pixel = -1;
8697 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
8698 }
8699 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8700 {
8701 pixel = f->output_data.x->scroll_bar_background_pixel;
8702 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8703 &pixel, 0.6, 0x4000))
8704 pixel = -1;
8705 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
8706 }
8707
8708 /* Tell the toolkit about them. */
8709 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
8710 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8711 /* We tried to allocate a color for the top/bottom shadow, and
8712 failed, so tell Xaw3d to use dithering instead. */
8713 {
8714 XtSetArg (av[ac], XtNbeNiceToColormap, True);
8715 ++ac;
8716 }
8717 else
8718 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
8719 be more consistent with other emacs 3d colors, and since Xaw3d is
8720 not good at dealing with allocation failure. */
8721 {
8722 /* This tells Xaw3d to use real colors instead of dithering for
8723 the shadows. */
8724 XtSetArg (av[ac], XtNbeNiceToColormap, False);
8725 ++ac;
8726
8727 /* Specify the colors. */
8728 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
8729 if (pixel != -1)
8730 {
8731 XtSetArg (av[ac], "topShadowPixel", pixel);
8732 ++ac;
8733 }
8734 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
8735 if (pixel != -1)
8736 {
8737 XtSetArg (av[ac], "bottomShadowPixel", pixel);
8738 ++ac;
8739 }
8740 }
8741
06a2c219
GM
8742 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
8743 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
8744
8745 {
8746 char *initial = "";
8747 char *val = initial;
8748 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
8749 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
8750 if (val == initial)
8751 { /* ARROW_SCROLL */
8752 xaw3d_arrow_scroll = True;
8753 /* Isn't that just a personal preference ? -sm */
8754 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
8755 }
8756 }
06a2c219
GM
8757
8758 /* Define callbacks. */
ec18280f
SM
8759 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
8760 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
8761 (XtPointer) bar);
8762
8763 /* Realize the widget. Only after that is the X window created. */
8764 XtRealizeWidget (widget);
8765
ec18280f 8766#endif /* !USE_MOTIF */
06a2c219
GM
8767
8768 /* Install an action hook that let's us detect when the user
8769 finishes interacting with a scroll bar. */
8770 if (action_hook_id == 0)
8771 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
8772
8773 /* Remember X window and widget in the scroll bar vector. */
8774 SET_SCROLL_BAR_X_WIDGET (bar, widget);
8775 xwindow = XtWindow (widget);
8776 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
8777
8778 UNBLOCK_INPUT;
8779}
8780
8781
8782/* Set the thumb size and position of scroll bar BAR. We are currently
8783 displaying PORTION out of a whole WHOLE, and our position POSITION. */
8784
8785static void
8786x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
8787 struct scroll_bar *bar;
8788 int portion, position, whole;
f451eb13 8789{
e83dc917
GM
8790 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8791 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
06a2c219 8792 float top, shown;
f451eb13 8793
06a2c219
GM
8794 if (whole == 0)
8795 top = 0, shown = 1;
8796 else
f451eb13 8797 {
06a2c219
GM
8798 top = (float) position / whole;
8799 shown = (float) portion / whole;
8800 }
f451eb13 8801
06a2c219 8802 BLOCK_INPUT;
f451eb13 8803
06a2c219
GM
8804#ifdef USE_MOTIF
8805 {
8806 int size, value;
06a2c219 8807
ec18280f 8808 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
8809 is the scroll bar's maximum and MIN is the scroll bar's minimum
8810 value. */
8811 size = shown * XM_SB_RANGE;
8812 size = min (size, XM_SB_RANGE);
8813 size = max (size, 1);
8814
8815 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
8816 value = top * XM_SB_RANGE;
8817 value = min (value, XM_SB_MAX - size);
8818 value = max (value, XM_SB_MIN);
8819
06a2c219
GM
8820 if (NILP (bar->dragging))
8821 XmScrollBarSetValues (widget, value, size, 0, 0, False);
8822 else if (last_scroll_bar_part == scroll_bar_down_arrow)
8823 /* This has the negative side effect that the slider value is
ec18280f 8824 not what it would be if we scrolled here using line-wise or
06a2c219
GM
8825 page-wise movement. */
8826 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
8827 else
8828 {
8829 /* If currently dragging, only update the slider size.
8830 This reduces flicker effects. */
8831 int old_value, old_size, increment, page_increment;
8832
8833 XmScrollBarGetValues (widget, &old_value, &old_size,
8834 &increment, &page_increment);
8835 XmScrollBarSetValues (widget, old_value,
8836 min (size, XM_SB_RANGE - old_value),
8837 0, 0, False);
8838 }
06a2c219 8839 }
ec18280f 8840#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 8841 {
ec18280f
SM
8842 float old_top, old_shown;
8843 Dimension height;
8844 XtVaGetValues (widget,
8845 XtNtopOfThumb, &old_top,
8846 XtNshown, &old_shown,
8847 XtNheight, &height,
8848 NULL);
8849
8850 /* Massage the top+shown values. */
8851 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8852 top = max (0, min (1, top));
8853 else
8854 top = old_top;
8855 /* Keep two pixels available for moving the thumb down. */
8856 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8857
8858 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8859 check that your system's configuration file contains a define
8860 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8861 if (top != old_top || shown != old_shown)
eb393530 8862 {
ec18280f 8863 if (NILP (bar->dragging))
eb393530 8864 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8865 else
8866 {
ec18280f
SM
8867#ifdef HAVE_XAW3D
8868 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8869 int scroll_mode = 0;
ec18280f
SM
8870
8871 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8872 if (xaw3d_arrow_scroll)
8873 {
8874 /* Xaw3d stupidly ignores resize requests while dragging
8875 so we have to make it believe it's not in dragging mode. */
8876 scroll_mode = sb->scrollbar.scroll_mode;
8877 if (scroll_mode == 2)
8878 sb->scrollbar.scroll_mode = 0;
8879 }
8880#endif
8881 /* Try to make the scrolling a tad smoother. */
8882 if (!xaw3d_pick_top)
8883 shown = min (shown, old_shown);
8884
8885 XawScrollbarSetThumb (widget, top, shown);
8886
8887#ifdef HAVE_XAW3D
8888 if (xaw3d_arrow_scroll && scroll_mode == 2)
8889 sb->scrollbar.scroll_mode = scroll_mode;
8890#endif
06a2c219 8891 }
06a2c219
GM
8892 }
8893 }
ec18280f 8894#endif /* !USE_MOTIF */
06a2c219
GM
8895
8896 UNBLOCK_INPUT;
f451eb13
JB
8897}
8898
06a2c219
GM
8899#endif /* USE_TOOLKIT_SCROLL_BARS */
8900
8901
8902\f
8903/************************************************************************
8904 Scroll bars, general
8905 ************************************************************************/
8906
8907/* Create a scroll bar and return the scroll bar vector for it. W is
8908 the Emacs window on which to create the scroll bar. TOP, LEFT,
8909 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8910 scroll bar. */
8911
ab648270 8912static struct scroll_bar *
06a2c219
GM
8913x_scroll_bar_create (w, top, left, width, height)
8914 struct window *w;
f451eb13
JB
8915 int top, left, width, height;
8916{
06a2c219 8917 struct frame *f = XFRAME (w->frame);
334208b7
RS
8918 struct scroll_bar *bar
8919 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8920
8921 BLOCK_INPUT;
8922
eccc05db 8923#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8924 x_create_toolkit_scroll_bar (f, bar);
8925#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8926 {
8927 XSetWindowAttributes a;
8928 unsigned long mask;
5c187dee 8929 Window window;
06a2c219
GM
8930
8931 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8932 if (a.background_pixel == -1)
8933 a.background_pixel = f->output_data.x->background_pixel;
8934
12ba150f 8935 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 8936 | ButtonMotionMask | PointerMotionHintMask
12ba150f 8937 | ExposureMask);
7a13e894 8938 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 8939
dbc4e1c1 8940 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8941
06a2c219
GM
8942 /* Clear the area of W that will serve as a scroll bar. This is
8943 for the case that a window has been split horizontally. In
8944 this case, no clear_frame is generated to reduce flickering. */
c5e6e06b
GM
8945 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8946 left, top, width,
8947 window_box_height (w), False);
06a2c219
GM
8948
8949 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8950 /* Position and size of scroll bar. */
8951 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8952 top,
8953 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8954 height,
8955 /* Border width, depth, class, and visual. */
8956 0,
8957 CopyFromParent,
8958 CopyFromParent,
8959 CopyFromParent,
8960 /* Attributes. */
8961 mask, &a);
8962 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 8963 }
06a2c219 8964#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8965
06a2c219 8966 XSETWINDOW (bar->window, w);
e0c1aef2
KH
8967 XSETINT (bar->top, top);
8968 XSETINT (bar->left, left);
8969 XSETINT (bar->width, width);
8970 XSETINT (bar->height, height);
8971 XSETINT (bar->start, 0);
8972 XSETINT (bar->end, 0);
12ba150f 8973 bar->dragging = Qnil;
f451eb13
JB
8974
8975 /* Add bar to its frame's list of scroll bars. */
334208b7 8976 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8977 bar->prev = Qnil;
334208b7 8978 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 8979 if (!NILP (bar->next))
e0c1aef2 8980 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 8981
06a2c219 8982 /* Map the window/widget. */
eccc05db 8983#ifdef USE_TOOLKIT_SCROLL_BARS
f964b4d7
GM
8984 {
8985 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
8986 XtConfigureWidget (scroll_bar,
8987 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8988 top,
8989 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8990 max (height, 1), 0);
8991 XtMapWidget (scroll_bar);
8992 }
06a2c219 8993#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 8994 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 8995#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8996
8997 UNBLOCK_INPUT;
12ba150f 8998 return bar;
f451eb13
JB
8999}
9000
06a2c219 9001
12ba150f 9002/* Draw BAR's handle in the proper position.
06a2c219 9003
12ba150f
JB
9004 If the handle is already drawn from START to END, don't bother
9005 redrawing it, unless REBUILD is non-zero; in that case, always
9006 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 9007 events.)
12ba150f
JB
9008
9009 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
9010 fit inside its rectangle, but if the user is dragging the scroll
9011 bar handle, we want to let them drag it down all the way, so that
9012 the bar's top is as far down as it goes; otherwise, there's no way
9013 to move to the very end of the buffer. */
9014
5c187dee
GM
9015#ifndef USE_TOOLKIT_SCROLL_BARS
9016
f451eb13 9017static void
ab648270
JB
9018x_scroll_bar_set_handle (bar, start, end, rebuild)
9019 struct scroll_bar *bar;
f451eb13 9020 int start, end;
12ba150f 9021 int rebuild;
f451eb13 9022{
12ba150f 9023 int dragging = ! NILP (bar->dragging);
ab648270 9024 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9025 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9026 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
9027
9028 /* If the display is already accurate, do nothing. */
9029 if (! rebuild
9030 && start == XINT (bar->start)
9031 && end == XINT (bar->end))
9032 return;
9033
f451eb13
JB
9034 BLOCK_INPUT;
9035
9036 {
d9cdbb3d
RS
9037 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
9038 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
9039 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
9040
9041 /* Make sure the values are reasonable, and try to preserve
9042 the distance between start and end. */
12ba150f
JB
9043 {
9044 int length = end - start;
9045
9046 if (start < 0)
9047 start = 0;
9048 else if (start > top_range)
9049 start = top_range;
9050 end = start + length;
9051
9052 if (end < start)
9053 end = start;
9054 else if (end > top_range && ! dragging)
9055 end = top_range;
9056 }
f451eb13 9057
ab648270 9058 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
9059 XSETINT (bar->start, start);
9060 XSETINT (bar->end, end);
f451eb13 9061
12ba150f
JB
9062 /* Clip the end position, just for display. */
9063 if (end > top_range)
9064 end = top_range;
f451eb13 9065
ab648270 9066 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
9067 below top positions, to make sure the handle is always at least
9068 that many pixels tall. */
ab648270 9069 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 9070
12ba150f
JB
9071 /* Draw the empty space above the handle. Note that we can't clear
9072 zero-height areas; that means "clear to end of window." */
9073 if (0 < start)
c5e6e06b
GM
9074 x_clear_area (FRAME_X_DISPLAY (f), w,
9075 /* x, y, width, height, and exposures. */
9076 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9077 VERTICAL_SCROLL_BAR_TOP_BORDER,
9078 inside_width, start,
9079 False);
f451eb13 9080
06a2c219
GM
9081 /* Change to proper foreground color if one is specified. */
9082 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9083 XSetForeground (FRAME_X_DISPLAY (f), gc,
9084 f->output_data.x->scroll_bar_foreground_pixel);
9085
12ba150f 9086 /* Draw the handle itself. */
334208b7 9087 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
12ba150f 9088 /* x, y, width, height */
ab648270
JB
9089 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9090 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 9091 inside_width, end - start);
f451eb13 9092
06a2c219
GM
9093 /* Restore the foreground color of the GC if we changed it above. */
9094 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9095 XSetForeground (FRAME_X_DISPLAY (f), gc,
9096 f->output_data.x->foreground_pixel);
f451eb13 9097
12ba150f
JB
9098 /* Draw the empty space below the handle. Note that we can't
9099 clear zero-height areas; that means "clear to end of window." */
9100 if (end < inside_height)
c5e6e06b
GM
9101 x_clear_area (FRAME_X_DISPLAY (f), w,
9102 /* x, y, width, height, and exposures. */
9103 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9104 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
9105 inside_width, inside_height - end,
9106 False);
f451eb13 9107
f451eb13
JB
9108 }
9109
f451eb13
JB
9110 UNBLOCK_INPUT;
9111}
9112
5c187dee 9113#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 9114
06a2c219
GM
9115/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
9116 nil. */
58769bee 9117
12ba150f 9118static void
ab648270
JB
9119x_scroll_bar_remove (bar)
9120 struct scroll_bar *bar;
12ba150f 9121{
e83dc917 9122 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
9123 BLOCK_INPUT;
9124
eccc05db 9125#ifdef USE_TOOLKIT_SCROLL_BARS
e83dc917
GM
9126 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
9127#else
9128 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
9129#endif
06a2c219 9130
ab648270
JB
9131 /* Disassociate this scroll bar from its window. */
9132 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
9133
9134 UNBLOCK_INPUT;
9135}
9136
06a2c219 9137
12ba150f
JB
9138/* Set the handle of the vertical scroll bar for WINDOW to indicate
9139 that we are displaying PORTION characters out of a total of WHOLE
ab648270 9140 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 9141 create one. */
06a2c219 9142
12ba150f 9143static void
06a2c219
GM
9144XTset_vertical_scroll_bar (w, portion, whole, position)
9145 struct window *w;
f451eb13
JB
9146 int portion, whole, position;
9147{
06a2c219 9148 struct frame *f = XFRAME (w->frame);
ab648270 9149 struct scroll_bar *bar;
3c6ede7b 9150 int top, height, left, sb_left, width, sb_width;
06a2c219 9151 int window_x, window_y, window_width, window_height;
06a2c219 9152
3c6ede7b 9153 /* Get window dimensions. */
06a2c219 9154 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
9155 top = window_y;
9156 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9157 height = window_height;
06a2c219 9158
3c6ede7b 9159 /* Compute the left edge of the scroll bar area. */
06a2c219 9160 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
9161 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
9162 else
9163 left = XFASTINT (w->left);
9164 left *= CANON_X_UNIT (f);
9165 left += FRAME_INTERNAL_BORDER_WIDTH (f);
9166
9167 /* Compute the width of the scroll bar which might be less than
9168 the width of the area reserved for the scroll bar. */
9169 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
9170 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 9171 else
3c6ede7b 9172 sb_width = width;
12ba150f 9173
3c6ede7b
GM
9174 /* Compute the left edge of the scroll bar. */
9175#ifdef USE_TOOLKIT_SCROLL_BARS
9176 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9177 sb_left = left + width - sb_width - (width - sb_width) / 2;
9178 else
9179 sb_left = left + (width - sb_width) / 2;
9180#else
9181 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9182 sb_left = left + width - sb_width;
9183 else
9184 sb_left = left;
9185#endif
9186
ab648270 9187 /* Does the scroll bar exist yet? */
06a2c219 9188 if (NILP (w->vertical_scroll_bar))
3c6ede7b 9189 {
f964b4d7 9190 if (width && height)
b547b6e8
GM
9191 {
9192 BLOCK_INPUT;
9193 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9194 left, top, width, height, False);
9195 UNBLOCK_INPUT;
9196 }
9197
3c6ede7b
GM
9198 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
9199 }
f451eb13 9200 else
12ba150f
JB
9201 {
9202 /* It may just need to be moved and resized. */
06a2c219
GM
9203 unsigned int mask = 0;
9204
9205 bar = XSCROLL_BAR (w->vertical_scroll_bar);
9206
9207 BLOCK_INPUT;
9208
3c6ede7b 9209 if (sb_left != XINT (bar->left))
06a2c219 9210 mask |= CWX;
3c6ede7b 9211 if (top != XINT (bar->top))
06a2c219 9212 mask |= CWY;
3c6ede7b 9213 if (sb_width != XINT (bar->width))
06a2c219 9214 mask |= CWWidth;
3c6ede7b 9215 if (height != XINT (bar->height))
06a2c219
GM
9216 mask |= CWHeight;
9217
9218#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
9219
9220 /* Since toolkit scroll bars are smaller than the space reserved
9221 for them on the frame, we have to clear "under" them. */
f964b4d7
GM
9222 if (width && height)
9223 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9224 left, top, width, height, False);
06a2c219
GM
9225
9226 /* Move/size the scroll bar widget. */
9227 if (mask)
e83dc917 9228 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
3c6ede7b
GM
9229 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9230 top,
9231 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
f964b4d7 9232 max (height, 1), 0);
06a2c219
GM
9233
9234#else /* not USE_TOOLKIT_SCROLL_BARS */
9235
357e7376
GM
9236 /* Clear areas not covered by the scroll bar because of
9237 VERTICAL_SCROLL_BAR_WIDTH_TRIM. */
e1f6572f
RS
9238 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
9239 {
c5e6e06b
GM
9240 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9241 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9242 height, False);
9243 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9244 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9245 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9246 height, False);
e1f6572f 9247 }
357e7376
GM
9248
9249 /* Clear areas not covered by the scroll bar because it's not as
9250 wide as the area reserved for it . This makes sure a
9251 previous mode line display is cleared after C-x 2 C-x 1, for
9252 example. */
9253 {
9254 int area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9255 int rest = area_width - sb_width;
38d2af0c
GM
9256 if (rest > 0 && height > 0)
9257 {
9258 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
9259 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9260 left + area_width - rest, top,
9261 rest, height, False);
9262 else
9263 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9264 left, top, rest, height, False);
9265 }
357e7376 9266 }
06a2c219
GM
9267
9268 /* Move/size the scroll bar window. */
9269 if (mask)
9270 {
9271 XWindowChanges wc;
9272
3c6ede7b
GM
9273 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
9274 wc.y = top;
9275 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
9276 wc.height = height;
06a2c219
GM
9277 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
9278 mask, &wc);
9279 }
9280
9281#endif /* not USE_TOOLKIT_SCROLL_BARS */
9282
9283 /* Remember new settings. */
3c6ede7b
GM
9284 XSETINT (bar->left, sb_left);
9285 XSETINT (bar->top, top);
9286 XSETINT (bar->width, sb_width);
9287 XSETINT (bar->height, height);
06a2c219
GM
9288
9289 UNBLOCK_INPUT;
12ba150f 9290 }
f451eb13 9291
eccc05db 9292#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
9293 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
9294#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 9295 /* Set the scroll bar's current state, unless we're currently being
f451eb13 9296 dragged. */
12ba150f 9297 if (NILP (bar->dragging))
f451eb13 9298 {
92857db0 9299 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 9300
12ba150f 9301 if (whole == 0)
ab648270 9302 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
9303 else
9304 {
43f868f5
JB
9305 int start = ((double) position * top_range) / whole;
9306 int end = ((double) (position + portion) * top_range) / whole;
ab648270 9307 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 9308 }
f451eb13 9309 }
06a2c219 9310#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9311
06a2c219 9312 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
9313}
9314
12ba150f 9315
f451eb13 9316/* The following three hooks are used when we're doing a thorough
ab648270 9317 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 9318 are going to be deleted, because keeping track of when windows go
12ba150f
JB
9319 away is a real pain - "Can you say set-window-configuration, boys
9320 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 9321 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 9322 from the fiery pit when we actually redisplay its window. */
f451eb13 9323
ab648270
JB
9324/* Arrange for all scroll bars on FRAME to be removed at the next call
9325 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
9326 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
9327
58769bee 9328static void
ab648270 9329XTcondemn_scroll_bars (frame)
f451eb13
JB
9330 FRAME_PTR frame;
9331{
f9e24cb9
RS
9332 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
9333 while (! NILP (FRAME_SCROLL_BARS (frame)))
9334 {
9335 Lisp_Object bar;
9336 bar = FRAME_SCROLL_BARS (frame);
9337 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
9338 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
9339 XSCROLL_BAR (bar)->prev = Qnil;
9340 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
9341 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
9342 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
9343 }
f451eb13
JB
9344}
9345
fa2dfc30 9346
06a2c219 9347/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 9348 Note that WINDOW isn't necessarily condemned at all. */
fa2dfc30 9349
f451eb13 9350static void
ab648270 9351XTredeem_scroll_bar (window)
12ba150f 9352 struct window *window;
f451eb13 9353{
ab648270 9354 struct scroll_bar *bar;
fa2dfc30 9355 struct frame *f;
12ba150f 9356
ab648270
JB
9357 /* We can't redeem this window's scroll bar if it doesn't have one. */
9358 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
9359 abort ();
9360
ab648270 9361 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
9362
9363 /* Unlink it from the condemned list. */
fa2dfc30
GM
9364 f = XFRAME (WINDOW_FRAME (window));
9365 if (NILP (bar->prev))
9366 {
9367 /* If the prev pointer is nil, it must be the first in one of
9368 the lists. */
9369 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
9370 /* It's not condemned. Everything's fine. */
9371 return;
9372 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
9373 window->vertical_scroll_bar))
9374 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
9375 else
9376 /* If its prev pointer is nil, it must be at the front of
9377 one or the other! */
9378 abort ();
9379 }
9380 else
9381 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f 9382
fa2dfc30
GM
9383 if (! NILP (bar->next))
9384 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 9385
fa2dfc30
GM
9386 bar->next = FRAME_SCROLL_BARS (f);
9387 bar->prev = Qnil;
9388 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
9389 if (! NILP (bar->next))
9390 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13
JB
9391}
9392
ab648270
JB
9393/* Remove all scroll bars on FRAME that haven't been saved since the
9394 last call to `*condemn_scroll_bars_hook'. */
06a2c219 9395
f451eb13 9396static void
ab648270 9397XTjudge_scroll_bars (f)
12ba150f 9398 FRAME_PTR f;
f451eb13 9399{
12ba150f 9400 Lisp_Object bar, next;
f451eb13 9401
ab648270 9402 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
9403
9404 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
9405 more events on the hapless scroll bars. */
9406 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
9407
9408 for (; ! NILP (bar); bar = next)
f451eb13 9409 {
ab648270 9410 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 9411
ab648270 9412 x_scroll_bar_remove (b);
12ba150f
JB
9413
9414 next = b->next;
9415 b->next = b->prev = Qnil;
f451eb13 9416 }
12ba150f 9417
ab648270 9418 /* Now there should be no references to the condemned scroll bars,
12ba150f 9419 and they should get garbage-collected. */
f451eb13
JB
9420}
9421
9422
06a2c219
GM
9423/* Handle an Expose or GraphicsExpose event on a scroll bar. This
9424 is a no-op when using toolkit scroll bars.
ab648270
JB
9425
9426 This may be called from a signal handler, so we have to ignore GC
9427 mark bits. */
06a2c219 9428
f451eb13 9429static void
ab648270
JB
9430x_scroll_bar_expose (bar, event)
9431 struct scroll_bar *bar;
f451eb13
JB
9432 XEvent *event;
9433{
06a2c219
GM
9434#ifndef USE_TOOLKIT_SCROLL_BARS
9435
ab648270 9436 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9437 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9438 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 9439 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 9440
f451eb13
JB
9441 BLOCK_INPUT;
9442
ab648270 9443 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 9444
06a2c219 9445 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 9446 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
9447
9448 /* x, y, width, height */
d9cdbb3d 9449 0, 0,
3cbd2e0b 9450 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
9451 XINT (bar->height) - 1);
9452
f451eb13 9453 UNBLOCK_INPUT;
06a2c219
GM
9454
9455#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9456}
9457
ab648270
JB
9458/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
9459 is set to something other than no_event, it is enqueued.
9460
9461 This may be called from a signal handler, so we have to ignore GC
9462 mark bits. */
06a2c219 9463
5c187dee
GM
9464#ifndef USE_TOOLKIT_SCROLL_BARS
9465
f451eb13 9466static void
ab648270
JB
9467x_scroll_bar_handle_click (bar, event, emacs_event)
9468 struct scroll_bar *bar;
f451eb13
JB
9469 XEvent *event;
9470 struct input_event *emacs_event;
9471{
0299d313 9472 if (! GC_WINDOWP (bar->window))
12ba150f
JB
9473 abort ();
9474
ab648270 9475 emacs_event->kind = scroll_bar_click;
69388238 9476 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
9477 emacs_event->modifiers
9478 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
9479 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
9480 event->xbutton.state)
9481 | (event->type == ButtonRelease
9482 ? up_modifier
9483 : down_modifier));
12ba150f 9484 emacs_event->frame_or_window = bar->window;
0f8aabe9 9485 emacs_event->arg = Qnil;
f451eb13 9486 emacs_event->timestamp = event->xbutton.time;
12ba150f 9487 {
06a2c219 9488#if 0
d9cdbb3d 9489 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 9490 int internal_height
d9cdbb3d 9491 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9492#endif
0299d313 9493 int top_range
d9cdbb3d 9494 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 9495 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
9496
9497 if (y < 0) y = 0;
9498 if (y > top_range) y = top_range;
9499
9500 if (y < XINT (bar->start))
ab648270
JB
9501 emacs_event->part = scroll_bar_above_handle;
9502 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9503 emacs_event->part = scroll_bar_handle;
12ba150f 9504 else
ab648270 9505 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
9506
9507 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
9508 they want to drag it. Lisp code needs to be able to decide
9509 whether or not we're dragging. */
929787e1 9510#if 0
12ba150f
JB
9511 /* If the user has just clicked on the handle, record where they're
9512 holding it. */
9513 if (event->type == ButtonPress
ab648270 9514 && emacs_event->part == scroll_bar_handle)
e0c1aef2 9515 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 9516#endif
12ba150f
JB
9517
9518 /* If the user has released the handle, set it to its final position. */
9519 if (event->type == ButtonRelease
9520 && ! NILP (bar->dragging))
9521 {
9522 int new_start = y - XINT (bar->dragging);
9523 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 9524
ab648270 9525 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
9526 bar->dragging = Qnil;
9527 }
f451eb13 9528
5116f055
JB
9529 /* Same deal here as the other #if 0. */
9530#if 0
58769bee 9531 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 9532 the handle. */
ab648270 9533 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
9534 emacs_event->x = bar->start;
9535 else
e0c1aef2 9536 XSETINT (emacs_event->x, y);
5116f055 9537#else
e0c1aef2 9538 XSETINT (emacs_event->x, y);
5116f055 9539#endif
f451eb13 9540
e0c1aef2 9541 XSETINT (emacs_event->y, top_range);
12ba150f
JB
9542 }
9543}
f451eb13 9544
ab648270
JB
9545/* Handle some mouse motion while someone is dragging the scroll bar.
9546
9547 This may be called from a signal handler, so we have to ignore GC
9548 mark bits. */
06a2c219 9549
f451eb13 9550static void
ab648270
JB
9551x_scroll_bar_note_movement (bar, event)
9552 struct scroll_bar *bar;
f451eb13
JB
9553 XEvent *event;
9554{
39d8bb4d
KH
9555 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
9556
f451eb13
JB
9557 last_mouse_movement_time = event->xmotion.time;
9558
39d8bb4d 9559 f->mouse_moved = 1;
e0c1aef2 9560 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
9561
9562 /* If we're dragging the bar, display it. */
ab648270 9563 if (! GC_NILP (bar->dragging))
f451eb13
JB
9564 {
9565 /* Where should the handle be now? */
12ba150f 9566 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 9567
12ba150f 9568 if (new_start != XINT (bar->start))
f451eb13 9569 {
12ba150f 9570 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 9571
ab648270 9572 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
9573 }
9574 }
f451eb13
JB
9575}
9576
5c187dee
GM
9577#endif /* !USE_TOOLKIT_SCROLL_BARS */
9578
12ba150f 9579/* Return information to the user about the current position of the mouse
ab648270 9580 on the scroll bar. */
06a2c219 9581
12ba150f 9582static void
334208b7
RS
9583x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
9584 FRAME_PTR *fp;
12ba150f 9585 Lisp_Object *bar_window;
ab648270 9586 enum scroll_bar_part *part;
12ba150f
JB
9587 Lisp_Object *x, *y;
9588 unsigned long *time;
9589{
ab648270 9590 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
9591 Window w = SCROLL_BAR_X_WINDOW (bar);
9592 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 9593 int win_x, win_y;
559cb2fb
JB
9594 Window dummy_window;
9595 int dummy_coord;
9596 unsigned int dummy_mask;
12ba150f 9597
cf7cb199
JB
9598 BLOCK_INPUT;
9599
ab648270 9600 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 9601 report that. */
334208b7 9602 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 9603
559cb2fb
JB
9604 /* Root, child, root x and root y. */
9605 &dummy_window, &dummy_window,
9606 &dummy_coord, &dummy_coord,
12ba150f 9607
559cb2fb
JB
9608 /* Position relative to scroll bar. */
9609 &win_x, &win_y,
12ba150f 9610
559cb2fb
JB
9611 /* Mouse buttons and modifier keys. */
9612 &dummy_mask))
7a13e894 9613 ;
559cb2fb
JB
9614 else
9615 {
06a2c219 9616#if 0
559cb2fb 9617 int inside_height
d9cdbb3d 9618 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9619#endif
559cb2fb 9620 int top_range
d9cdbb3d 9621 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
9622
9623 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
9624
9625 if (! NILP (bar->dragging))
9626 win_y -= XINT (bar->dragging);
9627
9628 if (win_y < 0)
9629 win_y = 0;
9630 if (win_y > top_range)
9631 win_y = top_range;
9632
334208b7 9633 *fp = f;
7a13e894 9634 *bar_window = bar->window;
559cb2fb
JB
9635
9636 if (! NILP (bar->dragging))
9637 *part = scroll_bar_handle;
9638 else if (win_y < XINT (bar->start))
9639 *part = scroll_bar_above_handle;
9640 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9641 *part = scroll_bar_handle;
9642 else
9643 *part = scroll_bar_below_handle;
12ba150f 9644
e0c1aef2
KH
9645 XSETINT (*x, win_y);
9646 XSETINT (*y, top_range);
12ba150f 9647
39d8bb4d 9648 f->mouse_moved = 0;
559cb2fb
JB
9649 last_mouse_scroll_bar = Qnil;
9650 }
12ba150f 9651
559cb2fb 9652 *time = last_mouse_movement_time;
cf7cb199 9653
cf7cb199 9654 UNBLOCK_INPUT;
12ba150f
JB
9655}
9656
f451eb13 9657
dbc4e1c1 9658/* The screen has been cleared so we may have changed foreground or
ab648270
JB
9659 background colors, and the scroll bars may need to be redrawn.
9660 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
9661 redraw them. */
9662
dfcf069d 9663void
ab648270 9664x_scroll_bar_clear (f)
dbc4e1c1
JB
9665 FRAME_PTR f;
9666{
06a2c219 9667#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
9668 Lisp_Object bar;
9669
b80c363e
RS
9670 /* We can have scroll bars even if this is 0,
9671 if we just turned off scroll bar mode.
9672 But in that case we should not clear them. */
9673 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
9674 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
9675 bar = XSCROLL_BAR (bar)->next)
c5e6e06b
GM
9676 XClearArea (FRAME_X_DISPLAY (f),
9677 SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
b80c363e 9678 0, 0, 0, 0, True);
06a2c219 9679#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
9680}
9681
06a2c219 9682/* This processes Expose events from the menu-bar specific X event
19126e11 9683 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 9684 when handling menu-bar or pop-up items. */
3afe33e7 9685
06a2c219 9686int
3afe33e7
RS
9687process_expose_from_menu (event)
9688 XEvent event;
9689{
9690 FRAME_PTR f;
19126e11 9691 struct x_display_info *dpyinfo;
06a2c219 9692 int frame_exposed_p = 0;
3afe33e7 9693
f94397b5
KH
9694 BLOCK_INPUT;
9695
19126e11
KH
9696 dpyinfo = x_display_info_for_display (event.xexpose.display);
9697 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
9698 if (f)
9699 {
9700 if (f->async_visible == 0)
9701 {
9702 f->async_visible = 1;
9703 f->async_iconified = 0;
06c488fd 9704 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
9705 SET_FRAME_GARBAGED (f);
9706 }
9707 else
9708 {
06a2c219
GM
9709 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
9710 event.xexpose.x, event.xexpose.y,
9711 event.xexpose.width, event.xexpose.height);
9712 frame_exposed_p = 1;
3afe33e7
RS
9713 }
9714 }
9715 else
9716 {
9717 struct scroll_bar *bar
9718 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9719
3afe33e7
RS
9720 if (bar)
9721 x_scroll_bar_expose (bar, &event);
9722 }
f94397b5
KH
9723
9724 UNBLOCK_INPUT;
06a2c219 9725 return frame_exposed_p;
3afe33e7 9726}
09756a85
RS
9727\f
9728/* Define a queue to save up SelectionRequest events for later handling. */
9729
9730struct selection_event_queue
9731 {
9732 XEvent event;
9733 struct selection_event_queue *next;
9734 };
9735
9736static struct selection_event_queue *queue;
9737
9738/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 9739
09756a85
RS
9740static int x_queue_selection_requests;
9741
9742/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 9743
09756a85 9744static void
334208b7
RS
9745x_queue_event (f, event)
9746 FRAME_PTR f;
09756a85
RS
9747 XEvent *event;
9748{
9749 struct selection_event_queue *queue_tmp
06a2c219 9750 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 9751
58769bee 9752 if (queue_tmp != NULL)
09756a85
RS
9753 {
9754 queue_tmp->event = *event;
9755 queue_tmp->next = queue;
9756 queue = queue_tmp;
9757 }
9758}
9759
9760/* Take all the queued events and put them back
9761 so that they get processed afresh. */
9762
9763static void
db3906fd
RS
9764x_unqueue_events (display)
9765 Display *display;
09756a85 9766{
58769bee 9767 while (queue != NULL)
09756a85
RS
9768 {
9769 struct selection_event_queue *queue_tmp = queue;
db3906fd 9770 XPutBackEvent (display, &queue_tmp->event);
09756a85 9771 queue = queue_tmp->next;
06a2c219 9772 xfree ((char *)queue_tmp);
09756a85
RS
9773 }
9774}
9775
9776/* Start queuing SelectionRequest events. */
9777
9778void
db3906fd
RS
9779x_start_queuing_selection_requests (display)
9780 Display *display;
09756a85
RS
9781{
9782 x_queue_selection_requests++;
9783}
9784
9785/* Stop queuing SelectionRequest events. */
9786
9787void
db3906fd
RS
9788x_stop_queuing_selection_requests (display)
9789 Display *display;
09756a85
RS
9790{
9791 x_queue_selection_requests--;
db3906fd 9792 x_unqueue_events (display);
09756a85 9793}
f451eb13
JB
9794\f
9795/* The main X event-reading loop - XTread_socket. */
dc6f92b8 9796
06a2c219 9797/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
9798 but we have to put it out here, since static variables within functions
9799 sometimes don't work. */
06a2c219 9800
dc6f92b8
JB
9801static Time enter_timestamp;
9802
11edeb03 9803/* This holds the state XLookupString needs to implement dead keys
58769bee 9804 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
9805 says that a portable program can't use this, but Stephen Gildea assures
9806 me that letting the compiler initialize it to zeros will work okay.
9807
9808 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
9809 given for enter_time stamp, above. */
9810
11edeb03
JB
9811static XComposeStatus compose_status;
9812
10e6549c
RS
9813/* Record the last 100 characters stored
9814 to help debug the loss-of-chars-during-GC problem. */
06a2c219 9815
2224b905
RS
9816static int temp_index;
9817static short temp_buffer[100];
10e6549c 9818
7a13e894
RS
9819/* Set this to nonzero to fake an "X I/O error"
9820 on a particular display. */
06a2c219 9821
7a13e894
RS
9822struct x_display_info *XTread_socket_fake_io_error;
9823
2224b905
RS
9824/* When we find no input here, we occasionally do a no-op command
9825 to verify that the X server is still running and we can still talk with it.
9826 We try all the open displays, one by one.
9827 This variable is used for cycling thru the displays. */
06a2c219 9828
2224b905
RS
9829static struct x_display_info *next_noop_dpyinfo;
9830
06a2c219
GM
9831#define SET_SAVED_MENU_EVENT(size) \
9832 do \
9833 { \
9834 if (f->output_data.x->saved_menu_event == 0) \
9835 f->output_data.x->saved_menu_event \
9836 = (XEvent *) xmalloc (sizeof (XEvent)); \
9837 bcopy (&event, f->output_data.x->saved_menu_event, size); \
9838 if (numchars >= 1) \
9839 { \
9840 bufp->kind = menu_bar_activate_event; \
9841 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 9842 bufp->arg = Qnil; \
06a2c219
GM
9843 bufp++; \
9844 count++; \
9845 numchars--; \
9846 } \
9847 } \
9848 while (0)
9849
8805890a 9850#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 9851#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 9852
dc6f92b8
JB
9853/* Read events coming from the X server.
9854 This routine is called by the SIGIO handler.
9855 We return as soon as there are no more events to be read.
9856
9857 Events representing keys are stored in buffer BUFP,
9858 which can hold up to NUMCHARS characters.
9859 We return the number of characters stored into the buffer,
9860 thus pretending to be `read'.
9861
dc6f92b8
JB
9862 EXPECTED is nonzero if the caller knows input is available. */
9863
7c5283e4 9864int
f66868ba 9865XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 9866 register int sd;
8805890a
KH
9867 /* register */ struct input_event *bufp;
9868 /* register */ int numchars;
dc6f92b8
JB
9869 int expected;
9870{
9871 int count = 0;
9872 int nbytes = 0;
dc6f92b8 9873 XEvent event;
f676886a 9874 struct frame *f;
66f55a9d 9875 int event_found = 0;
334208b7 9876 struct x_display_info *dpyinfo;
379b5ac0 9877 struct coding_system coding;
dc6f92b8 9878
9ac0d9e0 9879 if (interrupt_input_blocked)
dc6f92b8 9880 {
9ac0d9e0 9881 interrupt_input_pending = 1;
dc6f92b8
JB
9882 return -1;
9883 }
9884
9ac0d9e0 9885 interrupt_input_pending = 0;
dc6f92b8 9886 BLOCK_INPUT;
c0a04927
RS
9887
9888 /* So people can tell when we have read the available input. */
9889 input_signal_count++;
9890
dc6f92b8 9891 if (numchars <= 0)
06a2c219 9892 abort (); /* Don't think this happens. */
dc6f92b8 9893
bde5503b
GM
9894 ++handling_signal;
9895
379b5ac0
KH
9896 /* The input should be decoded if it is from XIM. Currently the
9897 locale of XIM is the same as that of the system. So, we can use
9898 Vlocale_coding_system which is initialized properly at Emacs
9899 startup time. */
9900 setup_coding_system (Vlocale_coding_system, &coding);
9901 coding.src_multibyte = 0;
9902 coding.dst_multibyte = 1;
9903 /* The input is converted to events, thus we can't handle
9904 composition. Anyway, there's no XIM that gives us composition
9905 information. */
9906 coding.composing = COMPOSITION_DISABLED;
9907
7a13e894
RS
9908 /* Find the display we are supposed to read input for.
9909 It's the one communicating on descriptor SD. */
9910 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9911 {
9912#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9913#ifdef FIOSNBIO
7a13e894
RS
9914 /* If available, Xlib uses FIOSNBIO to make the socket
9915 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9916 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9917 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9918 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9919#endif /* ! defined (FIOSNBIO) */
7a13e894 9920#endif
dc6f92b8 9921
7a13e894
RS
9922#if 0 /* This code can't be made to work, with multiple displays,
9923 and appears not to be used on any system any more.
9924 Also keyboard.c doesn't turn O_NDELAY on and off
9925 for X connections. */
dc6f92b8
JB
9926#ifndef SIGIO
9927#ifndef HAVE_SELECT
7a13e894
RS
9928 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9929 {
9930 extern int read_alarm_should_throw;
9931 read_alarm_should_throw = 1;
9932 XPeekEvent (dpyinfo->display, &event);
9933 read_alarm_should_throw = 0;
9934 }
c118dd06
JB
9935#endif /* HAVE_SELECT */
9936#endif /* SIGIO */
7a13e894 9937#endif
dc6f92b8 9938
7a13e894
RS
9939 /* For debugging, this gives a way to fake an I/O error. */
9940 if (dpyinfo == XTread_socket_fake_io_error)
9941 {
9942 XTread_socket_fake_io_error = 0;
9943 x_io_error_quitter (dpyinfo->display);
9944 }
dc6f92b8 9945
06a2c219 9946 while (XPending (dpyinfo->display))
dc6f92b8 9947 {
7a13e894 9948 XNextEvent (dpyinfo->display, &event);
06a2c219 9949
531483fb 9950#ifdef HAVE_X_I18N
d1bc4182 9951 {
f2be1146
GM
9952 /* Filter events for the current X input method.
9953 XFilterEvent returns non-zero if the input method has
9954 consumed the event. We pass the frame's X window to
9955 XFilterEvent because that's the one for which the IC
9956 was created. */
f5d11644
GM
9957 struct frame *f1 = x_any_window_to_frame (dpyinfo,
9958 event.xclient.window);
9959 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
9960 break;
9961 }
0cd6403b 9962#endif
7a13e894
RS
9963 event_found = 1;
9964
9965 switch (event.type)
9966 {
9967 case ClientMessage:
c047688c 9968 {
7a13e894
RS
9969 if (event.xclient.message_type
9970 == dpyinfo->Xatom_wm_protocols
9971 && event.xclient.format == 32)
c047688c 9972 {
7a13e894
RS
9973 if (event.xclient.data.l[0]
9974 == dpyinfo->Xatom_wm_take_focus)
c047688c 9975 {
8c1a6a84
RS
9976 /* Use x_any_window_to_frame because this
9977 could be the shell widget window
9978 if the frame has no title bar. */
9979 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
9980#ifdef HAVE_X_I18N
9981 /* Not quite sure this is needed -pd */
8c1a6a84 9982 if (f && FRAME_XIC (f))
6c183ba5
RS
9983 XSetICFocus (FRAME_XIC (f));
9984#endif
f1da8f06
GM
9985#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
9986 instructs the WM to set the input focus automatically for
9987 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
9988 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
9989 it has set the focus. So, XSetInputFocus below is not
9990 needed.
9991
9992 The call to XSetInputFocus below has also caused trouble. In
9993 cases where the XSetInputFocus done by the WM and the one
9994 below are temporally close (on a fast machine), the call
9995 below can generate additional FocusIn events which confuse
9996 Emacs. */
9997
bf7253f4
RS
9998 /* Since we set WM_TAKE_FOCUS, we must call
9999 XSetInputFocus explicitly. But not if f is null,
10000 since that might be an event for a deleted frame. */
7a13e894 10001 if (f)
bf7253f4
RS
10002 {
10003 Display *d = event.xclient.display;
10004 /* Catch and ignore errors, in case window has been
10005 iconified by a window manager such as GWM. */
10006 int count = x_catch_errors (d);
10007 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
10008 /* The ICCCM says this is
10009 the only valid choice. */
10010 RevertToParent,
bf7253f4
RS
10011 event.xclient.data.l[1]);
10012 /* This is needed to detect the error
10013 if there is an error. */
10014 XSync (d, False);
10015 x_uncatch_errors (d, count);
10016 }
7a13e894 10017 /* Not certain about handling scroll bars here */
f1da8f06 10018#endif /* 0 */
c047688c 10019 }
7a13e894
RS
10020 else if (event.xclient.data.l[0]
10021 == dpyinfo->Xatom_wm_save_yourself)
10022 {
10023 /* Save state modify the WM_COMMAND property to
06a2c219 10024 something which can reinstate us. This notifies
7a13e894
RS
10025 the session manager, who's looking for such a
10026 PropertyNotify. Can restart processing when
06a2c219 10027 a keyboard or mouse event arrives. */
7a13e894
RS
10028 if (numchars > 0)
10029 {
19126e11
KH
10030 f = x_top_window_to_frame (dpyinfo,
10031 event.xclient.window);
7a13e894
RS
10032
10033 /* This is just so we only give real data once
10034 for a single Emacs process. */
b86bd3dd 10035 if (f == SELECTED_FRAME ())
7a13e894
RS
10036 XSetCommand (FRAME_X_DISPLAY (f),
10037 event.xclient.window,
10038 initial_argv, initial_argc);
f000f5c5 10039 else if (f)
7a13e894
RS
10040 XSetCommand (FRAME_X_DISPLAY (f),
10041 event.xclient.window,
10042 0, 0);
10043 }
10044 }
10045 else if (event.xclient.data.l[0]
10046 == dpyinfo->Xatom_wm_delete_window)
1fb20991 10047 {
19126e11
KH
10048 struct frame *f
10049 = x_any_window_to_frame (dpyinfo,
10050 event.xclient.window);
1fb20991 10051
7a13e894
RS
10052 if (f)
10053 {
10054 if (numchars == 0)
10055 abort ();
1fb20991 10056
7a13e894
RS
10057 bufp->kind = delete_window_event;
10058 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10059 bufp->arg = Qnil;
7a13e894
RS
10060 bufp++;
10061
10062 count += 1;
10063 numchars -= 1;
10064 }
1fb20991 10065 }
c047688c 10066 }
7a13e894
RS
10067 else if (event.xclient.message_type
10068 == dpyinfo->Xatom_wm_configure_denied)
10069 {
10070 }
10071 else if (event.xclient.message_type
10072 == dpyinfo->Xatom_wm_window_moved)
10073 {
10074 int new_x, new_y;
19126e11
KH
10075 struct frame *f
10076 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 10077
7a13e894
RS
10078 new_x = event.xclient.data.s[0];
10079 new_y = event.xclient.data.s[1];
1fb20991 10080
7a13e894
RS
10081 if (f)
10082 {
7556890b
RS
10083 f->output_data.x->left_pos = new_x;
10084 f->output_data.x->top_pos = new_y;
7a13e894 10085 }
1fb20991 10086 }
0fdff6bb 10087#ifdef HACK_EDITRES
7a13e894
RS
10088 else if (event.xclient.message_type
10089 == dpyinfo->Xatom_editres)
10090 {
19126e11
KH
10091 struct frame *f
10092 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 10093 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 10094 &event, NULL);
7a13e894 10095 }
0fdff6bb 10096#endif /* HACK_EDITRES */
06a2c219
GM
10097 else if ((event.xclient.message_type
10098 == dpyinfo->Xatom_DONE)
10099 || (event.xclient.message_type
10100 == dpyinfo->Xatom_PAGE))
10101 {
10102 /* Ghostview job completed. Kill it. We could
10103 reply with "Next" if we received "Page", but we
10104 currently never do because we are interested in
10105 images, only, which should have 1 page. */
06a2c219
GM
10106 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
10107 struct frame *f
10108 = x_window_to_frame (dpyinfo, event.xclient.window);
10109 x_kill_gs_process (pixmap, f);
10110 expose_frame (f, 0, 0, 0, 0);
10111 }
10112#ifdef USE_TOOLKIT_SCROLL_BARS
10113 /* Scroll bar callbacks send a ClientMessage from which
10114 we construct an input_event. */
10115 else if (event.xclient.message_type
10116 == dpyinfo->Xatom_Scrollbar)
10117 {
10118 x_scroll_bar_to_input_event (&event, bufp);
10119 ++bufp, ++count, --numchars;
10120 goto out;
10121 }
10122#endif /* USE_TOOLKIT_SCROLL_BARS */
10123 else
10124 goto OTHER;
7a13e894
RS
10125 }
10126 break;
dc6f92b8 10127
7a13e894 10128 case SelectionNotify:
3afe33e7 10129#ifdef USE_X_TOOLKIT
19126e11 10130 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 10131 goto OTHER;
3afe33e7 10132#endif /* not USE_X_TOOLKIT */
dfcf069d 10133 x_handle_selection_notify (&event.xselection);
7a13e894 10134 break;
d56a553a 10135
06a2c219 10136 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 10137#ifdef USE_X_TOOLKIT
19126e11 10138 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 10139 goto OTHER;
3afe33e7 10140#endif /* USE_X_TOOLKIT */
7a13e894
RS
10141 {
10142 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 10143
7a13e894
RS
10144 if (numchars == 0)
10145 abort ();
d56a553a 10146
7a13e894
RS
10147 bufp->kind = selection_clear_event;
10148 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10149 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10150 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10151 bufp->frame_or_window = Qnil;
0f8aabe9 10152 bufp->arg = Qnil;
7a13e894 10153 bufp++;
d56a553a 10154
7a13e894
RS
10155 count += 1;
10156 numchars -= 1;
10157 }
10158 break;
dc6f92b8 10159
06a2c219 10160 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 10161#ifdef USE_X_TOOLKIT
19126e11 10162 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 10163 goto OTHER;
3afe33e7 10164#endif /* USE_X_TOOLKIT */
7a13e894 10165 if (x_queue_selection_requests)
19126e11 10166 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
10167 &event);
10168 else
10169 {
1d2b2268
GM
10170 XSelectionRequestEvent *eventp
10171 = (XSelectionRequestEvent *) &event;
dc6f92b8 10172
7a13e894
RS
10173 if (numchars == 0)
10174 abort ();
10175
10176 bufp->kind = selection_request_event;
10177 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10178 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
10179 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10180 SELECTION_EVENT_TARGET (bufp) = eventp->target;
10181 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
10182 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10183 bufp->frame_or_window = Qnil;
0f8aabe9 10184 bufp->arg = Qnil;
7a13e894
RS
10185 bufp++;
10186
10187 count += 1;
10188 numchars -= 1;
10189 }
10190 break;
10191
10192 case PropertyNotify:
1d2b2268
GM
10193#if 0 /* This is plain wrong. In the case that we are waiting for a
10194 PropertyNotify used as an ACK in incremental selection
10195 transfer, the property will be on the receiver's window. */
10196#if defined USE_X_TOOLKIT
19126e11 10197 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 10198 goto OTHER;
1d2b2268
GM
10199#endif
10200#endif
dfcf069d 10201 x_handle_property_notify (&event.xproperty);
1d2b2268 10202 goto OTHER;
dc6f92b8 10203
7a13e894 10204 case ReparentNotify:
19126e11 10205 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
10206 if (f)
10207 {
10208 int x, y;
7556890b 10209 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 10210 x_real_positions (f, &x, &y);
7556890b
RS
10211 f->output_data.x->left_pos = x;
10212 f->output_data.x->top_pos = y;
7a13e894
RS
10213 }
10214 break;
3bd330d4 10215
7a13e894 10216 case Expose:
19126e11 10217 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 10218 if (f)
dc6f92b8 10219 {
7a13e894
RS
10220 if (f->async_visible == 0)
10221 {
10222 f->async_visible = 1;
10223 f->async_iconified = 0;
06c488fd 10224 f->output_data.x->has_been_visible = 1;
7a13e894
RS
10225 SET_FRAME_GARBAGED (f);
10226 }
10227 else
06a2c219
GM
10228 expose_frame (x_window_to_frame (dpyinfo,
10229 event.xexpose.window),
10230 event.xexpose.x, event.xexpose.y,
10231 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
10232 }
10233 else
7a13e894 10234 {
12949a7f
EZ
10235#ifndef USE_TOOLKIT_SCROLL_BARS
10236 struct scroll_bar *bar;
10237#endif
01f67d2c 10238#if defined USE_LUCID
c95fc5f1
GM
10239 /* Submenus of the Lucid menu bar aren't widgets
10240 themselves, so there's no way to dispatch events
10241 to them. Recognize this case separately. */
10242 {
10243 Widget widget
10244 = x_window_to_menu_bar (event.xexpose.window);
10245 if (widget)
10246 xlwmenu_redisplay (widget);
10247 }
01f67d2c
PJ
10248#endif /* USE_LUCID */
10249
06a2c219
GM
10250#ifdef USE_TOOLKIT_SCROLL_BARS
10251 /* Dispatch event to the widget. */
10252 goto OTHER;
10253#else /* not USE_TOOLKIT_SCROLL_BARS */
12949a7f 10254 bar = x_window_to_scroll_bar (event.xexpose.window);
58769bee 10255
7a13e894
RS
10256 if (bar)
10257 x_scroll_bar_expose (bar, &event);
3afe33e7 10258#ifdef USE_X_TOOLKIT
7a13e894
RS
10259 else
10260 goto OTHER;
3afe33e7 10261#endif /* USE_X_TOOLKIT */
06a2c219 10262#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10263 }
10264 break;
dc6f92b8 10265
7a13e894 10266 case GraphicsExpose: /* This occurs when an XCopyArea's
d624284c
PJ
10267 source area was obscured or not
10268 available. */
19126e11 10269 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
10270 if (f)
10271 {
06a2c219
GM
10272 expose_frame (f,
10273 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
10274 event.xgraphicsexpose.width,
10275 event.xgraphicsexpose.height);
7a13e894 10276 }
3afe33e7 10277#ifdef USE_X_TOOLKIT
7a13e894
RS
10278 else
10279 goto OTHER;
3afe33e7 10280#endif /* USE_X_TOOLKIT */
7a13e894 10281 break;
dc6f92b8 10282
7a13e894 10283 case NoExpose: /* This occurs when an XCopyArea's
06a2c219 10284 source area was completely
d624284c 10285 available. */
7a13e894 10286 break;
dc6f92b8 10287
7a13e894 10288 case UnmapNotify:
06a2c219
GM
10289 /* Redo the mouse-highlight after the tooltip has gone. */
10290 if (event.xmap.window == tip_window)
10291 {
10292 tip_window = 0;
10293 redo_mouse_highlight ();
10294 }
10295
91ea2a7a 10296 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894 10297 if (f) /* F may no longer exist if
d624284c 10298 the frame was deleted. */
7a13e894
RS
10299 {
10300 /* While a frame is unmapped, display generation is
10301 disabled; you don't want to spend time updating a
10302 display that won't ever be seen. */
10303 f->async_visible = 0;
10304 /* We can't distinguish, from the event, whether the window
10305 has become iconified or invisible. So assume, if it
10306 was previously visible, than now it is iconified.
1aa6072f
RS
10307 But x_make_frame_invisible clears both
10308 the visible flag and the iconified flag;
10309 and that way, we know the window is not iconified now. */
7a13e894 10310 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
10311 {
10312 f->async_iconified = 1;
bddd097c 10313
1aa6072f
RS
10314 bufp->kind = iconify_event;
10315 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10316 bufp->arg = Qnil;
1aa6072f
RS
10317 bufp++;
10318 count++;
10319 numchars--;
10320 }
7a13e894 10321 }
7a13e894 10322 goto OTHER;
dc6f92b8 10323
7a13e894 10324 case MapNotify:
06a2c219
GM
10325 if (event.xmap.window == tip_window)
10326 /* The tooltip has been drawn already. Avoid
10327 the SET_FRAME_GARBAGED below. */
10328 goto OTHER;
10329
10330 /* We use x_top_window_to_frame because map events can
10331 come for sub-windows and they don't mean that the
10332 frame is visible. */
19126e11 10333 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
10334 if (f)
10335 {
10336 f->async_visible = 1;
10337 f->async_iconified = 0;
06c488fd 10338 f->output_data.x->has_been_visible = 1;
dc6f92b8 10339
7a13e894
RS
10340 /* wait_reading_process_input will notice this and update
10341 the frame's display structures. */
10342 SET_FRAME_GARBAGED (f);
bddd097c 10343
d806e720
RS
10344 if (f->iconified)
10345 {
10346 bufp->kind = deiconify_event;
10347 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10348 bufp->arg = Qnil;
d806e720
RS
10349 bufp++;
10350 count++;
10351 numchars--;
10352 }
e73ec6fa 10353 else if (! NILP (Vframe_list)
8e713be6 10354 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
10355 /* Force a redisplay sooner or later
10356 to update the frame titles
10357 in case this is the second frame. */
10358 record_asynch_buffer_change ();
7a13e894 10359 }
7a13e894 10360 goto OTHER;
dc6f92b8 10361
7a13e894 10362 case KeyPress:
19126e11 10363 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 10364
eccc05db 10365#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
10366 if (f == 0)
10367 {
2564ea1b
GM
10368 /* Scroll bars consume key events, but we want
10369 the keys to go to the scroll bar's frame. */
06a2c219
GM
10370 Widget widget = XtWindowToWidget (dpyinfo->display,
10371 event.xkey.window);
10372 if (widget && XmIsScrollBar (widget))
10373 {
10374 widget = XtParent (widget);
10375 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
10376 }
10377 }
eccc05db 10378#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
06a2c219 10379
7a13e894
RS
10380 if (f != 0)
10381 {
10382 KeySym keysym, orig_keysym;
379b5ac0
KH
10383 /* al%imercury@uunet.uu.net says that making this 81
10384 instead of 80 fixed a bug whereby meta chars made
10385 his Emacs hang.
10386
10387 It seems that some version of XmbLookupString has
10388 a bug of not returning XBufferOverflow in
10389 status_return even if the input is too long to
10390 fit in 81 bytes. So, we must prepare sufficient
10391 bytes for copy_buffer. 513 bytes (256 chars for
10392 two-byte character set) seems to be a faily good
10393 approximation. -- 2000.8.10 handa@etl.go.jp */
10394 unsigned char copy_buffer[513];
10395 unsigned char *copy_bufptr = copy_buffer;
10396 int copy_bufsiz = sizeof (copy_buffer);
7a13e894 10397 int modifiers;
64bb1782 10398
7a13e894
RS
10399 event.xkey.state
10400 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
10401 extra_keyboard_modifiers);
10402 modifiers = event.xkey.state;
3a2712f9 10403
7a13e894 10404 /* This will have to go some day... */
752a043f 10405
7a13e894
RS
10406 /* make_lispy_event turns chars into control chars.
10407 Don't do it here because XLookupString is too eager. */
10408 event.xkey.state &= ~ControlMask;
5d46f928
RS
10409 event.xkey.state &= ~(dpyinfo->meta_mod_mask
10410 | dpyinfo->super_mod_mask
10411 | dpyinfo->hyper_mod_mask
10412 | dpyinfo->alt_mod_mask);
10413
1cf4a0d1
RS
10414 /* In case Meta is ComposeCharacter,
10415 clear its status. According to Markus Ehrnsperger
10416 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
10417 this enables ComposeCharacter to work whether or
10418 not it is combined with Meta. */
10419 if (modifiers & dpyinfo->meta_mod_mask)
10420 bzero (&compose_status, sizeof (compose_status));
10421
6c183ba5
RS
10422#ifdef HAVE_X_I18N
10423 if (FRAME_XIC (f))
10424 {
f5d11644
GM
10425 Status status_return;
10426
6c183ba5 10427 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
10428 &event.xkey, copy_bufptr,
10429 copy_bufsiz, &keysym,
6c183ba5 10430 &status_return);
f5d11644
GM
10431 if (status_return == XBufferOverflow)
10432 {
10433 copy_bufsiz = nbytes + 1;
10434 copy_bufptr = (char *) alloca (copy_bufsiz);
10435 nbytes = XmbLookupString (FRAME_XIC (f),
10436 &event.xkey, copy_bufptr,
10437 copy_bufsiz, &keysym,
10438 &status_return);
10439 }
10440
1decb680
PE
10441 if (status_return == XLookupNone)
10442 break;
10443 else if (status_return == XLookupChars)
fdd9d55e
GM
10444 {
10445 keysym = NoSymbol;
10446 modifiers = 0;
10447 }
1decb680
PE
10448 else if (status_return != XLookupKeySym
10449 && status_return != XLookupBoth)
10450 abort ();
6c183ba5
RS
10451 }
10452 else
379b5ac0
KH
10453 nbytes = XLookupString (&event.xkey, copy_bufptr,
10454 copy_bufsiz, &keysym,
10455 &compose_status);
6c183ba5 10456#else
379b5ac0
KH
10457 nbytes = XLookupString (&event.xkey, copy_bufptr,
10458 copy_bufsiz, &keysym,
10459 &compose_status);
6c183ba5 10460#endif
dc6f92b8 10461
7a13e894 10462 orig_keysym = keysym;
55123275 10463
7a13e894
RS
10464 if (numchars > 1)
10465 {
10466 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
10467 || keysym == XK_Delete
1097aea0 10468#ifdef XK_ISO_Left_Tab
441affdb 10469 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 10470#endif
852bff8f 10471 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
10472 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
10473 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 10474#ifdef HPUX
7a13e894
RS
10475 /* This recognizes the "extended function keys".
10476 It seems there's no cleaner way.
10477 Test IsModifierKey to avoid handling mode_switch
10478 incorrectly. */
10479 || ((unsigned) (keysym) >= XK_Select
10480 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
10481#endif
10482#ifdef XK_dead_circumflex
7a13e894 10483 || orig_keysym == XK_dead_circumflex
69388238
RS
10484#endif
10485#ifdef XK_dead_grave
7a13e894 10486 || orig_keysym == XK_dead_grave
69388238
RS
10487#endif
10488#ifdef XK_dead_tilde
7a13e894 10489 || orig_keysym == XK_dead_tilde
69388238
RS
10490#endif
10491#ifdef XK_dead_diaeresis
7a13e894 10492 || orig_keysym == XK_dead_diaeresis
69388238
RS
10493#endif
10494#ifdef XK_dead_macron
7a13e894 10495 || orig_keysym == XK_dead_macron
69388238
RS
10496#endif
10497#ifdef XK_dead_degree
7a13e894 10498 || orig_keysym == XK_dead_degree
69388238
RS
10499#endif
10500#ifdef XK_dead_acute
7a13e894 10501 || orig_keysym == XK_dead_acute
69388238
RS
10502#endif
10503#ifdef XK_dead_cedilla
7a13e894 10504 || orig_keysym == XK_dead_cedilla
69388238
RS
10505#endif
10506#ifdef XK_dead_breve
7a13e894 10507 || orig_keysym == XK_dead_breve
69388238
RS
10508#endif
10509#ifdef XK_dead_ogonek
7a13e894 10510 || orig_keysym == XK_dead_ogonek
69388238
RS
10511#endif
10512#ifdef XK_dead_caron
7a13e894 10513 || orig_keysym == XK_dead_caron
69388238
RS
10514#endif
10515#ifdef XK_dead_doubleacute
7a13e894 10516 || orig_keysym == XK_dead_doubleacute
69388238
RS
10517#endif
10518#ifdef XK_dead_abovedot
7a13e894 10519 || orig_keysym == XK_dead_abovedot
c34790e0 10520#endif
7a13e894
RS
10521 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
10522 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
10523 /* Any "vendor-specific" key is ok. */
f0e299de
GM
10524 || (orig_keysym & (1 << 28))
10525 || (keysym != NoSymbol && nbytes == 0))
7a13e894 10526 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
10527#ifndef HAVE_X11R5
10528#ifdef XK_Mode_switch
7a13e894 10529 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
10530#endif
10531#ifdef XK_Num_Lock
7a13e894 10532 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
10533#endif
10534#endif /* not HAVE_X11R5 */
7a13e894 10535 ))
dc6f92b8 10536 {
10e6549c
RS
10537 if (temp_index == sizeof temp_buffer / sizeof (short))
10538 temp_index = 0;
7a13e894
RS
10539 temp_buffer[temp_index++] = keysym;
10540 bufp->kind = non_ascii_keystroke;
10541 bufp->code = keysym;
e0c1aef2 10542 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10543 bufp->arg = Qnil;
334208b7
RS
10544 bufp->modifiers
10545 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10546 modifiers);
1113d9db 10547 bufp->timestamp = event.xkey.time;
dc6f92b8 10548 bufp++;
7a13e894
RS
10549 count++;
10550 numchars--;
dc6f92b8 10551 }
7a13e894
RS
10552 else if (numchars > nbytes)
10553 {
10554 register int i;
379b5ac0 10555 register int c;
379b5ac0 10556 int nchars, len;
7a13e894
RS
10557
10558 for (i = 0; i < nbytes; i++)
10559 {
379b5ac0
KH
10560 if (temp_index == (sizeof temp_buffer
10561 / sizeof (short)))
7a13e894 10562 temp_index = 0;
379b5ac0
KH
10563 temp_buffer[temp_index++] = copy_bufptr[i];
10564 }
10565
10566 if (/* If the event is not from XIM, */
10567 event.xkey.keycode != 0
10568 /* or the current locale doesn't request
10569 decoding of the intup data, ... */
10570 || coding.type == coding_type_raw_text
10571 || coding.type == coding_type_no_conversion)
10572 {
10573 /* ... we can use the input data as is. */
10574 nchars = nbytes;
10575 }
10576 else
10577 {
10578 /* We have to decode the input data. */
10579 int require;
10580 unsigned char *p;
10581
10582 require = decoding_buffer_size (&coding, nbytes);
10583 p = (unsigned char *) alloca (require);
10584 coding.mode |= CODING_MODE_LAST_BLOCK;
10585 decode_coding (&coding, copy_bufptr, p,
10586 nbytes, require);
10587 nbytes = coding.produced;
10588 nchars = coding.produced_char;
10589 copy_bufptr = p;
10590 }
10591
10592 /* Convert the input data to a sequence of
10593 character events. */
10594 for (i = 0; i < nbytes; i += len)
10595 {
10596 c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
10597 nbytes - i, len);
10598 bufp->kind = (SINGLE_BYTE_CHAR_P (c)
10599 ? ascii_keystroke
10600 : multibyte_char_keystroke);
10601 bufp->code = c;
7a13e894 10602 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10603 bufp->arg = Qnil;
7a13e894
RS
10604 bufp->modifiers
10605 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10606 modifiers);
10607 bufp->timestamp = event.xkey.time;
10608 bufp++;
10609 }
10610
379b5ac0
KH
10611 count += nchars;
10612 numchars -= nchars;
1decb680
PE
10613
10614 if (keysym == NoSymbol)
10615 break;
7a13e894
RS
10616 }
10617 else
10618 abort ();
dc6f92b8 10619 }
10e6549c
RS
10620 else
10621 abort ();
dc6f92b8 10622 }
59ddecde
GM
10623#ifdef HAVE_X_I18N
10624 /* Don't dispatch this event since XtDispatchEvent calls
10625 XFilterEvent, and two calls in a row may freeze the
10626 client. */
10627 break;
10628#else
717ca130 10629 goto OTHER;
59ddecde 10630#endif
f451eb13 10631
f5d11644 10632 case KeyRelease:
59ddecde
GM
10633#ifdef HAVE_X_I18N
10634 /* Don't dispatch this event since XtDispatchEvent calls
10635 XFilterEvent, and two calls in a row may freeze the
10636 client. */
10637 break;
10638#else
f5d11644 10639 goto OTHER;
59ddecde 10640#endif
f5d11644 10641
7a13e894 10642 /* Here's a possible interpretation of the whole
06a2c219
GM
10643 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
10644 you get a FocusIn event, you have to get a FocusOut
10645 event before you relinquish the focus. If you
10646 haven't received a FocusIn event, then a mere
10647 LeaveNotify is enough to free you. */
f451eb13 10648
7a13e894 10649 case EnterNotify:
06a2c219 10650 {
06a2c219
GM
10651 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
10652
582c60f8 10653 if (event.xcrossing.focus)
06a2c219
GM
10654 {
10655 /* Avoid nasty pop/raise loops. */
10656 if (f && (!(f->auto_raise)
10657 || !(f->auto_lower)
10658 || (event.xcrossing.time - enter_timestamp) > 500))
10659 {
10660 x_new_focus_frame (dpyinfo, f);
10661 enter_timestamp = event.xcrossing.time;
10662 }
10663 }
10664 else if (f == dpyinfo->x_focus_frame)
10665 x_new_focus_frame (dpyinfo, 0);
10666
10667 /* EnterNotify counts as mouse movement,
10668 so update things that depend on mouse position. */
2533c408 10669 if (f && !f->output_data.x->hourglass_p)
06a2c219
GM
10670 note_mouse_movement (f, &event.xmotion);
10671 goto OTHER;
10672 }
dc6f92b8 10673
7a13e894 10674 case FocusIn:
19126e11 10675 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10676 if (event.xfocus.detail != NotifyPointer)
0f941935 10677 dpyinfo->x_focus_event_frame = f;
7a13e894 10678 if (f)
eb72635f
GM
10679 {
10680 x_new_focus_frame (dpyinfo, f);
10681
10682 /* Don't stop displaying the initial startup message
10683 for a switch-frame event we don't need. */
10684 if (GC_NILP (Vterminal_frame)
10685 && GC_CONSP (Vframe_list)
10686 && !GC_NILP (XCDR (Vframe_list)))
10687 {
10688 bufp->kind = FOCUS_IN_EVENT;
10689 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10690 bufp->arg = Qnil;
eb72635f
GM
10691 ++bufp, ++count, --numchars;
10692 }
10693 }
f9e24cb9 10694
6c183ba5
RS
10695#ifdef HAVE_X_I18N
10696 if (f && FRAME_XIC (f))
10697 XSetICFocus (FRAME_XIC (f));
10698#endif
10699
7a13e894 10700 goto OTHER;
10c5e63d 10701
7a13e894 10702 case LeaveNotify:
19126e11 10703 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 10704 if (f)
10c5e63d 10705 {
7a13e894 10706 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
10707 {
10708 /* If we move outside the frame, then we're
10709 certainly no longer on any text in the frame. */
10710 clear_mouse_face (dpyinfo);
10711 dpyinfo->mouse_face_mouse_frame = 0;
10712 }
10713
10714 /* Generate a nil HELP_EVENT to cancel a help-echo.
10715 Do it only if there's something to cancel.
10716 Otherwise, the startup message is cleared when
10717 the mouse leaves the frame. */
10718 if (any_help_event_p)
10719 {
be010514
GM
10720 Lisp_Object frame;
10721 int n;
10722
06a2c219 10723 XSETFRAME (frame, f);
82c5d67a 10724 help_echo = Qnil;
5ab2570d
GM
10725 n = gen_help_event (bufp, numchars,
10726 Qnil, frame, Qnil, Qnil, 0);
be010514 10727 bufp += n, count += n, numchars -= n;
06a2c219 10728 }
7a13e894 10729
582c60f8 10730 if (event.xcrossing.focus)
0f941935 10731 x_mouse_leave (dpyinfo);
10c5e63d 10732 else
7a13e894 10733 {
0f941935
KH
10734 if (f == dpyinfo->x_focus_event_frame)
10735 dpyinfo->x_focus_event_frame = 0;
10736 if (f == dpyinfo->x_focus_frame)
10737 x_new_focus_frame (dpyinfo, 0);
7a13e894 10738 }
10c5e63d 10739 }
7a13e894 10740 goto OTHER;
dc6f92b8 10741
7a13e894 10742 case FocusOut:
19126e11 10743 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10744 if (event.xfocus.detail != NotifyPointer
0f941935
KH
10745 && f == dpyinfo->x_focus_event_frame)
10746 dpyinfo->x_focus_event_frame = 0;
10747 if (f && f == dpyinfo->x_focus_frame)
10748 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 10749
6c183ba5
RS
10750#ifdef HAVE_X_I18N
10751 if (f && FRAME_XIC (f))
10752 XUnsetICFocus (FRAME_XIC (f));
10753#endif
10754
7a13e894 10755 goto OTHER;
dc6f92b8 10756
7a13e894 10757 case MotionNotify:
dc6f92b8 10758 {
06a2c219 10759 previous_help_echo = help_echo;
7cea38bc 10760 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 10761 help_echo_pos = -1;
06a2c219 10762
7a13e894
RS
10763 if (dpyinfo->grabbed && last_mouse_frame
10764 && FRAME_LIVE_P (last_mouse_frame))
10765 f = last_mouse_frame;
10766 else
19126e11 10767 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 10768
7a13e894
RS
10769 if (f)
10770 note_mouse_movement (f, &event.xmotion);
10771 else
10772 {
e88b3c50 10773#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10774 struct scroll_bar *bar
10775 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 10776
7a13e894
RS
10777 if (bar)
10778 x_scroll_bar_note_movement (bar, &event);
e88b3c50 10779#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 10780
06a2c219
GM
10781 /* If we move outside the frame, then we're
10782 certainly no longer on any text in the frame. */
7a13e894
RS
10783 clear_mouse_face (dpyinfo);
10784 }
06a2c219
GM
10785
10786 /* If the contents of the global variable help_echo
10787 has changed, generate a HELP_EVENT. */
b7e80413
SM
10788 if (!NILP (help_echo)
10789 || !NILP (previous_help_echo))
06a2c219
GM
10790 {
10791 Lisp_Object frame;
be010514 10792 int n;
06a2c219
GM
10793
10794 if (f)
10795 XSETFRAME (frame, f);
10796 else
10797 frame = Qnil;
10798
10799 any_help_event_p = 1;
5ab2570d 10800 n = gen_help_event (bufp, numchars, help_echo, frame,
7cea38bc
GM
10801 help_echo_window, help_echo_object,
10802 help_echo_pos);
be010514 10803 bufp += n, count += n, numchars -= n;
06a2c219
GM
10804 }
10805
10806 goto OTHER;
dc6f92b8 10807 }
dc6f92b8 10808
7a13e894 10809 case ConfigureNotify:
9829ddba
RS
10810 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
10811 if (f)
af395ec1 10812 {
5c187dee 10813#ifndef USE_X_TOOLKIT
bf1b7b30
KH
10814 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
10815 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 10816
2d7fc7e8
RS
10817 /* In the toolkit version, change_frame_size
10818 is called by the code that handles resizing
10819 of the EmacsFrame widget. */
7a13e894 10820
7a13e894
RS
10821 /* Even if the number of character rows and columns has
10822 not changed, the font size may have changed, so we need
10823 to check the pixel dimensions as well. */
10824 if (columns != f->width
10825 || rows != f->height
7556890b
RS
10826 || event.xconfigure.width != f->output_data.x->pixel_width
10827 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 10828 {
7d1e984f 10829 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 10830 SET_FRAME_GARBAGED (f);
e687d06e 10831 cancel_mouse_face (f);
7a13e894 10832 }
2d7fc7e8 10833#endif
af395ec1 10834
7556890b
RS
10835 f->output_data.x->pixel_width = event.xconfigure.width;
10836 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
10837
10838 /* What we have now is the position of Emacs's own window.
10839 Convert that to the position of the window manager window. */
dcb07ae9
RS
10840 x_real_positions (f, &f->output_data.x->left_pos,
10841 &f->output_data.x->top_pos);
10842
f5d11644
GM
10843#ifdef HAVE_X_I18N
10844 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
10845 xic_set_statusarea (f);
10846#endif
10847
dcb07ae9
RS
10848 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
10849 {
10850 /* Since the WM decorations come below top_pos now,
10851 we must put them below top_pos in the future. */
10852 f->output_data.x->win_gravity = NorthWestGravity;
10853 x_wm_set_size_hint (f, (long) 0, 0);
10854 }
8f08dc93
KH
10855#ifdef USE_MOTIF
10856 /* Some window managers pass (0,0) as the location of
10857 the window, and the Motif event handler stores it
10858 in the emacs widget, which messes up Motif menus. */
10859 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
10860 {
10861 event.xconfigure.x = f->output_data.x->widget->core.x;
10862 event.xconfigure.y = f->output_data.x->widget->core.y;
10863 }
06a2c219 10864#endif /* USE_MOTIF */
7a13e894 10865 }
2d7fc7e8 10866 goto OTHER;
dc6f92b8 10867
7a13e894
RS
10868 case ButtonPress:
10869 case ButtonRelease:
10870 {
10871 /* If we decide we want to generate an event to be seen
10872 by the rest of Emacs, we put it here. */
10873 struct input_event emacs_event;
9ea173e8 10874 int tool_bar_p = 0;
06a2c219 10875
7a13e894 10876 emacs_event.kind = no_event;
7a13e894 10877 bzero (&compose_status, sizeof (compose_status));
9b07615b 10878
06a2c219
GM
10879 if (dpyinfo->grabbed
10880 && last_mouse_frame
9f67f20b
RS
10881 && FRAME_LIVE_P (last_mouse_frame))
10882 f = last_mouse_frame;
10883 else
2224b905 10884 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 10885
06a2c219
GM
10886 if (f)
10887 {
9ea173e8
GM
10888 /* Is this in the tool-bar? */
10889 if (WINDOWP (f->tool_bar_window)
10890 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
10891 {
10892 Lisp_Object window;
10893 int p, x, y;
10894
10895 x = event.xbutton.x;
10896 y = event.xbutton.y;
10897
10898 /* Set x and y. */
10899 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 10900 if (EQ (window, f->tool_bar_window))
06a2c219 10901 {
9ea173e8
GM
10902 x_handle_tool_bar_click (f, &event.xbutton);
10903 tool_bar_p = 1;
06a2c219
GM
10904 }
10905 }
10906
9ea173e8 10907 if (!tool_bar_p)
06a2c219
GM
10908 if (!dpyinfo->x_focus_frame
10909 || f == dpyinfo->x_focus_frame)
10910 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
10911 }
10912 else
10913 {
06a2c219 10914#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10915 struct scroll_bar *bar
10916 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 10917
7a13e894
RS
10918 if (bar)
10919 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 10920#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10921 }
10922
10923 if (event.type == ButtonPress)
10924 {
10925 dpyinfo->grabbed |= (1 << event.xbutton.button);
10926 last_mouse_frame = f;
edad46f6
KH
10927 /* Ignore any mouse motion that happened
10928 before this event; any subsequent mouse-movement
10929 Emacs events should reflect only motion after
10930 the ButtonPress. */
a00e91cd
KH
10931 if (f != 0)
10932 f->mouse_moved = 0;
06a2c219 10933
9ea173e8
GM
10934 if (!tool_bar_p)
10935 last_tool_bar_item = -1;
7a13e894 10936 }
3afe33e7
RS
10937 else
10938 {
7a13e894 10939 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10940 }
23faf38f 10941
7a13e894
RS
10942 if (numchars >= 1 && emacs_event.kind != no_event)
10943 {
10944 bcopy (&emacs_event, bufp, sizeof (struct input_event));
10945 bufp++;
10946 count++;
10947 numchars--;
10948 }
3afe33e7
RS
10949
10950#ifdef USE_X_TOOLKIT
2224b905
RS
10951 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
10952 /* For a down-event in the menu bar,
10953 don't pass it to Xt right now.
10954 Instead, save it away
10955 and we will pass it to Xt from kbd_buffer_get_event.
10956 That way, we can run some Lisp code first. */
91375f8f
RS
10957 if (f && event.type == ButtonPress
10958 /* Verify the event is really within the menu bar
10959 and not just sent to it due to grabbing. */
10960 && event.xbutton.x >= 0
10961 && event.xbutton.x < f->output_data.x->pixel_width
10962 && event.xbutton.y >= 0
10963 && event.xbutton.y < f->output_data.x->menubar_height
10964 && event.xbutton.same_screen)
2224b905 10965 {
8805890a 10966 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
10967 XSETFRAME (last_mouse_press_frame, f);
10968 }
10969 else if (event.type == ButtonPress)
10970 {
10971 last_mouse_press_frame = Qnil;
30e671c3 10972 goto OTHER;
ce89ef46 10973 }
06a2c219 10974
2237cac9
RS
10975#ifdef USE_MOTIF /* This should do not harm for Lucid,
10976 but I am trying to be cautious. */
ce89ef46
RS
10977 else if (event.type == ButtonRelease)
10978 {
2237cac9 10979 if (!NILP (last_mouse_press_frame))
f10ded1c 10980 {
2237cac9
RS
10981 f = XFRAME (last_mouse_press_frame);
10982 if (f->output_data.x)
06a2c219 10983 SET_SAVED_BUTTON_EVENT;
f10ded1c 10984 }
06a2c219 10985 else
30e671c3 10986 goto OTHER;
2224b905 10987 }
2237cac9 10988#endif /* USE_MOTIF */
2224b905
RS
10989 else
10990 goto OTHER;
3afe33e7 10991#endif /* USE_X_TOOLKIT */
7a13e894
RS
10992 }
10993 break;
dc6f92b8 10994
7a13e894 10995 case CirculateNotify:
06a2c219
GM
10996 goto OTHER;
10997
7a13e894 10998 case CirculateRequest:
06a2c219
GM
10999 goto OTHER;
11000
11001 case VisibilityNotify:
11002 goto OTHER;
dc6f92b8 11003
7a13e894
RS
11004 case MappingNotify:
11005 /* Someone has changed the keyboard mapping - update the
11006 local cache. */
11007 switch (event.xmapping.request)
11008 {
11009 case MappingModifier:
11010 x_find_modifier_meanings (dpyinfo);
11011 /* This is meant to fall through. */
11012 case MappingKeyboard:
11013 XRefreshKeyboardMapping (&event.xmapping);
11014 }
7a13e894 11015 goto OTHER;
dc6f92b8 11016
7a13e894 11017 default:
7a13e894 11018 OTHER:
717ca130 11019#ifdef USE_X_TOOLKIT
7a13e894
RS
11020 BLOCK_INPUT;
11021 XtDispatchEvent (&event);
11022 UNBLOCK_INPUT;
3afe33e7 11023#endif /* USE_X_TOOLKIT */
7a13e894
RS
11024 break;
11025 }
dc6f92b8
JB
11026 }
11027 }
11028
06a2c219
GM
11029 out:;
11030
9a5196d0
RS
11031 /* On some systems, an X bug causes Emacs to get no more events
11032 when the window is destroyed. Detect that. (1994.) */
58769bee 11033 if (! event_found)
ef2a22d0 11034 {
ef2a22d0
RS
11035 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
11036 One XNOOP in 100 loops will make Emacs terminate.
11037 B. Bretthauer, 1994 */
11038 x_noop_count++;
58769bee 11039 if (x_noop_count >= 100)
ef2a22d0
RS
11040 {
11041 x_noop_count=0;
2224b905
RS
11042
11043 if (next_noop_dpyinfo == 0)
11044 next_noop_dpyinfo = x_display_list;
11045
11046 XNoOp (next_noop_dpyinfo->display);
11047
11048 /* Each time we get here, cycle through the displays now open. */
11049 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
11050 }
11051 }
502add23 11052
06a2c219 11053 /* If the focus was just given to an auto-raising frame,
0134a210 11054 raise it now. */
7a13e894 11055 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
11056 if (pending_autoraise_frame)
11057 {
11058 x_raise_frame (pending_autoraise_frame);
11059 pending_autoraise_frame = 0;
11060 }
0134a210 11061
dc6f92b8 11062 UNBLOCK_INPUT;
bde5503b 11063 --handling_signal;
dc6f92b8
JB
11064 return count;
11065}
06a2c219
GM
11066
11067
11068
dc6f92b8 11069\f
06a2c219
GM
11070/***********************************************************************
11071 Text Cursor
11072 ***********************************************************************/
11073
78a9a4c5 11074/* Notice if the text cursor of window W has been overwritten by a
f0a48a01
GM
11075 drawing operation that outputs N glyphs starting at START_X and
11076 ending at END_X in the line given by output_cursor.vpos.
bb4600a4 11077 Coordinates are area-relative. END_X < 0 means all the rest
f0a48a01 11078 of the line after START_X has been written. */
06a2c219
GM
11079
11080static void
f0a48a01 11081notice_overwritten_cursor (w, start_x, end_x)
06a2c219 11082 struct window *w;
f0a48a01 11083 int start_x, end_x;
06a2c219
GM
11084{
11085 if (updated_area == TEXT_AREA
f0a48a01 11086 && w->phys_cursor_on_p
06a2c219 11087 && output_cursor.vpos == w->phys_cursor.vpos
f0a48a01
GM
11088 && start_x <= w->phys_cursor.x
11089 && end_x > w->phys_cursor.x)
11090 w->phys_cursor_on_p = 0;
06a2c219 11091}
f451eb13
JB
11092
11093
06a2c219
GM
11094/* Set clipping for output in glyph row ROW. W is the window in which
11095 we operate. GC is the graphics context to set clipping in.
11096 WHOLE_LINE_P non-zero means include the areas used for truncation
11097 mark display and alike in the clipping rectangle.
11098
11099 ROW may be a text row or, e.g., a mode line. Text rows must be
11100 clipped to the interior of the window dedicated to text display,
11101 mode lines must be clipped to the whole window. */
dc6f92b8
JB
11102
11103static void
06a2c219
GM
11104x_clip_to_row (w, row, gc, whole_line_p)
11105 struct window *w;
11106 struct glyph_row *row;
11107 GC gc;
11108 int whole_line_p;
dc6f92b8 11109{
06a2c219
GM
11110 struct frame *f = XFRAME (WINDOW_FRAME (w));
11111 XRectangle clip_rect;
11112 int window_x, window_y, window_width, window_height;
dc6f92b8 11113
06a2c219 11114 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 11115
06a2c219
GM
11116 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
11117 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
11118 clip_rect.y = max (clip_rect.y, window_y);
11119 clip_rect.width = window_width;
11120 clip_rect.height = row->visible_height;
5c1aae96 11121
06a2c219
GM
11122 /* If clipping to the whole line, including trunc marks, extend
11123 the rectangle to the left and increase its width. */
11124 if (whole_line_p)
11125 {
110859fc
GM
11126 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
11127 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 11128 }
5c1aae96 11129
06a2c219 11130 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
11131}
11132
06a2c219
GM
11133
11134/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
11135
11136static void
06a2c219
GM
11137x_draw_hollow_cursor (w, row)
11138 struct window *w;
11139 struct glyph_row *row;
dc6f92b8 11140{
06a2c219
GM
11141 struct frame *f = XFRAME (WINDOW_FRAME (w));
11142 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11143 Display *dpy = FRAME_X_DISPLAY (f);
11144 int x, y, wd, h;
11145 XGCValues xgcv;
11146 struct glyph *cursor_glyph;
11147 GC gc;
11148
11149 /* Compute frame-relative coordinates from window-relative
11150 coordinates. */
11151 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11152 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
11153 + row->ascent - w->phys_cursor_ascent);
11154 h = row->height - 1;
11155
11156 /* Get the glyph the cursor is on. If we can't tell because
11157 the current matrix is invalid or such, give up. */
11158 cursor_glyph = get_phys_cursor_glyph (w);
11159 if (cursor_glyph == NULL)
dc6f92b8
JB
11160 return;
11161
06a2c219
GM
11162 /* Compute the width of the rectangle to draw. If on a stretch
11163 glyph, and `x-stretch-block-cursor' is nil, don't draw a
11164 rectangle as wide as the glyph, but use a canonical character
11165 width instead. */
11166 wd = cursor_glyph->pixel_width - 1;
11167 if (cursor_glyph->type == STRETCH_GLYPH
11168 && !x_stretch_cursor_p)
11169 wd = min (CANON_X_UNIT (f), wd);
11170
11171 /* The foreground of cursor_gc is typically the same as the normal
11172 background color, which can cause the cursor box to be invisible. */
11173 xgcv.foreground = f->output_data.x->cursor_pixel;
11174 if (dpyinfo->scratch_cursor_gc)
11175 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
11176 else
11177 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
11178 GCForeground, &xgcv);
11179 gc = dpyinfo->scratch_cursor_gc;
11180
11181 /* Set clipping, draw the rectangle, and reset clipping again. */
11182 x_clip_to_row (w, row, gc, 0);
11183 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
11184 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
11185}
11186
06a2c219
GM
11187
11188/* Draw a bar cursor on window W in glyph row ROW.
11189
11190 Implementation note: One would like to draw a bar cursor with an
11191 angle equal to the one given by the font property XA_ITALIC_ANGLE.
11192 Unfortunately, I didn't find a font yet that has this property set.
11193 --gerd. */
dc6f92b8
JB
11194
11195static void
f02d8aa0 11196x_draw_bar_cursor (w, row, width)
06a2c219
GM
11197 struct window *w;
11198 struct glyph_row *row;
f02d8aa0 11199 int width;
dc6f92b8 11200{
92f424df
GM
11201 struct frame *f = XFRAME (w->frame);
11202 struct glyph *cursor_glyph;
11203 GC gc;
11204 int x;
11205 unsigned long mask;
11206 XGCValues xgcv;
11207 Display *dpy;
11208 Window window;
06a2c219 11209
92f424df
GM
11210 /* If cursor is out of bounds, don't draw garbage. This can happen
11211 in mini-buffer windows when switching between echo area glyphs
11212 and mini-buffer. */
11213 cursor_glyph = get_phys_cursor_glyph (w);
11214 if (cursor_glyph == NULL)
11215 return;
06a2c219 11216
92f424df
GM
11217 /* If on an image, draw like a normal cursor. That's usually better
11218 visible than drawing a bar, esp. if the image is large so that
11219 the bar might not be in the window. */
11220 if (cursor_glyph->type == IMAGE_GLYPH)
11221 {
11222 struct glyph_row *row;
11223 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
11224 x_draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
11225 }
11226 else
11227 {
06a2c219
GM
11228 xgcv.background = f->output_data.x->cursor_pixel;
11229 xgcv.foreground = f->output_data.x->cursor_pixel;
11230 xgcv.graphics_exposures = 0;
11231 mask = GCForeground | GCBackground | GCGraphicsExposures;
11232 dpy = FRAME_X_DISPLAY (f);
11233 window = FRAME_X_WINDOW (f);
11234 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
92f424df 11235
06a2c219
GM
11236 if (gc)
11237 XChangeGC (dpy, gc, mask, &xgcv);
11238 else
11239 {
11240 gc = XCreateGC (dpy, window, mask, &xgcv);
11241 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
11242 }
92f424df 11243
f02d8aa0
GM
11244 if (width < 0)
11245 width = f->output_data.x->cursor_width;
92f424df 11246
06a2c219
GM
11247 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11248 x_clip_to_row (w, row, gc, 0);
11249 XFillRectangle (dpy, window, gc,
11250 x,
11251 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
f02d8aa0 11252 min (cursor_glyph->pixel_width, width),
06a2c219
GM
11253 row->height);
11254 XSetClipMask (dpy, gc, None);
11255 }
dc6f92b8
JB
11256}
11257
06a2c219
GM
11258
11259/* Clear the cursor of window W to background color, and mark the
11260 cursor as not shown. This is used when the text where the cursor
11261 is is about to be rewritten. */
11262
dc6f92b8 11263static void
06a2c219
GM
11264x_clear_cursor (w)
11265 struct window *w;
dc6f92b8 11266{
06a2c219
GM
11267 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
11268 x_update_window_cursor (w, 0);
11269}
90e65f07 11270
dbc4e1c1 11271
06a2c219
GM
11272/* Draw the cursor glyph of window W in glyph row ROW. See the
11273 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 11274
06a2c219
GM
11275static void
11276x_draw_phys_cursor_glyph (w, row, hl)
11277 struct window *w;
11278 struct glyph_row *row;
11279 enum draw_glyphs_face hl;
11280{
11281 /* If cursor hpos is out of bounds, don't draw garbage. This can
11282 happen in mini-buffer windows when switching between echo area
11283 glyphs and mini-buffer. */
11284 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e 11285 {
f0a48a01
GM
11286 int on_p = w->phys_cursor_on_p;
11287
66ac4b0e
GM
11288 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
11289 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
f0a48a01
GM
11290 hl, 0);
11291 w->phys_cursor_on_p = on_p;
66ac4b0e
GM
11292
11293 /* When we erase the cursor, and ROW is overlapped by other
11294 rows, make sure that these overlapping parts of other rows
11295 are redrawn. */
11296 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
11297 {
11298 if (row > w->current_matrix->rows
11299 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
11300 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
11301
11302 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
11303 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
11304 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
11305 }
11306 }
06a2c219 11307}
dbc4e1c1 11308
eea6af04 11309
06a2c219 11310/* Erase the image of a cursor of window W from the screen. */
eea6af04 11311
06a2c219
GM
11312static void
11313x_erase_phys_cursor (w)
11314 struct window *w;
11315{
11316 struct frame *f = XFRAME (w->frame);
11317 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11318 int hpos = w->phys_cursor.hpos;
11319 int vpos = w->phys_cursor.vpos;
11320 int mouse_face_here_p = 0;
11321 struct glyph_matrix *active_glyphs = w->current_matrix;
11322 struct glyph_row *cursor_row;
11323 struct glyph *cursor_glyph;
11324 enum draw_glyphs_face hl;
11325
11326 /* No cursor displayed or row invalidated => nothing to do on the
11327 screen. */
11328 if (w->phys_cursor_type == NO_CURSOR)
11329 goto mark_cursor_off;
11330
11331 /* VPOS >= active_glyphs->nrows means that window has been resized.
11332 Don't bother to erase the cursor. */
11333 if (vpos >= active_glyphs->nrows)
11334 goto mark_cursor_off;
11335
11336 /* If row containing cursor is marked invalid, there is nothing we
11337 can do. */
11338 cursor_row = MATRIX_ROW (active_glyphs, vpos);
11339 if (!cursor_row->enabled_p)
11340 goto mark_cursor_off;
11341
11342 /* This can happen when the new row is shorter than the old one.
11343 In this case, either x_draw_glyphs or clear_end_of_line
11344 should have cleared the cursor. Note that we wouldn't be
11345 able to erase the cursor in this case because we don't have a
11346 cursor glyph at hand. */
11347 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
11348 goto mark_cursor_off;
11349
11350 /* If the cursor is in the mouse face area, redisplay that when
11351 we clear the cursor. */
8801a864
KR
11352 if (! NILP (dpyinfo->mouse_face_window)
11353 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
11354 && (vpos > dpyinfo->mouse_face_beg_row
11355 || (vpos == dpyinfo->mouse_face_beg_row
11356 && hpos >= dpyinfo->mouse_face_beg_col))
11357 && (vpos < dpyinfo->mouse_face_end_row
11358 || (vpos == dpyinfo->mouse_face_end_row
11359 && hpos < dpyinfo->mouse_face_end_col))
11360 /* Don't redraw the cursor's spot in mouse face if it is at the
11361 end of a line (on a newline). The cursor appears there, but
11362 mouse highlighting does not. */
11363 && cursor_row->used[TEXT_AREA] > hpos)
11364 mouse_face_here_p = 1;
11365
11366 /* Maybe clear the display under the cursor. */
11367 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
11368 {
11369 int x;
045dee35 11370 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 11371
06a2c219
GM
11372 cursor_glyph = get_phys_cursor_glyph (w);
11373 if (cursor_glyph == NULL)
11374 goto mark_cursor_off;
dbc4e1c1 11375
e0300d33 11376 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
06a2c219 11377
c5e6e06b
GM
11378 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11379 x,
11380 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
11381 cursor_row->y)),
11382 cursor_glyph->pixel_width,
11383 cursor_row->visible_height,
11384 False);
dbc4e1c1 11385 }
06a2c219
GM
11386
11387 /* Erase the cursor by redrawing the character underneath it. */
11388 if (mouse_face_here_p)
11389 hl = DRAW_MOUSE_FACE;
06a2c219
GM
11390 else
11391 hl = DRAW_NORMAL_TEXT;
11392 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 11393
06a2c219
GM
11394 mark_cursor_off:
11395 w->phys_cursor_on_p = 0;
11396 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
11397}
11398
11399
b7f83f9e
GM
11400/* Non-zero if physical cursor of window W is within mouse face. */
11401
11402static int
11403cursor_in_mouse_face_p (w)
11404 struct window *w;
11405{
11406 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
11407 int in_mouse_face = 0;
11408
11409 if (WINDOWP (dpyinfo->mouse_face_window)
11410 && XWINDOW (dpyinfo->mouse_face_window) == w)
11411 {
11412 int hpos = w->phys_cursor.hpos;
11413 int vpos = w->phys_cursor.vpos;
11414
11415 if (vpos >= dpyinfo->mouse_face_beg_row
11416 && vpos <= dpyinfo->mouse_face_end_row
11417 && (vpos > dpyinfo->mouse_face_beg_row
11418 || hpos >= dpyinfo->mouse_face_beg_col)
11419 && (vpos < dpyinfo->mouse_face_end_row
11420 || hpos < dpyinfo->mouse_face_end_col
11421 || dpyinfo->mouse_face_past_end))
11422 in_mouse_face = 1;
11423 }
11424
11425 return in_mouse_face;
11426}
11427
11428
06a2c219
GM
11429/* Display or clear cursor of window W. If ON is zero, clear the
11430 cursor. If it is non-zero, display the cursor. If ON is nonzero,
11431 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 11432
06a2c219
GM
11433void
11434x_display_and_set_cursor (w, on, hpos, vpos, x, y)
11435 struct window *w;
11436 int on, hpos, vpos, x, y;
dbc4e1c1 11437{
06a2c219
GM
11438 struct frame *f = XFRAME (w->frame);
11439 int new_cursor_type;
f02d8aa0 11440 int new_cursor_width;
06a2c219
GM
11441 struct glyph_matrix *current_glyphs;
11442 struct glyph_row *glyph_row;
11443 struct glyph *glyph;
dbc4e1c1 11444
49d838ea 11445 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
11446 windows and frames; in the latter case, the frame or window may
11447 be in the midst of changing its size, and x and y may be off the
11448 window. */
11449 if (! FRAME_VISIBLE_P (f)
11450 || FRAME_GARBAGED_P (f)
11451 || vpos >= w->current_matrix->nrows
11452 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
11453 return;
11454
11455 /* If cursor is off and we want it off, return quickly. */
06a2c219 11456 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
11457 return;
11458
06a2c219
GM
11459 current_glyphs = w->current_matrix;
11460 glyph_row = MATRIX_ROW (current_glyphs, vpos);
11461 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
11462
11463 /* If cursor row is not enabled, we don't really know where to
11464 display the cursor. */
11465 if (!glyph_row->enabled_p)
11466 {
11467 w->phys_cursor_on_p = 0;
11468 return;
11469 }
11470
11471 xassert (interrupt_input_blocked);
11472
11473 /* Set new_cursor_type to the cursor we want to be displayed. In a
11474 mini-buffer window, we want the cursor only to appear if we are
11475 reading input from this window. For the selected window, we want
11476 the cursor type given by the frame parameter. If explicitly
11477 marked off, draw no cursor. In all other cases, we want a hollow
11478 box cursor. */
f02d8aa0 11479 new_cursor_width = -1;
9b4a7047
GM
11480 if (cursor_in_echo_area
11481 && FRAME_HAS_MINIBUF_P (f)
11482 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 11483 {
9b4a7047
GM
11484 if (w == XWINDOW (echo_area_window))
11485 new_cursor_type = FRAME_DESIRED_CURSOR (f);
06a2c219
GM
11486 else
11487 new_cursor_type = HOLLOW_BOX_CURSOR;
11488 }
06a2c219 11489 else
9b4a7047 11490 {
7a58ab59
GM
11491 if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
11492 || w != XWINDOW (f->selected_window))
9b4a7047 11493 {
e55a0b79
GM
11494 extern int cursor_in_non_selected_windows;
11495
5cefa566
GM
11496 if (MINI_WINDOW_P (w)
11497 || !cursor_in_non_selected_windows
11498 || NILP (XBUFFER (w->buffer)->cursor_type))
9b4a7047
GM
11499 new_cursor_type = NO_CURSOR;
11500 else
11501 new_cursor_type = HOLLOW_BOX_CURSOR;
11502 }
11503 else if (w->cursor_off_p)
11504 new_cursor_type = NO_CURSOR;
11505 else
f02d8aa0
GM
11506 {
11507 struct buffer *b = XBUFFER (w->buffer);
11508
11509 if (EQ (b->cursor_type, Qt))
11510 new_cursor_type = FRAME_DESIRED_CURSOR (f);
11511 else
11512 new_cursor_type = x_specified_cursor_type (b->cursor_type,
11513 &new_cursor_width);
11514 }
9b4a7047 11515 }
06a2c219
GM
11516
11517 /* If cursor is currently being shown and we don't want it to be or
11518 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 11519 erase it. */
06a2c219 11520 if (w->phys_cursor_on_p
dc6f92b8 11521 && (!on
06a2c219
GM
11522 || w->phys_cursor.x != x
11523 || w->phys_cursor.y != y
11524 || new_cursor_type != w->phys_cursor_type))
11525 x_erase_phys_cursor (w);
11526
11527 /* If the cursor is now invisible and we want it to be visible,
11528 display it. */
11529 if (on && !w->phys_cursor_on_p)
11530 {
11531 w->phys_cursor_ascent = glyph_row->ascent;
11532 w->phys_cursor_height = glyph_row->height;
11533
11534 /* Set phys_cursor_.* before x_draw_.* is called because some
11535 of them may need the information. */
11536 w->phys_cursor.x = x;
11537 w->phys_cursor.y = glyph_row->y;
11538 w->phys_cursor.hpos = hpos;
11539 w->phys_cursor.vpos = vpos;
11540 w->phys_cursor_type = new_cursor_type;
11541 w->phys_cursor_on_p = 1;
11542
11543 switch (new_cursor_type)
dc6f92b8 11544 {
06a2c219
GM
11545 case HOLLOW_BOX_CURSOR:
11546 x_draw_hollow_cursor (w, glyph_row);
11547 break;
11548
11549 case FILLED_BOX_CURSOR:
11550 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
11551 break;
11552
11553 case BAR_CURSOR:
f02d8aa0 11554 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
11555 break;
11556
11557 case NO_CURSOR:
11558 break;
dc6f92b8 11559
06a2c219
GM
11560 default:
11561 abort ();
11562 }
59ddecde
GM
11563
11564#ifdef HAVE_X_I18N
11565 if (w == XWINDOW (f->selected_window))
11566 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
11567 xic_set_preeditarea (w, x, y);
11568#endif
dc6f92b8
JB
11569 }
11570
06a2c219 11571#ifndef XFlush
f676886a 11572 if (updating_frame != f)
334208b7 11573 XFlush (FRAME_X_DISPLAY (f));
06a2c219 11574#endif
dc6f92b8
JB
11575}
11576
06a2c219
GM
11577
11578/* Display the cursor on window W, or clear it. X and Y are window
11579 relative pixel coordinates. HPOS and VPOS are glyph matrix
11580 positions. If W is not the selected window, display a hollow
11581 cursor. ON non-zero means display the cursor at X, Y which
11582 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 11583
dfcf069d 11584void
06a2c219
GM
11585x_display_cursor (w, on, hpos, vpos, x, y)
11586 struct window *w;
11587 int on, hpos, vpos, x, y;
dc6f92b8 11588{
f94397b5 11589 BLOCK_INPUT;
06a2c219 11590 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
11591 UNBLOCK_INPUT;
11592}
11593
06a2c219
GM
11594
11595/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
11596 Don't change the cursor's position. */
11597
dfcf069d 11598void
06a2c219 11599x_update_cursor (f, on_p)
5d46f928 11600 struct frame *f;
5d46f928 11601{
06a2c219
GM
11602 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
11603}
11604
11605
11606/* Call x_update_window_cursor with parameter ON_P on all leaf windows
11607 in the window tree rooted at W. */
11608
11609static void
11610x_update_cursor_in_window_tree (w, on_p)
11611 struct window *w;
11612 int on_p;
11613{
11614 while (w)
11615 {
11616 if (!NILP (w->hchild))
11617 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
11618 else if (!NILP (w->vchild))
11619 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
11620 else
11621 x_update_window_cursor (w, on_p);
11622
11623 w = NILP (w->next) ? 0 : XWINDOW (w->next);
11624 }
11625}
5d46f928 11626
f94397b5 11627
06a2c219
GM
11628/* Switch the display of W's cursor on or off, according to the value
11629 of ON. */
11630
11631static void
11632x_update_window_cursor (w, on)
11633 struct window *w;
11634 int on;
11635{
16b5d424
GM
11636 /* Don't update cursor in windows whose frame is in the process
11637 of being deleted. */
11638 if (w->current_matrix)
11639 {
11640 BLOCK_INPUT;
11641 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
11642 w->phys_cursor.x, w->phys_cursor.y);
11643 UNBLOCK_INPUT;
11644 }
dc6f92b8 11645}
06a2c219
GM
11646
11647
11648
dc6f92b8
JB
11649\f
11650/* Icons. */
11651
dbc4e1c1 11652/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
11653
11654int
990ba854 11655x_bitmap_icon (f, file)
f676886a 11656 struct frame *f;
990ba854 11657 Lisp_Object file;
dc6f92b8 11658{
06a2c219 11659 int bitmap_id;
dc6f92b8 11660
c118dd06 11661 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11662 return 1;
11663
990ba854 11664 /* Free up our existing icon bitmap if any. */
7556890b
RS
11665 if (f->output_data.x->icon_bitmap > 0)
11666 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11667 f->output_data.x->icon_bitmap = 0;
990ba854
RS
11668
11669 if (STRINGP (file))
7f2ae036
RS
11670 bitmap_id = x_create_bitmap_from_file (f, file);
11671 else
11672 {
990ba854 11673 /* Create the GNU bitmap if necessary. */
5bf01b68 11674 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
11675 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
11676 = x_create_bitmap_from_data (f, gnu_bits,
11677 gnu_width, gnu_height);
990ba854
RS
11678
11679 /* The first time we create the GNU bitmap,
06a2c219 11680 this increments the ref-count one extra time.
990ba854
RS
11681 As a result, the GNU bitmap is never freed.
11682 That way, we don't have to worry about allocating it again. */
334208b7 11683 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 11684
334208b7 11685 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
11686 }
11687
11688 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 11689 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
11690
11691 return 0;
11692}
11693
11694
1be2d067
KH
11695/* Make the x-window of frame F use a rectangle with text.
11696 Use ICON_NAME as the text. */
dc6f92b8
JB
11697
11698int
f676886a
JB
11699x_text_icon (f, icon_name)
11700 struct frame *f;
dc6f92b8
JB
11701 char *icon_name;
11702{
c118dd06 11703 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11704 return 1;
11705
1be2d067
KH
11706#ifdef HAVE_X11R4
11707 {
11708 XTextProperty text;
11709 text.value = (unsigned char *) icon_name;
11710 text.encoding = XA_STRING;
11711 text.format = 8;
11712 text.nitems = strlen (icon_name);
11713#ifdef USE_X_TOOLKIT
7556890b 11714 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
11715 &text);
11716#else /* not USE_X_TOOLKIT */
11717 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
11718#endif /* not USE_X_TOOLKIT */
11719 }
11720#else /* not HAVE_X11R4 */
11721 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
11722#endif /* not HAVE_X11R4 */
58769bee 11723
7556890b
RS
11724 if (f->output_data.x->icon_bitmap > 0)
11725 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11726 f->output_data.x->icon_bitmap = 0;
b1c884c3 11727 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
11728
11729 return 0;
11730}
11731\f
e99db5a1
RS
11732#define X_ERROR_MESSAGE_SIZE 200
11733
11734/* If non-nil, this should be a string.
11735 It means catch X errors and store the error message in this string. */
11736
11737static Lisp_Object x_error_message_string;
11738
11739/* An X error handler which stores the error message in
11740 x_error_message_string. This is called from x_error_handler if
11741 x_catch_errors is in effect. */
11742
06a2c219 11743static void
e99db5a1
RS
11744x_error_catcher (display, error)
11745 Display *display;
11746 XErrorEvent *error;
11747{
11748 XGetErrorText (display, error->error_code,
11749 XSTRING (x_error_message_string)->data,
11750 X_ERROR_MESSAGE_SIZE);
11751}
11752
11753/* Begin trapping X errors for display DPY. Actually we trap X errors
11754 for all displays, but DPY should be the display you are actually
11755 operating on.
11756
11757 After calling this function, X protocol errors no longer cause
11758 Emacs to exit; instead, they are recorded in the string
11759 stored in x_error_message_string.
11760
11761 Calling x_check_errors signals an Emacs error if an X error has
11762 occurred since the last call to x_catch_errors or x_check_errors.
11763
11764 Calling x_uncatch_errors resumes the normal error handling. */
11765
11766void x_check_errors ();
11767static Lisp_Object x_catch_errors_unwind ();
11768
11769int
11770x_catch_errors (dpy)
11771 Display *dpy;
11772{
11773 int count = specpdl_ptr - specpdl;
11774
11775 /* Make sure any errors from previous requests have been dealt with. */
11776 XSync (dpy, False);
11777
11778 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
11779
11780 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
11781 XSTRING (x_error_message_string)->data[0] = 0;
11782
11783 return count;
11784}
11785
11786/* Unbind the binding that we made to check for X errors. */
11787
11788static Lisp_Object
11789x_catch_errors_unwind (old_val)
11790 Lisp_Object old_val;
11791{
11792 x_error_message_string = old_val;
11793 return Qnil;
11794}
11795
11796/* If any X protocol errors have arrived since the last call to
11797 x_catch_errors or x_check_errors, signal an Emacs error using
11798 sprintf (a buffer, FORMAT, the x error message text) as the text. */
11799
11800void
11801x_check_errors (dpy, format)
11802 Display *dpy;
11803 char *format;
11804{
11805 /* Make sure to catch any errors incurred so far. */
11806 XSync (dpy, False);
11807
11808 if (XSTRING (x_error_message_string)->data[0])
11809 error (format, XSTRING (x_error_message_string)->data);
11810}
11811
9829ddba
RS
11812/* Nonzero if we had any X protocol errors
11813 since we did x_catch_errors on DPY. */
e99db5a1
RS
11814
11815int
11816x_had_errors_p (dpy)
11817 Display *dpy;
11818{
11819 /* Make sure to catch any errors incurred so far. */
11820 XSync (dpy, False);
11821
11822 return XSTRING (x_error_message_string)->data[0] != 0;
11823}
11824
9829ddba
RS
11825/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
11826
06a2c219 11827void
9829ddba
RS
11828x_clear_errors (dpy)
11829 Display *dpy;
11830{
11831 XSTRING (x_error_message_string)->data[0] = 0;
11832}
11833
e99db5a1
RS
11834/* Stop catching X protocol errors and let them make Emacs die.
11835 DPY should be the display that was passed to x_catch_errors.
11836 COUNT should be the value that was returned by
11837 the corresponding call to x_catch_errors. */
11838
11839void
11840x_uncatch_errors (dpy, count)
11841 Display *dpy;
11842 int count;
11843{
11844 unbind_to (count, Qnil);
11845}
11846
11847#if 0
11848static unsigned int x_wire_count;
11849x_trace_wire ()
11850{
11851 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
11852}
11853#endif /* ! 0 */
11854
11855\f
11856/* Handle SIGPIPE, which can happen when the connection to a server
11857 simply goes away. SIGPIPE is handled by x_connection_signal.
11858 Don't need to do anything, because the write which caused the
11859 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 11860 which will do the appropriate cleanup for us. */
e99db5a1
RS
11861
11862static SIGTYPE
11863x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 11864 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
11865{
11866#ifdef USG
11867 /* USG systems forget handlers when they are used;
11868 must reestablish each time */
11869 signal (signalnum, x_connection_signal);
11870#endif /* USG */
11871}
0da1ab50 11872
e99db5a1 11873\f
0da1ab50
GM
11874/************************************************************************
11875 Handling X errors
11876 ************************************************************************/
4746118a 11877
f0e299de
GM
11878/* Error message passed to x_connection_closed. */
11879
11880static char *error_msg;
11881
a7248e4f 11882/* Function installed as fatal_error_signal_hook in
f0e299de
GM
11883 x_connection_closed. Print the X error message, and exit normally,
11884 instead of dumping core when XtCloseDisplay fails. */
11885
11886static void
11887x_fatal_error_signal ()
11888{
11889 fprintf (stderr, "%s\n", error_msg);
11890 exit (70);
11891}
11892
0da1ab50
GM
11893/* Handle the loss of connection to display DPY. ERROR_MESSAGE is
11894 the text of an error message that lead to the connection loss. */
16bd92ea 11895
4746118a 11896static SIGTYPE
5978125e
GM
11897x_connection_closed (dpy, error_message)
11898 Display *dpy;
7a13e894 11899 char *error_message;
4746118a 11900{
5978125e 11901 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
7a13e894 11902 Lisp_Object frame, tail;
0da1ab50 11903 int count;
0da1ab50 11904
f0e299de
GM
11905 error_msg = (char *) alloca (strlen (error_message) + 1);
11906 strcpy (error_msg, error_message);
1a532e54
GM
11907 handling_signal = 0;
11908
0da1ab50
GM
11909 /* Prevent being called recursively because of an error condition
11910 below. Otherwise, we might end up with printing ``can't find per
11911 display information'' in the recursive call instead of printing
11912 the original message here. */
11913 count = x_catch_errors (dpy);
11914
8a4f36cc
GM
11915 /* We have to close the display to inform Xt that it doesn't
11916 exist anymore. If we don't, Xt will continue to wait for
11917 events from the display. As a consequence, a sequence of
11918
11919 M-x make-frame-on-display RET :1 RET
11920 ...kill the new frame, so that we get an IO error...
11921 M-x make-frame-on-display RET :1 RET
11922
11923 will indefinitely wait in Xt for events for display `:1', opened
11924 in the first class to make-frame-on-display.
6186a4a0 11925
8a4f36cc
GM
11926 Closing the display is reported to lead to a bus error on
11927 OpenWindows in certain situations. I suspect that is a bug
11928 in OpenWindows. I don't know how to cicumvent it here. */
11929
f613a4c8 11930#ifdef USE_X_TOOLKIT
ae24cb3b
GM
11931 /* If DPYINFO is null, this means we didn't open the display
11932 in the first place, so don't try to close it. */
11933 if (dpyinfo)
f0e299de
GM
11934 {
11935 extern void (*fatal_error_signal_hook) P_ ((void));
11936 fatal_error_signal_hook = x_fatal_error_signal;
11937 XtCloseDisplay (dpy);
11938 fatal_error_signal_hook = NULL;
11939 }
f613a4c8 11940#endif
adabc3a9 11941
8a4f36cc 11942 /* Indicate that this display is dead. */
9e80b57d
KR
11943 if (dpyinfo)
11944 dpyinfo->display = 0;
6186a4a0 11945
06a2c219 11946 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
11947 that are on the dead display. */
11948 FOR_EACH_FRAME (tail, frame)
11949 {
11950 Lisp_Object minibuf_frame;
11951 minibuf_frame
11952 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
11953 if (FRAME_X_P (XFRAME (frame))
11954 && FRAME_X_P (XFRAME (minibuf_frame))
11955 && ! EQ (frame, minibuf_frame)
11956 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
11957 Fdelete_frame (frame, Qt);
11958 }
11959
11960 /* Now delete all remaining frames on the dead display.
06a2c219 11961 We are now sure none of these is used as the mini-buffer
7a13e894
RS
11962 for another frame that we need to delete. */
11963 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
11964 if (FRAME_X_P (XFRAME (frame))
11965 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
11966 {
11967 /* Set this to t so that Fdelete_frame won't get confused
11968 trying to find a replacement. */
11969 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
11970 Fdelete_frame (frame, Qt);
11971 }
7a13e894 11972
482a1bd2
KH
11973 if (dpyinfo)
11974 x_delete_display (dpyinfo);
7a13e894 11975
0da1ab50
GM
11976 x_uncatch_errors (dpy, count);
11977
7a13e894
RS
11978 if (x_display_list == 0)
11979 {
f0e299de 11980 fprintf (stderr, "%s\n", error_msg);
7a13e894
RS
11981 shut_down_emacs (0, 0, Qnil);
11982 exit (70);
11983 }
12ba150f 11984
7a13e894
RS
11985 /* Ordinary stack unwind doesn't deal with these. */
11986#ifdef SIGIO
11987 sigunblock (sigmask (SIGIO));
11988#endif
11989 sigunblock (sigmask (SIGALRM));
11990 TOTALLY_UNBLOCK_INPUT;
11991
aa4d9a9e 11992 clear_waiting_for_input ();
f0e299de 11993 error ("%s", error_msg);
4746118a
JB
11994}
11995
0da1ab50 11996
7a13e894
RS
11997/* This is the usual handler for X protocol errors.
11998 It kills all frames on the display that we got the error for.
11999 If that was the only one, it prints an error message and kills Emacs. */
12000
06a2c219 12001static void
c118dd06
JB
12002x_error_quitter (display, error)
12003 Display *display;
12004 XErrorEvent *error;
12005{
7a13e894 12006 char buf[256], buf1[356];
dc6f92b8 12007
58769bee 12008 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 12009 original error handler. */
dc6f92b8 12010
c118dd06 12011 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 12012 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 12013 buf, error->request_code);
7a13e894 12014 x_connection_closed (display, buf1);
dc6f92b8
JB
12015}
12016
0da1ab50 12017
e99db5a1
RS
12018/* This is the first-level handler for X protocol errors.
12019 It calls x_error_quitter or x_error_catcher. */
7a13e894 12020
8922af5f 12021static int
e99db5a1 12022x_error_handler (display, error)
8922af5f 12023 Display *display;
e99db5a1 12024 XErrorEvent *error;
8922af5f 12025{
e99db5a1
RS
12026 if (! NILP (x_error_message_string))
12027 x_error_catcher (display, error);
12028 else
12029 x_error_quitter (display, error);
06a2c219 12030 return 0;
f9e24cb9 12031}
c118dd06 12032
e99db5a1
RS
12033/* This is the handler for X IO errors, always.
12034 It kills all frames on the display that we lost touch with.
12035 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 12036
c118dd06 12037static int
e99db5a1 12038x_io_error_quitter (display)
c118dd06 12039 Display *display;
c118dd06 12040{
e99db5a1 12041 char buf[256];
dc6f92b8 12042
e99db5a1
RS
12043 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
12044 x_connection_closed (display, buf);
06a2c219 12045 return 0;
dc6f92b8 12046}
dc6f92b8 12047\f
f451eb13
JB
12048/* Changing the font of the frame. */
12049
76bcdf39
RS
12050/* Give frame F the font named FONTNAME as its default font, and
12051 return the full name of that font. FONTNAME may be a wildcard
12052 pattern; in that case, we choose some font that fits the pattern.
12053 The return value shows which font we chose. */
12054
b5cf7a0e 12055Lisp_Object
f676886a
JB
12056x_new_font (f, fontname)
12057 struct frame *f;
dc6f92b8
JB
12058 register char *fontname;
12059{
dc43ef94 12060 struct font_info *fontp
ee569018 12061 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 12062
dc43ef94
KH
12063 if (!fontp)
12064 return Qnil;
2224a5fc 12065
dc43ef94 12066 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 12067 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
12068 f->output_data.x->fontset = -1;
12069
b2cad826
KH
12070 /* Compute the scroll bar width in character columns. */
12071 if (f->scroll_bar_pixel_width > 0)
12072 {
7556890b 12073 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
12074 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
12075 }
12076 else
4e61bddf
RS
12077 {
12078 int wid = FONT_WIDTH (f->output_data.x->font);
12079 f->scroll_bar_cols = (14 + wid - 1) / wid;
12080 }
b2cad826 12081
f676886a 12082 /* Now make the frame display the given font. */
c118dd06 12083 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 12084 {
7556890b
RS
12085 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
12086 f->output_data.x->font->fid);
12087 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
12088 f->output_data.x->font->fid);
12089 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
12090 f->output_data.x->font->fid);
f676886a 12091
a27f9f86 12092 frame_update_line_height (f);
3497f73e
GM
12093
12094 /* Don't change the size of a tip frame; there's no point in
12095 doing it because it's done in Fx_show_tip, and it leads to
12096 problems because the tip frame has no widget. */
12097 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
12098 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 12099 }
a27f9f86
RS
12100 else
12101 /* If we are setting a new frame's font for the first time,
12102 there are no faces yet, so this font's height is the line height. */
7556890b 12103 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 12104
dc43ef94
KH
12105 return build_string (fontp->full_name);
12106}
12107
12108/* Give frame F the fontset named FONTSETNAME as its default font, and
12109 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
12110 pattern; in that case, we choose some fontset that fits the pattern.
12111 The return value shows which fontset we chose. */
b5cf7a0e 12112
dc43ef94
KH
12113Lisp_Object
12114x_new_fontset (f, fontsetname)
12115 struct frame *f;
12116 char *fontsetname;
12117{
ee569018 12118 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 12119 Lisp_Object result;
b5cf7a0e 12120
dc43ef94
KH
12121 if (fontset < 0)
12122 return Qnil;
b5cf7a0e 12123
2da424f1
KH
12124 if (f->output_data.x->fontset == fontset)
12125 /* This fontset is already set in frame F. There's nothing more
12126 to do. */
ee569018 12127 return fontset_name (fontset);
dc43ef94 12128
ee569018 12129 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
12130
12131 if (!STRINGP (result))
12132 /* Can't load ASCII font. */
12133 return Qnil;
12134
12135 /* Since x_new_font doesn't update any fontset information, do it now. */
12136 f->output_data.x->fontset = fontset;
dc43ef94 12137
f5d11644
GM
12138#ifdef HAVE_X_I18N
12139 if (FRAME_XIC (f)
12140 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 12141 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
12142#endif
12143
dc43ef94 12144 return build_string (fontsetname);
dc6f92b8 12145}
f5d11644
GM
12146
12147\f
12148/***********************************************************************
12149 X Input Methods
12150 ***********************************************************************/
12151
12152#ifdef HAVE_X_I18N
12153
12154#ifdef HAVE_X11R6
12155
12156/* XIM destroy callback function, which is called whenever the
12157 connection to input method XIM dies. CLIENT_DATA contains a
12158 pointer to the x_display_info structure corresponding to XIM. */
12159
12160static void
12161xim_destroy_callback (xim, client_data, call_data)
12162 XIM xim;
12163 XPointer client_data;
12164 XPointer call_data;
12165{
12166 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
12167 Lisp_Object frame, tail;
12168
12169 BLOCK_INPUT;
12170
12171 /* No need to call XDestroyIC.. */
12172 FOR_EACH_FRAME (tail, frame)
12173 {
12174 struct frame *f = XFRAME (frame);
12175 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
12176 {
12177 FRAME_XIC (f) = NULL;
12178 if (FRAME_XIC_FONTSET (f))
12179 {
12180 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
12181 FRAME_XIC_FONTSET (f) = NULL;
12182 }
12183 }
12184 }
12185
12186 /* No need to call XCloseIM. */
12187 dpyinfo->xim = NULL;
12188 XFree (dpyinfo->xim_styles);
12189 UNBLOCK_INPUT;
12190}
12191
12192#endif /* HAVE_X11R6 */
12193
12194/* Open the connection to the XIM server on display DPYINFO.
12195 RESOURCE_NAME is the resource name Emacs uses. */
12196
12197static void
12198xim_open_dpy (dpyinfo, resource_name)
12199 struct x_display_info *dpyinfo;
12200 char *resource_name;
12201{
287f7dd6 12202#ifdef USE_XIM
f5d11644
GM
12203 XIM xim;
12204
12205 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
12206 dpyinfo->xim = xim;
12207
12208 if (xim)
12209 {
f5d11644
GM
12210#ifdef HAVE_X11R6
12211 XIMCallback destroy;
12212#endif
12213
12214 /* Get supported styles and XIM values. */
12215 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
12216
12217#ifdef HAVE_X11R6
12218 destroy.callback = xim_destroy_callback;
12219 destroy.client_data = (XPointer)dpyinfo;
cea2ad76 12220 /* This isn't prototyped in OSF 5.0. */
f5d11644
GM
12221 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
12222#endif
12223 }
287f7dd6
GM
12224
12225#else /* not USE_XIM */
12226 dpyinfo->xim = NULL;
12227#endif /* not USE_XIM */
f5d11644
GM
12228}
12229
12230
b9de836c 12231#ifdef HAVE_X11R6_XIM
f5d11644
GM
12232
12233struct xim_inst_t
12234{
12235 struct x_display_info *dpyinfo;
12236 char *resource_name;
12237};
12238
12239/* XIM instantiate callback function, which is called whenever an XIM
12240 server is available. DISPLAY is teh display of the XIM.
12241 CLIENT_DATA contains a pointer to an xim_inst_t structure created
12242 when the callback was registered. */
12243
12244static void
12245xim_instantiate_callback (display, client_data, call_data)
12246 Display *display;
12247 XPointer client_data;
12248 XPointer call_data;
12249{
12250 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
12251 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
12252
12253 /* We don't support multiple XIM connections. */
12254 if (dpyinfo->xim)
12255 return;
12256
12257 xim_open_dpy (dpyinfo, xim_inst->resource_name);
12258
12259 /* Create XIC for the existing frames on the same display, as long
12260 as they have no XIC. */
12261 if (dpyinfo->xim && dpyinfo->reference_count > 0)
12262 {
12263 Lisp_Object tail, frame;
12264
12265 BLOCK_INPUT;
12266 FOR_EACH_FRAME (tail, frame)
12267 {
12268 struct frame *f = XFRAME (frame);
12269
12270 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
12271 if (FRAME_XIC (f) == NULL)
12272 {
12273 create_frame_xic (f);
12274 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
12275 xic_set_statusarea (f);
12276 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
12277 {
12278 struct window *w = XWINDOW (f->selected_window);
12279 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
12280 }
12281 }
12282 }
12283
12284 UNBLOCK_INPUT;
12285 }
12286}
12287
b9de836c 12288#endif /* HAVE_X11R6_XIM */
f5d11644
GM
12289
12290
12291/* Open a connection to the XIM server on display DPYINFO.
12292 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
12293 connection only at the first time. On X11R6, open the connection
12294 in the XIM instantiate callback function. */
12295
12296static void
12297xim_initialize (dpyinfo, resource_name)
12298 struct x_display_info *dpyinfo;
12299 char *resource_name;
12300{
287f7dd6 12301#ifdef USE_XIM
b9de836c 12302#ifdef HAVE_X11R6_XIM
f5d11644
GM
12303 struct xim_inst_t *xim_inst;
12304 int len;
12305
12306 dpyinfo->xim = NULL;
12307 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
12308 xim_inst->dpyinfo = dpyinfo;
12309 len = strlen (resource_name);
12310 xim_inst->resource_name = (char *) xmalloc (len + 1);
12311 bcopy (resource_name, xim_inst->resource_name, len + 1);
12312 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12313 resource_name, EMACS_CLASS,
12314 xim_instantiate_callback,
2ebb2f8b
DL
12315 /* Fixme: This is XPointer in
12316 XFree86 but (XPointer *) on
12317 Tru64, at least. */
12318 (XPointer) xim_inst);
b9de836c 12319#else /* not HAVE_X11R6_XIM */
f5d11644
GM
12320 dpyinfo->xim = NULL;
12321 xim_open_dpy (dpyinfo, resource_name);
b9de836c 12322#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
12323
12324#else /* not USE_XIM */
12325 dpyinfo->xim = NULL;
12326#endif /* not USE_XIM */
f5d11644
GM
12327}
12328
12329
12330/* Close the connection to the XIM server on display DPYINFO. */
12331
12332static void
12333xim_close_dpy (dpyinfo)
12334 struct x_display_info *dpyinfo;
12335{
287f7dd6 12336#ifdef USE_XIM
b9de836c 12337#ifdef HAVE_X11R6_XIM
8a4f36cc
GM
12338 if (dpyinfo->display)
12339 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12340 NULL, EMACS_CLASS,
12341 xim_instantiate_callback, NULL);
b9de836c 12342#endif /* not HAVE_X11R6_XIM */
8a4f36cc
GM
12343 if (dpyinfo->display)
12344 XCloseIM (dpyinfo->xim);
f5d11644
GM
12345 dpyinfo->xim = NULL;
12346 XFree (dpyinfo->xim_styles);
287f7dd6 12347#endif /* USE_XIM */
f5d11644
GM
12348}
12349
b9de836c 12350#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
12351
12352
dc6f92b8 12353\f
2e365682
RS
12354/* Calculate the absolute position in frame F
12355 from its current recorded position values and gravity. */
12356
dfcf069d 12357void
43bca5d5 12358x_calc_absolute_position (f)
f676886a 12359 struct frame *f;
dc6f92b8 12360{
06a2c219 12361 Window child;
6dba1858 12362 int win_x = 0, win_y = 0;
7556890b 12363 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
12364 int this_window;
12365
9829ddba
RS
12366 /* We have nothing to do if the current position
12367 is already for the top-left corner. */
12368 if (! ((flags & XNegative) || (flags & YNegative)))
12369 return;
12370
c81412a0 12371#ifdef USE_X_TOOLKIT
7556890b 12372 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
12373#else
12374 this_window = FRAME_X_WINDOW (f);
12375#endif
6dba1858
RS
12376
12377 /* Find the position of the outside upper-left corner of
9829ddba
RS
12378 the inner window, with respect to the outer window.
12379 But do this only if we will need the results. */
7556890b 12380 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 12381 {
9829ddba
RS
12382 int count;
12383
6dba1858 12384 BLOCK_INPUT;
9829ddba
RS
12385 count = x_catch_errors (FRAME_X_DISPLAY (f));
12386 while (1)
12387 {
12388 x_clear_errors (FRAME_X_DISPLAY (f));
12389 XTranslateCoordinates (FRAME_X_DISPLAY (f),
12390
12391 /* From-window, to-window. */
12392 this_window,
12393 f->output_data.x->parent_desc,
12394
12395 /* From-position, to-position. */
12396 0, 0, &win_x, &win_y,
12397
12398 /* Child of win. */
12399 &child);
12400 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12401 {
12402 Window newroot, newparent = 0xdeadbeef;
12403 Window *newchildren;
2ebb2f8b 12404 unsigned int nchildren;
9829ddba
RS
12405
12406 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
12407 &newparent, &newchildren, &nchildren))
12408 break;
58769bee 12409
7c3c78a3 12410 XFree ((char *) newchildren);
6dba1858 12411
9829ddba
RS
12412 f->output_data.x->parent_desc = newparent;
12413 }
12414 else
12415 break;
12416 }
6dba1858 12417
9829ddba 12418 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
12419 UNBLOCK_INPUT;
12420 }
12421
12422 /* Treat negative positions as relative to the leftmost bottommost
12423 position that fits on the screen. */
20f55f9a 12424 if (flags & XNegative)
7556890b 12425 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
12426 - 2 * f->output_data.x->border_width - win_x
12427 - PIXEL_WIDTH (f)
12428 + f->output_data.x->left_pos);
dc6f92b8 12429
7708ced0
GM
12430 {
12431 int height = PIXEL_HEIGHT (f);
06a2c219 12432
7708ced0
GM
12433#if defined USE_X_TOOLKIT && defined USE_MOTIF
12434 /* Something is fishy here. When using Motif, starting Emacs with
12435 `-g -0-0', the frame appears too low by a few pixels.
12436
12437 This seems to be so because initially, while Emacs is starting,
12438 the column widget's height and the frame's pixel height are
12439 different. The column widget's height is the right one. In
12440 later invocations, when Emacs is up, the frame's pixel height
12441 is right, though.
12442
12443 It's not obvious where the initial small difference comes from.
12444 2000-12-01, gerd. */
12445
12446 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
06a2c219 12447#endif
2e365682 12448
7708ced0
GM
12449 if (flags & YNegative)
12450 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
12451 - 2 * f->output_data.x->border_width
12452 - win_y
12453 - height
12454 + f->output_data.x->top_pos);
12455 }
12456
3a35ab44
RS
12457 /* The left_pos and top_pos
12458 are now relative to the top and left screen edges,
12459 so the flags should correspond. */
7556890b 12460 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
12461}
12462
3a35ab44
RS
12463/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
12464 to really change the position, and 0 when calling from
12465 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
12466 position values). It is -1 when calling from x_set_frame_parameters,
12467 which means, do adjust for borders but don't change the gravity. */
3a35ab44 12468
dfcf069d 12469void
dc05a16b 12470x_set_offset (f, xoff, yoff, change_gravity)
f676886a 12471 struct frame *f;
dc6f92b8 12472 register int xoff, yoff;
dc05a16b 12473 int change_gravity;
dc6f92b8 12474{
4a4cbdd5
KH
12475 int modified_top, modified_left;
12476
aa3ff7c9 12477 if (change_gravity > 0)
3a35ab44 12478 {
7556890b
RS
12479 f->output_data.x->top_pos = yoff;
12480 f->output_data.x->left_pos = xoff;
12481 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 12482 if (xoff < 0)
7556890b 12483 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 12484 if (yoff < 0)
7556890b
RS
12485 f->output_data.x->size_hint_flags |= YNegative;
12486 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 12487 }
43bca5d5 12488 x_calc_absolute_position (f);
dc6f92b8
JB
12489
12490 BLOCK_INPUT;
c32cdd9a 12491 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 12492
7556890b
RS
12493 modified_left = f->output_data.x->left_pos;
12494 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
12495#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
12496 this seems to be unnecessary and incorrect. rms, 4/17/97. */
12497 /* It is a mystery why we need to add the border_width here
12498 when the frame is already visible, but experiment says we do. */
aa3ff7c9 12499 if (change_gravity != 0)
4a4cbdd5 12500 {
7556890b
RS
12501 modified_left += f->output_data.x->border_width;
12502 modified_top += f->output_data.x->border_width;
4a4cbdd5 12503 }
e73ec6fa 12504#endif
4a4cbdd5 12505
3afe33e7 12506#ifdef USE_X_TOOLKIT
7556890b 12507 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 12508 modified_left, modified_top);
3afe33e7 12509#else /* not USE_X_TOOLKIT */
334208b7 12510 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 12511 modified_left, modified_top);
3afe33e7 12512#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12513 UNBLOCK_INPUT;
12514}
12515
dc6f92b8 12516
499b1844
GM
12517/* Change the size of frame F's X window to COLS/ROWS in the case F
12518 doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
12519 top-left-corner window gravity for this size change and subsequent
12520 size changes. Otherwise we leave the window gravity unchanged. */
12521
12522static void
12523x_set_window_size_1 (f, change_gravity, cols, rows)
f676886a 12524 struct frame *f;
bc20ebbf 12525 int change_gravity;
b1c884c3 12526 int cols, rows;
dc6f92b8
JB
12527{
12528 int pixelwidth, pixelheight;
80fd1fe2 12529
b1c884c3 12530 check_frame_size (f, &rows, &cols);
7556890b 12531 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
12532 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
12533 ? 0
12534 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 12535 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 12536 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 12537 f->output_data.x->flags_areas_extra
110859fc 12538 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
12539 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
12540 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 12541
7556890b 12542 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 12543 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 12544
334208b7
RS
12545 XSync (FRAME_X_DISPLAY (f), False);
12546 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12547 pixelwidth, pixelheight);
b1c884c3
JB
12548
12549 /* Now, strictly speaking, we can't be sure that this is accurate,
12550 but the window manager will get around to dealing with the size
12551 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
12552 ConfigureNotify event gets here.
12553
12554 We could just not bother storing any of this information here,
12555 and let the ConfigureNotify event set everything up, but that
fddd5ceb 12556 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 12557 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
12558 point in the future when the ConfigureNotify event arrives.
12559
12560 We pass 1 for DELAY since we can't run Lisp code inside of
12561 a BLOCK_INPUT. */
7d1e984f 12562 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
12563 PIXEL_WIDTH (f) = pixelwidth;
12564 PIXEL_HEIGHT (f) = pixelheight;
12565
aee9a898
RS
12566 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
12567 receive in the ConfigureNotify event; if we get what we asked
12568 for, then the event won't cause the screen to become garbaged, so
12569 we have to make sure to do it here. */
12570 SET_FRAME_GARBAGED (f);
12571
12572 XFlush (FRAME_X_DISPLAY (f));
499b1844
GM
12573}
12574
12575
12576/* Call this to change the size of frame F's x-window.
12577 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
12578 for this size change and subsequent size changes.
12579 Otherwise we leave the window gravity unchanged. */
aee9a898 12580
499b1844
GM
12581void
12582x_set_window_size (f, change_gravity, cols, rows)
12583 struct frame *f;
12584 int change_gravity;
12585 int cols, rows;
12586{
12587 BLOCK_INPUT;
12588
12589#ifdef USE_X_TOOLKIT
12590
f1f4d345 12591 if (f->output_data.x->widget != NULL)
499b1844
GM
12592 {
12593 /* The x and y position of the widget is clobbered by the
12594 call to XtSetValues within EmacsFrameSetCharSize.
12595 This is a real kludge, but I don't understand Xt so I can't
12596 figure out a correct fix. Can anyone else tell me? -- rms. */
12597 int xpos = f->output_data.x->widget->core.x;
12598 int ypos = f->output_data.x->widget->core.y;
12599 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
12600 f->output_data.x->widget->core.x = xpos;
12601 f->output_data.x->widget->core.y = ypos;
12602 }
12603 else
12604 x_set_window_size_1 (f, change_gravity, cols, rows);
12605
12606#else /* not USE_X_TOOLKIT */
12607
12608 x_set_window_size_1 (f, change_gravity, cols, rows);
12609
aee9a898
RS
12610#endif /* not USE_X_TOOLKIT */
12611
4d73d038 12612 /* If cursor was outside the new size, mark it as off. */
06a2c219 12613 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 12614
aee9a898
RS
12615 /* Clear out any recollection of where the mouse highlighting was,
12616 since it might be in a place that's outside the new frame size.
12617 Actually checking whether it is outside is a pain in the neck,
12618 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 12619 cancel_mouse_face (f);
dbc4e1c1 12620
dc6f92b8
JB
12621 UNBLOCK_INPUT;
12622}
dc6f92b8 12623\f
d047c4eb 12624/* Mouse warping. */
dc6f92b8 12625
9b378208 12626void
f676886a
JB
12627x_set_mouse_position (f, x, y)
12628 struct frame *f;
dc6f92b8
JB
12629 int x, y;
12630{
12631 int pix_x, pix_y;
12632
7556890b
RS
12633 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
12634 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
12635
12636 if (pix_x < 0) pix_x = 0;
12637 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
12638
12639 if (pix_y < 0) pix_y = 0;
12640 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
12641
12642 BLOCK_INPUT;
dc6f92b8 12643
334208b7
RS
12644 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12645 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
12646 UNBLOCK_INPUT;
12647}
12648
9b378208
RS
12649/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
12650
12651void
12652x_set_mouse_pixel_position (f, pix_x, pix_y)
12653 struct frame *f;
12654 int pix_x, pix_y;
12655{
12656 BLOCK_INPUT;
12657
334208b7
RS
12658 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12659 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
12660 UNBLOCK_INPUT;
12661}
d047c4eb
KH
12662\f
12663/* focus shifting, raising and lowering. */
9b378208 12664
dfcf069d 12665void
f676886a
JB
12666x_focus_on_frame (f)
12667 struct frame *f;
dc6f92b8 12668{
1fb20991 12669#if 0 /* This proves to be unpleasant. */
f676886a 12670 x_raise_frame (f);
1fb20991 12671#endif
6d4238f3
JB
12672#if 0
12673 /* I don't think that the ICCCM allows programs to do things like this
12674 without the interaction of the window manager. Whatever you end up
f676886a 12675 doing with this code, do it to x_unfocus_frame too. */
334208b7 12676 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 12677 RevertToPointerRoot, CurrentTime);
c118dd06 12678#endif /* ! 0 */
dc6f92b8
JB
12679}
12680
dfcf069d 12681void
f676886a
JB
12682x_unfocus_frame (f)
12683 struct frame *f;
dc6f92b8 12684{
6d4238f3 12685#if 0
f676886a 12686 /* Look at the remarks in x_focus_on_frame. */
0f941935 12687 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 12688 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 12689 RevertToPointerRoot, CurrentTime);
c118dd06 12690#endif /* ! 0 */
dc6f92b8
JB
12691}
12692
f676886a 12693/* Raise frame F. */
dc6f92b8 12694
dfcf069d 12695void
f676886a
JB
12696x_raise_frame (f)
12697 struct frame *f;
dc6f92b8 12698{
3a88c238 12699 if (f->async_visible)
dc6f92b8
JB
12700 {
12701 BLOCK_INPUT;
3afe33e7 12702#ifdef USE_X_TOOLKIT
7556890b 12703 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12704#else /* not USE_X_TOOLKIT */
334208b7 12705 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12706#endif /* not USE_X_TOOLKIT */
334208b7 12707 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12708 UNBLOCK_INPUT;
12709 }
12710}
12711
f676886a 12712/* Lower frame F. */
dc6f92b8 12713
dfcf069d 12714void
f676886a
JB
12715x_lower_frame (f)
12716 struct frame *f;
dc6f92b8 12717{
3a88c238 12718 if (f->async_visible)
dc6f92b8
JB
12719 {
12720 BLOCK_INPUT;
3afe33e7 12721#ifdef USE_X_TOOLKIT
7556890b 12722 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12723#else /* not USE_X_TOOLKIT */
334208b7 12724 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12725#endif /* not USE_X_TOOLKIT */
334208b7 12726 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12727 UNBLOCK_INPUT;
12728 }
12729}
12730
dbc4e1c1 12731static void
6b0442dc 12732XTframe_raise_lower (f, raise_flag)
dbc4e1c1 12733 FRAME_PTR f;
6b0442dc 12734 int raise_flag;
dbc4e1c1 12735{
6b0442dc 12736 if (raise_flag)
dbc4e1c1
JB
12737 x_raise_frame (f);
12738 else
12739 x_lower_frame (f);
12740}
d047c4eb
KH
12741\f
12742/* Change of visibility. */
dc6f92b8 12743
9382638d
KH
12744/* This tries to wait until the frame is really visible.
12745 However, if the window manager asks the user where to position
12746 the frame, this will return before the user finishes doing that.
12747 The frame will not actually be visible at that time,
12748 but it will become visible later when the window manager
12749 finishes with it. */
12750
dfcf069d 12751void
f676886a
JB
12752x_make_frame_visible (f)
12753 struct frame *f;
dc6f92b8 12754{
990ba854 12755 Lisp_Object type;
1aa6072f 12756 int original_top, original_left;
31be9251
GM
12757 int retry_count = 2;
12758
12759 retry:
dc6f92b8 12760
dc6f92b8 12761 BLOCK_INPUT;
dc6f92b8 12762
990ba854
RS
12763 type = x_icon_type (f);
12764 if (!NILP (type))
12765 x_bitmap_icon (f, type);
bdcd49ba 12766
f676886a 12767 if (! FRAME_VISIBLE_P (f))
90e65f07 12768 {
1aa6072f
RS
12769 /* We test FRAME_GARBAGED_P here to make sure we don't
12770 call x_set_offset a second time
12771 if we get to x_make_frame_visible a second time
12772 before the window gets really visible. */
12773 if (! FRAME_ICONIFIED_P (f)
12774 && ! f->output_data.x->asked_for_visible)
12775 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
12776
12777 f->output_data.x->asked_for_visible = 1;
12778
90e65f07 12779 if (! EQ (Vx_no_window_manager, Qt))
f676886a 12780 x_wm_set_window_state (f, NormalState);
3afe33e7 12781#ifdef USE_X_TOOLKIT
d7a38a2e 12782 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 12783 XtMapWidget (f->output_data.x->widget);
3afe33e7 12784#else /* not USE_X_TOOLKIT */
7f9c7f94 12785 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12786#endif /* not USE_X_TOOLKIT */
0134a210
RS
12787#if 0 /* This seems to bring back scroll bars in the wrong places
12788 if the window configuration has changed. They seem
12789 to come back ok without this. */
ab648270 12790 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 12791 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 12792#endif
90e65f07 12793 }
dc6f92b8 12794
334208b7 12795 XFlush (FRAME_X_DISPLAY (f));
90e65f07 12796
0dacf791
RS
12797 /* Synchronize to ensure Emacs knows the frame is visible
12798 before we do anything else. We do this loop with input not blocked
12799 so that incoming events are handled. */
12800 {
12801 Lisp_Object frame;
12ce2351 12802 int count;
28c01ffe
RS
12803 /* This must be before UNBLOCK_INPUT
12804 since events that arrive in response to the actions above
12805 will set it when they are handled. */
12806 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
12807
12808 original_left = f->output_data.x->left_pos;
12809 original_top = f->output_data.x->top_pos;
c0a04927
RS
12810
12811 /* This must come after we set COUNT. */
12812 UNBLOCK_INPUT;
12813
2745e6c4 12814 /* We unblock here so that arriving X events are processed. */
1aa6072f 12815
dcb07ae9
RS
12816 /* Now move the window back to where it was "supposed to be".
12817 But don't do it if the gravity is negative.
12818 When the gravity is negative, this uses a position
28c01ffe
RS
12819 that is 3 pixels too low. Perhaps that's really the border width.
12820
12821 Don't do this if the window has never been visible before,
12822 because the window manager may choose the position
12823 and we don't want to override it. */
1aa6072f 12824
4d3f5d9a 12825 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 12826 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 12827 && previously_visible)
1aa6072f 12828 {
2745e6c4
RS
12829 Drawable rootw;
12830 int x, y;
12831 unsigned int width, height, border, depth;
06a2c219 12832
1aa6072f 12833 BLOCK_INPUT;
9829ddba 12834
06a2c219
GM
12835 /* On some window managers (such as FVWM) moving an existing
12836 window, even to the same place, causes the window manager
12837 to introduce an offset. This can cause the window to move
12838 to an unexpected location. Check the geometry (a little
12839 slow here) and then verify that the window is in the right
12840 place. If the window is not in the right place, move it
12841 there, and take the potential window manager hit. */
2745e6c4
RS
12842 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12843 &rootw, &x, &y, &width, &height, &border, &depth);
12844
12845 if (original_left != x || original_top != y)
12846 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12847 original_left, original_top);
12848
1aa6072f
RS
12849 UNBLOCK_INPUT;
12850 }
9829ddba 12851
e0c1aef2 12852 XSETFRAME (frame, f);
c0a04927 12853
12ce2351
GM
12854 /* Wait until the frame is visible. Process X events until a
12855 MapNotify event has been seen, or until we think we won't get a
12856 MapNotify at all.. */
12857 for (count = input_signal_count + 10;
12858 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 12859 {
12ce2351 12860 /* Force processing of queued events. */
334208b7 12861 x_sync (f);
12ce2351
GM
12862
12863 /* Machines that do polling rather than SIGIO have been
12864 observed to go into a busy-wait here. So we'll fake an
12865 alarm signal to let the handler know that there's something
12866 to be read. We used to raise a real alarm, but it seems
12867 that the handler isn't always enabled here. This is
12868 probably a bug. */
8b2f8d4e 12869 if (input_polling_used ())
3b2fa4e6 12870 {
12ce2351
GM
12871 /* It could be confusing if a real alarm arrives while
12872 processing the fake one. Turn it off and let the
12873 handler reset it. */
3e71d8f2 12874 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
12875 int old_poll_suppress_count = poll_suppress_count;
12876 poll_suppress_count = 1;
12877 poll_for_input_1 ();
12878 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 12879 }
12ce2351
GM
12880
12881 /* See if a MapNotify event has been processed. */
12882 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 12883 }
31be9251
GM
12884
12885 /* 2000-09-28: In
12886
12887 (let ((f (selected-frame)))
12888 (iconify-frame f)
12889 (raise-frame f))
12890
12891 the frame is not raised with various window managers on
12892 FreeBSD, Linux and Solaris. It turns out that, for some
12893 unknown reason, the call to XtMapWidget is completely ignored.
12894 Mapping the widget a second time works. */
12895
12896 if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
12897 goto retry;
0dacf791 12898 }
dc6f92b8
JB
12899}
12900
06a2c219 12901/* Change from mapped state to withdrawn state. */
dc6f92b8 12902
d047c4eb
KH
12903/* Make the frame visible (mapped and not iconified). */
12904
dfcf069d 12905void
f676886a
JB
12906x_make_frame_invisible (f)
12907 struct frame *f;
dc6f92b8 12908{
546e6d5b
RS
12909 Window window;
12910
12911#ifdef USE_X_TOOLKIT
12912 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 12913 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
12914#else /* not USE_X_TOOLKIT */
12915 window = FRAME_X_WINDOW (f);
12916#endif /* not USE_X_TOOLKIT */
dc6f92b8 12917
9319ae23 12918 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
12919 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
12920 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 12921
5627c40e 12922#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 12923 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 12924 return;
5627c40e 12925#endif
dc6f92b8
JB
12926
12927 BLOCK_INPUT;
c118dd06 12928
af31d76f
RS
12929 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
12930 that the current position of the window is user-specified, rather than
12931 program-specified, so that when the window is mapped again, it will be
12932 placed at the same location, without forcing the user to position it
12933 by hand again (they have already done that once for this window.) */
c32cdd9a 12934 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 12935
c118dd06
JB
12936#ifdef HAVE_X11R4
12937
334208b7
RS
12938 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
12939 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
12940 {
12941 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12942 error ("Can't notify window manager of window withdrawal");
c118dd06 12943 }
c118dd06 12944#else /* ! defined (HAVE_X11R4) */
16bd92ea 12945
c118dd06 12946 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
12947 if (! EQ (Vx_no_window_manager, Qt))
12948 {
16bd92ea 12949 XEvent unmap;
dc6f92b8 12950
16bd92ea 12951 unmap.xunmap.type = UnmapNotify;
546e6d5b 12952 unmap.xunmap.window = window;
334208b7 12953 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 12954 unmap.xunmap.from_configure = False;
334208b7
RS
12955 if (! XSendEvent (FRAME_X_DISPLAY (f),
12956 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 12957 False,
06a2c219 12958 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
12959 &unmap))
12960 {
12961 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12962 error ("Can't notify window manager of withdrawal");
16bd92ea 12963 }
dc6f92b8
JB
12964 }
12965
16bd92ea 12966 /* Unmap the window ourselves. Cheeky! */
334208b7 12967 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 12968#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 12969
5627c40e
RS
12970 /* We can't distinguish this from iconification
12971 just by the event that we get from the server.
12972 So we can't win using the usual strategy of letting
12973 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
12974 and synchronize with the server to make sure we agree. */
12975 f->visible = 0;
12976 FRAME_ICONIFIED_P (f) = 0;
12977 f->async_visible = 0;
12978 f->async_iconified = 0;
12979
334208b7 12980 x_sync (f);
5627c40e 12981
dc6f92b8
JB
12982 UNBLOCK_INPUT;
12983}
12984
06a2c219 12985/* Change window state from mapped to iconified. */
dc6f92b8 12986
dfcf069d 12987void
f676886a
JB
12988x_iconify_frame (f)
12989 struct frame *f;
dc6f92b8 12990{
3afe33e7 12991 int result;
990ba854 12992 Lisp_Object type;
dc6f92b8 12993
9319ae23 12994 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
12995 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
12996 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 12997
3a88c238 12998 if (f->async_iconified)
dc6f92b8
JB
12999 return;
13000
3afe33e7 13001 BLOCK_INPUT;
546e6d5b 13002
9af3143a
RS
13003 FRAME_SAMPLE_VISIBILITY (f);
13004
990ba854
RS
13005 type = x_icon_type (f);
13006 if (!NILP (type))
13007 x_bitmap_icon (f, type);
bdcd49ba
RS
13008
13009#ifdef USE_X_TOOLKIT
13010
546e6d5b
RS
13011 if (! FRAME_VISIBLE_P (f))
13012 {
13013 if (! EQ (Vx_no_window_manager, Qt))
13014 x_wm_set_window_state (f, IconicState);
13015 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 13016 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
13017 /* The server won't give us any event to indicate
13018 that an invisible frame was changed to an icon,
13019 so we have to record it here. */
13020 f->iconified = 1;
1e6bc770 13021 f->visible = 1;
9cf30a30 13022 f->async_iconified = 1;
1e6bc770 13023 f->async_visible = 0;
546e6d5b
RS
13024 UNBLOCK_INPUT;
13025 return;
13026 }
13027
334208b7 13028 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 13029 XtWindow (f->output_data.x->widget),
334208b7 13030 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
13031 UNBLOCK_INPUT;
13032
13033 if (!result)
546e6d5b 13034 error ("Can't notify window manager of iconification");
3afe33e7
RS
13035
13036 f->async_iconified = 1;
1e6bc770
RS
13037 f->async_visible = 0;
13038
8c002a25
KH
13039
13040 BLOCK_INPUT;
334208b7 13041 XFlush (FRAME_X_DISPLAY (f));
8c002a25 13042 UNBLOCK_INPUT;
3afe33e7
RS
13043#else /* not USE_X_TOOLKIT */
13044
fd13dbb2
RS
13045 /* Make sure the X server knows where the window should be positioned,
13046 in case the user deiconifies with the window manager. */
13047 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 13048 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 13049
16bd92ea
JB
13050 /* Since we don't know which revision of X we're running, we'll use both
13051 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
13052
13053 /* X11R4: send a ClientMessage to the window manager using the
13054 WM_CHANGE_STATE type. */
13055 {
13056 XEvent message;
58769bee 13057
c118dd06 13058 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 13059 message.xclient.type = ClientMessage;
334208b7 13060 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
13061 message.xclient.format = 32;
13062 message.xclient.data.l[0] = IconicState;
13063
334208b7
RS
13064 if (! XSendEvent (FRAME_X_DISPLAY (f),
13065 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
13066 False,
13067 SubstructureRedirectMask | SubstructureNotifyMask,
13068 &message))
dc6f92b8
JB
13069 {
13070 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13071 error ("Can't notify window manager of iconification");
dc6f92b8 13072 }
16bd92ea 13073 }
dc6f92b8 13074
58769bee 13075 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
13076 IconicState. */
13077 x_wm_set_window_state (f, IconicState);
dc6f92b8 13078
a9c00105
RS
13079 if (!FRAME_VISIBLE_P (f))
13080 {
13081 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 13082 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
13083 }
13084
3a88c238 13085 f->async_iconified = 1;
1e6bc770 13086 f->async_visible = 0;
dc6f92b8 13087
334208b7 13088 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 13089 UNBLOCK_INPUT;
8c002a25 13090#endif /* not USE_X_TOOLKIT */
dc6f92b8 13091}
19f71add 13092
d047c4eb 13093\f
19f71add 13094/* Free X resources of frame F. */
dc6f92b8 13095
dfcf069d 13096void
19f71add 13097x_free_frame_resources (f)
f676886a 13098 struct frame *f;
dc6f92b8 13099{
7f9c7f94
RS
13100 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13101
dc6f92b8 13102 BLOCK_INPUT;
c0ff3fab 13103
6186a4a0
RS
13104 /* If a display connection is dead, don't try sending more
13105 commands to the X server. */
19f71add 13106 if (dpyinfo->display)
6186a4a0 13107 {
19f71add 13108 if (f->output_data.x->icon_desc)
6186a4a0 13109 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
19f71add 13110
31f41daf 13111#ifdef HAVE_X_I18N
f5d11644
GM
13112 if (FRAME_XIC (f))
13113 free_frame_xic (f);
31f41daf 13114#endif
19f71add 13115
2662734b 13116 if (FRAME_X_WINDOW (f))
19f71add
GM
13117 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13118
3afe33e7 13119#ifdef USE_X_TOOLKIT
06a2c219 13120 if (f->output_data.x->widget)
30ca89f5
GM
13121 {
13122 XtDestroyWidget (f->output_data.x->widget);
13123 f->output_data.x->widget = NULL;
13124 }
6186a4a0 13125 free_frame_menubar (f);
3afe33e7
RS
13126#endif /* USE_X_TOOLKIT */
13127
3e71d8f2
GM
13128 unload_color (f, f->output_data.x->foreground_pixel);
13129 unload_color (f, f->output_data.x->background_pixel);
13130 unload_color (f, f->output_data.x->cursor_pixel);
13131 unload_color (f, f->output_data.x->cursor_foreground_pixel);
13132 unload_color (f, f->output_data.x->border_pixel);
13133 unload_color (f, f->output_data.x->mouse_pixel);
19f71add 13134
3e71d8f2
GM
13135 if (f->output_data.x->scroll_bar_background_pixel != -1)
13136 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
13137 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
13138 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
7c1bef7a
MB
13139#ifdef USE_TOOLKIT_SCROLL_BARS
13140 /* Scrollbar shadow colors. */
13141 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
13142 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
13143 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
13144 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
13145#endif /* USE_TOOLKIT_SCROLL_BARS */
3e71d8f2
GM
13146 if (f->output_data.x->white_relief.allocated_p)
13147 unload_color (f, f->output_data.x->white_relief.pixel);
13148 if (f->output_data.x->black_relief.allocated_p)
13149 unload_color (f, f->output_data.x->black_relief.pixel);
4ca78676 13150
19f71add
GM
13151 if (FRAME_FACE_CACHE (f))
13152 free_frame_faces (f);
13153
4ca78676 13154 x_free_gcs (f);
6186a4a0
RS
13155 XFlush (FRAME_X_DISPLAY (f));
13156 }
dc6f92b8 13157
df89d8a4 13158 if (f->output_data.x->saved_menu_event)
06a2c219 13159 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 13160
7556890b 13161 xfree (f->output_data.x);
19f71add
GM
13162 f->output_data.x = NULL;
13163
0f941935
KH
13164 if (f == dpyinfo->x_focus_frame)
13165 dpyinfo->x_focus_frame = 0;
13166 if (f == dpyinfo->x_focus_event_frame)
13167 dpyinfo->x_focus_event_frame = 0;
13168 if (f == dpyinfo->x_highlight_frame)
13169 dpyinfo->x_highlight_frame = 0;
c0ff3fab 13170
7f9c7f94 13171 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 13172 {
7f9c7f94
RS
13173 dpyinfo->mouse_face_beg_row
13174 = dpyinfo->mouse_face_beg_col = -1;
13175 dpyinfo->mouse_face_end_row
13176 = dpyinfo->mouse_face_end_col = -1;
13177 dpyinfo->mouse_face_window = Qnil;
21323706
RS
13178 dpyinfo->mouse_face_deferred_gc = 0;
13179 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 13180 }
0134a210 13181
c0ff3fab 13182 UNBLOCK_INPUT;
dc6f92b8 13183}
19f71add
GM
13184
13185
13186/* Destroy the X window of frame F. */
13187
13188void
13189x_destroy_window (f)
13190 struct frame *f;
13191{
13192 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13193
13194 /* If a display connection is dead, don't try sending more
13195 commands to the X server. */
13196 if (dpyinfo->display != 0)
13197 x_free_frame_resources (f);
13198
13199 dpyinfo->reference_count--;
13200}
13201
dc6f92b8 13202\f
f451eb13
JB
13203/* Setting window manager hints. */
13204
af31d76f
RS
13205/* Set the normal size hints for the window manager, for frame F.
13206 FLAGS is the flags word to use--or 0 meaning preserve the flags
13207 that the window now has.
13208 If USER_POSITION is nonzero, we set the USPosition
13209 flag (this is useful when FLAGS is 0). */
6dba1858 13210
dfcf069d 13211void
af31d76f 13212x_wm_set_size_hint (f, flags, user_position)
f676886a 13213 struct frame *f;
af31d76f
RS
13214 long flags;
13215 int user_position;
dc6f92b8
JB
13216{
13217 XSizeHints size_hints;
3afe33e7
RS
13218
13219#ifdef USE_X_TOOLKIT
7e4f2521
FP
13220 Arg al[2];
13221 int ac = 0;
13222 Dimension widget_width, widget_height;
7556890b 13223 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 13224#else /* not USE_X_TOOLKIT */
c118dd06 13225 Window window = FRAME_X_WINDOW (f);
3afe33e7 13226#endif /* not USE_X_TOOLKIT */
dc6f92b8 13227
b72a58fd
RS
13228 /* Setting PMaxSize caused various problems. */
13229 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 13230
7556890b
RS
13231 size_hints.x = f->output_data.x->left_pos;
13232 size_hints.y = f->output_data.x->top_pos;
7553a6b7 13233
7e4f2521
FP
13234#ifdef USE_X_TOOLKIT
13235 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
13236 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 13237 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
13238 size_hints.height = widget_height;
13239 size_hints.width = widget_width;
13240#else /* not USE_X_TOOLKIT */
f676886a
JB
13241 size_hints.height = PIXEL_HEIGHT (f);
13242 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 13243#endif /* not USE_X_TOOLKIT */
7553a6b7 13244
7556890b
RS
13245 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
13246 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
13247 size_hints.max_width
13248 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
13249 size_hints.max_height
13250 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 13251
d067ea8b
KH
13252 /* Calculate the base and minimum sizes.
13253
13254 (When we use the X toolkit, we don't do it here.
13255 Instead we copy the values that the widgets are using, below.) */
13256#ifndef USE_X_TOOLKIT
b1c884c3 13257 {
b0342f17 13258 int base_width, base_height;
0134a210 13259 int min_rows = 0, min_cols = 0;
b0342f17 13260
f451eb13
JB
13261 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
13262 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 13263
0134a210 13264 check_frame_size (f, &min_rows, &min_cols);
b0342f17 13265
0134a210
RS
13266 /* The window manager uses the base width hints to calculate the
13267 current number of rows and columns in the frame while
13268 resizing; min_width and min_height aren't useful for this
13269 purpose, since they might not give the dimensions for a
13270 zero-row, zero-column frame.
58769bee 13271
0134a210
RS
13272 We use the base_width and base_height members if we have
13273 them; otherwise, we set the min_width and min_height members
13274 to the size for a zero x zero frame. */
b0342f17
JB
13275
13276#ifdef HAVE_X11R4
0134a210
RS
13277 size_hints.flags |= PBaseSize;
13278 size_hints.base_width = base_width;
13279 size_hints.base_height = base_height;
13280 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
13281 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 13282#else
0134a210
RS
13283 size_hints.min_width = base_width;
13284 size_hints.min_height = base_height;
b0342f17 13285#endif
b1c884c3 13286 }
dc6f92b8 13287
d067ea8b 13288 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 13289 if (flags)
dc6f92b8 13290 {
d067ea8b
KH
13291 size_hints.flags |= flags;
13292 goto no_read;
13293 }
13294#endif /* not USE_X_TOOLKIT */
13295
13296 {
13297 XSizeHints hints; /* Sometimes I hate X Windows... */
13298 long supplied_return;
13299 int value;
af31d76f
RS
13300
13301#ifdef HAVE_X11R4
d067ea8b
KH
13302 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
13303 &supplied_return);
af31d76f 13304#else
d067ea8b 13305 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 13306#endif
58769bee 13307
d067ea8b
KH
13308#ifdef USE_X_TOOLKIT
13309 size_hints.base_height = hints.base_height;
13310 size_hints.base_width = hints.base_width;
13311 size_hints.min_height = hints.min_height;
13312 size_hints.min_width = hints.min_width;
13313#endif
13314
13315 if (flags)
13316 size_hints.flags |= flags;
13317 else
13318 {
13319 if (value == 0)
13320 hints.flags = 0;
13321 if (hints.flags & PSize)
13322 size_hints.flags |= PSize;
13323 if (hints.flags & PPosition)
13324 size_hints.flags |= PPosition;
13325 if (hints.flags & USPosition)
13326 size_hints.flags |= USPosition;
13327 if (hints.flags & USSize)
13328 size_hints.flags |= USSize;
13329 }
13330 }
13331
06a2c219 13332#ifndef USE_X_TOOLKIT
d067ea8b 13333 no_read:
06a2c219 13334#endif
0134a210 13335
af31d76f 13336#ifdef PWinGravity
7556890b 13337 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 13338 size_hints.flags |= PWinGravity;
dc05a16b 13339
af31d76f 13340 if (user_position)
6dba1858 13341 {
af31d76f
RS
13342 size_hints.flags &= ~ PPosition;
13343 size_hints.flags |= USPosition;
6dba1858 13344 }
2554751d 13345#endif /* PWinGravity */
6dba1858 13346
b0342f17 13347#ifdef HAVE_X11R4
334208b7 13348 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13349#else
334208b7 13350 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13351#endif
dc6f92b8
JB
13352}
13353
13354/* Used for IconicState or NormalState */
06a2c219 13355
dfcf069d 13356void
f676886a
JB
13357x_wm_set_window_state (f, state)
13358 struct frame *f;
dc6f92b8
JB
13359 int state;
13360{
3afe33e7 13361#ifdef USE_X_TOOLKIT
546e6d5b
RS
13362 Arg al[1];
13363
13364 XtSetArg (al[0], XtNinitialState, state);
7556890b 13365 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 13366#else /* not USE_X_TOOLKIT */
c118dd06 13367 Window window = FRAME_X_WINDOW (f);
dc6f92b8 13368
7556890b
RS
13369 f->output_data.x->wm_hints.flags |= StateHint;
13370 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 13371
7556890b 13372 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 13373#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13374}
13375
dfcf069d 13376void
7f2ae036 13377x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 13378 struct frame *f;
7f2ae036 13379 int pixmap_id;
dc6f92b8 13380{
d2bd6bc4
RS
13381 Pixmap icon_pixmap;
13382
06a2c219 13383#ifndef USE_X_TOOLKIT
c118dd06 13384 Window window = FRAME_X_WINDOW (f);
75231bad 13385#endif
dc6f92b8 13386
7f2ae036 13387 if (pixmap_id > 0)
dbc4e1c1 13388 {
d2bd6bc4 13389 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 13390 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
13391 }
13392 else
68568555
RS
13393 {
13394 /* It seems there is no way to turn off use of an icon pixmap.
13395 The following line does it, only if no icon has yet been created,
13396 for some window managers. But with mwm it crashes.
13397 Some people say it should clear the IconPixmapHint bit in this case,
13398 but that doesn't work, and the X consortium said it isn't the
13399 right thing at all. Since there is no way to win,
13400 best to explicitly give up. */
13401#if 0
13402 f->output_data.x->wm_hints.icon_pixmap = None;
13403#else
13404 return;
13405#endif
13406 }
b1c884c3 13407
d2bd6bc4
RS
13408#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
13409
13410 {
13411 Arg al[1];
13412 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
13413 XtSetValues (f->output_data.x->widget, al, 1);
13414 }
13415
13416#else /* not USE_X_TOOLKIT */
13417
7556890b
RS
13418 f->output_data.x->wm_hints.flags |= IconPixmapHint;
13419 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
13420
13421#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13422}
13423
dfcf069d 13424void
f676886a
JB
13425x_wm_set_icon_position (f, icon_x, icon_y)
13426 struct frame *f;
dc6f92b8
JB
13427 int icon_x, icon_y;
13428{
75231bad 13429#ifdef USE_X_TOOLKIT
7556890b 13430 Window window = XtWindow (f->output_data.x->widget);
75231bad 13431#else
c118dd06 13432 Window window = FRAME_X_WINDOW (f);
75231bad 13433#endif
dc6f92b8 13434
7556890b
RS
13435 f->output_data.x->wm_hints.flags |= IconPositionHint;
13436 f->output_data.x->wm_hints.icon_x = icon_x;
13437 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 13438
7556890b 13439 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
13440}
13441
13442\f
06a2c219
GM
13443/***********************************************************************
13444 Fonts
13445 ***********************************************************************/
dc43ef94
KH
13446
13447/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 13448
dc43ef94
KH
13449struct font_info *
13450x_get_font_info (f, font_idx)
13451 FRAME_PTR f;
13452 int font_idx;
13453{
13454 return (FRAME_X_FONT_TABLE (f) + font_idx);
13455}
13456
13457
9c11f79e
GM
13458/* Return a list of names of available fonts matching PATTERN on frame F.
13459
13460 If SIZE is > 0, it is the size (maximum bounds width) of fonts
13461 to be listed.
13462
13463 SIZE < 0 means include scalable fonts.
13464
13465 Frame F null means we have not yet created any frame on X, and
13466 consult the first display in x_display_list. MAXNAMES sets a limit
13467 on how many fonts to match. */
dc43ef94
KH
13468
13469Lisp_Object
13470x_list_fonts (f, pattern, size, maxnames)
9c11f79e 13471 struct frame *f;
dc43ef94
KH
13472 Lisp_Object pattern;
13473 int size;
13474 int maxnames;
13475{
06a2c219
GM
13476 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
13477 Lisp_Object tem, second_best;
9c11f79e
GM
13478 struct x_display_info *dpyinfo
13479 = f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
13480 Display *dpy = dpyinfo->display;
09c6077f 13481 int try_XLoadQueryFont = 0;
53ca4657 13482 int count;
9c11f79e
GM
13483 int allow_scalable_fonts_p = 0;
13484
13485 if (size < 0)
13486 {
13487 allow_scalable_fonts_p = 1;
13488 size = 0;
13489 }
dc43ef94 13490
6b0efe73 13491 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
13492 if (NILP (patterns))
13493 patterns = Fcons (pattern, Qnil);
81ba44e5 13494
09c6077f
KH
13495 if (maxnames == 1 && !size)
13496 /* We can return any single font matching PATTERN. */
13497 try_XLoadQueryFont = 1;
9a32686f 13498
8e713be6 13499 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 13500 {
dc43ef94 13501 int num_fonts;
3e71d8f2 13502 char **names = NULL;
dc43ef94 13503
8e713be6 13504 pattern = XCAR (patterns);
536f4067
RS
13505 /* See if we cached the result for this particular query.
13506 The cache is an alist of the form:
9c11f79e
GM
13507 ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */
13508 tem = XCDR (dpyinfo->name_list_element);
13509 key = Fcons (Fcons (pattern, make_number (maxnames)),
13510 allow_scalable_fonts_p ? Qt : Qnil);
13511 list = Fassoc (key, tem);
13512 if (!NILP (list))
b5210ea7
KH
13513 {
13514 list = Fcdr_safe (list);
13515 /* We have a cashed list. Don't have to get the list again. */
13516 goto label_cached;
13517 }
13518
13519 /* At first, put PATTERN in the cache. */
09c6077f 13520
dc43ef94 13521 BLOCK_INPUT;
17d85edc
KH
13522 count = x_catch_errors (dpy);
13523
09c6077f
KH
13524 if (try_XLoadQueryFont)
13525 {
13526 XFontStruct *font;
13527 unsigned long value;
13528
13529 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
13530 if (x_had_errors_p (dpy))
13531 {
13532 /* This error is perhaps due to insufficient memory on X
13533 server. Let's just ignore it. */
13534 font = NULL;
13535 x_clear_errors (dpy);
13536 }
13537
09c6077f
KH
13538 if (font
13539 && XGetFontProperty (font, XA_FONT, &value))
13540 {
13541 char *name = (char *) XGetAtomName (dpy, (Atom) value);
13542 int len = strlen (name);
01c752b5 13543 char *tmp;
09c6077f 13544
6f6512e8
KH
13545 /* If DXPC (a Differential X Protocol Compressor)
13546 Ver.3.7 is running, XGetAtomName will return null
13547 string. We must avoid such a name. */
13548 if (len == 0)
13549 try_XLoadQueryFont = 0;
13550 else
13551 {
13552 num_fonts = 1;
13553 names = (char **) alloca (sizeof (char *));
13554 /* Some systems only allow alloca assigned to a
13555 simple var. */
13556 tmp = (char *) alloca (len + 1); names[0] = tmp;
13557 bcopy (name, names[0], len + 1);
13558 XFree (name);
13559 }
09c6077f
KH
13560 }
13561 else
13562 try_XLoadQueryFont = 0;
a083fd23
RS
13563
13564 if (font)
13565 XFreeFont (dpy, font);
09c6077f
KH
13566 }
13567
13568 if (!try_XLoadQueryFont)
17d85edc
KH
13569 {
13570 /* We try at least 10 fonts because XListFonts will return
13571 auto-scaled fonts at the head. */
13572 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
13573 &num_fonts);
13574 if (x_had_errors_p (dpy))
13575 {
13576 /* This error is perhaps due to insufficient memory on X
13577 server. Let's just ignore it. */
13578 names = NULL;
13579 x_clear_errors (dpy);
13580 }
13581 }
13582
13583 x_uncatch_errors (dpy, count);
dc43ef94
KH
13584 UNBLOCK_INPUT;
13585
13586 if (names)
13587 {
13588 int i;
dc43ef94
KH
13589
13590 /* Make a list of all the fonts we got back.
13591 Store that in the font cache for the display. */
13592 for (i = 0; i < num_fonts; i++)
13593 {
06a2c219 13594 int width = 0;
dc43ef94 13595 char *p = names[i];
06a2c219
GM
13596 int average_width = -1, dashes = 0;
13597
dc43ef94 13598 /* Count the number of dashes in NAMES[I]. If there are
9c11f79e
GM
13599 14 dashes, and the field value following 12th dash
13600 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
13601 is usually too ugly to be used for editing. Let's
13602 ignore it. */
dc43ef94
KH
13603 while (*p)
13604 if (*p++ == '-')
13605 {
13606 dashes++;
13607 if (dashes == 7) /* PIXEL_SIZE field */
13608 width = atoi (p);
13609 else if (dashes == 12) /* AVERAGE_WIDTH field */
13610 average_width = atoi (p);
13611 }
9c11f79e
GM
13612
13613 if (allow_scalable_fonts_p
13614 || dashes < 14 || average_width != 0)
dc43ef94
KH
13615 {
13616 tem = build_string (names[i]);
13617 if (NILP (Fassoc (tem, list)))
13618 {
13619 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
13620 && ((fast_c_string_match_ignore_case
13621 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
13622 >= 0))
13623 /* We can set the value of PIXEL_SIZE to the
b5210ea7 13624 width of this font. */
dc43ef94
KH
13625 list = Fcons (Fcons (tem, make_number (width)), list);
13626 else
13627 /* For the moment, width is not known. */
13628 list = Fcons (Fcons (tem, Qnil), list);
13629 }
13630 }
13631 }
e38f4136 13632
09c6077f 13633 if (!try_XLoadQueryFont)
e38f4136
GM
13634 {
13635 BLOCK_INPUT;
13636 XFreeFontNames (names);
13637 UNBLOCK_INPUT;
13638 }
dc43ef94
KH
13639 }
13640
b5210ea7 13641 /* Now store the result in the cache. */
f3fbd155
KR
13642 XSETCDR (dpyinfo->name_list_element,
13643 Fcons (Fcons (key, list), XCDR (dpyinfo->name_list_element)));
dc43ef94 13644
b5210ea7
KH
13645 label_cached:
13646 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 13647
b5210ea7
KH
13648 newlist = second_best = Qnil;
13649 /* Make a list of the fonts that have the right width. */
8e713be6 13650 for (; CONSP (list); list = XCDR (list))
b5210ea7 13651 {
536f4067
RS
13652 int found_size;
13653
8e713be6 13654 tem = XCAR (list);
dc43ef94 13655
8e713be6 13656 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
13657 continue;
13658 if (!size)
13659 {
8e713be6 13660 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
13661 continue;
13662 }
dc43ef94 13663
8e713be6 13664 if (!INTEGERP (XCDR (tem)))
dc43ef94 13665 {
b5210ea7 13666 /* Since we have not yet known the size of this font, we
9c11f79e 13667 must try slow function call XLoadQueryFont. */
dc43ef94
KH
13668 XFontStruct *thisinfo;
13669
13670 BLOCK_INPUT;
17d85edc 13671 count = x_catch_errors (dpy);
dc43ef94 13672 thisinfo = XLoadQueryFont (dpy,
8e713be6 13673 XSTRING (XCAR (tem))->data);
17d85edc
KH
13674 if (x_had_errors_p (dpy))
13675 {
13676 /* This error is perhaps due to insufficient memory on X
13677 server. Let's just ignore it. */
13678 thisinfo = NULL;
13679 x_clear_errors (dpy);
13680 }
13681 x_uncatch_errors (dpy, count);
dc43ef94
KH
13682 UNBLOCK_INPUT;
13683
13684 if (thisinfo)
13685 {
f3fbd155
KR
13686 XSETCDR (tem,
13687 (thisinfo->min_bounds.width == 0
13688 ? make_number (0)
13689 : make_number (thisinfo->max_bounds.width)));
e38f4136 13690 BLOCK_INPUT;
dc43ef94 13691 XFreeFont (dpy, thisinfo);
e38f4136 13692 UNBLOCK_INPUT;
dc43ef94
KH
13693 }
13694 else
b5210ea7 13695 /* For unknown reason, the previous call of XListFont had
06a2c219 13696 returned a font which can't be opened. Record the size
b5210ea7 13697 as 0 not to try to open it again. */
f3fbd155 13698 XSETCDR (tem, make_number (0));
dc43ef94 13699 }
536f4067 13700
8e713be6 13701 found_size = XINT (XCDR (tem));
536f4067 13702 if (found_size == size)
8e713be6 13703 newlist = Fcons (XCAR (tem), newlist);
536f4067 13704 else if (found_size > 0)
b5210ea7 13705 {
536f4067 13706 if (NILP (second_best))
b5210ea7 13707 second_best = tem;
536f4067
RS
13708 else if (found_size < size)
13709 {
8e713be6
KR
13710 if (XINT (XCDR (second_best)) > size
13711 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
13712 second_best = tem;
13713 }
13714 else
13715 {
8e713be6
KR
13716 if (XINT (XCDR (second_best)) > size
13717 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
13718 second_best = tem;
13719 }
b5210ea7
KH
13720 }
13721 }
13722 if (!NILP (newlist))
13723 break;
13724 else if (!NILP (second_best))
13725 {
8e713be6 13726 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 13727 break;
dc43ef94 13728 }
dc43ef94
KH
13729 }
13730
13731 return newlist;
13732}
13733
06a2c219
GM
13734
13735#if GLYPH_DEBUG
13736
13737/* Check that FONT is valid on frame F. It is if it can be found in F's
13738 font table. */
13739
13740static void
13741x_check_font (f, font)
13742 struct frame *f;
13743 XFontStruct *font;
13744{
13745 int i;
13746 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13747
13748 xassert (font != NULL);
13749
13750 for (i = 0; i < dpyinfo->n_fonts; i++)
13751 if (dpyinfo->font_table[i].name
13752 && font == dpyinfo->font_table[i].font)
13753 break;
13754
13755 xassert (i < dpyinfo->n_fonts);
13756}
13757
13758#endif /* GLYPH_DEBUG != 0 */
13759
13760/* Set *W to the minimum width, *H to the minimum font height of FONT.
13761 Note: There are (broken) X fonts out there with invalid XFontStruct
13762 min_bounds contents. For example, handa@etl.go.jp reports that
13763 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
13764 have font->min_bounds.width == 0. */
13765
13766static INLINE void
13767x_font_min_bounds (font, w, h)
13768 XFontStruct *font;
13769 int *w, *h;
13770{
13771 *h = FONT_HEIGHT (font);
13772 *w = font->min_bounds.width;
13773
13774 /* Try to handle the case where FONT->min_bounds has invalid
13775 contents. Since the only font known to have invalid min_bounds
13776 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
13777 if (*w <= 0)
13778 *w = font->max_bounds.width;
13779}
13780
13781
13782/* Compute the smallest character width and smallest font height over
13783 all fonts available on frame F. Set the members smallest_char_width
13784 and smallest_font_height in F's x_display_info structure to
13785 the values computed. Value is non-zero if smallest_font_height or
13786 smallest_char_width become smaller than they were before. */
13787
13788static int
13789x_compute_min_glyph_bounds (f)
13790 struct frame *f;
13791{
13792 int i;
13793 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13794 XFontStruct *font;
13795 int old_width = dpyinfo->smallest_char_width;
13796 int old_height = dpyinfo->smallest_font_height;
13797
13798 dpyinfo->smallest_font_height = 100000;
13799 dpyinfo->smallest_char_width = 100000;
13800
13801 for (i = 0; i < dpyinfo->n_fonts; ++i)
13802 if (dpyinfo->font_table[i].name)
13803 {
13804 struct font_info *fontp = dpyinfo->font_table + i;
13805 int w, h;
13806
13807 font = (XFontStruct *) fontp->font;
13808 xassert (font != (XFontStruct *) ~0);
13809 x_font_min_bounds (font, &w, &h);
13810
13811 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
13812 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
13813 }
13814
13815 xassert (dpyinfo->smallest_char_width > 0
13816 && dpyinfo->smallest_font_height > 0);
13817
13818 return (dpyinfo->n_fonts == 1
13819 || dpyinfo->smallest_char_width < old_width
13820 || dpyinfo->smallest_font_height < old_height);
13821}
13822
13823
dc43ef94
KH
13824/* Load font named FONTNAME of the size SIZE for frame F, and return a
13825 pointer to the structure font_info while allocating it dynamically.
13826 If SIZE is 0, load any size of font.
13827 If loading is failed, return NULL. */
13828
13829struct font_info *
13830x_load_font (f, fontname, size)
13831 struct frame *f;
13832 register char *fontname;
13833 int size;
13834{
13835 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13836 Lisp_Object font_names;
d645aaa4 13837 int count;
dc43ef94
KH
13838
13839 /* Get a list of all the fonts that match this name. Once we
13840 have a list of matching fonts, we compare them against the fonts
13841 we already have by comparing names. */
09c6077f 13842 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
13843
13844 if (!NILP (font_names))
13845 {
13846 Lisp_Object tail;
13847 int i;
13848
13849 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 13850 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
13851 if (dpyinfo->font_table[i].name
13852 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 13853 XSTRING (XCAR (tail))->data)
06a2c219 13854 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 13855 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
13856 return (dpyinfo->font_table + i);
13857 }
13858
13859 /* Load the font and add it to the table. */
13860 {
13861 char *full_name;
13862 XFontStruct *font;
13863 struct font_info *fontp;
13864 unsigned long value;
06a2c219 13865 int i;
dc43ef94 13866
2da424f1
KH
13867 /* If we have found fonts by x_list_font, load one of them. If
13868 not, we still try to load a font by the name given as FONTNAME
13869 because XListFonts (called in x_list_font) of some X server has
13870 a bug of not finding a font even if the font surely exists and
13871 is loadable by XLoadQueryFont. */
e1d6d5b9 13872 if (size > 0 && !NILP (font_names))
8e713be6 13873 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
13874
13875 BLOCK_INPUT;
d645aaa4 13876 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 13877 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
13878 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
13879 {
13880 /* This error is perhaps due to insufficient memory on X
13881 server. Let's just ignore it. */
13882 font = NULL;
13883 x_clear_errors (FRAME_X_DISPLAY (f));
13884 }
13885 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 13886 UNBLOCK_INPUT;
b5210ea7 13887 if (!font)
dc43ef94
KH
13888 return NULL;
13889
06a2c219
GM
13890 /* Find a free slot in the font table. */
13891 for (i = 0; i < dpyinfo->n_fonts; ++i)
13892 if (dpyinfo->font_table[i].name == NULL)
13893 break;
13894
13895 /* If no free slot found, maybe enlarge the font table. */
13896 if (i == dpyinfo->n_fonts
13897 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 13898 {
06a2c219
GM
13899 int sz;
13900 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
13901 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 13902 dpyinfo->font_table
06a2c219 13903 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
13904 }
13905
06a2c219
GM
13906 fontp = dpyinfo->font_table + i;
13907 if (i == dpyinfo->n_fonts)
13908 ++dpyinfo->n_fonts;
dc43ef94
KH
13909
13910 /* Now fill in the slots of *FONTP. */
13911 BLOCK_INPUT;
13912 fontp->font = font;
06a2c219 13913 fontp->font_idx = i;
dc43ef94
KH
13914 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
13915 bcopy (fontname, fontp->name, strlen (fontname) + 1);
13916
13917 /* Try to get the full name of FONT. Put it in FULL_NAME. */
13918 full_name = 0;
13919 if (XGetFontProperty (font, XA_FONT, &value))
13920 {
13921 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
13922 char *p = name;
13923 int dashes = 0;
13924
13925 /* Count the number of dashes in the "full name".
13926 If it is too few, this isn't really the font's full name,
13927 so don't use it.
13928 In X11R4, the fonts did not come with their canonical names
13929 stored in them. */
13930 while (*p)
13931 {
13932 if (*p == '-')
13933 dashes++;
13934 p++;
13935 }
13936
13937 if (dashes >= 13)
13938 {
13939 full_name = (char *) xmalloc (p - name + 1);
13940 bcopy (name, full_name, p - name + 1);
13941 }
13942
13943 XFree (name);
13944 }
13945
13946 if (full_name != 0)
13947 fontp->full_name = full_name;
13948 else
13949 fontp->full_name = fontp->name;
13950
13951 fontp->size = font->max_bounds.width;
d5749adb 13952 fontp->height = FONT_HEIGHT (font);
dc43ef94 13953
2da424f1
KH
13954 if (NILP (font_names))
13955 {
13956 /* We come here because of a bug of XListFonts mentioned at
13957 the head of this block. Let's store this information in
13958 the cache for x_list_fonts. */
13959 Lisp_Object lispy_name = build_string (fontname);
13960 Lisp_Object lispy_full_name = build_string (fontp->full_name);
9c11f79e
GM
13961 Lisp_Object key = Fcons (Fcons (lispy_name, make_number (256)),
13962 Qnil);
2da424f1 13963
f3fbd155
KR
13964 XSETCDR (dpyinfo->name_list_element,
13965 Fcons (Fcons (key,
13966 Fcons (Fcons (lispy_full_name,
13967 make_number (fontp->size)),
13968 Qnil)),
13969 XCDR (dpyinfo->name_list_element)));
2da424f1 13970 if (full_name)
9c11f79e
GM
13971 {
13972 key = Fcons (Fcons (lispy_full_name, make_number (256)),
13973 Qnil);
f3fbd155
KR
13974 XSETCDR (dpyinfo->name_list_element,
13975 Fcons (Fcons (key,
13976 Fcons (Fcons (lispy_full_name,
13977 make_number (fontp->size)),
13978 Qnil)),
13979 XCDR (dpyinfo->name_list_element)));
9c11f79e 13980 }
2da424f1
KH
13981 }
13982
dc43ef94
KH
13983 /* The slot `encoding' specifies how to map a character
13984 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
13985 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
13986 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 13987 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 13988 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
13989 which is never used by any charset. If mapping can't be
13990 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
13991 fontp->encoding[1]
13992 = (font->max_byte1 == 0
13993 /* 1-byte font */
13994 ? (font->min_char_or_byte2 < 0x80
13995 ? (font->max_char_or_byte2 < 0x80
13996 ? 0 /* 0x20..0x7F */
8ff102bd 13997 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
13998 : 1) /* 0xA0..0xFF */
13999 /* 2-byte font */
14000 : (font->min_byte1 < 0x80
14001 ? (font->max_byte1 < 0x80
14002 ? (font->min_char_or_byte2 < 0x80
14003 ? (font->max_char_or_byte2 < 0x80
14004 ? 0 /* 0x2020..0x7F7F */
8ff102bd 14005 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 14006 : 3) /* 0x20A0..0x7FFF */
8ff102bd 14007 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
14008 : (font->min_char_or_byte2 < 0x80
14009 ? (font->max_char_or_byte2 < 0x80
14010 ? 2 /* 0xA020..0xFF7F */
8ff102bd 14011 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
14012 : 1))); /* 0xA0A0..0xFFFF */
14013
14014 fontp->baseline_offset
14015 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
14016 ? (long) value : 0);
14017 fontp->relative_compose
14018 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
14019 ? (long) value : 0);
f78798df
KH
14020 fontp->default_ascent
14021 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
14022 ? (long) value : 0);
dc43ef94 14023
06a2c219
GM
14024 /* Set global flag fonts_changed_p to non-zero if the font loaded
14025 has a character with a smaller width than any other character
14026 before, or if the font loaded has a smalle>r height than any
14027 other font loaded before. If this happens, it will make a
14028 glyph matrix reallocation necessary. */
14029 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 14030 UNBLOCK_INPUT;
dc43ef94
KH
14031 return fontp;
14032 }
14033}
14034
06a2c219
GM
14035
14036/* Return a pointer to struct font_info of a font named FONTNAME for
14037 frame F. If no such font is loaded, return NULL. */
14038
dc43ef94
KH
14039struct font_info *
14040x_query_font (f, fontname)
14041 struct frame *f;
14042 register char *fontname;
14043{
14044 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14045 int i;
14046
14047 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
14048 if (dpyinfo->font_table[i].name
14049 && (!strcmp (dpyinfo->font_table[i].name, fontname)
14050 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
14051 return (dpyinfo->font_table + i);
14052 return NULL;
14053}
14054
06a2c219
GM
14055
14056/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
14057 `encoder' of the structure. */
14058
14059void
14060x_find_ccl_program (fontp)
14061 struct font_info *fontp;
14062{
a42f54e6 14063 Lisp_Object list, elt;
a6582676 14064
f9b5db02 14065 elt = Qnil;
8e713be6 14066 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 14067 {
8e713be6 14068 elt = XCAR (list);
a6582676 14069 if (CONSP (elt)
8e713be6 14070 && STRINGP (XCAR (elt))
9f2feff6
KH
14071 && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
14072 >= 0)
14073 || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
14074 >= 0)))
a42f54e6
KH
14075 break;
14076 }
f9b5db02 14077
a42f54e6
KH
14078 if (! NILP (list))
14079 {
d27f8ca7
KH
14080 struct ccl_program *ccl
14081 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 14082
8e713be6 14083 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
14084 xfree (ccl);
14085 else
14086 fontp->font_encoder = ccl;
a6582676
KH
14087 }
14088}
14089
06a2c219 14090
dc43ef94 14091\f
06a2c219
GM
14092/***********************************************************************
14093 Initialization
14094 ***********************************************************************/
f451eb13 14095
3afe33e7
RS
14096#ifdef USE_X_TOOLKIT
14097static XrmOptionDescRec emacs_options[] = {
14098 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
14099 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
14100
14101 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
14102 XrmoptionSepArg, NULL},
14103 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
14104
14105 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14106 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14107 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14108 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14109 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14110 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
14111 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
14112};
14113#endif /* USE_X_TOOLKIT */
14114
7a13e894
RS
14115static int x_initialized;
14116
29b38361
KH
14117#ifdef MULTI_KBOARD
14118/* Test whether two display-name strings agree up to the dot that separates
14119 the screen number from the server number. */
14120static int
14121same_x_server (name1, name2)
14122 char *name1, *name2;
14123{
14124 int seen_colon = 0;
cf591cc1
RS
14125 unsigned char *system_name = XSTRING (Vsystem_name)->data;
14126 int system_name_length = strlen (system_name);
14127 int length_until_period = 0;
14128
14129 while (system_name[length_until_period] != 0
14130 && system_name[length_until_period] != '.')
14131 length_until_period++;
14132
14133 /* Treat `unix' like an empty host name. */
14134 if (! strncmp (name1, "unix:", 5))
14135 name1 += 4;
14136 if (! strncmp (name2, "unix:", 5))
14137 name2 += 4;
14138 /* Treat this host's name like an empty host name. */
14139 if (! strncmp (name1, system_name, system_name_length)
14140 && name1[system_name_length] == ':')
14141 name1 += system_name_length;
14142 if (! strncmp (name2, system_name, system_name_length)
14143 && name2[system_name_length] == ':')
14144 name2 += system_name_length;
14145 /* Treat this host's domainless name like an empty host name. */
14146 if (! strncmp (name1, system_name, length_until_period)
14147 && name1[length_until_period] == ':')
14148 name1 += length_until_period;
14149 if (! strncmp (name2, system_name, length_until_period)
14150 && name2[length_until_period] == ':')
14151 name2 += length_until_period;
14152
29b38361
KH
14153 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
14154 {
14155 if (*name1 == ':')
14156 seen_colon++;
14157 if (seen_colon && *name1 == '.')
14158 return 1;
14159 }
14160 return (seen_colon
14161 && (*name1 == '.' || *name1 == '\0')
14162 && (*name2 == '.' || *name2 == '\0'));
14163}
14164#endif
14165
334208b7 14166struct x_display_info *
1f8255f2 14167x_term_init (display_name, xrm_option, resource_name)
334208b7 14168 Lisp_Object display_name;
1f8255f2
RS
14169 char *xrm_option;
14170 char *resource_name;
dc6f92b8 14171{
334208b7 14172 int connection;
7a13e894 14173 Display *dpy;
334208b7
RS
14174 struct x_display_info *dpyinfo;
14175 XrmDatabase xrdb;
14176
60439948
KH
14177 BLOCK_INPUT;
14178
7a13e894
RS
14179 if (!x_initialized)
14180 {
14181 x_initialize ();
14182 x_initialized = 1;
14183 }
dc6f92b8 14184
3afe33e7 14185#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
14186 /* weiner@footloose.sps.mot.com reports that this causes
14187 errors with X11R5:
14188 X protocol error: BadAtom (invalid Atom parameter)
14189 on protocol request 18skiloaf.
14190 So let's not use it until R6. */
14191#ifdef HAVE_X11XTR6
bdcd49ba
RS
14192 XtSetLanguageProc (NULL, NULL, NULL);
14193#endif
14194
7f9c7f94
RS
14195 {
14196 int argc = 0;
14197 char *argv[3];
14198
14199 argv[0] = "";
14200 argc = 1;
14201 if (xrm_option)
14202 {
14203 argv[argc++] = "-xrm";
14204 argv[argc++] = xrm_option;
14205 }
14206 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
14207 resource_name, EMACS_CLASS,
14208 emacs_options, XtNumber (emacs_options),
14209 &argc, argv);
39d8bb4d
KH
14210
14211#ifdef HAVE_X11XTR6
10537cb1 14212 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 14213 fixup_locale ();
39d8bb4d 14214#endif
7f9c7f94 14215 }
3afe33e7
RS
14216
14217#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
14218#ifdef HAVE_X11R5
14219 XSetLocaleModifiers ("");
14220#endif
7a13e894 14221 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 14222#endif /* not USE_X_TOOLKIT */
334208b7 14223
7a13e894
RS
14224 /* Detect failure. */
14225 if (dpy == 0)
60439948
KH
14226 {
14227 UNBLOCK_INPUT;
14228 return 0;
14229 }
7a13e894
RS
14230
14231 /* We have definitely succeeded. Record the new connection. */
14232
14233 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
f04e1297 14234 bzero (dpyinfo, sizeof *dpyinfo);
7a13e894 14235
29b38361
KH
14236#ifdef MULTI_KBOARD
14237 {
14238 struct x_display_info *share;
14239 Lisp_Object tail;
14240
14241 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
14242 share = share->next, tail = XCDR (tail))
14243 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
14244 XSTRING (display_name)->data))
14245 break;
14246 if (share)
14247 dpyinfo->kboard = share->kboard;
14248 else
14249 {
14250 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
14251 init_kboard (dpyinfo->kboard);
59e755be
KH
14252 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
14253 {
14254 char *vendor = ServerVendor (dpy);
9b6ed9f3 14255 UNBLOCK_INPUT;
59e755be
KH
14256 dpyinfo->kboard->Vsystem_key_alist
14257 = call1 (Qvendor_specific_keysyms,
14258 build_string (vendor ? vendor : ""));
9b6ed9f3 14259 BLOCK_INPUT;
59e755be
KH
14260 }
14261
29b38361
KH
14262 dpyinfo->kboard->next_kboard = all_kboards;
14263 all_kboards = dpyinfo->kboard;
0ad5446c
KH
14264 /* Don't let the initial kboard remain current longer than necessary.
14265 That would cause problems if a file loaded on startup tries to
06a2c219 14266 prompt in the mini-buffer. */
0ad5446c
KH
14267 if (current_kboard == initial_kboard)
14268 current_kboard = dpyinfo->kboard;
29b38361
KH
14269 }
14270 dpyinfo->kboard->reference_count++;
14271 }
b9737ad3
KH
14272#endif
14273
7a13e894
RS
14274 /* Put this display on the chain. */
14275 dpyinfo->next = x_display_list;
14276 x_display_list = dpyinfo;
14277
14278 /* Put it on x_display_name_list as well, to keep them parallel. */
14279 x_display_name_list = Fcons (Fcons (display_name, Qnil),
14280 x_display_name_list);
8e713be6 14281 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
14282
14283 dpyinfo->display = dpy;
dc6f92b8 14284
dc6f92b8 14285#if 0
7a13e894 14286 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 14287#endif /* ! 0 */
7a13e894
RS
14288
14289 dpyinfo->x_id_name
fc932ac6
RS
14290 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
14291 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
14292 + 2);
14293 sprintf (dpyinfo->x_id_name, "%s@%s",
14294 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
14295
14296 /* Figure out which modifier bits mean what. */
334208b7 14297 x_find_modifier_meanings (dpyinfo);
f451eb13 14298
ab648270 14299 /* Get the scroll bar cursor. */
7a13e894 14300 dpyinfo->vertical_scroll_bar_cursor
334208b7 14301 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 14302
334208b7
RS
14303 xrdb = x_load_resources (dpyinfo->display, xrm_option,
14304 resource_name, EMACS_CLASS);
14305#ifdef HAVE_XRMSETDATABASE
14306 XrmSetDatabase (dpyinfo->display, xrdb);
14307#else
14308 dpyinfo->display->db = xrdb;
14309#endif
547d9db8 14310 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
14311 all versions. */
14312 dpyinfo->xrdb = xrdb;
334208b7
RS
14313
14314 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
14315 DefaultScreen (dpyinfo->display));
5ff67d81 14316 select_visual (dpyinfo);
43bd1b2b 14317 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
14318 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
14319 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
14320 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
14321 dpyinfo->grabbed = 0;
14322 dpyinfo->reference_count = 0;
14323 dpyinfo->icon_bitmap_id = -1;
06a2c219 14324 dpyinfo->font_table = NULL;
7a13e894
RS
14325 dpyinfo->n_fonts = 0;
14326 dpyinfo->font_table_size = 0;
14327 dpyinfo->bitmaps = 0;
14328 dpyinfo->bitmaps_size = 0;
14329 dpyinfo->bitmaps_last = 0;
14330 dpyinfo->scratch_cursor_gc = 0;
14331 dpyinfo->mouse_face_mouse_frame = 0;
14332 dpyinfo->mouse_face_deferred_gc = 0;
14333 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
14334 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 14335 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894 14336 dpyinfo->mouse_face_window = Qnil;
0a61c667 14337 dpyinfo->mouse_face_overlay = Qnil;
7a13e894
RS
14338 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
14339 dpyinfo->mouse_face_defer = 0;
0f941935
KH
14340 dpyinfo->x_focus_frame = 0;
14341 dpyinfo->x_focus_event_frame = 0;
14342 dpyinfo->x_highlight_frame = 0;
06a2c219 14343 dpyinfo->image_cache = make_image_cache ();
334208b7 14344
43bd1b2b 14345 /* See if a private colormap is requested. */
5ff67d81
GM
14346 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
14347 {
14348 if (dpyinfo->visual->class == PseudoColor)
14349 {
14350 Lisp_Object value;
14351 value = display_x_get_resource (dpyinfo,
14352 build_string ("privateColormap"),
14353 build_string ("PrivateColormap"),
14354 Qnil, Qnil);
14355 if (STRINGP (value)
14356 && (!strcmp (XSTRING (value)->data, "true")
14357 || !strcmp (XSTRING (value)->data, "on")))
14358 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
14359 }
43bd1b2b 14360 }
5ff67d81
GM
14361 else
14362 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
14363 dpyinfo->visual, AllocNone);
43bd1b2b 14364
06a2c219
GM
14365 {
14366 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
14367 double pixels = DisplayHeight (dpyinfo->display, screen_number);
14368 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
14369 dpyinfo->resy = pixels * 25.4 / mm;
14370 pixels = DisplayWidth (dpyinfo->display, screen_number);
14371 mm = DisplayWidthMM (dpyinfo->display, screen_number);
14372 dpyinfo->resx = pixels * 25.4 / mm;
14373 }
14374
334208b7
RS
14375 dpyinfo->Xatom_wm_protocols
14376 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
14377 dpyinfo->Xatom_wm_take_focus
14378 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
14379 dpyinfo->Xatom_wm_save_yourself
14380 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
14381 dpyinfo->Xatom_wm_delete_window
14382 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
14383 dpyinfo->Xatom_wm_change_state
14384 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
14385 dpyinfo->Xatom_wm_configure_denied
14386 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
14387 dpyinfo->Xatom_wm_window_moved
14388 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
14389 dpyinfo->Xatom_editres
14390 = XInternAtom (dpyinfo->display, "Editres", False);
14391 dpyinfo->Xatom_CLIPBOARD
14392 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
14393 dpyinfo->Xatom_TIMESTAMP
14394 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
14395 dpyinfo->Xatom_TEXT
14396 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
14397 dpyinfo->Xatom_COMPOUND_TEXT
14398 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
14399 dpyinfo->Xatom_DELETE
14400 = XInternAtom (dpyinfo->display, "DELETE", False);
14401 dpyinfo->Xatom_MULTIPLE
14402 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
14403 dpyinfo->Xatom_INCR
14404 = XInternAtom (dpyinfo->display, "INCR", False);
14405 dpyinfo->Xatom_EMACS_TMP
14406 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
14407 dpyinfo->Xatom_TARGETS
14408 = XInternAtom (dpyinfo->display, "TARGETS", False);
14409 dpyinfo->Xatom_NULL
14410 = XInternAtom (dpyinfo->display, "NULL", False);
14411 dpyinfo->Xatom_ATOM_PAIR
14412 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
14413 /* For properties of font. */
14414 dpyinfo->Xatom_PIXEL_SIZE
14415 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
14416 dpyinfo->Xatom_MULE_BASELINE_OFFSET
14417 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
14418 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
14419 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
14420 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
14421 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 14422
06a2c219
GM
14423 /* Ghostscript support. */
14424 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
14425 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
14426
14427 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
14428 False);
14429
547d9db8
KH
14430 dpyinfo->cut_buffers_initialized = 0;
14431
334208b7
RS
14432 connection = ConnectionNumber (dpyinfo->display);
14433 dpyinfo->connection = connection;
14434
dc43ef94 14435 {
5d7cc324
RS
14436 char null_bits[1];
14437
14438 null_bits[0] = 0x00;
dc43ef94
KH
14439
14440 dpyinfo->null_pixel
14441 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14442 null_bits, 1, 1, (long) 0, (long) 0,
14443 1);
14444 }
14445
06a2c219
GM
14446 {
14447 extern int gray_bitmap_width, gray_bitmap_height;
10659c77 14448 extern char *gray_bitmap_bits;
06a2c219
GM
14449 dpyinfo->gray
14450 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14451 gray_bitmap_bits,
14452 gray_bitmap_width, gray_bitmap_height,
14453 (unsigned long) 1, (unsigned long) 0, 1);
14454 }
14455
f5d11644
GM
14456#ifdef HAVE_X_I18N
14457 xim_initialize (dpyinfo, resource_name);
14458#endif
14459
87485d6f
MW
14460#ifdef subprocesses
14461 /* This is only needed for distinguishing keyboard and process input. */
334208b7 14462 if (connection != 0)
7a13e894 14463 add_keyboard_wait_descriptor (connection);
87485d6f 14464#endif
6d4238f3 14465
041b69ac 14466#ifndef F_SETOWN_BUG
dc6f92b8 14467#ifdef F_SETOWN
dc6f92b8 14468#ifdef F_SETOWN_SOCK_NEG
61c3ce62 14469 /* stdin is a socket here */
334208b7 14470 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 14471#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 14472 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
14473#endif /* ! defined (F_SETOWN_SOCK_NEG) */
14474#endif /* ! defined (F_SETOWN) */
041b69ac 14475#endif /* F_SETOWN_BUG */
dc6f92b8
JB
14476
14477#ifdef SIGIO
eee20f6a
KH
14478 if (interrupt_input)
14479 init_sigio (connection);
c118dd06 14480#endif /* ! defined (SIGIO) */
dc6f92b8 14481
51b592fb 14482#ifdef USE_LUCID
f8c39f51 14483#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
14484 /* Make sure that we have a valid font for dialog boxes
14485 so that Xt does not crash. */
14486 {
14487 Display *dpy = dpyinfo->display;
14488 XrmValue d, fr, to;
14489 Font font;
e99db5a1 14490 int count;
51b592fb
RS
14491
14492 d.addr = (XPointer)&dpy;
14493 d.size = sizeof (Display *);
14494 fr.addr = XtDefaultFont;
14495 fr.size = sizeof (XtDefaultFont);
14496 to.size = sizeof (Font *);
14497 to.addr = (XPointer)&font;
e99db5a1 14498 count = x_catch_errors (dpy);
51b592fb
RS
14499 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
14500 abort ();
14501 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
14502 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 14503 x_uncatch_errors (dpy, count);
51b592fb
RS
14504 }
14505#endif
f8c39f51 14506#endif
51b592fb 14507
34e23e5a
GM
14508 /* See if we should run in synchronous mode. This is useful
14509 for debugging X code. */
14510 {
14511 Lisp_Object value;
14512 value = display_x_get_resource (dpyinfo,
14513 build_string ("synchronous"),
14514 build_string ("Synchronous"),
14515 Qnil, Qnil);
14516 if (STRINGP (value)
14517 && (!strcmp (XSTRING (value)->data, "true")
14518 || !strcmp (XSTRING (value)->data, "on")))
14519 XSynchronize (dpyinfo->display, True);
14520 }
14521
60439948
KH
14522 UNBLOCK_INPUT;
14523
7a13e894
RS
14524 return dpyinfo;
14525}
14526\f
14527/* Get rid of display DPYINFO, assuming all frames are already gone,
14528 and without sending any more commands to the X server. */
dc6f92b8 14529
7a13e894
RS
14530void
14531x_delete_display (dpyinfo)
14532 struct x_display_info *dpyinfo;
14533{
14534 delete_keyboard_wait_descriptor (dpyinfo->connection);
14535
14536 /* Discard this display from x_display_name_list and x_display_list.
14537 We can't use Fdelq because that can quit. */
14538 if (! NILP (x_display_name_list)
8e713be6
KR
14539 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
14540 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
14541 else
14542 {
14543 Lisp_Object tail;
14544
14545 tail = x_display_name_list;
8e713be6 14546 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 14547 {
bffcfca9 14548 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 14549 {
f3fbd155 14550 XSETCDR (tail, XCDR (XCDR (tail)));
7a13e894
RS
14551 break;
14552 }
8e713be6 14553 tail = XCDR (tail);
7a13e894
RS
14554 }
14555 }
14556
9bda743f
GM
14557 if (next_noop_dpyinfo == dpyinfo)
14558 next_noop_dpyinfo = dpyinfo->next;
14559
7a13e894
RS
14560 if (x_display_list == dpyinfo)
14561 x_display_list = dpyinfo->next;
7f9c7f94
RS
14562 else
14563 {
14564 struct x_display_info *tail;
7a13e894 14565
7f9c7f94
RS
14566 for (tail = x_display_list; tail; tail = tail->next)
14567 if (tail->next == dpyinfo)
14568 tail->next = tail->next->next;
14569 }
7a13e894 14570
0d777288
RS
14571#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
14572#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
14573 XrmDestroyDatabase (dpyinfo->xrdb);
14574#endif
0d777288 14575#endif
29b38361
KH
14576#ifdef MULTI_KBOARD
14577 if (--dpyinfo->kboard->reference_count == 0)
39f79001 14578 delete_kboard (dpyinfo->kboard);
b9737ad3 14579#endif
f5d11644
GM
14580#ifdef HAVE_X_I18N
14581 if (dpyinfo->xim)
14582 xim_close_dpy (dpyinfo);
14583#endif
14584
b9737ad3
KH
14585 xfree (dpyinfo->font_table);
14586 xfree (dpyinfo->x_id_name);
f04e1297 14587 xfree (dpyinfo->color_cells);
b9737ad3 14588 xfree (dpyinfo);
7a13e894 14589}
f04e1297 14590
7a13e894
RS
14591\f
14592/* Set up use of X before we make the first connection. */
14593
06a2c219
GM
14594static struct redisplay_interface x_redisplay_interface =
14595{
14596 x_produce_glyphs,
14597 x_write_glyphs,
14598 x_insert_glyphs,
14599 x_clear_end_of_line,
14600 x_scroll_run,
14601 x_after_update_window_line,
14602 x_update_window_begin,
14603 x_update_window_end,
14604 XTcursor_to,
14605 x_flush,
71b8321e 14606 x_clear_mouse_face,
66ac4b0e
GM
14607 x_get_glyph_overhangs,
14608 x_fix_overlapping_area
06a2c219
GM
14609};
14610
dfcf069d 14611void
7a13e894
RS
14612x_initialize ()
14613{
06a2c219
GM
14614 rif = &x_redisplay_interface;
14615
14616 clear_frame_hook = x_clear_frame;
14617 ins_del_lines_hook = x_ins_del_lines;
06a2c219 14618 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
14619 ring_bell_hook = XTring_bell;
14620 reset_terminal_modes_hook = XTreset_terminal_modes;
14621 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
14622 update_begin_hook = x_update_begin;
14623 update_end_hook = x_update_end;
dc6f92b8
JB
14624 set_terminal_window_hook = XTset_terminal_window;
14625 read_socket_hook = XTread_socket;
b8009dd1 14626 frame_up_to_date_hook = XTframe_up_to_date;
90e65f07 14627 mouse_position_hook = XTmouse_position;
f451eb13 14628 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 14629 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
14630 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
14631 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
14632 redeem_scroll_bar_hook = XTredeem_scroll_bar;
14633 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 14634 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 14635
f676886a 14636 scroll_region_ok = 1; /* we'll scroll partial frames */
9017309f 14637 char_ins_del_ok = 1;
dc6f92b8
JB
14638 line_ins_del_ok = 1; /* we'll just blt 'em */
14639 fast_clear_end_of_line = 1; /* X does this well */
58769bee 14640 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
14641 off the bottom */
14642 baud_rate = 19200;
14643
7a13e894 14644 x_noop_count = 0;
9ea173e8 14645 last_tool_bar_item = -1;
06a2c219
GM
14646 any_help_event_p = 0;
14647
b30b24cb
RS
14648 /* Try to use interrupt input; if we can't, then start polling. */
14649 Fset_input_mode (Qt, Qnil, Qt, Qnil);
14650
7f9c7f94
RS
14651#ifdef USE_X_TOOLKIT
14652 XtToolkitInitialize ();
651f03b6 14653
7f9c7f94 14654 Xt_app_con = XtCreateApplicationContext ();
651f03b6
GM
14655
14656 /* Register a converter from strings to pixels, which uses
14657 Emacs' color allocation infrastructure. */
14658 XtAppSetTypeConverter (Xt_app_con,
14659 XtRString, XtRPixel, cvt_string_to_pixel,
14660 cvt_string_to_pixel_args,
14661 XtNumber (cvt_string_to_pixel_args),
14662 XtCacheByDisplay, cvt_pixel_dtor);
14663
665881ad 14664 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
14665
14666 /* Install an asynchronous timer that processes Xt timeout events
14667 every 0.1s. This is necessary because some widget sets use
14668 timeouts internally, for example the LessTif menu bar, or the
14669 Xaw3d scroll bar. When Xt timouts aren't processed, these
14670 widgets don't behave normally. */
14671 {
14672 EMACS_TIME interval;
14673 EMACS_SET_SECS_USECS (interval, 0, 100000);
14674 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
14675 }
db74249b 14676#endif
bffcfca9 14677
eccc05db 14678#ifdef USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
14679 xaw3d_arrow_scroll = False;
14680 xaw3d_pick_top = True;
7f9c7f94
RS
14681#endif
14682
58769bee 14683 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 14684 original error handler. */
e99db5a1 14685 XSetErrorHandler (x_error_handler);
334208b7 14686 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 14687
06a2c219 14688 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
14689#ifdef SIGWINCH
14690 signal (SIGWINCH, SIG_DFL);
c118dd06 14691#endif /* ! defined (SIGWINCH) */
dc6f92b8 14692
92e2441b 14693 signal (SIGPIPE, x_connection_signal);
dc6f92b8 14694}
55123275 14695
06a2c219 14696
55123275
JB
14697void
14698syms_of_xterm ()
14699{
e99db5a1
RS
14700 staticpro (&x_error_message_string);
14701 x_error_message_string = Qnil;
14702
7a13e894
RS
14703 staticpro (&x_display_name_list);
14704 x_display_name_list = Qnil;
334208b7 14705
ab648270 14706 staticpro (&last_mouse_scroll_bar);
e53cb100 14707 last_mouse_scroll_bar = Qnil;
59e755be
KH
14708
14709 staticpro (&Qvendor_specific_keysyms);
14710 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
14711
14712 staticpro (&last_mouse_press_frame);
14713 last_mouse_press_frame = Qnil;
06a2c219 14714
06a2c219 14715 help_echo = Qnil;
be010514
GM
14716 staticpro (&help_echo);
14717 help_echo_object = Qnil;
14718 staticpro (&help_echo_object);
7cea38bc
GM
14719 help_echo_window = Qnil;
14720 staticpro (&help_echo_window);
06a2c219 14721 previous_help_echo = Qnil;
be010514
GM
14722 staticpro (&previous_help_echo);
14723 help_echo_pos = -1;
06a2c219 14724
7ee72033
MB
14725 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
14726 doc: /* *Non-nil means draw block cursor as wide as the glyph under it.
228299fa
GM
14727For example, if a block cursor is over a tab, it will be drawn as
14728wide as that tab on the display. */);
06a2c219
GM
14729 x_stretch_cursor_p = 0;
14730
a72d5ce5 14731 DEFVAR_BOOL ("x-use-underline-position-properties",
7ee72033
MB
14732 &x_use_underline_position_properties,
14733 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
228299fa
GM
14734Nil means ignore them. If you encounter fonts with bogus
14735UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
14736to 4.1, set this to nil. */);
a72d5ce5
GM
14737 x_use_underline_position_properties = 1;
14738
7ee72033
MB
14739 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
14740 doc: /* What X toolkit scroll bars Emacs uses.
228299fa
GM
14741A value of nil means Emacs doesn't use X toolkit scroll bars.
14742Otherwise, value is a symbol describing the X toolkit. */);
eccc05db 14743#ifdef USE_TOOLKIT_SCROLL_BARS
5bf04520
GM
14744#ifdef USE_MOTIF
14745 Vx_toolkit_scroll_bars = intern ("motif");
14746#elif defined HAVE_XAW3D
14747 Vx_toolkit_scroll_bars = intern ("xaw3d");
14748#else
14749 Vx_toolkit_scroll_bars = intern ("xaw");
14750#endif
06a2c219 14751#else
5bf04520 14752 Vx_toolkit_scroll_bars = Qnil;
06a2c219
GM
14753#endif
14754
06a2c219
GM
14755 staticpro (&last_mouse_motion_frame);
14756 last_mouse_motion_frame = Qnil;
55123275 14757}
6cf0ae86 14758
1d6c120a 14759#endif /* HAVE_X_WINDOWS */