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