Change doc-string comments to `new style' [w/`doc:' keyword].
[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 *));
439static void XTreassert_line_highlight P_ ((int, int));
440static void x_change_line_highlight P_ ((int, int, int, int));
441static void XTset_terminal_modes P_ ((void));
442static void XTreset_terminal_modes P_ ((void));
443static void XTcursor_to P_ ((int, int, int, int));
444static void x_write_glyphs P_ ((struct glyph *, int));
445static void x_clear_end_of_line P_ ((int));
446static void x_clear_frame P_ ((void));
447static void x_clear_cursor P_ ((struct window *));
448static void frame_highlight P_ ((struct frame *));
449static void frame_unhighlight P_ ((struct frame *));
450static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
451static void XTframe_rehighlight P_ ((struct frame *));
452static void x_frame_rehighlight P_ ((struct x_display_info *));
453static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
f02d8aa0 454static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
06a2c219
GM
455static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
456 XRectangle *));
457static void expose_frame P_ ((struct frame *, int, int, int, int));
82f053ab 458static int expose_window_tree P_ ((struct window *, XRectangle *));
a39202f6 459static int expose_window P_ ((struct window *, XRectangle *));
06a2c219
GM
460static void expose_area P_ ((struct window *, struct glyph_row *,
461 XRectangle *, enum glyph_row_area));
82f053ab 462static int expose_line P_ ((struct window *, struct glyph_row *,
06a2c219
GM
463 XRectangle *));
464static void x_update_cursor_in_window_tree P_ ((struct window *, int));
465static void x_update_window_cursor P_ ((struct window *, int));
466static void x_erase_phys_cursor P_ ((struct window *));
467void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
468static void x_draw_bitmap P_ ((struct window *, struct glyph_row *,
469 enum bitmap_type));
470
471static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
472 GC, int));
473static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
474static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
78a9a4c5 475static void notice_overwritten_cursor P_ ((struct window *, int, int));
06a2c219 476static void x_flush P_ ((struct frame *f));
952291d9
GM
477static void x_update_begin P_ ((struct frame *));
478static void x_update_window_begin P_ ((struct window *));
479static void x_draw_vertical_border P_ ((struct window *));
480static void x_after_update_window_line P_ ((struct glyph_row *));
481static INLINE void take_vertical_position_into_account P_ ((struct it *));
482static void x_produce_stretch_glyph P_ ((struct it *));
b52b65bd
GM
483static struct scroll_bar *x_window_to_scroll_bar P_ ((Window));
484static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
485 enum scroll_bar_part *,
486 Lisp_Object *, Lisp_Object *,
487 unsigned long *));
06a2c219
GM
488
489/* Flush display of frame F, or of all frames if F is null. */
490
491static void
492x_flush (f)
493 struct frame *f;
494{
495 BLOCK_INPUT;
496 if (f == NULL)
497 {
498 Lisp_Object rest, frame;
499 FOR_EACH_FRAME (rest, frame)
500 x_flush (XFRAME (frame));
501 }
502 else if (FRAME_X_P (f))
503 XFlush (FRAME_X_DISPLAY (f));
504 UNBLOCK_INPUT;
505}
506
dc6f92b8 507
06a2c219
GM
508/* Remove calls to XFlush by defining XFlush to an empty replacement.
509 Calls to XFlush should be unnecessary because the X output buffer
510 is flushed automatically as needed by calls to XPending,
511 XNextEvent, or XWindowEvent according to the XFlush man page.
512 XTread_socket calls XPending. Removing XFlush improves
513 performance. */
514
515#define XFlush(DISPLAY) (void) 0
b8009dd1 516
334208b7 517\f
06a2c219
GM
518/***********************************************************************
519 Debugging
520 ***********************************************************************/
521
9382638d 522#if 0
06a2c219
GM
523
524/* This is a function useful for recording debugging information about
525 the sequence of occurrences in this file. */
9382638d
KH
526
527struct record
528{
529 char *locus;
530 int type;
531};
532
533struct record event_record[100];
534
535int event_record_index;
536
537record_event (locus, type)
538 char *locus;
539 int type;
540{
541 if (event_record_index == sizeof (event_record) / sizeof (struct record))
542 event_record_index = 0;
543
544 event_record[event_record_index].locus = locus;
545 event_record[event_record_index].type = type;
546 event_record_index++;
547}
548
549#endif /* 0 */
06a2c219
GM
550
551
9382638d 552\f
334208b7
RS
553/* Return the struct x_display_info corresponding to DPY. */
554
555struct x_display_info *
556x_display_info_for_display (dpy)
557 Display *dpy;
558{
559 struct x_display_info *dpyinfo;
560
561 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
562 if (dpyinfo->display == dpy)
563 return dpyinfo;
16bd92ea 564
334208b7
RS
565 return 0;
566}
f451eb13 567
06a2c219
GM
568
569\f
570/***********************************************************************
571 Starting and ending an update
572 ***********************************************************************/
573
574/* Start an update of frame F. This function is installed as a hook
575 for update_begin, i.e. it is called when update_begin is called.
576 This function is called prior to calls to x_update_window_begin for
577 each window being updated. Currently, there is nothing to do here
578 because all interesting stuff is done on a window basis. */
dc6f92b8 579
dfcf069d 580static void
06a2c219 581x_update_begin (f)
f676886a 582 struct frame *f;
58769bee 583{
06a2c219
GM
584 /* Nothing to do. */
585}
dc6f92b8 586
dc6f92b8 587
06a2c219
GM
588/* Start update of window W. Set the global variable updated_window
589 to the window being updated and set output_cursor to the cursor
590 position of W. */
dc6f92b8 591
06a2c219
GM
592static void
593x_update_window_begin (w)
594 struct window *w;
595{
596 struct frame *f = XFRAME (WINDOW_FRAME (w));
597 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
598
599 updated_window = w;
600 set_output_cursor (&w->cursor);
b8009dd1 601
06a2c219 602 BLOCK_INPUT;
d1bc4182 603
06a2c219 604 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 605 {
514e4681 606 /* Don't do highlighting for mouse motion during the update. */
06a2c219 607 display_info->mouse_face_defer = 1;
37c2c98b 608
06a2c219
GM
609 /* If F needs to be redrawn, simply forget about any prior mouse
610 highlighting. */
9f67f20b 611 if (FRAME_GARBAGED_P (f))
06a2c219
GM
612 display_info->mouse_face_window = Qnil;
613
64f26cf5
GM
614#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
615 their mouse_face_p flag set, which means that they are always
616 unequal to rows in a desired matrix which never have that
617 flag set. So, rows containing mouse-face glyphs are never
618 scrolled, and we don't have to switch the mouse highlight off
619 here to prevent it from being scrolled. */
620
06a2c219
GM
621 /* Can we tell that this update does not affect the window
622 where the mouse highlight is? If so, no need to turn off.
623 Likewise, don't do anything if the frame is garbaged;
624 in that case, the frame's current matrix that we would use
625 is all wrong, and we will redisplay that line anyway. */
626 if (!NILP (display_info->mouse_face_window)
627 && w == XWINDOW (display_info->mouse_face_window))
514e4681 628 {
06a2c219 629 int i;
514e4681 630
06a2c219
GM
631 for (i = 0; i < w->desired_matrix->nrows; ++i)
632 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
633 break;
634
06a2c219
GM
635 if (i < w->desired_matrix->nrows)
636 clear_mouse_face (display_info);
514e4681 637 }
64f26cf5 638#endif /* 0 */
b8009dd1 639 }
6ccf47d1 640
dc6f92b8
JB
641 UNBLOCK_INPUT;
642}
643
06a2c219
GM
644
645/* Draw a vertical window border to the right of window W if W doesn't
646 have vertical scroll bars. */
647
dfcf069d 648static void
06a2c219
GM
649x_draw_vertical_border (w)
650 struct window *w;
58769bee 651{
06a2c219
GM
652 struct frame *f = XFRAME (WINDOW_FRAME (w));
653
654 /* Redraw borders between horizontally adjacent windows. Don't
655 do it for frames with vertical scroll bars because either the
656 right scroll bar of a window, or the left scroll bar of its
657 neighbor will suffice as a border. */
658 if (!WINDOW_RIGHTMOST_P (w)
659 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
660 {
661 int x0, x1, y0, y1;
dc6f92b8 662
06a2c219 663 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
110859fc 664 x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
665 y1 -= 1;
666
667 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
668 f->output_data.x->normal_gc, x1, y0, x1, y1);
669 }
670}
671
672
71b8321e
GM
673/* End update of window W (which is equal to updated_window).
674
675 Draw vertical borders between horizontally adjacent windows, and
676 display W's cursor if CURSOR_ON_P is non-zero.
677
678 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
679 glyphs in mouse-face were overwritten. In that case we have to
680 make sure that the mouse-highlight is properly redrawn.
681
682 W may be a menu bar pseudo-window in case we don't have X toolkit
683 support. Such windows don't have a cursor, so don't display it
684 here. */
06a2c219
GM
685
686static void
71b8321e 687x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 688 struct window *w;
71b8321e 689 int cursor_on_p, mouse_face_overwritten_p;
06a2c219 690{
140330de
GM
691 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
692
06a2c219
GM
693 if (!w->pseudo_window_p)
694 {
695 BLOCK_INPUT;
71b8321e 696
06a2c219
GM
697 if (cursor_on_p)
698 x_display_and_set_cursor (w, 1, output_cursor.hpos,
699 output_cursor.vpos,
700 output_cursor.x, output_cursor.y);
71b8321e 701
06a2c219
GM
702 x_draw_vertical_border (w);
703 UNBLOCK_INPUT;
704 }
705
140330de
GM
706 /* If a row with mouse-face was overwritten, arrange for
707 XTframe_up_to_date to redisplay the mouse highlight. */
708 if (mouse_face_overwritten_p)
709 {
710 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
711 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
712 dpyinfo->mouse_face_window = Qnil;
713 }
714
06a2c219
GM
715 updated_window = NULL;
716}
dc6f92b8 717
dc6f92b8 718
06a2c219
GM
719/* End update of frame F. This function is installed as a hook in
720 update_end. */
721
722static void
723x_update_end (f)
724 struct frame *f;
725{
726 /* Mouse highlight may be displayed again. */
aa8bff2e 727 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 728
06a2c219 729 BLOCK_INPUT;
334208b7 730 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
731 UNBLOCK_INPUT;
732}
b8009dd1 733
06a2c219
GM
734
735/* This function is called from various places in xdisp.c whenever a
736 complete update has been performed. The global variable
737 updated_window is not available here. */
b8009dd1 738
dfcf069d 739static void
b8009dd1 740XTframe_up_to_date (f)
06a2c219 741 struct frame *f;
b8009dd1 742{
06a2c219 743 if (FRAME_X_P (f))
514e4681 744 {
06a2c219 745 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 746
06a2c219
GM
747 if (dpyinfo->mouse_face_deferred_gc
748 || f == dpyinfo->mouse_face_mouse_frame)
749 {
750 BLOCK_INPUT;
751 if (dpyinfo->mouse_face_mouse_frame)
752 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
753 dpyinfo->mouse_face_mouse_x,
754 dpyinfo->mouse_face_mouse_y);
755 dpyinfo->mouse_face_deferred_gc = 0;
756 UNBLOCK_INPUT;
757 }
514e4681 758 }
b8009dd1 759}
06a2c219
GM
760
761
762/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
763 arrow bitmaps, or clear the areas where they would be displayed
764 before DESIRED_ROW is made current. The window being updated is
765 found in updated_window. This function It is called from
766 update_window_line only if it is known that there are differences
767 between bitmaps to be drawn between current row and DESIRED_ROW. */
768
769static void
770x_after_update_window_line (desired_row)
771 struct glyph_row *desired_row;
772{
773 struct window *w = updated_window;
774
775 xassert (w);
776
777 if (!desired_row->mode_line_p && !w->pseudo_window_p)
778 {
c5e6e06b
GM
779 struct frame *f;
780 int width;
781
06a2c219
GM
782 BLOCK_INPUT;
783 x_draw_row_bitmaps (w, desired_row);
784
785 /* When a window has disappeared, make sure that no rest of
786 full-width rows stays visible in the internal border. */
c5e6e06b
GM
787 if (windows_or_buffers_changed
788 && (f = XFRAME (w->frame),
789 width = FRAME_INTERNAL_BORDER_WIDTH (f),
790 width != 0))
06a2c219 791 {
06a2c219 792 int height = desired_row->visible_height;
110859fc
GM
793 int x = (window_box_right (w, -1)
794 + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
795 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
796
c5e6e06b
GM
797 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
798 x, y, width, height, False);
06a2c219
GM
799 }
800
801 UNBLOCK_INPUT;
802 }
803}
804
805
806/* Draw the bitmap WHICH in one of the areas to the left or right of
807 window W. ROW is the glyph row for which to display the bitmap; it
808 determines the vertical position at which the bitmap has to be
809 drawn. */
810
811static void
812x_draw_bitmap (w, row, which)
813 struct window *w;
814 struct glyph_row *row;
815 enum bitmap_type which;
816{
817 struct frame *f = XFRAME (WINDOW_FRAME (w));
818 Display *display = FRAME_X_DISPLAY (f);
819 Window window = FRAME_X_WINDOW (f);
820 int x, y, wd, h, dy;
821 unsigned char *bits;
822 Pixmap pixmap;
823 GC gc = f->output_data.x->normal_gc;
824 struct face *face;
825 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
826
827 /* Must clip because of partially visible lines. */
828 x_clip_to_row (w, row, gc, 1);
829
830 switch (which)
831 {
832 case LEFT_TRUNCATION_BITMAP:
833 wd = left_width;
834 h = left_height;
835 bits = left_bits;
836 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
837 - wd
110859fc 838 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
839 break;
840
841 case OVERLAY_ARROW_BITMAP:
842 wd = left_width;
843 h = left_height;
844 bits = ov_bits;
845 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
846 - wd
110859fc 847 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
848 break;
849
850 case RIGHT_TRUNCATION_BITMAP:
851 wd = right_width;
852 h = right_height;
853 bits = right_bits;
854 x = window_box_right (w, -1);
110859fc 855 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
856 break;
857
858 case CONTINUED_LINE_BITMAP:
859 wd = right_width;
860 h = right_height;
861 bits = continued_bits;
862 x = window_box_right (w, -1);
110859fc 863 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
864 break;
865
866 case CONTINUATION_LINE_BITMAP:
867 wd = continuation_width;
868 h = continuation_height;
869 bits = continuation_bits;
870 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
871 - wd
110859fc 872 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
873 break;
874
875 case ZV_LINE_BITMAP:
876 wd = zv_width;
877 h = zv_height;
878 bits = zv_bits;
879 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
880 - wd
110859fc 881 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
882 break;
883
884 default:
885 abort ();
886 }
887
888 /* Convert to frame coordinates. Set dy to the offset in the row to
889 start drawing the bitmap. */
890 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
891 dy = (row->height - h) / 2;
892
893 /* Draw the bitmap. I believe these small pixmaps can be cached
894 by the server. */
895 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
896 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
897 face->foreground,
898 face->background, depth);
899 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
900 XFreePixmap (display, pixmap);
901 XSetClipMask (display, gc, None);
902}
903
904
905/* Draw flags bitmaps for glyph row ROW on window W. Call this
906 function with input blocked. */
907
908static void
909x_draw_row_bitmaps (w, row)
910 struct window *w;
911 struct glyph_row *row;
912{
913 struct frame *f = XFRAME (w->frame);
914 enum bitmap_type bitmap;
915 struct face *face;
045dee35 916 int header_line_height = -1;
06a2c219
GM
917
918 xassert (interrupt_input_blocked);
919
920 /* If row is completely invisible, because of vscrolling, we
921 don't have to draw anything. */
922 if (row->visible_height <= 0)
923 return;
924
925 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
926 PREPARE_FACE_FOR_DISPLAY (f, face);
927
928 /* Decide which bitmap to draw at the left side. */
929 if (row->overlay_arrow_p)
930 bitmap = OVERLAY_ARROW_BITMAP;
931 else if (row->truncated_on_left_p)
932 bitmap = LEFT_TRUNCATION_BITMAP;
933 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
934 bitmap = CONTINUATION_LINE_BITMAP;
935 else if (row->indicate_empty_line_p)
936 bitmap = ZV_LINE_BITMAP;
937 else
938 bitmap = NO_BITMAP;
939
940 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
941 the flags area. */
942 if (bitmap == NO_BITMAP
110859fc 943 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
944 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
945 {
946 /* If W has a vertical border to its left, don't draw over it. */
947 int border = ((XFASTINT (w->left) > 0
948 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
949 ? 1 : 0);
950 int left = window_box_left (w, -1);
951
045dee35
GM
952 if (header_line_height < 0)
953 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
954
955 /* In case the same realized face is used for bitmap areas and
956 for something displayed in the text (e.g. face `region' on
957 mono-displays, the fill style may have been changed to
958 FillSolid in x_draw_glyph_string_background. */
959 if (face->stipple)
960 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
961 else
962 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
963
06a2c219
GM
964 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
965 face->gc,
966 (left
110859fc 967 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219 968 + border),
045dee35 969 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 970 row->y)),
110859fc 971 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
06a2c219 972 row->visible_height);
dcd08bfb
GM
973 if (!face->stipple)
974 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
975 }
976
977 /* Draw the left bitmap. */
978 if (bitmap != NO_BITMAP)
979 x_draw_bitmap (w, row, bitmap);
980
981 /* Decide which bitmap to draw at the right side. */
982 if (row->truncated_on_right_p)
983 bitmap = RIGHT_TRUNCATION_BITMAP;
984 else if (row->continued_p)
985 bitmap = CONTINUED_LINE_BITMAP;
986 else
987 bitmap = NO_BITMAP;
988
989 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
990 the flags area. */
991 if (bitmap == NO_BITMAP
110859fc 992 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
993 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
994 {
995 int right = window_box_right (w, -1);
996
045dee35
GM
997 if (header_line_height < 0)
998 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
999
1000 /* In case the same realized face is used for bitmap areas and
1001 for something displayed in the text (e.g. face `region' on
1002 mono-displays, the fill style may have been changed to
1003 FillSolid in x_draw_glyph_string_background. */
1004 if (face->stipple)
1005 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
1006 else
1007 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
1008 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1009 face->gc,
1010 right,
045dee35 1011 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 1012 row->y)),
110859fc 1013 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
06a2c219 1014 row->visible_height);
dcd08bfb
GM
1015 if (!face->stipple)
1016 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
1017 }
1018
1019 /* Draw the right bitmap. */
1020 if (bitmap != NO_BITMAP)
1021 x_draw_bitmap (w, row, bitmap);
1022}
1023
dc6f92b8 1024\f
06a2c219
GM
1025/***********************************************************************
1026 Line Highlighting
1027 ***********************************************************************/
dc6f92b8 1028
06a2c219
GM
1029/* External interface to control of standout mode. Not used for X
1030 frames. Aborts when called. */
1031
1032static void
dc6f92b8
JB
1033XTreassert_line_highlight (new, vpos)
1034 int new, vpos;
1035{
06a2c219 1036 abort ();
dc6f92b8
JB
1037}
1038
06a2c219
GM
1039
1040/* Call this when about to modify line at position VPOS and change
1041 whether it is highlighted. Not used for X frames. Aborts when
1042 called. */
dc6f92b8 1043
dfcf069d 1044static void
06a2c219
GM
1045x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1046 int new_highlight, vpos, y, first_unused_hpos;
dc6f92b8 1047{
06a2c219 1048 abort ();
dc6f92b8
JB
1049}
1050
06a2c219
GM
1051
1052/* This is called when starting Emacs and when restarting after
1053 suspend. When starting Emacs, no X window is mapped. And nothing
1054 must be done to Emacs's own window if it is suspended (though that
1055 rarely happens). */
dc6f92b8 1056
dfcf069d 1057static void
dc6f92b8
JB
1058XTset_terminal_modes ()
1059{
1060}
1061
06a2c219
GM
1062/* This is called when exiting or suspending Emacs. Exiting will make
1063 the X-windows go away, and suspending requires no action. */
dc6f92b8 1064
dfcf069d 1065static void
dc6f92b8
JB
1066XTreset_terminal_modes ()
1067{
dc6f92b8 1068}
06a2c219
GM
1069
1070
dc6f92b8 1071\f
06a2c219
GM
1072/***********************************************************************
1073 Output Cursor
1074 ***********************************************************************/
1075
1076/* Set the global variable output_cursor to CURSOR. All cursor
1077 positions are relative to updated_window. */
dc6f92b8 1078
dfcf069d 1079static void
06a2c219
GM
1080set_output_cursor (cursor)
1081 struct cursor_pos *cursor;
dc6f92b8 1082{
06a2c219
GM
1083 output_cursor.hpos = cursor->hpos;
1084 output_cursor.vpos = cursor->vpos;
1085 output_cursor.x = cursor->x;
1086 output_cursor.y = cursor->y;
1087}
1088
1089
1090/* Set a nominal cursor position.
dc6f92b8 1091
06a2c219
GM
1092 HPOS and VPOS are column/row positions in a window glyph matrix. X
1093 and Y are window text area relative pixel positions.
1094
1095 If this is done during an update, updated_window will contain the
1096 window that is being updated and the position is the future output
1097 cursor position for that window. If updated_window is null, use
1098 selected_window and display the cursor at the given position. */
1099
1100static void
1101XTcursor_to (vpos, hpos, y, x)
1102 int vpos, hpos, y, x;
1103{
1104 struct window *w;
1105
1106 /* If updated_window is not set, work on selected_window. */
1107 if (updated_window)
1108 w = updated_window;
1109 else
1110 w = XWINDOW (selected_window);
dbcb258a 1111
06a2c219
GM
1112 /* Set the output cursor. */
1113 output_cursor.hpos = hpos;
1114 output_cursor.vpos = vpos;
1115 output_cursor.x = x;
1116 output_cursor.y = y;
dc6f92b8 1117
06a2c219
GM
1118 /* If not called as part of an update, really display the cursor.
1119 This will also set the cursor position of W. */
1120 if (updated_window == NULL)
dc6f92b8
JB
1121 {
1122 BLOCK_INPUT;
06a2c219 1123 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1124 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1125 UNBLOCK_INPUT;
1126 }
1127}
dc43ef94 1128
06a2c219
GM
1129
1130\f
1131/***********************************************************************
1132 Display Iterator
1133 ***********************************************************************/
1134
1135/* Function prototypes of this page. */
1136
1137static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1138 struct glyph *,
ee569018
KH
1139 XChar2b *,
1140 int *));
06a2c219
GM
1141static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1142 int, XChar2b *, int));
1143static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1144static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1145static void x_append_glyph P_ ((struct it *));
b4192550 1146static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1147static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1148 int, int, double));
1149static void x_produce_glyphs P_ ((struct it *));
06a2c219 1150static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1151
1152
e2ef8ee6
GM
1153/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1154 is not contained in the font. */
dc43ef94 1155
06a2c219 1156static INLINE XCharStruct *
ee569018 1157x_per_char_metric (font, char2b)
06a2c219
GM
1158 XFontStruct *font;
1159 XChar2b *char2b;
1160{
1161 /* The result metric information. */
1162 XCharStruct *pcm = NULL;
dc6f92b8 1163
06a2c219 1164 xassert (font && char2b);
dc6f92b8 1165
06a2c219 1166 if (font->per_char != NULL)
dc6f92b8 1167 {
06a2c219 1168 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1169 {
06a2c219
GM
1170 /* min_char_or_byte2 specifies the linear character index
1171 corresponding to the first element of the per_char array,
1172 max_char_or_byte2 is the index of the last character. A
1173 character with non-zero CHAR2B->byte1 is not in the font.
1174 A character with byte2 less than min_char_or_byte2 or
1175 greater max_char_or_byte2 is not in the font. */
1176 if (char2b->byte1 == 0
1177 && char2b->byte2 >= font->min_char_or_byte2
1178 && char2b->byte2 <= font->max_char_or_byte2)
1179 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1180 }
06a2c219 1181 else
dc6f92b8 1182 {
06a2c219
GM
1183 /* If either min_byte1 or max_byte1 are nonzero, both
1184 min_char_or_byte2 and max_char_or_byte2 are less than
1185 256, and the 2-byte character index values corresponding
1186 to the per_char array element N (counting from 0) are:
1187
1188 byte1 = N/D + min_byte1
1189 byte2 = N\D + min_char_or_byte2
1190
1191 where:
1192
1193 D = max_char_or_byte2 - min_char_or_byte2 + 1
1194 / = integer division
1195 \ = integer modulus */
1196 if (char2b->byte1 >= font->min_byte1
1197 && char2b->byte1 <= font->max_byte1
1198 && char2b->byte2 >= font->min_char_or_byte2
1199 && char2b->byte2 <= font->max_char_or_byte2)
1200 {
1201 pcm = (font->per_char
1202 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1203 * (char2b->byte1 - font->min_byte1))
1204 + (char2b->byte2 - font->min_char_or_byte2));
1205 }
dc6f92b8 1206 }
06a2c219
GM
1207 }
1208 else
1209 {
1210 /* If the per_char pointer is null, all glyphs between the first
1211 and last character indexes inclusive have the same
1212 information, as given by both min_bounds and max_bounds. */
1213 if (char2b->byte2 >= font->min_char_or_byte2
1214 && char2b->byte2 <= font->max_char_or_byte2)
1215 pcm = &font->max_bounds;
1216 }
dc6f92b8 1217
ee569018 1218 return ((pcm == NULL
3e71d8f2 1219 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1220 ? NULL : pcm);
06a2c219 1221}
b73b6aaf 1222
57b03282 1223
06a2c219
GM
1224/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1225 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1226
06a2c219
GM
1227static INLINE void
1228x_encode_char (c, char2b, font_info)
1229 int c;
1230 XChar2b *char2b;
1231 struct font_info *font_info;
1232{
1233 int charset = CHAR_CHARSET (c);
1234 XFontStruct *font = font_info->font;
1235
1236 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1237 This may be either a program in a special encoder language or a
1238 fixed encoding. */
1239 if (font_info->font_encoder)
1240 {
1241 /* It's a program. */
1242 struct ccl_program *ccl = font_info->font_encoder;
1243
1244 if (CHARSET_DIMENSION (charset) == 1)
1245 {
1246 ccl->reg[0] = charset;
1247 ccl->reg[1] = char2b->byte2;
1248 }
1249 else
1250 {
1251 ccl->reg[0] = charset;
1252 ccl->reg[1] = char2b->byte1;
1253 ccl->reg[2] = char2b->byte2;
1254 }
1255
1256 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1257
1258 /* We assume that MSBs are appropriately set/reset by CCL
1259 program. */
1260 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1261 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1262 else
1263 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1264 }
1265 else if (font_info->encoding[charset])
1266 {
1267 /* Fixed encoding scheme. See fontset.h for the meaning of the
1268 encoding numbers. */
1269 int enc = font_info->encoding[charset];
1270
1271 if ((enc == 1 || enc == 2)
1272 && CHARSET_DIMENSION (charset) == 2)
1273 char2b->byte1 |= 0x80;
1274
1275 if (enc == 1 || enc == 3)
1276 char2b->byte2 |= 0x80;
1277 }
1278}
1279
1280
1281/* Get face and two-byte form of character C in face FACE_ID on frame
1282 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1283 means we want to display multibyte text. Value is a pointer to a
1284 realized face that is ready for display. */
1285
1286static INLINE struct face *
1287x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1288 struct frame *f;
1289 int c, face_id;
1290 XChar2b *char2b;
1291 int multibyte_p;
1292{
1293 struct face *face = FACE_FROM_ID (f, face_id);
1294
1295 if (!multibyte_p)
1296 {
1297 /* Unibyte case. We don't have to encode, but we have to make
1298 sure to use a face suitable for unibyte. */
1299 char2b->byte1 = 0;
1300 char2b->byte2 = c;
ee569018
KH
1301 face_id = FACE_FOR_CHAR (f, face, c);
1302 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1303 }
1304 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1305 {
1306 /* Case of ASCII in a face known to fit ASCII. */
1307 char2b->byte1 = 0;
1308 char2b->byte2 = c;
1309 }
1310 else
1311 {
1312 int c1, c2, charset;
1313
1314 /* Split characters into bytes. If c2 is -1 afterwards, C is
1315 really a one-byte character so that byte1 is zero. */
1316 SPLIT_CHAR (c, charset, c1, c2);
1317 if (c2 > 0)
1318 char2b->byte1 = c1, char2b->byte2 = c2;
1319 else
1320 char2b->byte1 = 0, char2b->byte2 = c1;
1321
06a2c219 1322 /* Maybe encode the character in *CHAR2B. */
ee569018 1323 if (face->font != NULL)
06a2c219
GM
1324 {
1325 struct font_info *font_info
1326 = FONT_INFO_FROM_ID (f, face->font_info_id);
1327 if (font_info)
ee569018 1328 x_encode_char (c, char2b, font_info);
06a2c219
GM
1329 }
1330 }
1331
1332 /* Make sure X resources of the face are allocated. */
1333 xassert (face != NULL);
1334 PREPARE_FACE_FOR_DISPLAY (f, face);
1335
1336 return face;
1337}
1338
1339
1340/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1341 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1342 a pointer to a realized face that is ready for display. */
1343
1344static INLINE struct face *
ee569018 1345x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1346 struct frame *f;
1347 struct glyph *glyph;
1348 XChar2b *char2b;
ee569018 1349 int *two_byte_p;
06a2c219
GM
1350{
1351 struct face *face;
1352
1353 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1354 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1355
ee569018
KH
1356 if (two_byte_p)
1357 *two_byte_p = 0;
1358
06a2c219
GM
1359 if (!glyph->multibyte_p)
1360 {
1361 /* Unibyte case. We don't have to encode, but we have to make
1362 sure to use a face suitable for unibyte. */
1363 char2b->byte1 = 0;
43d120d8 1364 char2b->byte2 = glyph->u.ch;
06a2c219 1365 }
43d120d8
KH
1366 else if (glyph->u.ch < 128
1367 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1368 {
1369 /* Case of ASCII in a face known to fit ASCII. */
1370 char2b->byte1 = 0;
43d120d8 1371 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1372 }
1373 else
1374 {
1375 int c1, c2, charset;
1376
1377 /* Split characters into bytes. If c2 is -1 afterwards, C is
1378 really a one-byte character so that byte1 is zero. */
43d120d8 1379 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1380 if (c2 > 0)
1381 char2b->byte1 = c1, char2b->byte2 = c2;
1382 else
1383 char2b->byte1 = 0, char2b->byte2 = c1;
1384
1385 /* Maybe encode the character in *CHAR2B. */
1386 if (charset != CHARSET_ASCII)
1387 {
1388 struct font_info *font_info
1389 = FONT_INFO_FROM_ID (f, face->font_info_id);
1390 if (font_info)
1391 {
43d120d8 1392 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1393 if (two_byte_p)
1394 *two_byte_p
1395 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1396 }
1397 }
1398 }
1399
1400 /* Make sure X resources of the face are allocated. */
1401 xassert (face != NULL);
1402 PREPARE_FACE_FOR_DISPLAY (f, face);
1403 return face;
1404}
1405
1406
1407/* Store one glyph for IT->char_to_display in IT->glyph_row.
1408 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1409
1410static INLINE void
1411x_append_glyph (it)
1412 struct it *it;
1413{
1414 struct glyph *glyph;
1415 enum glyph_row_area area = it->area;
1416
1417 xassert (it->glyph_row);
1418 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1419
1420 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1421 if (glyph < it->glyph_row->glyphs[area + 1])
1422 {
06a2c219
GM
1423 glyph->charpos = CHARPOS (it->position);
1424 glyph->object = it->object;
88d75730 1425 glyph->pixel_width = it->pixel_width;
06a2c219 1426 glyph->voffset = it->voffset;
88d75730 1427 glyph->type = CHAR_GLYPH;
06a2c219 1428 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1429 glyph->left_box_line_p = it->start_of_box_run_p;
1430 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1431 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1432 || it->phys_descent > it->descent);
88d75730 1433 glyph->padding_p = 0;
ee569018 1434 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1435 glyph->face_id = it->face_id;
1436 glyph->u.ch = it->char_to_display;
06a2c219
GM
1437 ++it->glyph_row->used[area];
1438 }
1439}
1440
b4192550
KH
1441/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1442 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1443
1444static INLINE void
1445x_append_composite_glyph (it)
1446 struct it *it;
1447{
1448 struct glyph *glyph;
1449 enum glyph_row_area area = it->area;
1450
1451 xassert (it->glyph_row);
1452
1453 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1454 if (glyph < it->glyph_row->glyphs[area + 1])
1455 {
b4192550
KH
1456 glyph->charpos = CHARPOS (it->position);
1457 glyph->object = it->object;
88d75730 1458 glyph->pixel_width = it->pixel_width;
b4192550 1459 glyph->voffset = it->voffset;
88d75730 1460 glyph->type = COMPOSITE_GLYPH;
b4192550 1461 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1462 glyph->left_box_line_p = it->start_of_box_run_p;
1463 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1464 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1465 || it->phys_descent > it->descent);
88d75730
GM
1466 glyph->padding_p = 0;
1467 glyph->glyph_not_available_p = 0;
1468 glyph->face_id = it->face_id;
1469 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1470 ++it->glyph_row->used[area];
1471 }
1472}
1473
06a2c219
GM
1474
1475/* Change IT->ascent and IT->height according to the setting of
1476 IT->voffset. */
1477
1478static INLINE void
1479take_vertical_position_into_account (it)
1480 struct it *it;
1481{
1482 if (it->voffset)
1483 {
1484 if (it->voffset < 0)
1485 /* Increase the ascent so that we can display the text higher
1486 in the line. */
1487 it->ascent += abs (it->voffset);
1488 else
1489 /* Increase the descent so that we can display the text lower
1490 in the line. */
1491 it->descent += it->voffset;
1492 }
1493}
1494
1495
1496/* Produce glyphs/get display metrics for the image IT is loaded with.
1497 See the description of struct display_iterator in dispextern.h for
1498 an overview of struct display_iterator. */
1499
1500static void
1501x_produce_image_glyph (it)
1502 struct it *it;
1503{
1504 struct image *img;
1505 struct face *face;
1506
1507 xassert (it->what == IT_IMAGE);
1508
1509 face = FACE_FROM_ID (it->f, it->face_id);
1510 img = IMAGE_FROM_ID (it->f, it->image_id);
1511 xassert (img);
1512
1513 /* Make sure X resources of the face and image are loaded. */
1514 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1515 prepare_image_for_display (it->f, img);
1516
95af8492 1517 it->ascent = it->phys_ascent = image_ascent (img, face);
22d650b8
GM
1518 it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
1519 it->pixel_width = img->width + 2 * img->hmargin;
06a2c219
GM
1520
1521 it->nglyphs = 1;
1522
1523 if (face->box != FACE_NO_BOX)
1524 {
ea2ba0d4
KH
1525 if (face->box_line_width > 0)
1526 {
1527 it->ascent += face->box_line_width;
1528 it->descent += face->box_line_width;
1529 }
06a2c219
GM
1530
1531 if (it->start_of_box_run_p)
ea2ba0d4 1532 it->pixel_width += abs (face->box_line_width);
06a2c219 1533 if (it->end_of_box_run_p)
ea2ba0d4 1534 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1535 }
1536
1537 take_vertical_position_into_account (it);
1538
1539 if (it->glyph_row)
1540 {
1541 struct glyph *glyph;
1542 enum glyph_row_area area = it->area;
1543
1544 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1545 if (glyph < it->glyph_row->glyphs[area + 1])
1546 {
06a2c219
GM
1547 glyph->charpos = CHARPOS (it->position);
1548 glyph->object = it->object;
88d75730 1549 glyph->pixel_width = it->pixel_width;
06a2c219 1550 glyph->voffset = it->voffset;
88d75730 1551 glyph->type = IMAGE_GLYPH;
06a2c219 1552 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1553 glyph->left_box_line_p = it->start_of_box_run_p;
1554 glyph->right_box_line_p = it->end_of_box_run_p;
1555 glyph->overlaps_vertically_p = 0;
1556 glyph->padding_p = 0;
1557 glyph->glyph_not_available_p = 0;
1558 glyph->face_id = it->face_id;
1559 glyph->u.img_id = img->id;
06a2c219
GM
1560 ++it->glyph_row->used[area];
1561 }
1562 }
1563}
1564
1565
1566/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1567 of the glyph, WIDTH and HEIGHT are the width and height of the
1568 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1569 ascent of the glyph (0 <= ASCENT <= 1). */
1570
1571static void
1572x_append_stretch_glyph (it, object, width, height, ascent)
1573 struct it *it;
1574 Lisp_Object object;
1575 int width, height;
1576 double ascent;
1577{
1578 struct glyph *glyph;
1579 enum glyph_row_area area = it->area;
1580
1581 xassert (ascent >= 0 && ascent <= 1);
1582
1583 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1584 if (glyph < it->glyph_row->glyphs[area + 1])
1585 {
06a2c219
GM
1586 glyph->charpos = CHARPOS (it->position);
1587 glyph->object = object;
88d75730 1588 glyph->pixel_width = width;
06a2c219 1589 glyph->voffset = it->voffset;
88d75730 1590 glyph->type = STRETCH_GLYPH;
06a2c219 1591 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1592 glyph->left_box_line_p = it->start_of_box_run_p;
1593 glyph->right_box_line_p = it->end_of_box_run_p;
1594 glyph->overlaps_vertically_p = 0;
1595 glyph->padding_p = 0;
1596 glyph->glyph_not_available_p = 0;
1597 glyph->face_id = it->face_id;
1598 glyph->u.stretch.ascent = height * ascent;
1599 glyph->u.stretch.height = height;
06a2c219
GM
1600 ++it->glyph_row->used[area];
1601 }
1602}
1603
1604
1605/* Produce a stretch glyph for iterator IT. IT->object is the value
1606 of the glyph property displayed. The value must be a list
1607 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1608 being recognized:
1609
1610 1. `:width WIDTH' specifies that the space should be WIDTH *
1611 canonical char width wide. WIDTH may be an integer or floating
1612 point number.
1613
1614 2. `:relative-width FACTOR' specifies that the width of the stretch
1615 should be computed from the width of the first character having the
1616 `glyph' property, and should be FACTOR times that width.
1617
1618 3. `:align-to HPOS' specifies that the space should be wide enough
1619 to reach HPOS, a value in canonical character units.
1620
1621 Exactly one of the above pairs must be present.
1622
1623 4. `:height HEIGHT' specifies that the height of the stretch produced
1624 should be HEIGHT, measured in canonical character units.
1625
1626 5. `:relative-height FACTOR' specifies that the height of the the
1627 stretch should be FACTOR times the height of the characters having
1628 the glyph property.
1629
1630 Either none or exactly one of 4 or 5 must be present.
1631
1632 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1633 of the stretch should be used for the ascent of the stretch.
1634 ASCENT must be in the range 0 <= ASCENT <= 100. */
1635
1636#define NUMVAL(X) \
1637 ((INTEGERP (X) || FLOATP (X)) \
1638 ? XFLOATINT (X) \
1639 : - 1)
1640
1641
1642static void
1643x_produce_stretch_glyph (it)
1644 struct it *it;
1645{
1646 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1647#if GLYPH_DEBUG
1648 extern Lisp_Object Qspace;
1649#endif
1650 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1651 extern Lisp_Object QCrelative_width, QCrelative_height;
1652 extern Lisp_Object QCalign_to;
1653 Lisp_Object prop, plist;
1654 double width = 0, height = 0, ascent = 0;
1655 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1656 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1657
1658 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1659
1660 /* List should start with `space'. */
1661 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1662 plist = XCDR (it->object);
1663
1664 /* Compute the width of the stretch. */
1665 if (prop = Fplist_get (plist, QCwidth),
1666 NUMVAL (prop) > 0)
1667 /* Absolute width `:width WIDTH' specified and valid. */
1668 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1669 else if (prop = Fplist_get (plist, QCrelative_width),
1670 NUMVAL (prop) > 0)
1671 {
1672 /* Relative width `:relative-width FACTOR' specified and valid.
1673 Compute the width of the characters having the `glyph'
1674 property. */
1675 struct it it2;
1676 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1677
1678 it2 = *it;
1679 if (it->multibyte_p)
1680 {
1681 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1682 - IT_BYTEPOS (*it));
1683 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1684 }
1685 else
1686 it2.c = *p, it2.len = 1;
1687
1688 it2.glyph_row = NULL;
1689 it2.what = IT_CHARACTER;
1690 x_produce_glyphs (&it2);
1691 width = NUMVAL (prop) * it2.pixel_width;
1692 }
1693 else if (prop = Fplist_get (plist, QCalign_to),
1694 NUMVAL (prop) > 0)
1695 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1696 else
1697 /* Nothing specified -> width defaults to canonical char width. */
1698 width = CANON_X_UNIT (it->f);
1699
1700 /* Compute height. */
1701 if (prop = Fplist_get (plist, QCheight),
1702 NUMVAL (prop) > 0)
1703 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1704 else if (prop = Fplist_get (plist, QCrelative_height),
1705 NUMVAL (prop) > 0)
1706 height = FONT_HEIGHT (font) * NUMVAL (prop);
1707 else
1708 height = FONT_HEIGHT (font);
1709
1710 /* Compute percentage of height used for ascent. If
1711 `:ascent ASCENT' is present and valid, use that. Otherwise,
1712 derive the ascent from the font in use. */
1713 if (prop = Fplist_get (plist, QCascent),
1714 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1715 ascent = NUMVAL (prop) / 100.0;
1716 else
1717 ascent = (double) font->ascent / FONT_HEIGHT (font);
1718
1719 if (width <= 0)
1720 width = 1;
1721 if (height <= 0)
1722 height = 1;
1723
1724 if (it->glyph_row)
1725 {
1726 Lisp_Object object = it->stack[it->sp - 1].string;
1727 if (!STRINGP (object))
1728 object = it->w->buffer;
1729 x_append_stretch_glyph (it, object, width, height, ascent);
1730 }
1731
1732 it->pixel_width = width;
66ac4b0e
GM
1733 it->ascent = it->phys_ascent = height * ascent;
1734 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1735 it->nglyphs = 1;
1736
1737 if (face->box != FACE_NO_BOX)
1738 {
ea2ba0d4
KH
1739 if (face->box_line_width > 0)
1740 {
1741 it->ascent += face->box_line_width;
1742 it->descent += face->box_line_width;
1743 }
06a2c219
GM
1744
1745 if (it->start_of_box_run_p)
ea2ba0d4 1746 it->pixel_width += abs (face->box_line_width);
06a2c219 1747 if (it->end_of_box_run_p)
ea2ba0d4 1748 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1749 }
1750
1751 take_vertical_position_into_account (it);
1752}
1753
b4192550
KH
1754/* Return proper value to be used as baseline offset of font that has
1755 ASCENT and DESCENT to draw characters by the font at the vertical
1756 center of the line of frame F.
1757
1758 Here, out task is to find the value of BOFF in the following figure;
1759
1760 -------------------------+-----------+-
1761 -+-+---------+-+ | |
1762 | | | | | |
1763 | | | | F_ASCENT F_HEIGHT
1764 | | | ASCENT | |
1765 HEIGHT | | | | |
1766 | | |-|-+------+-----------|------- baseline
1767 | | | | BOFF | |
1768 | |---------|-+-+ | |
1769 | | | DESCENT | |
1770 -+-+---------+-+ F_DESCENT |
1771 -------------------------+-----------+-
1772
1773 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1774 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1775 DESCENT = FONT->descent
1776 HEIGHT = FONT_HEIGHT (FONT)
1777 F_DESCENT = (F->output_data.x->font->descent
1778 - F->output_data.x->baseline_offset)
1779 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1780*/
1781
458f45fa
KH
1782#define VCENTER_BASELINE_OFFSET(FONT, F) \
1783 ((FONT)->descent \
1784 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT)) \
1785 + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \
1786 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1787
1788/* Produce glyphs/get display metrics for the display element IT is
1789 loaded with. See the description of struct display_iterator in
1790 dispextern.h for an overview of struct display_iterator. */
1791
1792static void
1793x_produce_glyphs (it)
1794 struct it *it;
1795{
ee569018
KH
1796 it->glyph_not_available_p = 0;
1797
06a2c219
GM
1798 if (it->what == IT_CHARACTER)
1799 {
1800 XChar2b char2b;
1801 XFontStruct *font;
ee569018 1802 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1803 XCharStruct *pcm;
06a2c219 1804 int font_not_found_p;
b4192550
KH
1805 struct font_info *font_info;
1806 int boff; /* baseline offset */
a4249304
KH
1807 /* We may change it->multibyte_p upon unibyte<->multibyte
1808 conversion. So, save the current value now and restore it
1809 later.
1810
1811 Note: It seems that we don't have to record multibyte_p in
1812 struct glyph because the character code itself tells if or
1813 not the character is multibyte. Thus, in the future, we must
1814 consider eliminating the field `multibyte_p' in the struct
c347a1c3 1815 glyph. */
a4249304 1816 int saved_multibyte_p = it->multibyte_p;
06a2c219 1817
ee569018
KH
1818 /* Maybe translate single-byte characters to multibyte, or the
1819 other way. */
06a2c219 1820 it->char_to_display = it->c;
ee569018 1821 if (!ASCII_BYTE_P (it->c))
06a2c219 1822 {
ee569018
KH
1823 if (unibyte_display_via_language_environment
1824 && SINGLE_BYTE_CHAR_P (it->c)
1825 && (it->c >= 0240
1826 || !NILP (Vnonascii_translation_table)))
1827 {
1828 it->char_to_display = unibyte_char_to_multibyte (it->c);
a4249304 1829 it->multibyte_p = 1;
ee569018
KH
1830 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1831 face = FACE_FROM_ID (it->f, it->face_id);
1832 }
1833 else if (!SINGLE_BYTE_CHAR_P (it->c)
1834 && !it->multibyte_p)
1835 {
c347a1c3 1836 it->multibyte_p = 1;
ee569018
KH
1837 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1838 face = FACE_FROM_ID (it->f, it->face_id);
1839 }
06a2c219
GM
1840 }
1841
ee569018
KH
1842 /* Get font to use. Encode IT->char_to_display. */
1843 x_get_char_face_and_encoding (it->f, it->char_to_display,
1844 it->face_id, &char2b,
1845 it->multibyte_p);
06a2c219
GM
1846 font = face->font;
1847
1848 /* When no suitable font found, use the default font. */
1849 font_not_found_p = font == NULL;
1850 if (font_not_found_p)
b4192550
KH
1851 {
1852 font = FRAME_FONT (it->f);
1853 boff = it->f->output_data.x->baseline_offset;
1854 font_info = NULL;
1855 }
1856 else
1857 {
1858 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1859 boff = font_info->baseline_offset;
1860 if (font_info->vertical_centering)
1861 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1862 }
06a2c219
GM
1863
1864 if (it->char_to_display >= ' '
1865 && (!it->multibyte_p || it->char_to_display < 128))
1866 {
1867 /* Either unibyte or ASCII. */
1868 int stretched_p;
1869
1870 it->nglyphs = 1;
06a2c219
GM
1871
1872 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1873 it->ascent = font->ascent + boff;
1874 it->descent = font->descent - boff;
474848ac
GM
1875
1876 if (pcm)
1877 {
1878 it->phys_ascent = pcm->ascent + boff;
1879 it->phys_descent = pcm->descent - boff;
1880 it->pixel_width = pcm->width;
1881 }
1882 else
1883 {
1884 it->glyph_not_available_p = 1;
1885 it->phys_ascent = font->ascent + boff;
1886 it->phys_descent = font->descent - boff;
1887 it->pixel_width = FONT_WIDTH (font);
1888 }
06a2c219
GM
1889
1890 /* If this is a space inside a region of text with
1891 `space-width' property, change its width. */
1892 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1893 if (stretched_p)
1894 it->pixel_width *= XFLOATINT (it->space_width);
1895
1896 /* If face has a box, add the box thickness to the character
1897 height. If character has a box line to the left and/or
1898 right, add the box line width to the character's width. */
1899 if (face->box != FACE_NO_BOX)
1900 {
1901 int thick = face->box_line_width;
1902
ea2ba0d4
KH
1903 if (thick > 0)
1904 {
1905 it->ascent += thick;
1906 it->descent += thick;
1907 }
1908 else
1909 thick = -thick;
1910
06a2c219
GM
1911 if (it->start_of_box_run_p)
1912 it->pixel_width += thick;
1913 if (it->end_of_box_run_p)
1914 it->pixel_width += thick;
1915 }
1916
1917 /* If face has an overline, add the height of the overline
1918 (1 pixel) and a 1 pixel margin to the character height. */
1919 if (face->overline_p)
1920 it->ascent += 2;
1921
1922 take_vertical_position_into_account (it);
1923
1924 /* If we have to actually produce glyphs, do it. */
1925 if (it->glyph_row)
1926 {
1927 if (stretched_p)
1928 {
1929 /* Translate a space with a `space-width' property
1930 into a stretch glyph. */
1931 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1932 x_append_stretch_glyph (it, it->object, it->pixel_width,
1933 it->ascent + it->descent, ascent);
1934 }
1935 else
1936 x_append_glyph (it);
1937
1938 /* If characters with lbearing or rbearing are displayed
1939 in this line, record that fact in a flag of the
1940 glyph row. This is used to optimize X output code. */
1c7e22fd 1941 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1942 it->glyph_row->contains_overlapping_glyphs_p = 1;
1943 }
1944 }
1945 else if (it->char_to_display == '\n')
1946 {
1947 /* A newline has no width but we need the height of the line. */
1948 it->pixel_width = 0;
1949 it->nglyphs = 0;
b4192550
KH
1950 it->ascent = it->phys_ascent = font->ascent + boff;
1951 it->descent = it->phys_descent = font->descent - boff;
06a2c219 1952
ea2ba0d4
KH
1953 if (face->box != FACE_NO_BOX
1954 && face->box_line_width > 0)
06a2c219 1955 {
ea2ba0d4
KH
1956 it->ascent += face->box_line_width;
1957 it->descent += face->box_line_width;
06a2c219
GM
1958 }
1959 }
1960 else if (it->char_to_display == '\t')
1961 {
1962 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1963 int x = it->current_x + it->continuation_lines_width;
06a2c219 1964 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
2a32b5ea
GM
1965
1966 /* If the distance from the current position to the next tab
1967 stop is less than a canonical character width, use the
1968 tab stop after that. */
1969 if (next_tab_x - x < CANON_X_UNIT (it->f))
1970 next_tab_x += tab_width;
06a2c219
GM
1971
1972 it->pixel_width = next_tab_x - x;
1973 it->nglyphs = 1;
b4192550
KH
1974 it->ascent = it->phys_ascent = font->ascent + boff;
1975 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1976
1977 if (it->glyph_row)
1978 {
1979 double ascent = (double) it->ascent / (it->ascent + it->descent);
1980 x_append_stretch_glyph (it, it->object, it->pixel_width,
1981 it->ascent + it->descent, ascent);
1982 }
1983 }
1984 else
1985 {
1986 /* A multi-byte character. Assume that the display width of the
1987 character is the width of the character multiplied by the
b4192550 1988 width of the font. */
06a2c219 1989
b4192550
KH
1990 /* If we found a font, this font should give us the right
1991 metrics. If we didn't find a font, use the frame's
1992 default font and calculate the width of the character
1993 from the charset width; this is what old redisplay code
1994 did. */
1995 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
1996 if (font_not_found_p || !pcm)
1997 {
1998 int charset = CHAR_CHARSET (it->char_to_display);
1999
2000 it->glyph_not_available_p = 1;
2001 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
2002 * CHARSET_WIDTH (charset));
2003 it->phys_ascent = font->ascent + boff;
2004 it->phys_descent = font->descent - boff;
2005 }
2006 else
2007 {
2008 it->pixel_width = pcm->width;
2009 it->phys_ascent = pcm->ascent + boff;
2010 it->phys_descent = pcm->descent - boff;
2011 if (it->glyph_row
2012 && (pcm->lbearing < 0
2013 || pcm->rbearing > pcm->width))
2014 it->glyph_row->contains_overlapping_glyphs_p = 1;
2015 }
b4192550
KH
2016 it->nglyphs = 1;
2017 it->ascent = font->ascent + boff;
2018 it->descent = font->descent - boff;
06a2c219
GM
2019 if (face->box != FACE_NO_BOX)
2020 {
2021 int thick = face->box_line_width;
ea2ba0d4
KH
2022
2023 if (thick > 0)
2024 {
2025 it->ascent += thick;
2026 it->descent += thick;
2027 }
2028 else
2029 thick = - thick;
06a2c219
GM
2030
2031 if (it->start_of_box_run_p)
2032 it->pixel_width += thick;
2033 if (it->end_of_box_run_p)
2034 it->pixel_width += thick;
2035 }
2036
2037 /* If face has an overline, add the height of the overline
2038 (1 pixel) and a 1 pixel margin to the character height. */
2039 if (face->overline_p)
2040 it->ascent += 2;
2041
2042 take_vertical_position_into_account (it);
2043
2044 if (it->glyph_row)
2045 x_append_glyph (it);
2046 }
a4249304 2047 it->multibyte_p = saved_multibyte_p;
06a2c219 2048 }
b4192550
KH
2049 else if (it->what == IT_COMPOSITION)
2050 {
2051 /* Note: A composition is represented as one glyph in the
2052 glyph matrix. There are no padding glyphs. */
2053 XChar2b char2b;
2054 XFontStruct *font;
ee569018 2055 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2056 XCharStruct *pcm;
2057 int font_not_found_p;
2058 struct font_info *font_info;
2059 int boff; /* baseline offset */
2060 struct composition *cmp = composition_table[it->cmp_id];
2061
2062 /* Maybe translate single-byte characters to multibyte. */
2063 it->char_to_display = it->c;
2064 if (unibyte_display_via_language_environment
2065 && SINGLE_BYTE_CHAR_P (it->c)
2066 && (it->c >= 0240
2067 || (it->c >= 0200
2068 && !NILP (Vnonascii_translation_table))))
2069 {
2070 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2071 }
2072
2073 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2074 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2075 face = FACE_FROM_ID (it->f, it->face_id);
2076 x_get_char_face_and_encoding (it->f, it->char_to_display,
2077 it->face_id, &char2b, it->multibyte_p);
b4192550
KH
2078 font = face->font;
2079
2080 /* When no suitable font found, use the default font. */
2081 font_not_found_p = font == NULL;
2082 if (font_not_found_p)
2083 {
2084 font = FRAME_FONT (it->f);
2085 boff = it->f->output_data.x->baseline_offset;
2086 font_info = NULL;
2087 }
2088 else
2089 {
2090 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2091 boff = font_info->baseline_offset;
2092 if (font_info->vertical_centering)
2093 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2094 }
2095
2096 /* There are no padding glyphs, so there is only one glyph to
2097 produce for the composition. Important is that pixel_width,
2098 ascent and descent are the values of what is drawn by
2099 draw_glyphs (i.e. the values of the overall glyphs composed). */
2100 it->nglyphs = 1;
2101
2102 /* If we have not yet calculated pixel size data of glyphs of
2103 the composition for the current face font, calculate them
2104 now. Theoretically, we have to check all fonts for the
2105 glyphs, but that requires much time and memory space. So,
2106 here we check only the font of the first glyph. This leads
2107 to incorrect display very rarely, and C-l (recenter) can
2108 correct the display anyway. */
2109 if (cmp->font != (void *) font)
2110 {
2111 /* Ascent and descent of the font of the first character of
2112 this composition (adjusted by baseline offset). Ascent
2113 and descent of overall glyphs should not be less than
2114 them respectively. */
2115 int font_ascent = font->ascent + boff;
2116 int font_descent = font->descent - boff;
2117 /* Bounding box of the overall glyphs. */
2118 int leftmost, rightmost, lowest, highest;
329bed06 2119 int i, width, ascent, descent;
b4192550
KH
2120
2121 cmp->font = (void *) font;
2122
2123 /* Initialize the bounding box. */
1bdeec2e
KH
2124 if (font_info
2125 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2126 {
2127 width = pcm->width;
2128 ascent = pcm->ascent;
2129 descent = pcm->descent;
2130 }
2131 else
2132 {
2133 width = FONT_WIDTH (font);
2134 ascent = font->ascent;
2135 descent = font->descent;
2136 }
2137
2138 rightmost = width;
2139 lowest = - descent + boff;
2140 highest = ascent + boff;
b4192550 2141 leftmost = 0;
329bed06 2142
b4192550
KH
2143 if (font_info
2144 && font_info->default_ascent
2145 && CHAR_TABLE_P (Vuse_default_ascent)
2146 && !NILP (Faref (Vuse_default_ascent,
2147 make_number (it->char_to_display))))
2148 highest = font_info->default_ascent + boff;
2149
2150 /* Draw the first glyph at the normal position. It may be
2151 shifted to right later if some other glyphs are drawn at
2152 the left. */
2153 cmp->offsets[0] = 0;
2154 cmp->offsets[1] = boff;
2155
2156 /* Set cmp->offsets for the remaining glyphs. */
2157 for (i = 1; i < cmp->glyph_len; i++)
2158 {
2159 int left, right, btm, top;
2160 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2161 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2162
2163 face = FACE_FROM_ID (it->f, face_id);
2164 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2165 it->multibyte_p);
b4192550
KH
2166 font = face->font;
2167 if (font == NULL)
2168 {
2169 font = FRAME_FONT (it->f);
2170 boff = it->f->output_data.x->baseline_offset;
2171 font_info = NULL;
2172 }
2173 else
2174 {
2175 font_info
2176 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2177 boff = font_info->baseline_offset;
2178 if (font_info->vertical_centering)
2179 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2180 }
2181
1bdeec2e
KH
2182 if (font_info
2183 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2184 {
2185 width = pcm->width;
2186 ascent = pcm->ascent;
2187 descent = pcm->descent;
2188 }
2189 else
2190 {
2191 width = FONT_WIDTH (font);
1bdeec2e
KH
2192 ascent = 1;
2193 descent = 0;
329bed06 2194 }
b4192550
KH
2195
2196 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2197 {
2198 /* Relative composition with or without
2199 alternate chars. */
329bed06
GM
2200 left = (leftmost + rightmost - width) / 2;
2201 btm = - descent + boff;
b4192550
KH
2202 if (font_info && font_info->relative_compose
2203 && (! CHAR_TABLE_P (Vignore_relative_composition)
2204 || NILP (Faref (Vignore_relative_composition,
2205 make_number (ch)))))
2206 {
2207
329bed06 2208 if (- descent >= font_info->relative_compose)
b4192550
KH
2209 /* One extra pixel between two glyphs. */
2210 btm = highest + 1;
329bed06 2211 else if (ascent <= 0)
b4192550 2212 /* One extra pixel between two glyphs. */
329bed06 2213 btm = lowest - 1 - ascent - descent;
b4192550
KH
2214 }
2215 }
2216 else
2217 {
2218 /* A composition rule is specified by an integer
2219 value that encodes global and new reference
2220 points (GREF and NREF). GREF and NREF are
2221 specified by numbers as below:
2222
2223 0---1---2 -- ascent
2224 | |
2225 | |
2226 | |
2227 9--10--11 -- center
2228 | |
2229 ---3---4---5--- baseline
2230 | |
2231 6---7---8 -- descent
2232 */
2233 int rule = COMPOSITION_RULE (cmp, i);
2234 int gref, nref, grefx, grefy, nrefx, nrefy;
2235
2236 COMPOSITION_DECODE_RULE (rule, gref, nref);
2237 grefx = gref % 3, nrefx = nref % 3;
2238 grefy = gref / 3, nrefy = nref / 3;
2239
2240 left = (leftmost
2241 + grefx * (rightmost - leftmost) / 2
329bed06 2242 - nrefx * width / 2);
b4192550
KH
2243 btm = ((grefy == 0 ? highest
2244 : grefy == 1 ? 0
2245 : grefy == 2 ? lowest
2246 : (highest + lowest) / 2)
329bed06
GM
2247 - (nrefy == 0 ? ascent + descent
2248 : nrefy == 1 ? descent - boff
b4192550 2249 : nrefy == 2 ? 0
329bed06 2250 : (ascent + descent) / 2));
b4192550
KH
2251 }
2252
2253 cmp->offsets[i * 2] = left;
329bed06 2254 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2255
2256 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2257 right = left + width;
2258 top = btm + descent + ascent;
b4192550
KH
2259 if (left < leftmost)
2260 leftmost = left;
2261 if (right > rightmost)
2262 rightmost = right;
2263 if (top > highest)
2264 highest = top;
2265 if (btm < lowest)
2266 lowest = btm;
2267 }
2268
2269 /* If there are glyphs whose x-offsets are negative,
2270 shift all glyphs to the right and make all x-offsets
2271 non-negative. */
2272 if (leftmost < 0)
2273 {
2274 for (i = 0; i < cmp->glyph_len; i++)
2275 cmp->offsets[i * 2] -= leftmost;
2276 rightmost -= leftmost;
2277 }
2278
2279 cmp->pixel_width = rightmost;
2280 cmp->ascent = highest;
2281 cmp->descent = - lowest;
2282 if (cmp->ascent < font_ascent)
2283 cmp->ascent = font_ascent;
2284 if (cmp->descent < font_descent)
2285 cmp->descent = font_descent;
2286 }
2287
2288 it->pixel_width = cmp->pixel_width;
2289 it->ascent = it->phys_ascent = cmp->ascent;
2290 it->descent = it->phys_descent = cmp->descent;
2291
2292 if (face->box != FACE_NO_BOX)
2293 {
2294 int thick = face->box_line_width;
ea2ba0d4
KH
2295
2296 if (thick > 0)
2297 {
2298 it->ascent += thick;
2299 it->descent += thick;
2300 }
2301 else
2302 thick = - thick;
b4192550
KH
2303
2304 if (it->start_of_box_run_p)
2305 it->pixel_width += thick;
2306 if (it->end_of_box_run_p)
2307 it->pixel_width += thick;
2308 }
2309
2310 /* If face has an overline, add the height of the overline
2311 (1 pixel) and a 1 pixel margin to the character height. */
2312 if (face->overline_p)
2313 it->ascent += 2;
2314
2315 take_vertical_position_into_account (it);
2316
2317 if (it->glyph_row)
2318 x_append_composite_glyph (it);
2319 }
06a2c219
GM
2320 else if (it->what == IT_IMAGE)
2321 x_produce_image_glyph (it);
2322 else if (it->what == IT_STRETCH)
2323 x_produce_stretch_glyph (it);
2324
3017fdd1
GM
2325 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2326 because this isn't true for images with `:ascent 100'. */
2327 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2328 if (it->area == TEXT_AREA)
2329 it->current_x += it->pixel_width;
66ac4b0e 2330
d365f5bb
GM
2331 it->descent += it->extra_line_spacing;
2332
06a2c219
GM
2333 it->max_ascent = max (it->max_ascent, it->ascent);
2334 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2335 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2336 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2337}
2338
2339
2340/* Estimate the pixel height of the mode or top line on frame F.
2341 FACE_ID specifies what line's height to estimate. */
2342
2343int
2344x_estimate_mode_line_height (f, face_id)
2345 struct frame *f;
2346 enum face_id face_id;
2347{
43281ee3 2348 int height = FONT_HEIGHT (FRAME_FONT (f));
06a2c219
GM
2349
2350 /* This function is called so early when Emacs starts that the face
2351 cache and mode line face are not yet initialized. */
2352 if (FRAME_FACE_CACHE (f))
2353 {
2354 struct face *face = FACE_FROM_ID (f, face_id);
2355 if (face)
43281ee3
GM
2356 {
2357 if (face->font)
2358 height = FONT_HEIGHT (face->font);
ea2ba0d4
KH
2359 if (face->box_line_width > 0)
2360 height += 2 * face->box_line_width;
43281ee3 2361 }
06a2c219
GM
2362 }
2363
2364 return height;
2365}
2366
2367\f
2368/***********************************************************************
2369 Glyph display
2370 ***********************************************************************/
2371
2372/* A sequence of glyphs to be drawn in the same face.
2373
2374 This data structure is not really completely X specific, so it
2375 could possibly, at least partially, be useful for other systems. It
2376 is currently not part of the external redisplay interface because
2377 it's not clear what other systems will need. */
2378
2379struct glyph_string
2380{
2381 /* X-origin of the string. */
2382 int x;
2383
2384 /* Y-origin and y-position of the base line of this string. */
2385 int y, ybase;
2386
2387 /* The width of the string, not including a face extension. */
2388 int width;
2389
2390 /* The width of the string, including a face extension. */
2391 int background_width;
2392
2393 /* The height of this string. This is the height of the line this
2394 string is drawn in, and can be different from the height of the
2395 font the string is drawn in. */
2396 int height;
2397
2398 /* Number of pixels this string overwrites in front of its x-origin.
2399 This number is zero if the string has an lbearing >= 0; it is
2400 -lbearing, if the string has an lbearing < 0. */
2401 int left_overhang;
2402
2403 /* Number of pixels this string overwrites past its right-most
2404 nominal x-position, i.e. x + width. Zero if the string's
2405 rbearing is <= its nominal width, rbearing - width otherwise. */
2406 int right_overhang;
2407
2408 /* The frame on which the glyph string is drawn. */
2409 struct frame *f;
2410
2411 /* The window on which the glyph string is drawn. */
2412 struct window *w;
2413
2414 /* X display and window for convenience. */
2415 Display *display;
2416 Window window;
2417
2418 /* The glyph row for which this string was built. It determines the
2419 y-origin and height of the string. */
2420 struct glyph_row *row;
2421
2422 /* The area within row. */
2423 enum glyph_row_area area;
2424
2425 /* Characters to be drawn, and number of characters. */
2426 XChar2b *char2b;
2427 int nchars;
2428
06a2c219
GM
2429 /* A face-override for drawing cursors, mouse face and similar. */
2430 enum draw_glyphs_face hl;
2431
2432 /* Face in which this string is to be drawn. */
2433 struct face *face;
2434
2435 /* Font in which this string is to be drawn. */
2436 XFontStruct *font;
2437
2438 /* Font info for this string. */
2439 struct font_info *font_info;
2440
b4192550
KH
2441 /* Non-null means this string describes (part of) a composition.
2442 All characters from char2b are drawn composed. */
2443 struct composition *cmp;
06a2c219
GM
2444
2445 /* Index of this glyph string's first character in the glyph
b4192550
KH
2446 definition of CMP. If this is zero, this glyph string describes
2447 the first character of a composition. */
06a2c219
GM
2448 int gidx;
2449
2450 /* 1 means this glyph strings face has to be drawn to the right end
2451 of the window's drawing area. */
2452 unsigned extends_to_end_of_line_p : 1;
2453
2454 /* 1 means the background of this string has been drawn. */
2455 unsigned background_filled_p : 1;
2456
2457 /* 1 means glyph string must be drawn with 16-bit functions. */
2458 unsigned two_byte_p : 1;
2459
2460 /* 1 means that the original font determined for drawing this glyph
2461 string could not be loaded. The member `font' has been set to
2462 the frame's default font in this case. */
2463 unsigned font_not_found_p : 1;
2464
2465 /* 1 means that the face in which this glyph string is drawn has a
2466 stipple pattern. */
2467 unsigned stippled_p : 1;
2468
66ac4b0e
GM
2469 /* 1 means only the foreground of this glyph string must be drawn,
2470 and we should use the physical height of the line this glyph
2471 string appears in as clip rect. */
2472 unsigned for_overlaps_p : 1;
2473
06a2c219
GM
2474 /* The GC to use for drawing this glyph string. */
2475 GC gc;
2476
2477 /* A pointer to the first glyph in the string. This glyph
2478 corresponds to char2b[0]. Needed to draw rectangles if
2479 font_not_found_p is 1. */
2480 struct glyph *first_glyph;
2481
2482 /* Image, if any. */
2483 struct image *img;
2484
2485 struct glyph_string *next, *prev;
2486};
2487
2488
61869b99 2489#if GLYPH_DEBUG
06a2c219
GM
2490
2491static void
2492x_dump_glyph_string (s)
2493 struct glyph_string *s;
2494{
2495 fprintf (stderr, "glyph string\n");
2496 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2497 s->x, s->y, s->width, s->height);
2498 fprintf (stderr, " ybase = %d\n", s->ybase);
2499 fprintf (stderr, " hl = %d\n", s->hl);
2500 fprintf (stderr, " left overhang = %d, right = %d\n",
2501 s->left_overhang, s->right_overhang);
2502 fprintf (stderr, " nchars = %d\n", s->nchars);
2503 fprintf (stderr, " extends to end of line = %d\n",
2504 s->extends_to_end_of_line_p);
2505 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2506 fprintf (stderr, " bg width = %d\n", s->background_width);
2507}
2508
2509#endif /* GLYPH_DEBUG */
2510
2511
2512
2513static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2514 struct glyph_string **,
2515 struct glyph_string *,
2516 struct glyph_string *));
2517static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2518 struct glyph_string **,
2519 struct glyph_string *,
2520 struct glyph_string *));
2521static void x_append_glyph_string P_ ((struct glyph_string **,
2522 struct glyph_string **,
2523 struct glyph_string *));
2524static int x_left_overwritten P_ ((struct glyph_string *));
2525static int x_left_overwriting P_ ((struct glyph_string *));
2526static int x_right_overwritten P_ ((struct glyph_string *));
2527static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2528static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2529 int));
06a2c219
GM
2530static void x_init_glyph_string P_ ((struct glyph_string *,
2531 XChar2b *, struct window *,
2532 struct glyph_row *,
2533 enum glyph_row_area, int,
2534 enum draw_glyphs_face));
2535static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2536 enum glyph_row_area, int, int,
66ac4b0e 2537 enum draw_glyphs_face, int *, int *, int));
06a2c219
GM
2538static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2539static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2540static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2541 int));
2542static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2543static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2544static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2545static void x_draw_glyph_string P_ ((struct glyph_string *));
2546static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2547static void x_set_cursor_gc P_ ((struct glyph_string *));
2548static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2549static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2550static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2551 int *, int *));
2552static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2553static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2554 unsigned long *, double, int));
06a2c219 2555static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2556 double, int, unsigned long));
06a2c219
GM
2557static void x_setup_relief_colors P_ ((struct glyph_string *));
2558static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2559static void x_draw_image_relief P_ ((struct glyph_string *));
2560static void x_draw_image_foreground P_ ((struct glyph_string *));
2561static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2562static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2563static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2564 int, int, int));
2565static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2566 int, int, int, int, XRectangle *));
2567static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2568 int, int, int, XRectangle *));
66ac4b0e
GM
2569static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2570 enum glyph_row_area));
209f68d9
GM
2571static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2572 struct glyph_row *,
2573 enum glyph_row_area, int, int));
06a2c219 2574
163dcff3
GM
2575#if GLYPH_DEBUG
2576static void x_check_font P_ ((struct frame *, XFontStruct *));
2577#endif
2578
06a2c219 2579
06a2c219
GM
2580/* Append the list of glyph strings with head H and tail T to the list
2581 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2582
2583static INLINE void
2584x_append_glyph_string_lists (head, tail, h, t)
2585 struct glyph_string **head, **tail;
2586 struct glyph_string *h, *t;
2587{
2588 if (h)
2589 {
2590 if (*head)
2591 (*tail)->next = h;
2592 else
2593 *head = h;
2594 h->prev = *tail;
2595 *tail = t;
2596 }
2597}
2598
2599
2600/* Prepend the list of glyph strings with head H and tail T to the
2601 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2602 result. */
2603
2604static INLINE void
2605x_prepend_glyph_string_lists (head, tail, h, t)
2606 struct glyph_string **head, **tail;
2607 struct glyph_string *h, *t;
2608{
2609 if (h)
2610 {
2611 if (*head)
2612 (*head)->prev = t;
2613 else
2614 *tail = t;
2615 t->next = *head;
2616 *head = h;
2617 }
2618}
2619
2620
2621/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2622 Set *HEAD and *TAIL to the resulting list. */
2623
2624static INLINE void
2625x_append_glyph_string (head, tail, s)
2626 struct glyph_string **head, **tail;
2627 struct glyph_string *s;
2628{
2629 s->next = s->prev = NULL;
2630 x_append_glyph_string_lists (head, tail, s, s);
2631}
2632
2633
2634/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2635 face. */
2636
2637static void
2638x_set_cursor_gc (s)
2639 struct glyph_string *s;
2640{
2641 if (s->font == FRAME_FONT (s->f)
2642 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2643 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2644 && !s->cmp)
06a2c219
GM
2645 s->gc = s->f->output_data.x->cursor_gc;
2646 else
2647 {
2648 /* Cursor on non-default face: must merge. */
2649 XGCValues xgcv;
2650 unsigned long mask;
2651
2652 xgcv.background = s->f->output_data.x->cursor_pixel;
2653 xgcv.foreground = s->face->background;
2654
2655 /* If the glyph would be invisible, try a different foreground. */
2656 if (xgcv.foreground == xgcv.background)
2657 xgcv.foreground = s->face->foreground;
2658 if (xgcv.foreground == xgcv.background)
2659 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2660 if (xgcv.foreground == xgcv.background)
2661 xgcv.foreground = s->face->foreground;
2662
2663 /* Make sure the cursor is distinct from text in this face. */
2664 if (xgcv.background == s->face->background
2665 && xgcv.foreground == s->face->foreground)
2666 {
2667 xgcv.background = s->face->foreground;
2668 xgcv.foreground = s->face->background;
2669 }
2670
2671 IF_DEBUG (x_check_font (s->f, s->font));
2672 xgcv.font = s->font->fid;
2673 xgcv.graphics_exposures = False;
2674 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2675
2676 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2677 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2678 mask, &xgcv);
2679 else
2680 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2681 = XCreateGC (s->display, s->window, mask, &xgcv);
2682
2683 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2684 }
2685}
2686
2687
2688/* Set up S->gc of glyph string S for drawing text in mouse face. */
2689
2690static void
2691x_set_mouse_face_gc (s)
2692 struct glyph_string *s;
2693{
2694 int face_id;
ee569018 2695 struct face *face;
06a2c219 2696
e4ded23c 2697 /* What face has to be used last for the mouse face? */
06a2c219 2698 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2699 face = FACE_FROM_ID (s->f, face_id);
e4ded23c
GM
2700 if (face == NULL)
2701 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2702
033e3e18
GM
2703 if (s->first_glyph->type == CHAR_GLYPH)
2704 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2705 else
2706 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2707 s->face = FACE_FROM_ID (s->f, face_id);
2708 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2709
2710 /* If font in this face is same as S->font, use it. */
2711 if (s->font == s->face->font)
2712 s->gc = s->face->gc;
2713 else
2714 {
2715 /* Otherwise construct scratch_cursor_gc with values from FACE
2716 but font FONT. */
2717 XGCValues xgcv;
2718 unsigned long mask;
2719
2720 xgcv.background = s->face->background;
2721 xgcv.foreground = s->face->foreground;
2722 IF_DEBUG (x_check_font (s->f, s->font));
2723 xgcv.font = s->font->fid;
2724 xgcv.graphics_exposures = False;
2725 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2726
2727 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2728 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2729 mask, &xgcv);
2730 else
2731 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2732 = XCreateGC (s->display, s->window, mask, &xgcv);
2733
2734 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2735 }
2736
2737 xassert (s->gc != 0);
2738}
2739
2740
2741/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2742 Faces to use in the mode line have already been computed when the
2743 matrix was built, so there isn't much to do, here. */
2744
2745static INLINE void
2746x_set_mode_line_face_gc (s)
2747 struct glyph_string *s;
2748{
2749 s->gc = s->face->gc;
06a2c219
GM
2750}
2751
2752
2753/* Set S->gc of glyph string S for drawing that glyph string. Set
2754 S->stippled_p to a non-zero value if the face of S has a stipple
2755 pattern. */
2756
2757static INLINE void
2758x_set_glyph_string_gc (s)
2759 struct glyph_string *s;
2760{
209f68d9
GM
2761 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2762
06a2c219
GM
2763 if (s->hl == DRAW_NORMAL_TEXT)
2764 {
2765 s->gc = s->face->gc;
2766 s->stippled_p = s->face->stipple != 0;
2767 }
2768 else if (s->hl == DRAW_INVERSE_VIDEO)
2769 {
2770 x_set_mode_line_face_gc (s);
2771 s->stippled_p = s->face->stipple != 0;
2772 }
2773 else if (s->hl == DRAW_CURSOR)
2774 {
2775 x_set_cursor_gc (s);
2776 s->stippled_p = 0;
2777 }
2778 else if (s->hl == DRAW_MOUSE_FACE)
2779 {
2780 x_set_mouse_face_gc (s);
2781 s->stippled_p = s->face->stipple != 0;
2782 }
2783 else if (s->hl == DRAW_IMAGE_RAISED
2784 || s->hl == DRAW_IMAGE_SUNKEN)
2785 {
2786 s->gc = s->face->gc;
2787 s->stippled_p = s->face->stipple != 0;
2788 }
2789 else
2790 {
2791 s->gc = s->face->gc;
2792 s->stippled_p = s->face->stipple != 0;
2793 }
2794
2795 /* GC must have been set. */
2796 xassert (s->gc != 0);
2797}
2798
2799
2800/* Return in *R the clipping rectangle for glyph string S. */
2801
2802static void
2803x_get_glyph_string_clip_rect (s, r)
2804 struct glyph_string *s;
2805 XRectangle *r;
2806{
2807 if (s->row->full_width_p)
2808 {
2809 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2810 int canon_x = CANON_X_UNIT (s->f);
2811
2812 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2813 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2814
2815 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2816 {
1da3fd71 2817 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2818 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2819 r->x -= width;
2820 }
2821
b9432a85 2822 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2823
06a2c219
GM
2824 /* Unless displaying a mode or menu bar line, which are always
2825 fully visible, clip to the visible part of the row. */
2826 if (s->w->pseudo_window_p)
2827 r->height = s->row->visible_height;
2828 else
2829 r->height = s->height;
2830 }
2831 else
2832 {
2833 /* This is a text line that may be partially visible. */
2834 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2835 r->width = window_box_width (s->w, s->area);
2836 r->height = s->row->visible_height;
2837 }
2838
66ac4b0e
GM
2839 /* If S draws overlapping rows, it's sufficient to use the top and
2840 bottom of the window for clipping because this glyph string
2841 intentionally draws over other lines. */
2842 if (s->for_overlaps_p)
2843 {
045dee35 2844 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2845 r->height = window_text_bottom_y (s->w) - r->y;
2846 }
98b8a90f
GM
2847 else
2848 {
2849 /* Don't use S->y for clipping because it doesn't take partially
2850 visible lines into account. For example, it can be negative for
2851 partially visible lines at the top of a window. */
2852 if (!s->row->full_width_p
2853 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
2854 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
2855 else
2856 r->y = max (0, s->row->y);
2857
2858 /* If drawing a tool-bar window, draw it over the internal border
2859 at the top of the window. */
2860 if (s->w == XWINDOW (s->f->tool_bar_window))
2861 r->y -= s->f->output_data.x->internal_border_width;
2862 }
2863
66ac4b0e 2864 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2865}
2866
2867
2868/* Set clipping for output of glyph string S. S may be part of a mode
2869 line or menu if we don't have X toolkit support. */
2870
2871static INLINE void
2872x_set_glyph_string_clipping (s)
2873 struct glyph_string *s;
2874{
2875 XRectangle r;
2876 x_get_glyph_string_clip_rect (s, &r);
2877 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2878}
2879
2880
2881/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2882 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2883
2884static INLINE void
2885x_compute_glyph_string_overhangs (s)
2886 struct glyph_string *s;
2887{
b4192550 2888 if (s->cmp == NULL
06a2c219
GM
2889 && s->first_glyph->type == CHAR_GLYPH)
2890 {
2891 XCharStruct cs;
2892 int direction, font_ascent, font_descent;
2893 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2894 &font_ascent, &font_descent, &cs);
2895 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2896 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2897 }
2898}
2899
2900
2901/* Compute overhangs and x-positions for glyph string S and its
2902 predecessors, or successors. X is the starting x-position for S.
2903 BACKWARD_P non-zero means process predecessors. */
2904
2905static void
2906x_compute_overhangs_and_x (s, x, backward_p)
2907 struct glyph_string *s;
2908 int x;
2909 int backward_p;
2910{
2911 if (backward_p)
2912 {
2913 while (s)
2914 {
2915 x_compute_glyph_string_overhangs (s);
2916 x -= s->width;
2917 s->x = x;
2918 s = s->prev;
2919 }
2920 }
2921 else
2922 {
2923 while (s)
2924 {
2925 x_compute_glyph_string_overhangs (s);
2926 s->x = x;
2927 x += s->width;
2928 s = s->next;
2929 }
2930 }
2931}
2932
2933
2934/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2935 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2936 assumed to be zero. */
06a2c219
GM
2937
2938static void
2939x_get_glyph_overhangs (glyph, f, left, right)
2940 struct glyph *glyph;
2941 struct frame *f;
2942 int *left, *right;
2943{
06a2c219
GM
2944 *left = *right = 0;
2945
b4192550 2946 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2947 {
2948 XFontStruct *font;
2949 struct face *face;
2950 struct font_info *font_info;
2951 XChar2b char2b;
ee569018
KH
2952 XCharStruct *pcm;
2953
2954 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2955 font = face->font;
2956 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2957 if (font
2958 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2959 {
06a2c219
GM
2960 if (pcm->rbearing > pcm->width)
2961 *right = pcm->rbearing - pcm->width;
2962 if (pcm->lbearing < 0)
2963 *left = -pcm->lbearing;
2964 }
2965 }
2966}
2967
2968
2969/* Return the index of the first glyph preceding glyph string S that
2970 is overwritten by S because of S's left overhang. Value is -1
2971 if no glyphs are overwritten. */
2972
2973static int
2974x_left_overwritten (s)
2975 struct glyph_string *s;
2976{
2977 int k;
2978
2979 if (s->left_overhang)
2980 {
2981 int x = 0, i;
2982 struct glyph *glyphs = s->row->glyphs[s->area];
2983 int first = s->first_glyph - glyphs;
2984
2985 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2986 x -= glyphs[i].pixel_width;
2987
2988 k = i + 1;
2989 }
2990 else
2991 k = -1;
2992
2993 return k;
2994}
2995
2996
2997/* Return the index of the first glyph preceding glyph string S that
2998 is overwriting S because of its right overhang. Value is -1 if no
2999 glyph in front of S overwrites S. */
3000
3001static int
3002x_left_overwriting (s)
3003 struct glyph_string *s;
3004{
3005 int i, k, x;
3006 struct glyph *glyphs = s->row->glyphs[s->area];
3007 int first = s->first_glyph - glyphs;
3008
3009 k = -1;
3010 x = 0;
3011 for (i = first - 1; i >= 0; --i)
3012 {
3013 int left, right;
3014 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3015 if (x + right > 0)
3016 k = i;
3017 x -= glyphs[i].pixel_width;
3018 }
3019
3020 return k;
3021}
3022
3023
3024/* Return the index of the last glyph following glyph string S that is
3025 not overwritten by S because of S's right overhang. Value is -1 if
3026 no such glyph is found. */
3027
3028static int
3029x_right_overwritten (s)
3030 struct glyph_string *s;
3031{
3032 int k = -1;
3033
3034 if (s->right_overhang)
3035 {
3036 int x = 0, i;
3037 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3038 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3039 int end = s->row->used[s->area];
3040
3041 for (i = first; i < end && s->right_overhang > x; ++i)
3042 x += glyphs[i].pixel_width;
3043
3044 k = i;
3045 }
3046
3047 return k;
3048}
3049
3050
3051/* Return the index of the last glyph following glyph string S that
3052 overwrites S because of its left overhang. Value is negative
3053 if no such glyph is found. */
3054
3055static int
3056x_right_overwriting (s)
3057 struct glyph_string *s;
3058{
3059 int i, k, x;
3060 int end = s->row->used[s->area];
3061 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3062 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3063
3064 k = -1;
3065 x = 0;
3066 for (i = first; i < end; ++i)
3067 {
3068 int left, right;
3069 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3070 if (x - left < 0)
3071 k = i;
3072 x += glyphs[i].pixel_width;
3073 }
3074
3075 return k;
3076}
3077
3078
3079/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3080
3081static INLINE void
3082x_clear_glyph_string_rect (s, x, y, w, h)
3083 struct glyph_string *s;
3084 int x, y, w, h;
3085{
3086 XGCValues xgcv;
3087 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3088 XSetForeground (s->display, s->gc, xgcv.background);
3089 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3090 XSetForeground (s->display, s->gc, xgcv.foreground);
3091}
3092
3093
3094/* Draw the background of glyph_string S. If S->background_filled_p
3095 is non-zero don't draw it. FORCE_P non-zero means draw the
3096 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3097 when a string preceding S draws into the background of S, or S
3098 contains the first component of a composition. */
06a2c219
GM
3099
3100static void
3101x_draw_glyph_string_background (s, force_p)
3102 struct glyph_string *s;
3103 int force_p;
3104{
3105 /* Nothing to do if background has already been drawn or if it
3106 shouldn't be drawn in the first place. */
3107 if (!s->background_filled_p)
3108 {
ea2ba0d4
KH
3109 int box_line_width = max (s->face->box_line_width, 0);
3110
b4192550 3111 if (s->stippled_p)
06a2c219
GM
3112 {
3113 /* Fill background with a stipple pattern. */
3114 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3115 XFillRectangle (s->display, s->window, s->gc, s->x,
ea2ba0d4 3116 s->y + box_line_width,
06a2c219 3117 s->background_width,
ea2ba0d4 3118 s->height - 2 * box_line_width);
06a2c219
GM
3119 XSetFillStyle (s->display, s->gc, FillSolid);
3120 s->background_filled_p = 1;
3121 }
ea2ba0d4 3122 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
06a2c219
GM
3123 || s->font_not_found_p
3124 || s->extends_to_end_of_line_p
06a2c219
GM
3125 || force_p)
3126 {
ea2ba0d4 3127 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
06a2c219 3128 s->background_width,
ea2ba0d4 3129 s->height - 2 * box_line_width);
06a2c219
GM
3130 s->background_filled_p = 1;
3131 }
3132 }
3133}
3134
3135
3136/* Draw the foreground of glyph string S. */
3137
3138static void
3139x_draw_glyph_string_foreground (s)
3140 struct glyph_string *s;
3141{
3142 int i, x;
3143
3144 /* If first glyph of S has a left box line, start drawing the text
3145 of S to the right of that box line. */
3146 if (s->face->box != FACE_NO_BOX
3147 && s->first_glyph->left_box_line_p)
ea2ba0d4 3148 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
3149 else
3150 x = s->x;
3151
b4192550
KH
3152 /* Draw characters of S as rectangles if S's font could not be
3153 loaded. */
3154 if (s->font_not_found_p)
06a2c219 3155 {
b4192550 3156 for (i = 0; i < s->nchars; ++i)
06a2c219 3157 {
b4192550
KH
3158 struct glyph *g = s->first_glyph + i;
3159 XDrawRectangle (s->display, s->window,
3160 s->gc, x, s->y, g->pixel_width - 1,
3161 s->height - 1);
3162 x += g->pixel_width;
06a2c219
GM
3163 }
3164 }
3165 else
3166 {
b4192550
KH
3167 char *char1b = (char *) s->char2b;
3168 int boff = s->font_info->baseline_offset;
06a2c219 3169
b4192550
KH
3170 if (s->font_info->vertical_centering)
3171 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3172
3173 /* If we can use 8-bit functions, condense S->char2b. */
3174 if (!s->two_byte_p)
3175 for (i = 0; i < s->nchars; ++i)
3176 char1b[i] = s->char2b[i].byte2;
3177
3178 /* Draw text with XDrawString if background has already been
3179 filled. Otherwise, use XDrawImageString. (Note that
3180 XDrawImageString is usually faster than XDrawString.) Always
3181 use XDrawImageString when drawing the cursor so that there is
3182 no chance that characters under a box cursor are invisible. */
3183 if (s->for_overlaps_p
3184 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3185 {
3186 /* Draw characters with 16-bit or 8-bit functions. */
3187 if (s->two_byte_p)
3188 XDrawString16 (s->display, s->window, s->gc, x,
3189 s->ybase - boff, s->char2b, s->nchars);
3190 else
3191 XDrawString (s->display, s->window, s->gc, x,
3192 s->ybase - boff, char1b, s->nchars);
3193 }
06a2c219
GM
3194 else
3195 {
b4192550
KH
3196 if (s->two_byte_p)
3197 XDrawImageString16 (s->display, s->window, s->gc, x,
3198 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3199 else
b4192550
KH
3200 XDrawImageString (s->display, s->window, s->gc, x,
3201 s->ybase - boff, char1b, s->nchars);
3202 }
3203 }
3204}
06a2c219 3205
b4192550 3206/* Draw the foreground of composite glyph string S. */
06a2c219 3207
b4192550
KH
3208static void
3209x_draw_composite_glyph_string_foreground (s)
3210 struct glyph_string *s;
3211{
3212 int i, x;
06a2c219 3213
b4192550
KH
3214 /* If first glyph of S has a left box line, start drawing the text
3215 of S to the right of that box line. */
3216 if (s->face->box != FACE_NO_BOX
3217 && s->first_glyph->left_box_line_p)
ea2ba0d4 3218 x = s->x + abs (s->face->box_line_width);
b4192550
KH
3219 else
3220 x = s->x;
06a2c219 3221
b4192550
KH
3222 /* S is a glyph string for a composition. S->gidx is the index of
3223 the first character drawn for glyphs of this composition.
3224 S->gidx == 0 means we are drawing the very first character of
3225 this composition. */
06a2c219 3226
b4192550
KH
3227 /* Draw a rectangle for the composition if the font for the very
3228 first character of the composition could not be loaded. */
3229 if (s->font_not_found_p)
3230 {
3231 if (s->gidx == 0)
3232 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3233 s->width - 1, s->height - 1);
3234 }
3235 else
3236 {
3237 for (i = 0; i < s->nchars; i++, ++s->gidx)
3238 XDrawString16 (s->display, s->window, s->gc,
3239 x + s->cmp->offsets[s->gidx * 2],
3240 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3241 s->char2b + i, 1);
06a2c219
GM
3242 }
3243}
3244
3245
80c32bcc
GM
3246#ifdef USE_X_TOOLKIT
3247
3e71d8f2 3248static struct frame *x_frame_of_widget P_ ((Widget));
651f03b6
GM
3249static Boolean cvt_string_to_pixel P_ ((Display *, XrmValue *, Cardinal *,
3250 XrmValue *, XrmValue *, XtPointer *));
3251static void cvt_pixel_dtor P_ ((XtAppContext, XrmValue *, XtPointer,
3252 XrmValue *, Cardinal *));
80c32bcc 3253
3e71d8f2
GM
3254
3255/* Return the frame on which widget WIDGET is used.. Abort if frame
3256 cannot be determined. */
3257
e851c833 3258static struct frame *
3e71d8f2 3259x_frame_of_widget (widget)
80c32bcc 3260 Widget widget;
80c32bcc 3261{
80c32bcc 3262 struct x_display_info *dpyinfo;
5c187dee 3263 Lisp_Object tail;
3e71d8f2
GM
3264 struct frame *f;
3265
80c32bcc
GM
3266 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3267
3268 /* Find the top-level shell of the widget. Note that this function
3269 can be called when the widget is not yet realized, so XtWindow
3270 (widget) == 0. That's the reason we can't simply use
3271 x_any_window_to_frame. */
3272 while (!XtIsTopLevelShell (widget))
3273 widget = XtParent (widget);
3274
3275 /* Look for a frame with that top-level widget. Allocate the color
3276 on that frame to get the right gamma correction value. */
3277 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3278 if (GC_FRAMEP (XCAR (tail))
3279 && (f = XFRAME (XCAR (tail)),
3280 (f->output_data.nothing != 1
3281 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3282 && f->output_data.x->widget == widget)
3e71d8f2 3283 return f;
80c32bcc
GM
3284
3285 abort ();
3286}
3287
3e71d8f2
GM
3288
3289/* Allocate the color COLOR->pixel on the screen and display of
3290 widget WIDGET in colormap CMAP. If an exact match cannot be
3291 allocated, try the nearest color available. Value is non-zero
3292 if successful. This is called from lwlib. */
3293
3294int
3295x_alloc_nearest_color_for_widget (widget, cmap, color)
3296 Widget widget;
3297 Colormap cmap;
3298 XColor *color;
3299{
3300 struct frame *f = x_frame_of_widget (widget);
3301 return x_alloc_nearest_color (f, cmap, color);
3302}
3303
3304
46d516e5
MB
3305/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3306 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3307 If this produces the same color as PIXEL, try a color where all RGB
3308 values have DELTA added. Return the allocated color in *PIXEL.
3309 DISPLAY is the X display, CMAP is the colormap to operate on.
3310 Value is non-zero if successful. */
3311
3312int
3313x_alloc_lighter_color_for_widget (widget, display, cmap, pixel, factor, delta)
3314 Widget widget;
3315 Display *display;
3316 Colormap cmap;
3317 unsigned long *pixel;
3318 double factor;
3319 int delta;
3320{
3321 struct frame *f = x_frame_of_widget (widget);
3322 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
3323}
3324
3325
651f03b6
GM
3326/* Structure specifying which arguments should be passed by Xt to
3327 cvt_string_to_pixel. We want the widget's screen and colormap. */
3328
3329static XtConvertArgRec cvt_string_to_pixel_args[] =
3330 {
3331 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.screen),
3332 sizeof (Screen *)},
3333 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.colormap),
3334 sizeof (Colormap)}
3335 };
3336
3337
3338/* The address of this variable is returned by
3339 cvt_string_to_pixel. */
3340
3341static Pixel cvt_string_to_pixel_value;
3342
3343
3344/* Convert a color name to a pixel color.
3345
3346 DPY is the display we are working on.
3347
3348 ARGS is an array of *NARGS XrmValue structures holding additional
3349 information about the widget for which the conversion takes place.
3350 The contents of this array are determined by the specification
3351 in cvt_string_to_pixel_args.
3352
3353 FROM is a pointer to an XrmValue which points to the color name to
3354 convert. TO is an XrmValue in which to return the pixel color.
3355
3356 CLOSURE_RET is a pointer to user-data, in which we record if
3357 we allocated the color or not.
3358
3359 Value is True if successful, False otherwise. */
3360
3361static Boolean
3362cvt_string_to_pixel (dpy, args, nargs, from, to, closure_ret)
3363 Display *dpy;
3364 XrmValue *args;
3365 Cardinal *nargs;
3366 XrmValue *from, *to;
3367 XtPointer *closure_ret;
3368{
3369 Screen *screen;
3370 Colormap cmap;
3371 Pixel pixel;
3372 String color_name;
3373 XColor color;
3374
3375 if (*nargs != 2)
3376 {
3377 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3378 "wrongParameters", "cvt_string_to_pixel",
3379 "XtToolkitError",
3380 "Screen and colormap args required", NULL, NULL);
3381 return False;
3382 }
3383
3384 screen = *(Screen **) args[0].addr;
3385 cmap = *(Colormap *) args[1].addr;
3386 color_name = (String) from->addr;
3387
3388 if (strcmp (color_name, XtDefaultBackground) == 0)
3389 {
3390 *closure_ret = (XtPointer) False;
3391 pixel = WhitePixelOfScreen (screen);
3392 }
3393 else if (strcmp (color_name, XtDefaultForeground) == 0)
3394 {
3395 *closure_ret = (XtPointer) False;
3396 pixel = BlackPixelOfScreen (screen);
3397 }
3398 else if (XParseColor (dpy, cmap, color_name, &color)
3399 && x_alloc_nearest_color_1 (dpy, cmap, &color))
3400 {
3401 pixel = color.pixel;
3402 *closure_ret = (XtPointer) True;
3403 }
3404 else
3405 {
3406 String params[1];
3407 Cardinal nparams = 1;
3408
3409 params[0] = color_name;
3410 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3411 "badValue", "cvt_string_to_pixel",
3412 "XtToolkitError", "Invalid color `%s'",
3413 params, &nparams);
3414 return False;
3415 }
3416
3417 if (to->addr != NULL)
3418 {
3419 if (to->size < sizeof (Pixel))
3420 {
3421 to->size = sizeof (Pixel);
3422 return False;
3423 }
3424
3425 *(Pixel *) to->addr = pixel;
3426 }
3427 else
3428 {
3429 cvt_string_to_pixel_value = pixel;
3430 to->addr = (XtPointer) &cvt_string_to_pixel_value;
3431 }
3432
3433 to->size = sizeof (Pixel);
3434 return True;
3435}
3436
3437
3438/* Free a pixel color which was previously allocated via
3439 cvt_string_to_pixel. This is registered as the destructor
3440 for this type of resource via XtSetTypeConverter.
3441
3442 APP is the application context in which we work.
3443
3444 TO is a pointer to an XrmValue holding the color to free.
3445 CLOSURE is the value we stored in CLOSURE_RET for this color
3446 in cvt_string_to_pixel.
3447
3448 ARGS and NARGS are like for cvt_string_to_pixel. */
3449
3450static void
3451cvt_pixel_dtor (app, to, closure, args, nargs)
3452 XtAppContext app;
3453 XrmValuePtr to;
3454 XtPointer closure;
3455 XrmValuePtr args;
3456 Cardinal *nargs;
3457{
3458 if (*nargs != 2)
3459 {
3460 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
3461 "XtToolkitError",
3462 "Screen and colormap arguments required",
3463 NULL, NULL);
3464 }
3465 else if (closure != NULL)
3466 {
3467 /* We did allocate the pixel, so free it. */
3468 Screen *screen = *(Screen **) args[0].addr;
3469 Colormap cmap = *(Colormap *) args[1].addr;
3470 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
97762eb7 3471 (Pixel *) to->addr, 1);
651f03b6
GM
3472 }
3473}
3474
3475
80c32bcc
GM
3476#endif /* USE_X_TOOLKIT */
3477
3478
f04e1297 3479/* Value is an array of XColor structures for the contents of the
651f03b6 3480 color map of display DPY. Set *NCELLS to the size of the array.
f04e1297
GM
3481 Note that this probably shouldn't be called for large color maps,
3482 say a 24-bit TrueColor map. */
3483
3484static const XColor *
651f03b6
GM
3485x_color_cells (dpy, ncells)
3486 Display *dpy;
f04e1297
GM
3487 int *ncells;
3488{
651f03b6 3489 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
f04e1297
GM
3490
3491 if (dpyinfo->color_cells == NULL)
3492 {
651f03b6 3493 Screen *screen = dpyinfo->screen;
f04e1297
GM
3494 int i;
3495
3496 dpyinfo->ncolor_cells
651f03b6 3497 = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
f04e1297
GM
3498 dpyinfo->color_cells
3499 = (XColor *) xmalloc (dpyinfo->ncolor_cells
3500 * sizeof *dpyinfo->color_cells);
3501
3502 for (i = 0; i < dpyinfo->ncolor_cells; ++i)
3503 dpyinfo->color_cells[i].pixel = i;
3504
651f03b6 3505 XQueryColors (dpy, dpyinfo->cmap,
f04e1297
GM
3506 dpyinfo->color_cells, dpyinfo->ncolor_cells);
3507 }
3508
3509 *ncells = dpyinfo->ncolor_cells;
3510 return dpyinfo->color_cells;
3511}
3512
3513
3514/* On frame F, translate pixel colors to RGB values for the NCOLORS
3515 colors in COLORS. Use cached information, if available. */
3516
3517void
3518x_query_colors (f, colors, ncolors)
3519 struct frame *f;
3520 XColor *colors;
3521 int ncolors;
3522{
3523 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3524
3525 if (dpyinfo->color_cells)
3526 {
3527 int i;
3528 for (i = 0; i < ncolors; ++i)
3529 {
3530 unsigned long pixel = colors[i].pixel;
3531 xassert (pixel < dpyinfo->ncolor_cells);
3532 xassert (dpyinfo->color_cells[pixel].pixel == pixel);
3533 colors[i] = dpyinfo->color_cells[pixel];
3534 }
3535 }
3536 else
3537 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
3538}
3539
3540
3541/* On frame F, translate pixel color to RGB values for the color in
3542 COLOR. Use cached information, if available. */
3543
3544void
3545x_query_color (f, color)
3546 struct frame *f;
3547 XColor *color;
3548{
3549 x_query_colors (f, color, 1);
3550}
3551
3552
651f03b6
GM
3553/* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
3554 exact match can't be allocated, try the nearest color available.
3555 Value is non-zero if successful. Set *COLOR to the color
3556 allocated. */
06a2c219 3557
651f03b6
GM
3558static int
3559x_alloc_nearest_color_1 (dpy, cmap, color)
3560 Display *dpy;
06a2c219
GM
3561 Colormap cmap;
3562 XColor *color;
3563{
80c32bcc
GM
3564 int rc;
3565
651f03b6 3566 rc = XAllocColor (dpy, cmap, color);
06a2c219
GM
3567 if (rc == 0)
3568 {
3569 /* If we got to this point, the colormap is full, so we're going
3570 to try to get the next closest color. The algorithm used is
3571 a least-squares matching, which is what X uses for closest
3572 color matching with StaticColor visuals. */
3573 int nearest, i;
3574 unsigned long nearest_delta = ~0;
f04e1297 3575 int ncells;
651f03b6 3576 const XColor *cells = x_color_cells (dpy, &ncells);
06a2c219
GM
3577
3578 for (nearest = i = 0; i < ncells; ++i)
3579 {
3580 long dred = (color->red >> 8) - (cells[i].red >> 8);
3581 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3582 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3583 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3584
3585 if (delta < nearest_delta)
3586 {
3587 nearest = i;
3588 nearest_delta = delta;
3589 }
3590 }
3591
3592 color->red = cells[nearest].red;
3593 color->green = cells[nearest].green;
3594 color->blue = cells[nearest].blue;
651f03b6 3595 rc = XAllocColor (dpy, cmap, color);
06a2c219 3596 }
35efe0a1
GM
3597 else
3598 {
3599 /* If allocation succeeded, and the allocated pixel color is not
3600 equal to a cached pixel color recorded earlier, there was a
3601 change in the colormap, so clear the color cache. */
651f03b6 3602 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
35efe0a1
GM
3603 XColor *cached_color;
3604
3605 if (dpyinfo->color_cells
3606 && (cached_color = &dpyinfo->color_cells[color->pixel],
cae71efe
GM
3607 (cached_color->red != color->red
3608 || cached_color->blue != color->blue
3609 || cached_color->green != color->green)))
35efe0a1
GM
3610 {
3611 xfree (dpyinfo->color_cells);
3612 dpyinfo->color_cells = NULL;
3613 dpyinfo->ncolor_cells = 0;
3614 }
3615 }
06a2c219 3616
d9c545da
GM
3617#ifdef DEBUG_X_COLORS
3618 if (rc)
3619 register_color (color->pixel);
3620#endif /* DEBUG_X_COLORS */
3621
06a2c219
GM
3622 return rc;
3623}
3624
3625
651f03b6
GM
3626/* Allocate the color COLOR->pixel on frame F, colormap CMAP. If an
3627 exact match can't be allocated, try the nearest color available.
3628 Value is non-zero if successful. Set *COLOR to the color
3629 allocated. */
3630
3631int
3632x_alloc_nearest_color (f, cmap, color)
3633 struct frame *f;
3634 Colormap cmap;
3635 XColor *color;
3636{
3637 gamma_correct (f, color);
3638 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
3639}
3640
3641
d9c545da
GM
3642/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3643 It's necessary to do this instead of just using PIXEL directly to
3644 get color reference counts right. */
3645
3646unsigned long
3647x_copy_color (f, pixel)
3648 struct frame *f;
3649 unsigned long pixel;
3650{
3651 XColor color;
3652
3653 color.pixel = pixel;
3654 BLOCK_INPUT;
f04e1297 3655 x_query_color (f, &color);
d9c545da
GM
3656 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3657 UNBLOCK_INPUT;
3658#ifdef DEBUG_X_COLORS
3659 register_color (pixel);
3660#endif
3661 return color.pixel;
3662}
3663
3664
3e71d8f2
GM
3665/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3666 It's necessary to do this instead of just using PIXEL directly to
3667 get color reference counts right. */
3668
3669unsigned long
3670x_copy_dpy_color (dpy, cmap, pixel)
3671 Display *dpy;
3672 Colormap cmap;
3673 unsigned long pixel;
3674{
3675 XColor color;
3676
3677 color.pixel = pixel;
3678 BLOCK_INPUT;
3679 XQueryColor (dpy, cmap, &color);
3680 XAllocColor (dpy, cmap, &color);
3681 UNBLOCK_INPUT;
3682#ifdef DEBUG_X_COLORS
3683 register_color (pixel);
3684#endif
3685 return color.pixel;
3686}
3687
3688
6d8b0acd 3689/* Brightness beyond which a color won't have its highlight brightness
d7361edf 3690 boosted.
6d8b0acd 3691
d7361edf
MB
3692 Nominally, highlight colors for `3d' faces are calculated by
3693 brightening an object's color by a constant scale factor, but this
3694 doesn't yield good results for dark colors, so for colors who's
3695 brightness is less than this value (on a scale of 0-65535) have an
3696 use an additional additive factor.
6d8b0acd
MB
3697
3698 The value here is set so that the default menu-bar/mode-line color
3699 (grey75) will not have its highlights changed at all. */
3700#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
3701
3702
06a2c219
GM
3703/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3704 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3705 If this produces the same color as PIXEL, try a color where all RGB
3706 values have DELTA added. Return the allocated color in *PIXEL.
3707 DISPLAY is the X display, CMAP is the colormap to operate on.
3708 Value is non-zero if successful. */
3709
3710static int
3711x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3712 struct frame *f;
3713 Display *display;
3714 Colormap cmap;
3715 unsigned long *pixel;
68c45bf0 3716 double factor;
06a2c219
GM
3717 int delta;
3718{
3719 XColor color, new;
6d8b0acd 3720 long bright;
06a2c219
GM
3721 int success_p;
3722
3723 /* Get RGB color values. */
3724 color.pixel = *pixel;
f04e1297 3725 x_query_color (f, &color);
06a2c219
GM
3726
3727 /* Change RGB values by specified FACTOR. Avoid overflow! */
3728 xassert (factor >= 0);
3729 new.red = min (0xffff, factor * color.red);
3730 new.green = min (0xffff, factor * color.green);
3731 new.blue = min (0xffff, factor * color.blue);
3732
d7361edf
MB
3733 /* Calculate brightness of COLOR. */
3734 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
6d8b0acd
MB
3735
3736 /* We only boost colors that are darker than
3737 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3738 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3739 /* Make an additive adjustment to NEW, because it's dark enough so
3740 that scaling by FACTOR alone isn't enough. */
3741 {
3742 /* How far below the limit this color is (0 - 1, 1 being darker). */
3743 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3744 /* The additive adjustment. */
d7361edf 3745 int min_delta = delta * dimness * factor / 2;
6d8b0acd
MB
3746
3747 if (factor < 1)
3748 {
6d8b0acd
MB
3749 new.red = max (0, new.red - min_delta);
3750 new.green = max (0, new.green - min_delta);
3751 new.blue = max (0, new.blue - min_delta);
3752 }
3753 else
3754 {
3755 new.red = min (0xffff, min_delta + new.red);
3756 new.green = min (0xffff, min_delta + new.green);
3757 new.blue = min (0xffff, min_delta + new.blue);
3758 }
3759 }
3760
06a2c219 3761 /* Try to allocate the color. */
80c32bcc 3762 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3763 if (success_p)
3764 {
3765 if (new.pixel == *pixel)
3766 {
3767 /* If we end up with the same color as before, try adding
3768 delta to the RGB values. */
0d605c67 3769 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3770
3771 new.red = min (0xffff, delta + color.red);
3772 new.green = min (0xffff, delta + color.green);
3773 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3774 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3775 }
3776 else
3777 success_p = 1;
3778 *pixel = new.pixel;
3779 }
3780
3781 return success_p;
3782}
3783
3784
3785/* Set up the foreground color for drawing relief lines of glyph
3786 string S. RELIEF is a pointer to a struct relief containing the GC
3787 with which lines will be drawn. Use a color that is FACTOR or
3788 DELTA lighter or darker than the relief's background which is found
3789 in S->f->output_data.x->relief_background. If such a color cannot
3790 be allocated, use DEFAULT_PIXEL, instead. */
3791
3792static void
3793x_setup_relief_color (f, relief, factor, delta, default_pixel)
3794 struct frame *f;
3795 struct relief *relief;
68c45bf0 3796 double factor;
06a2c219
GM
3797 int delta;
3798 unsigned long default_pixel;
3799{
3800 XGCValues xgcv;
3801 struct x_output *di = f->output_data.x;
3802 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3803 unsigned long pixel;
3804 unsigned long background = di->relief_background;
43bd1b2b 3805 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3806 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3807 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3808
3809 xgcv.graphics_exposures = False;
3810 xgcv.line_width = 1;
3811
3812 /* Free previously allocated color. The color cell will be reused
3813 when it has been freed as many times as it was allocated, so this
3814 doesn't affect faces using the same colors. */
3815 if (relief->gc
3816 && relief->allocated_p)
3817 {
0d605c67 3818 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3819 relief->allocated_p = 0;
3820 }
3821
3822 /* Allocate new color. */
3823 xgcv.foreground = default_pixel;
3824 pixel = background;
dcd08bfb
GM
3825 if (dpyinfo->n_planes != 1
3826 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3827 {
3828 relief->allocated_p = 1;
3829 xgcv.foreground = relief->pixel = pixel;
3830 }
3831
3832 if (relief->gc == 0)
3833 {
dcd08bfb 3834 xgcv.stipple = dpyinfo->gray;
06a2c219 3835 mask |= GCStipple;
dcd08bfb 3836 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3837 }
3838 else
dcd08bfb 3839 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3840}
3841
3842
3843/* Set up colors for the relief lines around glyph string S. */
3844
3845static void
3846x_setup_relief_colors (s)
3847 struct glyph_string *s;
3848{
3849 struct x_output *di = s->f->output_data.x;
3850 unsigned long color;
3851
3852 if (s->face->use_box_color_for_shadows_p)
3853 color = s->face->box_color;
3854 else
3855 {
3856 XGCValues xgcv;
3857
3858 /* Get the background color of the face. */
3859 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3860 color = xgcv.background;
3861 }
3862
3863 if (di->white_relief.gc == 0
3864 || color != di->relief_background)
3865 {
3866 di->relief_background = color;
3867 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3868 WHITE_PIX_DEFAULT (s->f));
3869 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3870 BLACK_PIX_DEFAULT (s->f));
3871 }
3872}
3873
3874
3875/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3876 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3877 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3878 relief. LEFT_P non-zero means draw a relief on the left side of
3879 the rectangle. RIGHT_P non-zero means draw a relief on the right
3880 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3881 when drawing. */
3882
3883static void
3884x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3885 raised_p, left_p, right_p, clip_rect)
3886 struct frame *f;
3887 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3888 XRectangle *clip_rect;
3889{
de507556
GM
3890 Display *dpy = FRAME_X_DISPLAY (f);
3891 Window window = FRAME_X_WINDOW (f);
06a2c219
GM
3892 int i;
3893 GC gc;
3894
3895 if (raised_p)
3896 gc = f->output_data.x->white_relief.gc;
3897 else
3898 gc = f->output_data.x->black_relief.gc;
de507556 3899 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3900
3901 /* Top. */
3902 for (i = 0; i < width; ++i)
de507556 3903 XDrawLine (dpy, window, gc,
06a2c219
GM
3904 left_x + i * left_p, top_y + i,
3905 right_x + 1 - i * right_p, top_y + i);
3906
3907 /* Left. */
3908 if (left_p)
3909 for (i = 0; i < width; ++i)
de507556 3910 XDrawLine (dpy, window, gc,
44655e77 3911 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
06a2c219 3912
de507556 3913 XSetClipMask (dpy, gc, None);
06a2c219
GM
3914 if (raised_p)
3915 gc = f->output_data.x->black_relief.gc;
3916 else
3917 gc = f->output_data.x->white_relief.gc;
de507556 3918 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3919
3920 /* Bottom. */
3921 for (i = 0; i < width; ++i)
de507556
GM
3922 XDrawLine (dpy, window, gc,
3923 left_x + i * left_p, bottom_y - i,
3924 right_x + 2 - i * right_p, bottom_y - i);
06a2c219
GM
3925
3926 /* Right. */
3927 if (right_p)
3928 for (i = 0; i < width; ++i)
de507556 3929 XDrawLine (dpy, window, gc,
06a2c219
GM
3930 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3931
de507556 3932 XSetClipMask (dpy, gc, None);
06a2c219
GM
3933}
3934
3935
3936/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3937 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3938 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3939 left side of the rectangle. RIGHT_P non-zero means draw a line
3940 on the right side of the rectangle. CLIP_RECT is the clipping
3941 rectangle to use when drawing. */
3942
3943static void
3944x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3945 left_p, right_p, clip_rect)
3946 struct glyph_string *s;
3947 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3948 XRectangle *clip_rect;
3949{
3950 XGCValues xgcv;
3951
3952 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3953 XSetForeground (s->display, s->gc, s->face->box_color);
3954 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3955
3956 /* Top. */
3957 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3958 left_x, top_y, right_x - left_x + 1, width);
06a2c219
GM
3959
3960 /* Left. */
3961 if (left_p)
3962 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3963 left_x, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3964
3965 /* Bottom. */
3966 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3967 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
06a2c219
GM
3968
3969 /* Right. */
3970 if (right_p)
3971 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3972 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3973
3974 XSetForeground (s->display, s->gc, xgcv.foreground);
3975 XSetClipMask (s->display, s->gc, None);
3976}
3977
3978
3979/* Draw a box around glyph string S. */
3980
3981static void
3982x_draw_glyph_string_box (s)
3983 struct glyph_string *s;
3984{
3985 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3986 int left_p, right_p;
3987 struct glyph *last_glyph;
3988 XRectangle clip_rect;
3989
3990 last_x = window_box_right (s->w, s->area);
3991 if (s->row->full_width_p
3992 && !s->w->pseudo_window_p)
3993 {
110859fc 3994 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
06a2c219
GM
3995 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3996 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3997 }
3998
3999 /* The glyph that may have a right box line. */
b4192550 4000 last_glyph = (s->cmp || s->img
06a2c219
GM
4001 ? s->first_glyph
4002 : s->first_glyph + s->nchars - 1);
4003
ea2ba0d4 4004 width = abs (s->face->box_line_width);
06a2c219
GM
4005 raised_p = s->face->box == FACE_RAISED_BOX;
4006 left_x = s->x;
57ac7c81
GM
4007 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
4008 ? last_x - 1
4009 : min (last_x, s->x + s->background_width) - 1);
06a2c219
GM
4010 top_y = s->y;
4011 bottom_y = top_y + s->height - 1;
4012
4013 left_p = (s->first_glyph->left_box_line_p
4014 || (s->hl == DRAW_MOUSE_FACE
4015 && (s->prev == NULL
4016 || s->prev->hl != s->hl)));
4017 right_p = (last_glyph->right_box_line_p
4018 || (s->hl == DRAW_MOUSE_FACE
4019 && (s->next == NULL
4020 || s->next->hl != s->hl)));
4021
4022 x_get_glyph_string_clip_rect (s, &clip_rect);
4023
4024 if (s->face->box == FACE_SIMPLE_BOX)
4025 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4026 left_p, right_p, &clip_rect);
4027 else
4028 {
4029 x_setup_relief_colors (s);
4030 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
4031 width, raised_p, left_p, right_p, &clip_rect);
4032 }
4033}
4034
4035
4036/* Draw foreground of image glyph string S. */
4037
4038static void
4039x_draw_image_foreground (s)
4040 struct glyph_string *s;
4041{
4042 int x;
95af8492 4043 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4044
4045 /* If first glyph of S has a left box line, start drawing it to the
4046 right of that line. */
4047 if (s->face->box != FACE_NO_BOX
4048 && s->first_glyph->left_box_line_p)
ea2ba0d4 4049 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4050 else
4051 x = s->x;
4052
4053 /* If there is a margin around the image, adjust x- and y-position
4054 by that margin. */
22d650b8
GM
4055 x += s->img->hmargin;
4056 y += s->img->vmargin;
06a2c219
GM
4057
4058 if (s->img->pixmap)
4059 {
4060 if (s->img->mask)
4061 {
4062 /* We can't set both a clip mask and use XSetClipRectangles
4063 because the latter also sets a clip mask. We also can't
4064 trust on the shape extension to be available
4065 (XShapeCombineRegion). So, compute the rectangle to draw
4066 manually. */
4067 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4068 | GCFunction);
4069 XGCValues xgcv;
4070 XRectangle clip_rect, image_rect, r;
4071
4072 xgcv.clip_mask = s->img->mask;
4073 xgcv.clip_x_origin = x;
4074 xgcv.clip_y_origin = y;
4075 xgcv.function = GXcopy;
4076 XChangeGC (s->display, s->gc, mask, &xgcv);
4077
4078 x_get_glyph_string_clip_rect (s, &clip_rect);
4079 image_rect.x = x;
4080 image_rect.y = y;
4081 image_rect.width = s->img->width;
4082 image_rect.height = s->img->height;
4083 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4084 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4085 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
4086 }
4087 else
4088 {
49ad1d99
GM
4089 unsigned long mask = GCClipXOrigin | GCClipYOrigin | GCFunction;
4090 XGCValues xgcv;
4091 XRectangle clip_rect, image_rect, r;
4092
4093 x_get_glyph_string_clip_rect (s, &clip_rect);
4094 image_rect.x = x;
4095 image_rect.y = y;
4096 image_rect.width = s->img->width;
4097 image_rect.height = s->img->height;
4098 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4099 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4100 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
06a2c219
GM
4101
4102 /* When the image has a mask, we can expect that at
4103 least part of a mouse highlight or a block cursor will
4104 be visible. If the image doesn't have a mask, make
4105 a block cursor visible by drawing a rectangle around
4106 the image. I believe it's looking better if we do
4107 nothing here for mouse-face. */
4108 if (s->hl == DRAW_CURSOR)
4109 XDrawRectangle (s->display, s->window, s->gc, x, y,
4110 s->img->width - 1, s->img->height - 1);
4111 }
4112 }
4113 else
4114 /* Draw a rectangle if image could not be loaded. */
4115 XDrawRectangle (s->display, s->window, s->gc, x, y,
4116 s->img->width - 1, s->img->height - 1);
4117}
4118
4119
4120/* Draw a relief around the image glyph string S. */
4121
4122static void
4123x_draw_image_relief (s)
4124 struct glyph_string *s;
4125{
4126 int x0, y0, x1, y1, thick, raised_p;
4127 XRectangle r;
4128 int x;
95af8492 4129 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4130
4131 /* If first glyph of S has a left box line, start drawing it to the
4132 right of that line. */
4133 if (s->face->box != FACE_NO_BOX
4134 && s->first_glyph->left_box_line_p)
ea2ba0d4 4135 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4136 else
4137 x = s->x;
4138
4139 /* If there is a margin around the image, adjust x- and y-position
4140 by that margin. */
22d650b8
GM
4141 x += s->img->hmargin;
4142 y += s->img->vmargin;
06a2c219
GM
4143
4144 if (s->hl == DRAW_IMAGE_SUNKEN
4145 || s->hl == DRAW_IMAGE_RAISED)
4146 {
9ea173e8 4147 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
06a2c219
GM
4148 raised_p = s->hl == DRAW_IMAGE_RAISED;
4149 }
4150 else
4151 {
4152 thick = abs (s->img->relief);
4153 raised_p = s->img->relief > 0;
4154 }
4155
4156 x0 = x - thick;
4157 y0 = y - thick;
4158 x1 = x + s->img->width + thick - 1;
4159 y1 = y + s->img->height + thick - 1;
4160
4161 x_setup_relief_colors (s);
4162 x_get_glyph_string_clip_rect (s, &r);
4163 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
4164}
4165
4166
4167/* Draw the foreground of image glyph string S to PIXMAP. */
4168
4169static void
4170x_draw_image_foreground_1 (s, pixmap)
4171 struct glyph_string *s;
4172 Pixmap pixmap;
4173{
4174 int x;
95af8492 4175 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
4176
4177 /* If first glyph of S has a left box line, start drawing it to the
4178 right of that line. */
4179 if (s->face->box != FACE_NO_BOX
4180 && s->first_glyph->left_box_line_p)
ea2ba0d4 4181 x = abs (s->face->box_line_width);
06a2c219
GM
4182 else
4183 x = 0;
4184
4185 /* If there is a margin around the image, adjust x- and y-position
4186 by that margin. */
22d650b8
GM
4187 x += s->img->hmargin;
4188 y += s->img->vmargin;
dc43ef94 4189
06a2c219
GM
4190 if (s->img->pixmap)
4191 {
4192 if (s->img->mask)
4193 {
4194 /* We can't set both a clip mask and use XSetClipRectangles
4195 because the latter also sets a clip mask. We also can't
4196 trust on the shape extension to be available
4197 (XShapeCombineRegion). So, compute the rectangle to draw
4198 manually. */
4199 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4200 | GCFunction);
4201 XGCValues xgcv;
4202
4203 xgcv.clip_mask = s->img->mask;
4204 xgcv.clip_x_origin = x;
4205 xgcv.clip_y_origin = y;
4206 xgcv.function = GXcopy;
4207 XChangeGC (s->display, s->gc, mask, &xgcv);
4208
4209 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4210 0, 0, s->img->width, s->img->height, x, y);
4211 XSetClipMask (s->display, s->gc, None);
4212 }
4213 else
4214 {
4215 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4216 0, 0, s->img->width, s->img->height, x, y);
4217
4218 /* When the image has a mask, we can expect that at
4219 least part of a mouse highlight or a block cursor will
4220 be visible. If the image doesn't have a mask, make
4221 a block cursor visible by drawing a rectangle around
4222 the image. I believe it's looking better if we do
4223 nothing here for mouse-face. */
4224 if (s->hl == DRAW_CURSOR)
4225 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4226 s->img->width - 1, s->img->height - 1);
4227 }
4228 }
4229 else
4230 /* Draw a rectangle if image could not be loaded. */
4231 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4232 s->img->width - 1, s->img->height - 1);
4233}
dc43ef94 4234
990ba854 4235
06a2c219
GM
4236/* Draw part of the background of glyph string S. X, Y, W, and H
4237 give the rectangle to draw. */
a9a5b0a5 4238
06a2c219
GM
4239static void
4240x_draw_glyph_string_bg_rect (s, x, y, w, h)
4241 struct glyph_string *s;
4242 int x, y, w, h;
4243{
4244 if (s->stippled_p)
4245 {
4246 /* Fill background with a stipple pattern. */
4247 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4248 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4249 XSetFillStyle (s->display, s->gc, FillSolid);
4250 }
4251 else
4252 x_clear_glyph_string_rect (s, x, y, w, h);
4253}
07e34cb0 4254
b5210ea7 4255
06a2c219 4256/* Draw image glyph string S.
dc43ef94 4257
06a2c219
GM
4258 s->y
4259 s->x +-------------------------
4260 | s->face->box
4261 |
4262 | +-------------------------
4263 | | s->img->margin
4264 | |
4265 | | +-------------------
4266 | | | the image
dc43ef94 4267
06a2c219 4268 */
dc43ef94 4269
06a2c219
GM
4270static void
4271x_draw_image_glyph_string (s)
4272 struct glyph_string *s;
4273{
4274 int x, y;
ea2ba0d4
KH
4275 int box_line_hwidth = abs (s->face->box_line_width);
4276 int box_line_vwidth = max (s->face->box_line_width, 0);
06a2c219
GM
4277 int height;
4278 Pixmap pixmap = None;
4279
ea2ba0d4 4280 height = s->height - 2 * box_line_vwidth;
06a2c219
GM
4281
4282 /* Fill background with face under the image. Do it only if row is
4283 taller than image or if image has a clip mask to reduce
4284 flickering. */
4285 s->stippled_p = s->face->stipple != 0;
4286 if (height > s->img->height
22d650b8
GM
4287 || s->img->hmargin
4288 || s->img->vmargin
06a2c219
GM
4289 || s->img->mask
4290 || s->img->pixmap == 0
4291 || s->width != s->background_width)
4292 {
ea2ba0d4
KH
4293 if (box_line_hwidth && s->first_glyph->left_box_line_p)
4294 x = s->x + box_line_hwidth;
06a2c219
GM
4295 else
4296 x = s->x;
4297
ea2ba0d4 4298 y = s->y + box_line_vwidth;
06a2c219
GM
4299
4300 if (s->img->mask)
4301 {
f9b5db02
GM
4302 /* Create a pixmap as large as the glyph string. Fill it
4303 with the background color. Copy the image to it, using
4304 its mask. Copy the temporary pixmap to the display. */
06a2c219
GM
4305 Screen *screen = FRAME_X_SCREEN (s->f);
4306 int depth = DefaultDepthOfScreen (screen);
4307
4308 /* Create a pixmap as large as the glyph string. */
4309 pixmap = XCreatePixmap (s->display, s->window,
4310 s->background_width,
4311 s->height, depth);
4312
4313 /* Don't clip in the following because we're working on the
4314 pixmap. */
4315 XSetClipMask (s->display, s->gc, None);
4316
4317 /* Fill the pixmap with the background color/stipple. */
4318 if (s->stippled_p)
4319 {
4320 /* Fill background with a stipple pattern. */
4321 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4322 XFillRectangle (s->display, pixmap, s->gc,
4323 0, 0, s->background_width, s->height);
4324 XSetFillStyle (s->display, s->gc, FillSolid);
4325 }
4326 else
4327 {
4328 XGCValues xgcv;
4329 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4330 &xgcv);
4331 XSetForeground (s->display, s->gc, xgcv.background);
4332 XFillRectangle (s->display, pixmap, s->gc,
4333 0, 0, s->background_width, s->height);
4334 XSetForeground (s->display, s->gc, xgcv.foreground);
4335 }
4336 }
4337 else
06a2c219
GM
4338 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
4339
4340 s->background_filled_p = 1;
4341 }
dc43ef94 4342
06a2c219
GM
4343 /* Draw the foreground. */
4344 if (pixmap != None)
4345 {
4346 x_draw_image_foreground_1 (s, pixmap);
4347 x_set_glyph_string_clipping (s);
4348 XCopyArea (s->display, pixmap, s->window, s->gc,
4349 0, 0, s->background_width, s->height, s->x, s->y);
4350 XFreePixmap (s->display, pixmap);
4351 }
4352 else
4353 x_draw_image_foreground (s);
b5210ea7 4354
06a2c219
GM
4355 /* If we must draw a relief around the image, do it. */
4356 if (s->img->relief
4357 || s->hl == DRAW_IMAGE_RAISED
4358 || s->hl == DRAW_IMAGE_SUNKEN)
4359 x_draw_image_relief (s);
4360}
8c1a6a84 4361
990ba854 4362
06a2c219 4363/* Draw stretch glyph string S. */
dc43ef94 4364
06a2c219
GM
4365static void
4366x_draw_stretch_glyph_string (s)
4367 struct glyph_string *s;
4368{
4369 xassert (s->first_glyph->type == STRETCH_GLYPH);
4370 s->stippled_p = s->face->stipple != 0;
990ba854 4371
06a2c219
GM
4372 if (s->hl == DRAW_CURSOR
4373 && !x_stretch_cursor_p)
4374 {
4375 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4376 as wide as the stretch glyph. */
4377 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4378
06a2c219
GM
4379 /* Draw cursor. */
4380 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4381
06a2c219
GM
4382 /* Clear rest using the GC of the original non-cursor face. */
4383 if (width < s->background_width)
4384 {
06a2c219
GM
4385 int x = s->x + width, y = s->y;
4386 int w = s->background_width - width, h = s->height;
4387 XRectangle r;
b7f83f9e 4388 GC gc;
dc43ef94 4389
b7f83f9e
GM
4390 if (s->row->mouse_face_p
4391 && cursor_in_mouse_face_p (s->w))
4392 {
4393 x_set_mouse_face_gc (s);
4394 gc = s->gc;
4395 }
4396 else
4397 gc = s->face->gc;
4398
06a2c219
GM
4399 x_get_glyph_string_clip_rect (s, &r);
4400 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
b7f83f9e 4401
06a2c219
GM
4402 if (s->face->stipple)
4403 {
4404 /* Fill background with a stipple pattern. */
4405 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4406 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4407 XSetFillStyle (s->display, gc, FillSolid);
4408 }
4409 else
4410 {
4411 XGCValues xgcv;
4412 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4413 XSetForeground (s->display, gc, xgcv.background);
4414 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4415 XSetForeground (s->display, gc, xgcv.foreground);
4416 }
4417 }
4418 }
61e9f9f3 4419 else if (!s->background_filled_p)
06a2c219
GM
4420 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4421 s->height);
4422
4423 s->background_filled_p = 1;
4424}
4425
4426
4427/* Draw glyph string S. */
4428
4429static void
4430x_draw_glyph_string (s)
4431 struct glyph_string *s;
4432{
4458cf11
KH
4433 int relief_drawn_p = 0;
4434
06a2c219
GM
4435 /* If S draws into the background of its successor, draw the
4436 background of the successor first so that S can draw into it.
4437 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4438 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4439 {
4440 xassert (s->next->img == NULL);
4441 x_set_glyph_string_gc (s->next);
4442 x_set_glyph_string_clipping (s->next);
4443 x_draw_glyph_string_background (s->next, 1);
4444 }
97210f4e 4445
06a2c219
GM
4446 /* Set up S->gc, set clipping and draw S. */
4447 x_set_glyph_string_gc (s);
06a2c219 4448
4458cf11
KH
4449 /* Draw relief (if any) in advance for char/composition so that the
4450 glyph string can be drawn over it. */
4451 if (!s->for_overlaps_p
4452 && s->face->box != FACE_NO_BOX
4453 && (s->first_glyph->type == CHAR_GLYPH
4454 || s->first_glyph->type == COMPOSITE_GLYPH))
4455
4456 {
e6269cbb 4457 x_set_glyph_string_clipping (s);
4458cf11
KH
4458 x_draw_glyph_string_background (s, 1);
4459 x_draw_glyph_string_box (s);
e6269cbb 4460 x_set_glyph_string_clipping (s);
4458cf11
KH
4461 relief_drawn_p = 1;
4462 }
e6269cbb
GM
4463 else
4464 x_set_glyph_string_clipping (s);
4458cf11 4465
06a2c219
GM
4466 switch (s->first_glyph->type)
4467 {
4468 case IMAGE_GLYPH:
4469 x_draw_image_glyph_string (s);
4470 break;
4471
4472 case STRETCH_GLYPH:
4473 x_draw_stretch_glyph_string (s);
4474 break;
4475
4476 case CHAR_GLYPH:
66ac4b0e
GM
4477 if (s->for_overlaps_p)
4478 s->background_filled_p = 1;
4479 else
4480 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4481 x_draw_glyph_string_foreground (s);
4482 break;
4483
b4192550
KH
4484 case COMPOSITE_GLYPH:
4485 if (s->for_overlaps_p || s->gidx > 0)
4486 s->background_filled_p = 1;
4487 else
4488 x_draw_glyph_string_background (s, 1);
4489 x_draw_composite_glyph_string_foreground (s);
4490 break;
4491
06a2c219
GM
4492 default:
4493 abort ();
4494 }
4495
66ac4b0e 4496 if (!s->for_overlaps_p)
06a2c219 4497 {
66ac4b0e
GM
4498 /* Draw underline. */
4499 if (s->face->underline_p)
4500 {
e24e84cc
GM
4501 unsigned long tem, h;
4502 int y;
06a2c219 4503
e24e84cc 4504 /* Get the underline thickness. Default is 1 pixel. */
66ac4b0e
GM
4505 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4506 h = 1;
e24e84cc
GM
4507
4508 /* Get the underline position. This is the recommended
4509 vertical offset in pixels from the baseline to the top of
4510 the underline. This is a signed value according to the
4511 specs, and its default is
4512
4513 ROUND ((maximum descent) / 2), with
4514 ROUND(x) = floor (x + 0.5) */
4515
a72d5ce5
GM
4516 if (x_use_underline_position_properties
4517 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
e24e84cc
GM
4518 y = s->ybase + (long) tem;
4519 else if (s->face->font)
4520 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4521 else
a02f1be0 4522 y = s->y + s->height - h;
06a2c219 4523
66ac4b0e 4524 if (s->face->underline_defaulted_p)
e24e84cc
GM
4525 XFillRectangle (s->display, s->window, s->gc,
4526 s->x, y, s->width, h);
66ac4b0e
GM
4527 else
4528 {
4529 XGCValues xgcv;
4530 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4531 XSetForeground (s->display, s->gc, s->face->underline_color);
e24e84cc
GM
4532 XFillRectangle (s->display, s->window, s->gc,
4533 s->x, y, s->width, h);
66ac4b0e
GM
4534 XSetForeground (s->display, s->gc, xgcv.foreground);
4535 }
dc6f92b8 4536 }
07e34cb0 4537
66ac4b0e
GM
4538 /* Draw overline. */
4539 if (s->face->overline_p)
06a2c219 4540 {
66ac4b0e
GM
4541 unsigned long dy = 0, h = 1;
4542
4543 if (s->face->overline_color_defaulted_p)
4544 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4545 s->width, h);
4546 else
4547 {
4548 XGCValues xgcv;
4549 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4550 XSetForeground (s->display, s->gc, s->face->overline_color);
4551 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4552 s->width, h);
4553 XSetForeground (s->display, s->gc, xgcv.foreground);
4554 }
06a2c219 4555 }
06a2c219 4556
66ac4b0e
GM
4557 /* Draw strike-through. */
4558 if (s->face->strike_through_p)
06a2c219 4559 {
66ac4b0e
GM
4560 unsigned long h = 1;
4561 unsigned long dy = (s->height - h) / 2;
4562
4563 if (s->face->strike_through_color_defaulted_p)
4564 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4565 s->width, h);
4566 else
4567 {
4568 XGCValues xgcv;
4569 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4570 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4571 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4572 s->width, h);
4573 XSetForeground (s->display, s->gc, xgcv.foreground);
4574 }
06a2c219 4575 }
06a2c219 4576
4458cf11
KH
4577 /* Draw relief if not yet drawn. */
4578 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
66ac4b0e
GM
4579 x_draw_glyph_string_box (s);
4580 }
06a2c219
GM
4581
4582 /* Reset clipping. */
4583 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4584}
07e34cb0 4585
06a2c219 4586
b4192550
KH
4587static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4588 struct face **, int));
06a2c219 4589
06a2c219 4590
209f68d9
GM
4591/* Fill glyph string S with composition components specified by S->cmp.
4592
b4192550
KH
4593 FACES is an array of faces for all components of this composition.
4594 S->gidx is the index of the first component for S.
4595 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4596 use its physical height for clipping.
06a2c219 4597
b4192550 4598 Value is the index of a component not in S. */
07e34cb0 4599
b4192550
KH
4600static int
4601x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4602 struct glyph_string *s;
b4192550 4603 struct face **faces;
66ac4b0e 4604 int overlaps_p;
07e34cb0 4605{
b4192550 4606 int i;
06a2c219 4607
b4192550 4608 xassert (s);
06a2c219 4609
b4192550 4610 s->for_overlaps_p = overlaps_p;
06a2c219 4611
b4192550
KH
4612 s->face = faces[s->gidx];
4613 s->font = s->face->font;
4614 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4615
b4192550
KH
4616 /* For all glyphs of this composition, starting at the offset
4617 S->gidx, until we reach the end of the definition or encounter a
4618 glyph that requires the different face, add it to S. */
4619 ++s->nchars;
4620 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4621 ++s->nchars;
06a2c219 4622
b4192550
KH
4623 /* All glyph strings for the same composition has the same width,
4624 i.e. the width set for the first component of the composition. */
06a2c219 4625
06a2c219
GM
4626 s->width = s->first_glyph->pixel_width;
4627
4628 /* If the specified font could not be loaded, use the frame's
4629 default font, but record the fact that we couldn't load it in
4630 the glyph string so that we can draw rectangles for the
4631 characters of the glyph string. */
4632 if (s->font == NULL)
4633 {
4634 s->font_not_found_p = 1;
4635 s->font = FRAME_FONT (s->f);
4636 }
4637
4638 /* Adjust base line for subscript/superscript text. */
4639 s->ybase += s->first_glyph->voffset;
4640
4641 xassert (s->face && s->face->gc);
4642
4643 /* This glyph string must always be drawn with 16-bit functions. */
4644 s->two_byte_p = 1;
b4192550
KH
4645
4646 return s->gidx + s->nchars;
06a2c219
GM
4647}
4648
4649
209f68d9
GM
4650/* Fill glyph string S from a sequence of character glyphs.
4651
06a2c219 4652 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4653 first glyph to consider, END is the index of the last + 1.
4654 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4655 use its physical height for clipping.
66ac4b0e
GM
4656
4657 Value is the index of the first glyph not in S. */
06a2c219
GM
4658
4659static int
66ac4b0e 4660x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4661 struct glyph_string *s;
4662 int face_id;
66ac4b0e 4663 int start, end, overlaps_p;
06a2c219
GM
4664{
4665 struct glyph *glyph, *last;
4666 int voffset;
ee569018 4667 int glyph_not_available_p;
06a2c219 4668
06a2c219
GM
4669 xassert (s->f == XFRAME (s->w->frame));
4670 xassert (s->nchars == 0);
4671 xassert (start >= 0 && end > start);
4672
66ac4b0e 4673 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4674 glyph = s->row->glyphs[s->area] + start;
4675 last = s->row->glyphs[s->area] + end;
4676 voffset = glyph->voffset;
4677
ee569018
KH
4678 glyph_not_available_p = glyph->glyph_not_available_p;
4679
06a2c219
GM
4680 while (glyph < last
4681 && glyph->type == CHAR_GLYPH
4682 && glyph->voffset == voffset
ee569018
KH
4683 /* Same face id implies same font, nowadays. */
4684 && glyph->face_id == face_id
4685 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4686 {
ee569018
KH
4687 int two_byte_p;
4688
06a2c219 4689 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4690 s->char2b + s->nchars,
4691 &two_byte_p);
4692 s->two_byte_p = two_byte_p;
06a2c219
GM
4693 ++s->nchars;
4694 xassert (s->nchars <= end - start);
4695 s->width += glyph->pixel_width;
4696 ++glyph;
4697 }
4698
4699 s->font = s->face->font;
4700 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4701
4702 /* If the specified font could not be loaded, use the frame's font,
4703 but record the fact that we couldn't load it in
4704 S->font_not_found_p so that we can draw rectangles for the
4705 characters of the glyph string. */
ee569018 4706 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4707 {
4708 s->font_not_found_p = 1;
4709 s->font = FRAME_FONT (s->f);
4710 }
4711
4712 /* Adjust base line for subscript/superscript text. */
4713 s->ybase += voffset;
66ac4b0e 4714
06a2c219
GM
4715 xassert (s->face && s->face->gc);
4716 return glyph - s->row->glyphs[s->area];
07e34cb0 4717}
dc6f92b8 4718
06a2c219
GM
4719
4720/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4721
dfcf069d 4722static void
06a2c219
GM
4723x_fill_image_glyph_string (s)
4724 struct glyph_string *s;
4725{
4726 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4727 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4728 xassert (s->img);
43d120d8 4729 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4730 s->font = s->face->font;
4731 s->width = s->first_glyph->pixel_width;
4732
4733 /* Adjust base line for subscript/superscript text. */
4734 s->ybase += s->first_glyph->voffset;
4735}
4736
4737
209f68d9 4738/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4739
209f68d9
GM
4740 ROW is the glyph row in which the glyphs are found, AREA is the
4741 area within the row. START is the index of the first glyph to
4742 consider, END is the index of the last + 1.
4743
4744 Value is the index of the first glyph not in S. */
4745
4746static int
4747x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4748 struct glyph_string *s;
209f68d9
GM
4749 struct glyph_row *row;
4750 enum glyph_row_area area;
4751 int start, end;
06a2c219 4752{
209f68d9
GM
4753 struct glyph *glyph, *last;
4754 int voffset, face_id;
4755
06a2c219 4756 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4757
4758 glyph = s->row->glyphs[s->area] + start;
4759 last = s->row->glyphs[s->area] + end;
4760 face_id = glyph->face_id;
4761 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4762 s->font = s->face->font;
209f68d9
GM
4763 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4764 s->width = glyph->pixel_width;
4765 voffset = glyph->voffset;
4766
4767 for (++glyph;
4768 (glyph < last
4769 && glyph->type == STRETCH_GLYPH
4770 && glyph->voffset == voffset
4771 && glyph->face_id == face_id);
4772 ++glyph)
4773 s->width += glyph->pixel_width;
06a2c219
GM
4774
4775 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4776 s->ybase += voffset;
4777
c296fc01
GM
4778 /* The case that face->gc == 0 is handled when drawing the glyph
4779 string by calling PREPARE_FACE_FOR_DISPLAY. */
4780 xassert (s->face);
209f68d9 4781 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4782}
4783
4784
4785/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4786 of XChar2b structures for S; it can't be allocated in
4787 x_init_glyph_string because it must be allocated via `alloca'. W
4788 is the window on which S is drawn. ROW and AREA are the glyph row
4789 and area within the row from which S is constructed. START is the
4790 index of the first glyph structure covered by S. HL is a
4791 face-override for drawing S. */
4792
4793static void
4794x_init_glyph_string (s, char2b, w, row, area, start, hl)
4795 struct glyph_string *s;
4796 XChar2b *char2b;
4797 struct window *w;
4798 struct glyph_row *row;
4799 enum glyph_row_area area;
4800 int start;
4801 enum draw_glyphs_face hl;
4802{
4803 bzero (s, sizeof *s);
4804 s->w = w;
4805 s->f = XFRAME (w->frame);
4806 s->display = FRAME_X_DISPLAY (s->f);
4807 s->window = FRAME_X_WINDOW (s->f);
4808 s->char2b = char2b;
4809 s->hl = hl;
4810 s->row = row;
4811 s->area = area;
4812 s->first_glyph = row->glyphs[area] + start;
4813 s->height = row->height;
4814 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4815
9ea173e8
GM
4816 /* Display the internal border below the tool-bar window. */
4817 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4818 s->y -= s->f->output_data.x->internal_border_width;
4819
4820 s->ybase = s->y + row->ascent;
4821}
4822
4823
4824/* Set background width of glyph string S. START is the index of the
4825 first glyph following S. LAST_X is the right-most x-position + 1
4826 in the drawing area. */
4827
4828static INLINE void
4829x_set_glyph_string_background_width (s, start, last_x)
4830 struct glyph_string *s;
4831 int start;
4832 int last_x;
4833{
4834 /* If the face of this glyph string has to be drawn to the end of
4835 the drawing area, set S->extends_to_end_of_line_p. */
4836 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4837
4838 if (start == s->row->used[s->area]
eb79f5cc 4839 && s->area == TEXT_AREA
7b0870b2
GM
4840 && ((s->hl == DRAW_NORMAL_TEXT
4841 && (s->row->fill_line_p
4842 || s->face->background != default_face->background
4843 || s->face->stipple != default_face->stipple
4844 || s->row->mouse_face_p))
4845 || s->hl == DRAW_MOUSE_FACE))
4846 s->extends_to_end_of_line_p = 1;
06a2c219
GM
4847
4848 /* If S extends its face to the end of the line, set its
4849 background_width to the distance to the right edge of the drawing
4850 area. */
4851 if (s->extends_to_end_of_line_p)
1da3fd71 4852 s->background_width = last_x - s->x + 1;
06a2c219
GM
4853 else
4854 s->background_width = s->width;
4855}
4856
4857
4858/* Add a glyph string for a stretch glyph to the list of strings
4859 between HEAD and TAIL. START is the index of the stretch glyph in
4860 row area AREA of glyph row ROW. END is the index of the last glyph
4861 in that glyph row area. X is the current output position assigned
4862 to the new glyph string constructed. HL overrides that face of the
4863 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4864 is the right-most x-position of the drawing area. */
4865
8abee2e1
DL
4866/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4867 and below -- keep them on one line. */
4868#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4869 do \
4870 { \
4871 s = (struct glyph_string *) alloca (sizeof *s); \
4872 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4873 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4874 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4875 s->x = (X); \
4876 } \
4877 while (0)
4878
4879
4880/* Add a glyph string for an image glyph to the list of strings
4881 between HEAD and TAIL. START is the index of the image glyph in
4882 row area AREA of glyph row ROW. END is the index of the last glyph
4883 in that glyph row area. X is the current output position assigned
4884 to the new glyph string constructed. HL overrides that face of the
4885 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4886 is the right-most x-position of the drawing area. */
4887
8abee2e1 4888#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4889 do \
4890 { \
4891 s = (struct glyph_string *) alloca (sizeof *s); \
4892 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4893 x_fill_image_glyph_string (s); \
4894 x_append_glyph_string (&HEAD, &TAIL, s); \
4895 ++START; \
4896 s->x = (X); \
4897 } \
4898 while (0)
4899
4900
4901/* Add a glyph string for a sequence of character glyphs to the list
4902 of strings between HEAD and TAIL. START is the index of the first
4903 glyph in row area AREA of glyph row ROW that is part of the new
4904 glyph string. END is the index of the last glyph in that glyph row
4905 area. X is the current output position assigned to the new glyph
4906 string constructed. HL overrides that face of the glyph; e.g. it
4907 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4908 right-most x-position of the drawing area. */
4909
8abee2e1 4910#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4911 do \
4912 { \
3e71d8f2 4913 int c, face_id; \
06a2c219
GM
4914 XChar2b *char2b; \
4915 \
43d120d8 4916 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4917 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4918 \
b4192550
KH
4919 s = (struct glyph_string *) alloca (sizeof *s); \
4920 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4921 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4922 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4923 s->x = (X); \
4924 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4925 OVERLAPS_P); \
06a2c219
GM
4926 } \
4927 while (0)
4928
4929
b4192550
KH
4930/* Add a glyph string for a composite sequence to the list of strings
4931 between HEAD and TAIL. START is the index of the first glyph in
4932 row area AREA of glyph row ROW that is part of the new glyph
4933 string. END is the index of the last glyph in that glyph row area.
4934 X is the current output position assigned to the new glyph string
4935 constructed. HL overrides that face of the glyph; e.g. it is
4936 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4937 x-position of the drawing area. */
4938
6c27ec25 4939#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4940 do { \
43d120d8
KH
4941 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4942 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4943 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4944 struct composition *cmp = composition_table[cmp_id]; \
4945 int glyph_len = cmp->glyph_len; \
4946 XChar2b *char2b; \
4947 struct face **faces; \
4948 struct glyph_string *first_s = NULL; \
4949 int n; \
4950 \
ee569018 4951 base_face = base_face->ascii_face; \
b4192550
KH
4952 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4953 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4954 /* At first, fill in `char2b' and `faces'. */ \
4955 for (n = 0; n < glyph_len; n++) \
4956 { \
43d120d8 4957 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4958 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4959 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4960 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4961 this_face_id, char2b + n, 1); \
b4192550
KH
4962 } \
4963 \
4964 /* Make glyph_strings for each glyph sequence that is drawable by \
4965 the same face, and append them to HEAD/TAIL. */ \
4966 for (n = 0; n < cmp->glyph_len;) \
4967 { \
4968 s = (struct glyph_string *) alloca (sizeof *s); \
4969 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4970 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4971 s->cmp = cmp; \
4972 s->gidx = n; \
b4192550
KH
4973 s->x = (X); \
4974 \
4975 if (n == 0) \
4976 first_s = s; \
4977 \
4978 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4979 } \
4980 \
4981 ++START; \
4982 s = first_s; \
4983 } while (0)
4984
4985
06a2c219
GM
4986/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4987 of AREA of glyph row ROW on window W between indices START and END.
4988 HL overrides the face for drawing glyph strings, e.g. it is
4989 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4990 x-positions of the drawing area.
4991
4992 This is an ugly monster macro construct because we must use alloca
4993 to allocate glyph strings (because x_draw_glyphs can be called
4994 asynchronously). */
4995
8abee2e1 4996#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4997 do \
4998 { \
4999 HEAD = TAIL = NULL; \
5000 while (START < END) \
5001 { \
5002 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
5003 switch (first_glyph->type) \
5004 { \
5005 case CHAR_GLYPH: \
5006 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
5007 TAIL, HL, X, LAST_X, \
5008 OVERLAPS_P); \
06a2c219
GM
5009 break; \
5010 \
b4192550
KH
5011 case COMPOSITE_GLYPH: \
5012 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
5013 HEAD, TAIL, HL, X, LAST_X,\
5014 OVERLAPS_P); \
5015 break; \
5016 \
06a2c219
GM
5017 case STRETCH_GLYPH: \
5018 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
5019 HEAD, TAIL, HL, X, LAST_X); \
5020 break; \
5021 \
5022 case IMAGE_GLYPH: \
5023 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
5024 TAIL, HL, X, LAST_X); \
5025 break; \
5026 \
5027 default: \
5028 abort (); \
5029 } \
5030 \
5031 x_set_glyph_string_background_width (s, START, LAST_X); \
5032 (X) += s->width; \
5033 } \
5034 } \
5035 while (0)
5036
5037
5038/* Draw glyphs between START and END in AREA of ROW on window W,
5039 starting at x-position X. X is relative to AREA in W. HL is a
5040 face-override with the following meaning:
5041
5042 DRAW_NORMAL_TEXT draw normally
5043 DRAW_CURSOR draw in cursor face
5044 DRAW_MOUSE_FACE draw in mouse face.
5045 DRAW_INVERSE_VIDEO draw in mode line face
5046 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
5047 DRAW_IMAGE_RAISED draw an image with a raised relief around it
5048
5049 If REAL_START is non-null, return in *REAL_START the real starting
5050 position for display. This can be different from START in case
5051 overlapping glyphs must be displayed. If REAL_END is non-null,
5052 return in *REAL_END the real end position for display. This can be
5053 different from END in case overlapping glyphs must be displayed.
5054
66ac4b0e
GM
5055 If OVERLAPS_P is non-zero, draw only the foreground of characters
5056 and clip to the physical height of ROW.
5057
06a2c219
GM
5058 Value is the x-position reached, relative to AREA of W. */
5059
5060static int
66ac4b0e
GM
5061x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end,
5062 overlaps_p)
06a2c219
GM
5063 struct window *w;
5064 int x;
5065 struct glyph_row *row;
5066 enum glyph_row_area area;
5067 int start, end;
5068 enum draw_glyphs_face hl;
5069 int *real_start, *real_end;
66ac4b0e 5070 int overlaps_p;
dc6f92b8 5071{
06a2c219
GM
5072 struct glyph_string *head, *tail;
5073 struct glyph_string *s;
5074 int last_x, area_width;
5075 int x_reached;
5076 int i, j;
5077
5078 /* Let's rather be paranoid than getting a SEGV. */
06a2c219 5079 end = min (end, row->used[area]);
a8710abf
GM
5080 start = max (0, start);
5081 start = min (end, start);
06a2c219
GM
5082 if (real_start)
5083 *real_start = start;
5084 if (real_end)
5085 *real_end = end;
5086
5087 /* Translate X to frame coordinates. Set last_x to the right
5088 end of the drawing area. */
5089 if (row->full_width_p)
5090 {
5091 /* X is relative to the left edge of W, without scroll bars
5092 or flag areas. */
5093 struct frame *f = XFRAME (w->frame);
110859fc 5094 /* int width = FRAME_FLAGS_AREA_WIDTH (f); */
06a2c219 5095 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 5096
06a2c219
GM
5097 x += window_left_x;
5098 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
5099 last_x = window_left_x + area_width;
5100
5101 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5102 {
110859fc 5103 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
5104 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
5105 last_x += width;
5106 else
5107 x -= width;
5108 }
dc6f92b8 5109
b9432a85 5110 x += FRAME_INTERNAL_BORDER_WIDTH (f);
98fedd97 5111 last_x += FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
5112 }
5113 else
dc6f92b8 5114 {
06a2c219
GM
5115 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
5116 area_width = window_box_width (w, area);
5117 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
5118 }
5119
06a2c219
GM
5120 /* Build a doubly-linked list of glyph_string structures between
5121 head and tail from what we have to draw. Note that the macro
5122 BUILD_GLYPH_STRINGS will modify its start parameter. That's
5123 the reason we use a separate variable `i'. */
5124 i = start;
66ac4b0e
GM
5125 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
5126 overlaps_p);
06a2c219
GM
5127 if (tail)
5128 x_reached = tail->x + tail->background_width;
5129 else
5130 x_reached = x;
90e65f07 5131
06a2c219
GM
5132 /* If there are any glyphs with lbearing < 0 or rbearing > width in
5133 the row, redraw some glyphs in front or following the glyph
5134 strings built above. */
a8710abf 5135 if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
5136 {
5137 int dummy_x = 0;
5138 struct glyph_string *h, *t;
5139
5140 /* Compute overhangs for all glyph strings. */
5141 for (s = head; s; s = s->next)
5142 x_compute_glyph_string_overhangs (s);
5143
5144 /* Prepend glyph strings for glyphs in front of the first glyph
5145 string that are overwritten because of the first glyph
5146 string's left overhang. The background of all strings
5147 prepended must be drawn because the first glyph string
5148 draws over it. */
5149 i = x_left_overwritten (head);
5150 if (i >= 0)
5151 {
5152 j = i;
5153 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
5154 DRAW_NORMAL_TEXT, dummy_x, last_x,
5155 overlaps_p);
06a2c219
GM
5156 start = i;
5157 if (real_start)
5158 *real_start = start;
5159 x_compute_overhangs_and_x (t, head->x, 1);
5160 x_prepend_glyph_string_lists (&head, &tail, h, t);
5161 }
58769bee 5162
06a2c219
GM
5163 /* Prepend glyph strings for glyphs in front of the first glyph
5164 string that overwrite that glyph string because of their
5165 right overhang. For these strings, only the foreground must
5166 be drawn, because it draws over the glyph string at `head'.
5167 The background must not be drawn because this would overwrite
5168 right overhangs of preceding glyphs for which no glyph
5169 strings exist. */
5170 i = x_left_overwriting (head);
5171 if (i >= 0)
5172 {
5173 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
5174 DRAW_NORMAL_TEXT, dummy_x, last_x,
5175 overlaps_p);
06a2c219
GM
5176 for (s = h; s; s = s->next)
5177 s->background_filled_p = 1;
5178 if (real_start)
5179 *real_start = i;
5180 x_compute_overhangs_and_x (t, head->x, 1);
5181 x_prepend_glyph_string_lists (&head, &tail, h, t);
5182 }
dbcb258a 5183
06a2c219
GM
5184 /* Append glyphs strings for glyphs following the last glyph
5185 string tail that are overwritten by tail. The background of
5186 these strings has to be drawn because tail's foreground draws
5187 over it. */
5188 i = x_right_overwritten (tail);
5189 if (i >= 0)
5190 {
5191 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5192 DRAW_NORMAL_TEXT, x, last_x,
5193 overlaps_p);
06a2c219
GM
5194 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5195 x_append_glyph_string_lists (&head, &tail, h, t);
5196 if (real_end)
5197 *real_end = i;
5198 }
dc6f92b8 5199
06a2c219
GM
5200 /* Append glyph strings for glyphs following the last glyph
5201 string tail that overwrite tail. The foreground of such
5202 glyphs has to be drawn because it writes into the background
5203 of tail. The background must not be drawn because it could
5204 paint over the foreground of following glyphs. */
5205 i = x_right_overwriting (tail);
5206 if (i >= 0)
5207 {
5208 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5209 DRAW_NORMAL_TEXT, x, last_x,
5210 overlaps_p);
06a2c219
GM
5211 for (s = h; s; s = s->next)
5212 s->background_filled_p = 1;
5213 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5214 x_append_glyph_string_lists (&head, &tail, h, t);
5215 if (real_end)
5216 *real_end = i;
5217 }
5218 }
58769bee 5219
06a2c219
GM
5220 /* Draw all strings. */
5221 for (s = head; s; s = s->next)
5222 x_draw_glyph_string (s);
dc6f92b8 5223
06a2c219
GM
5224 /* Value is the x-position up to which drawn, relative to AREA of W.
5225 This doesn't include parts drawn because of overhangs. */
5226 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
5227 if (!row->full_width_p)
5228 {
5229 if (area > LEFT_MARGIN_AREA)
5230 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
5231 if (area > TEXT_AREA)
5232 x_reached -= window_box_width (w, TEXT_AREA);
5233 }
a8710abf 5234
06a2c219
GM
5235 return x_reached;
5236}
dc6f92b8 5237
dc6f92b8 5238
66ac4b0e
GM
5239/* Fix the display of area AREA of overlapping row ROW in window W. */
5240
5241static void
5242x_fix_overlapping_area (w, row, area)
5243 struct window *w;
5244 struct glyph_row *row;
5245 enum glyph_row_area area;
5246{
5247 int i, x;
5248
5249 BLOCK_INPUT;
5250
5251 if (area == LEFT_MARGIN_AREA)
5252 x = 0;
5253 else if (area == TEXT_AREA)
5254 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5255 else
5256 x = (window_box_width (w, LEFT_MARGIN_AREA)
5257 + window_box_width (w, TEXT_AREA));
5258
5259 for (i = 0; i < row->used[area];)
5260 {
5261 if (row->glyphs[area][i].overlaps_vertically_p)
5262 {
5263 int start = i, start_x = x;
5264
5265 do
5266 {
5267 x += row->glyphs[area][i].pixel_width;
5268 ++i;
5269 }
5270 while (i < row->used[area]
5271 && row->glyphs[area][i].overlaps_vertically_p);
5272
5273 x_draw_glyphs (w, start_x, row, area, start, i,
5274 (row->inverse_p
5275 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
5276 NULL, NULL, 1);
5277 }
5278 else
5279 {
5280 x += row->glyphs[area][i].pixel_width;
5281 ++i;
5282 }
5283 }
5284
5285 UNBLOCK_INPUT;
5286}
5287
5288
06a2c219
GM
5289/* Output LEN glyphs starting at START at the nominal cursor position.
5290 Advance the nominal cursor over the text. The global variable
5291 updated_window contains the window being updated, updated_row is
5292 the glyph row being updated, and updated_area is the area of that
5293 row being updated. */
dc6f92b8 5294
06a2c219
GM
5295static void
5296x_write_glyphs (start, len)
5297 struct glyph *start;
5298 int len;
5299{
5300 int x, hpos, real_start, real_end;
d9cdbb3d 5301
06a2c219 5302 xassert (updated_window && updated_row);
dc6f92b8 5303 BLOCK_INPUT;
06a2c219
GM
5304
5305 /* Write glyphs. */
dc6f92b8 5306
06a2c219
GM
5307 hpos = start - updated_row->glyphs[updated_area];
5308 x = x_draw_glyphs (updated_window, output_cursor.x,
5309 updated_row, updated_area,
5310 hpos, hpos + len,
5311 (updated_row->inverse_p
5312 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
66ac4b0e 5313 &real_start, &real_end, 0);
b30ec466 5314
06a2c219 5315 /* If we drew over the cursor, note that it is not visible any more. */
78a9a4c5 5316 notice_overwritten_cursor (updated_window, real_start,
06a2c219 5317 real_end - real_start);
dc6f92b8
JB
5318
5319 UNBLOCK_INPUT;
06a2c219
GM
5320
5321 /* Advance the output cursor. */
5322 output_cursor.hpos += len;
5323 output_cursor.x = x;
dc6f92b8
JB
5324}
5325
0cdd0c9f 5326
06a2c219 5327/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 5328
06a2c219
GM
5329static void
5330x_insert_glyphs (start, len)
5331 struct glyph *start;
5332 register int len;
5333{
5334 struct frame *f;
5335 struct window *w;
5336 int line_height, shift_by_width, shifted_region_width;
5337 struct glyph_row *row;
5338 struct glyph *glyph;
5339 int frame_x, frame_y, hpos, real_start, real_end;
58769bee 5340
06a2c219 5341 xassert (updated_window && updated_row);
0cdd0c9f 5342 BLOCK_INPUT;
06a2c219
GM
5343 w = updated_window;
5344 f = XFRAME (WINDOW_FRAME (w));
5345
5346 /* Get the height of the line we are in. */
5347 row = updated_row;
5348 line_height = row->height;
5349
5350 /* Get the width of the glyphs to insert. */
5351 shift_by_width = 0;
5352 for (glyph = start; glyph < start + len; ++glyph)
5353 shift_by_width += glyph->pixel_width;
5354
5355 /* Get the width of the region to shift right. */
5356 shifted_region_width = (window_box_width (w, updated_area)
5357 - output_cursor.x
5358 - shift_by_width);
5359
5360 /* Shift right. */
bf0ab8a2 5361 frame_x = window_box_left (w, updated_area) + output_cursor.x;
06a2c219
GM
5362 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
5363 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5364 f->output_data.x->normal_gc,
5365 frame_x, frame_y,
5366 shifted_region_width, line_height,
5367 frame_x + shift_by_width, frame_y);
5368
5369 /* Write the glyphs. */
5370 hpos = start - row->glyphs[updated_area];
5371 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
66ac4b0e 5372 DRAW_NORMAL_TEXT, &real_start, &real_end, 0);
78a9a4c5 5373 notice_overwritten_cursor (w, real_start, real_end - real_start);
06a2c219
GM
5374
5375 /* Advance the output cursor. */
5376 output_cursor.hpos += len;
5377 output_cursor.x += shift_by_width;
0cdd0c9f
RS
5378 UNBLOCK_INPUT;
5379}
0cdd0c9f 5380
0cdd0c9f 5381
06a2c219
GM
5382/* Delete N glyphs at the nominal cursor position. Not implemented
5383 for X frames. */
c83febd7
RS
5384
5385static void
06a2c219
GM
5386x_delete_glyphs (n)
5387 register int n;
c83febd7 5388{
06a2c219 5389 abort ();
c83febd7
RS
5390}
5391
0cdd0c9f 5392
c5e6e06b
GM
5393/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
5394 If they are <= 0, this is probably an error. */
5395
5396void
5397x_clear_area (dpy, window, x, y, width, height, exposures)
5398 Display *dpy;
5399 Window window;
5400 int x, y;
5401 int width, height;
5402 int exposures;
5403{
5404 xassert (width > 0 && height > 0);
5405 XClearArea (dpy, window, x, y, width, height, exposures);
5406}
5407
5408
06a2c219
GM
5409/* Erase the current text line from the nominal cursor position
5410 (inclusive) to pixel column TO_X (exclusive). The idea is that
5411 everything from TO_X onward is already erased.
5412
5413 TO_X is a pixel position relative to updated_area of
5414 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 5415
06a2c219
GM
5416static void
5417x_clear_end_of_line (to_x)
5418 int to_x;
5419{
5420 struct frame *f;
5421 struct window *w = updated_window;
5422 int max_x, min_y, max_y;
5423 int from_x, from_y, to_y;
5424
5425 xassert (updated_window && updated_row);
5426 f = XFRAME (w->frame);
5427
5428 if (updated_row->full_width_p)
5429 {
5430 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
5431 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5432 && !w->pseudo_window_p)
5433 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 5434 }
06a2c219
GM
5435 else
5436 max_x = window_box_width (w, updated_area);
5437 max_y = window_text_bottom_y (w);
dc6f92b8 5438
06a2c219
GM
5439 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5440 of window. For TO_X > 0, truncate to end of drawing area. */
5441 if (to_x == 0)
5442 return;
5443 else if (to_x < 0)
5444 to_x = max_x;
5445 else
5446 to_x = min (to_x, max_x);
dbc4e1c1 5447
06a2c219
GM
5448 to_y = min (max_y, output_cursor.y + updated_row->height);
5449
5450 /* Notice if the cursor will be cleared by this operation. */
5451 if (!updated_row->full_width_p)
78a9a4c5 5452 notice_overwritten_cursor (w, output_cursor.hpos, -1);
dbc4e1c1 5453
06a2c219
GM
5454 from_x = output_cursor.x;
5455
5456 /* Translate to frame coordinates. */
5457 if (updated_row->full_width_p)
5458 {
5459 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5460 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5461 }
0cdd0c9f
RS
5462 else
5463 {
06a2c219
GM
5464 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5465 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5466 }
5467
045dee35 5468 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5469 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5470 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5471
5472 /* Prevent inadvertently clearing to end of the X window. */
5473 if (to_x > from_x && to_y > from_y)
5474 {
5475 BLOCK_INPUT;
c5e6e06b
GM
5476 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5477 from_x, from_y, to_x - from_x, to_y - from_y,
5478 False);
06a2c219 5479 UNBLOCK_INPUT;
0cdd0c9f 5480 }
0cdd0c9f 5481}
dbc4e1c1 5482
0cdd0c9f 5483
06a2c219 5484/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5485 frame. Otherwise clear the selected frame. */
06a2c219
GM
5486
5487static void
5488x_clear_frame ()
0cdd0c9f 5489{
06a2c219 5490 struct frame *f;
0cdd0c9f 5491
06a2c219
GM
5492 if (updating_frame)
5493 f = updating_frame;
0cdd0c9f 5494 else
b86bd3dd 5495 f = SELECTED_FRAME ();
58769bee 5496
06a2c219
GM
5497 /* Clearing the frame will erase any cursor, so mark them all as no
5498 longer visible. */
5499 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5500 output_cursor.hpos = output_cursor.vpos = 0;
5501 output_cursor.x = -1;
5502
5503 /* We don't set the output cursor here because there will always
5504 follow an explicit cursor_to. */
5505 BLOCK_INPUT;
5506 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5507
5508 /* We have to clear the scroll bars, too. If we have changed
5509 colors or something like that, then they should be notified. */
5510 x_scroll_bar_clear (f);
0cdd0c9f 5511
06a2c219
GM
5512 XFlush (FRAME_X_DISPLAY (f));
5513 UNBLOCK_INPUT;
dc6f92b8 5514}
06a2c219
GM
5515
5516
dc6f92b8 5517\f
dbc4e1c1
JB
5518/* Invert the middle quarter of the frame for .15 sec. */
5519
06a2c219
GM
5520/* We use the select system call to do the waiting, so we have to make
5521 sure it's available. If it isn't, we just won't do visual bells. */
5522
dbc4e1c1
JB
5523#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5524
06a2c219
GM
5525
5526/* Subtract the `struct timeval' values X and Y, storing the result in
5527 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5528
5529static int
5530timeval_subtract (result, x, y)
5531 struct timeval *result, x, y;
5532{
06a2c219
GM
5533 /* Perform the carry for the later subtraction by updating y. This
5534 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5535 if (x.tv_usec < y.tv_usec)
5536 {
5537 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5538 y.tv_usec -= 1000000 * nsec;
5539 y.tv_sec += nsec;
5540 }
06a2c219 5541
dbc4e1c1
JB
5542 if (x.tv_usec - y.tv_usec > 1000000)
5543 {
5544 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5545 y.tv_usec += 1000000 * nsec;
5546 y.tv_sec -= nsec;
5547 }
5548
06a2c219
GM
5549 /* Compute the time remaining to wait. tv_usec is certainly
5550 positive. */
dbc4e1c1
JB
5551 result->tv_sec = x.tv_sec - y.tv_sec;
5552 result->tv_usec = x.tv_usec - y.tv_usec;
5553
06a2c219
GM
5554 /* Return indication of whether the result should be considered
5555 negative. */
dbc4e1c1
JB
5556 return x.tv_sec < y.tv_sec;
5557}
dc6f92b8 5558
dfcf069d 5559void
f676886a
JB
5560XTflash (f)
5561 struct frame *f;
dc6f92b8 5562{
dbc4e1c1 5563 BLOCK_INPUT;
dc6f92b8 5564
dbc4e1c1
JB
5565 {
5566 GC gc;
dc6f92b8 5567
06a2c219
GM
5568 /* Create a GC that will use the GXxor function to flip foreground
5569 pixels into background pixels. */
dbc4e1c1
JB
5570 {
5571 XGCValues values;
dc6f92b8 5572
dbc4e1c1 5573 values.function = GXxor;
7556890b
RS
5574 values.foreground = (f->output_data.x->foreground_pixel
5575 ^ f->output_data.x->background_pixel);
58769bee 5576
334208b7 5577 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5578 GCFunction | GCForeground, &values);
5579 }
dc6f92b8 5580
dbc4e1c1 5581 {
e84e14c3
RS
5582 /* Get the height not including a menu bar widget. */
5583 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5584 /* Height of each line to flash. */
5585 int flash_height = FRAME_LINE_HEIGHT (f);
5586 /* These will be the left and right margins of the rectangles. */
5587 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5588 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5589
5590 int width;
5591
5592 /* Don't flash the area between a scroll bar and the frame
5593 edge it is next to. */
5594 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5595 {
5596 case vertical_scroll_bar_left:
5597 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5598 break;
5599
5600 case vertical_scroll_bar_right:
5601 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5602 break;
06a2c219
GM
5603
5604 default:
5605 break;
e84e14c3
RS
5606 }
5607
5608 width = flash_right - flash_left;
5609
5610 /* If window is tall, flash top and bottom line. */
5611 if (height > 3 * FRAME_LINE_HEIGHT (f))
5612 {
5613 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5614 flash_left,
5615 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5616 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5617 width, flash_height);
5618 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5619 flash_left,
5620 (height - flash_height
5621 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5622 width, flash_height);
5623 }
5624 else
5625 /* If it is short, flash it all. */
5626 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5627 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5628 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5629
06a2c219 5630 x_flush (f);
dc6f92b8 5631
dbc4e1c1 5632 {
06a2c219 5633 struct timeval wakeup;
dc6f92b8 5634
66c30ea1 5635 EMACS_GET_TIME (wakeup);
dc6f92b8 5636
dbc4e1c1
JB
5637 /* Compute time to wait until, propagating carry from usecs. */
5638 wakeup.tv_usec += 150000;
5639 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5640 wakeup.tv_usec %= 1000000;
5641
101922c3
GM
5642 /* Keep waiting until past the time wakeup or any input gets
5643 available. */
5644 while (! detect_input_pending ())
dbc4e1c1 5645 {
101922c3 5646 struct timeval current;
dbc4e1c1
JB
5647 struct timeval timeout;
5648
101922c3 5649 EMACS_GET_TIME (current);
dbc4e1c1 5650
101922c3
GM
5651 /* Break if result would be negative. */
5652 if (timeval_subtract (&current, wakeup, current))
dbc4e1c1
JB
5653 break;
5654
101922c3
GM
5655 /* How long `select' should wait. */
5656 timeout.tv_sec = 0;
5657 timeout.tv_usec = 10000;
5658
dbc4e1c1 5659 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5660 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5661 }
5662 }
58769bee 5663
e84e14c3
RS
5664 /* If window is tall, flash top and bottom line. */
5665 if (height > 3 * FRAME_LINE_HEIGHT (f))
5666 {
5667 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5668 flash_left,
5669 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5670 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5671 width, flash_height);
5672 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5673 flash_left,
5674 (height - flash_height
5675 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5676 width, flash_height);
5677 }
5678 else
5679 /* If it is short, flash it all. */
5680 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5681 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5682 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5683
334208b7 5684 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5685 x_flush (f);
dc6f92b8 5686 }
dbc4e1c1
JB
5687 }
5688
5689 UNBLOCK_INPUT;
dc6f92b8
JB
5690}
5691
06a2c219 5692#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5693
5694
dc6f92b8
JB
5695/* Make audible bell. */
5696
dfcf069d 5697void
dc6f92b8
JB
5698XTring_bell ()
5699{
b86bd3dd
GM
5700 struct frame *f = SELECTED_FRAME ();
5701
5702 if (FRAME_X_DISPLAY (f))
5703 {
dbc4e1c1 5704#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5705 if (visible_bell)
5706 XTflash (f);
5707 else
dbc4e1c1 5708#endif
b86bd3dd
GM
5709 {
5710 BLOCK_INPUT;
5711 XBell (FRAME_X_DISPLAY (f), 0);
5712 XFlush (FRAME_X_DISPLAY (f));
5713 UNBLOCK_INPUT;
5714 }
dc6f92b8
JB
5715 }
5716}
06a2c219 5717
dc6f92b8 5718\f
06a2c219
GM
5719/* Specify how many text lines, from the top of the window,
5720 should be affected by insert-lines and delete-lines operations.
5721 This, and those operations, are used only within an update
5722 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5723
dfcf069d 5724static void
06a2c219
GM
5725XTset_terminal_window (n)
5726 register int n;
dc6f92b8 5727{
06a2c219 5728 /* This function intentionally left blank. */
dc6f92b8
JB
5729}
5730
06a2c219
GM
5731
5732\f
5733/***********************************************************************
5734 Line Dance
5735 ***********************************************************************/
5736
5737/* Perform an insert-lines or delete-lines operation, inserting N
5738 lines or deleting -N lines at vertical position VPOS. */
5739
dfcf069d 5740static void
06a2c219
GM
5741x_ins_del_lines (vpos, n)
5742 int vpos, n;
dc6f92b8
JB
5743{
5744 abort ();
5745}
06a2c219
GM
5746
5747
5748/* Scroll part of the display as described by RUN. */
dc6f92b8 5749
dfcf069d 5750static void
06a2c219
GM
5751x_scroll_run (w, run)
5752 struct window *w;
5753 struct run *run;
dc6f92b8 5754{
06a2c219
GM
5755 struct frame *f = XFRAME (w->frame);
5756 int x, y, width, height, from_y, to_y, bottom_y;
5757
5758 /* Get frame-relative bounding box of the text display area of W,
5759 without mode lines. Include in this box the flags areas to the
5760 left and right of W. */
5761 window_box (w, -1, &x, &y, &width, &height);
110859fc
GM
5762 width += FRAME_X_FLAGS_AREA_WIDTH (f);
5763 x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
5764
5765 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5766 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5767 bottom_y = y + height;
dc6f92b8 5768
06a2c219
GM
5769 if (to_y < from_y)
5770 {
5771 /* Scrolling up. Make sure we don't copy part of the mode
5772 line at the bottom. */
5773 if (from_y + run->height > bottom_y)
5774 height = bottom_y - from_y;
5775 else
5776 height = run->height;
5777 }
dc6f92b8 5778 else
06a2c219
GM
5779 {
5780 /* Scolling down. Make sure we don't copy over the mode line.
5781 at the bottom. */
5782 if (to_y + run->height > bottom_y)
5783 height = bottom_y - to_y;
5784 else
5785 height = run->height;
5786 }
7a13e894 5787
06a2c219
GM
5788 BLOCK_INPUT;
5789
5790 /* Cursor off. Will be switched on again in x_update_window_end. */
5791 updated_window = w;
5792 x_clear_cursor (w);
5793
5794 XCopyArea (FRAME_X_DISPLAY (f),
5795 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5796 f->output_data.x->normal_gc,
5797 x, from_y,
5798 width, height,
5799 x, to_y);
5800
5801 UNBLOCK_INPUT;
5802}
dc6f92b8 5803
dc6f92b8 5804
06a2c219
GM
5805\f
5806/***********************************************************************
5807 Exposure Events
5808 ***********************************************************************/
5809
5810/* Redisplay an exposed area of frame F. X and Y are the upper-left
5811 corner of the exposed rectangle. W and H are width and height of
5812 the exposed area. All are pixel values. W or H zero means redraw
5813 the entire frame. */
dc6f92b8 5814
06a2c219
GM
5815static void
5816expose_frame (f, x, y, w, h)
5817 struct frame *f;
5818 int x, y, w, h;
dc6f92b8 5819{
06a2c219 5820 XRectangle r;
82f053ab 5821 int mouse_face_overwritten_p = 0;
dc6f92b8 5822
06a2c219 5823 TRACE ((stderr, "expose_frame "));
dc6f92b8 5824
06a2c219
GM
5825 /* No need to redraw if frame will be redrawn soon. */
5826 if (FRAME_GARBAGED_P (f))
dc6f92b8 5827 {
06a2c219
GM
5828 TRACE ((stderr, " garbaged\n"));
5829 return;
5830 }
5831
5832 /* If basic faces haven't been realized yet, there is no point in
5833 trying to redraw anything. This can happen when we get an expose
5834 event while Emacs is starting, e.g. by moving another window. */
5835 if (FRAME_FACE_CACHE (f) == NULL
5836 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5837 {
5838 TRACE ((stderr, " no faces\n"));
5839 return;
58769bee 5840 }
06a2c219
GM
5841
5842 if (w == 0 || h == 0)
58769bee 5843 {
06a2c219
GM
5844 r.x = r.y = 0;
5845 r.width = CANON_X_UNIT (f) * f->width;
5846 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5847 }
5848 else
5849 {
06a2c219
GM
5850 r.x = x;
5851 r.y = y;
5852 r.width = w;
5853 r.height = h;
5854 }
5855
5856 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
82f053ab 5857 mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
06a2c219 5858
9ea173e8 5859 if (WINDOWP (f->tool_bar_window))
82f053ab
GM
5860 mouse_face_overwritten_p
5861 |= expose_window (XWINDOW (f->tool_bar_window), &r);
06a2c219
GM
5862
5863#ifndef USE_X_TOOLKIT
5864 if (WINDOWP (f->menu_bar_window))
82f053ab
GM
5865 mouse_face_overwritten_p
5866 |= expose_window (XWINDOW (f->menu_bar_window), &r);
06a2c219 5867#endif /* not USE_X_TOOLKIT */
82f053ab
GM
5868
5869 /* Some window managers support a focus-follows-mouse style with
5870 delayed raising of frames. Imagine a partially obscured frame,
5871 and moving the mouse into partially obscured mouse-face on that
5872 frame. The visible part of the mouse-face will be highlighted,
5873 then the WM raises the obscured frame. With at least one WM, KDE
5874 2.1, Emacs is not getting any event for the raising of the frame
5875 (even tried with SubstructureRedirectMask), only Expose events.
5876 These expose events will draw text normally, i.e. not
5877 highlighted. Which means we must redo the highlight here.
5878 Subsume it under ``we love X''. --gerd 2001-08-15 */
5879 if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
5880 {
5881 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5882 if (f == dpyinfo->mouse_face_mouse_frame)
5883 {
5884 int x = dpyinfo->mouse_face_mouse_x;
5885 int y = dpyinfo->mouse_face_mouse_y;
5886 clear_mouse_face (dpyinfo);
5887 note_mouse_highlight (f, x, y);
5888 }
5889 }
dc6f92b8
JB
5890}
5891
06a2c219
GM
5892
5893/* Redraw (parts) of all windows in the window tree rooted at W that
82f053ab
GM
5894 intersect R. R contains frame pixel coordinates. Value is
5895 non-zero if the exposure overwrites mouse-face. */
06a2c219 5896
82f053ab 5897static int
06a2c219
GM
5898expose_window_tree (w, r)
5899 struct window *w;
5900 XRectangle *r;
dc6f92b8 5901{
82f053ab
GM
5902 struct frame *f = XFRAME (w->frame);
5903 int mouse_face_overwritten_p = 0;
5904
5905 while (w && !FRAME_GARBAGED_P (f))
06a2c219
GM
5906 {
5907 if (!NILP (w->hchild))
82f053ab
GM
5908 mouse_face_overwritten_p
5909 |= expose_window_tree (XWINDOW (w->hchild), r);
06a2c219 5910 else if (!NILP (w->vchild))
82f053ab
GM
5911 mouse_face_overwritten_p
5912 |= expose_window_tree (XWINDOW (w->vchild), r);
5913 else
5914 mouse_face_overwritten_p |= expose_window (w, r);
5915
a02f1be0 5916 w = NILP (w->next) ? NULL : XWINDOW (w->next);
06a2c219 5917 }
82f053ab
GM
5918
5919 return mouse_face_overwritten_p;
06a2c219 5920}
58769bee 5921
dc6f92b8 5922
06a2c219
GM
5923/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5924 which intersects rectangle R. R is in window-relative coordinates. */
5925
5926static void
5927expose_area (w, row, r, area)
5928 struct window *w;
5929 struct glyph_row *row;
5930 XRectangle *r;
5931 enum glyph_row_area area;
5932{
06a2c219
GM
5933 struct glyph *first = row->glyphs[area];
5934 struct glyph *end = row->glyphs[area] + row->used[area];
5935 struct glyph *last;
4bc6dcc7 5936 int first_x, start_x, x;
06a2c219 5937
6fb13182
GM
5938 if (area == TEXT_AREA && row->fill_line_p)
5939 /* If row extends face to end of line write the whole line. */
4bc6dcc7 5940 x_draw_glyphs (w, 0, row, area,
6fb13182 5941 0, row->used[area],
06a2c219 5942 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5943 NULL, NULL, 0);
6fb13182
GM
5944 else
5945 {
4bc6dcc7
GM
5946 /* Set START_X to the window-relative start position for drawing glyphs of
5947 AREA. The first glyph of the text area can be partially visible.
5948 The first glyphs of other areas cannot. */
5949 if (area == LEFT_MARGIN_AREA)
5950 start_x = 0;
5951 else if (area == TEXT_AREA)
5952 start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5953 else
5954 start_x = (window_box_width (w, LEFT_MARGIN_AREA)
5955 + window_box_width (w, TEXT_AREA));
5956 x = start_x;
5957
6fb13182
GM
5958 /* Find the first glyph that must be redrawn. */
5959 while (first < end
5960 && x + first->pixel_width < r->x)
5961 {
5962 x += first->pixel_width;
5963 ++first;
5964 }
5965
5966 /* Find the last one. */
5967 last = first;
5968 first_x = x;
5969 while (last < end
5970 && x < r->x + r->width)
5971 {
5972 x += last->pixel_width;
5973 ++last;
5974 }
5975
5976 /* Repaint. */
5977 if (last > first)
4bc6dcc7 5978 x_draw_glyphs (w, first_x - start_x, row, area,
6fb13182
GM
5979 first - row->glyphs[area],
5980 last - row->glyphs[area],
5981 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5982 NULL, NULL, 0);
5983 }
06a2c219
GM
5984}
5985
58769bee 5986
06a2c219 5987/* Redraw the parts of the glyph row ROW on window W intersecting
82f053ab
GM
5988 rectangle R. R is in window-relative coordinates. Value is
5989 non-zero if mouse-face was overwritten. */
dc6f92b8 5990
82f053ab 5991static int
06a2c219
GM
5992expose_line (w, row, r)
5993 struct window *w;
5994 struct glyph_row *row;
5995 XRectangle *r;
5996{
5997 xassert (row->enabled_p);
5998
5999 if (row->mode_line_p || w->pseudo_window_p)
6000 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
6001 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 6002 NULL, NULL, 0);
06a2c219
GM
6003 else
6004 {
6005 if (row->used[LEFT_MARGIN_AREA])
6006 expose_area (w, row, r, LEFT_MARGIN_AREA);
6007 if (row->used[TEXT_AREA])
6008 expose_area (w, row, r, TEXT_AREA);
6009 if (row->used[RIGHT_MARGIN_AREA])
6010 expose_area (w, row, r, RIGHT_MARGIN_AREA);
6011 x_draw_row_bitmaps (w, row);
6012 }
82f053ab
GM
6013
6014 return row->mouse_face_p;
06a2c219 6015}
dc6f92b8 6016
58769bee 6017
06a2c219
GM
6018/* Return non-zero if W's cursor intersects rectangle R. */
6019
6020static int
6021x_phys_cursor_in_rect_p (w, r)
6022 struct window *w;
6023 XRectangle *r;
6024{
6025 XRectangle cr, result;
6026 struct glyph *cursor_glyph;
6027
6028 cursor_glyph = get_phys_cursor_glyph (w);
6029 if (cursor_glyph)
6030 {
6031 cr.x = w->phys_cursor.x;
6032 cr.y = w->phys_cursor.y;
6033 cr.width = cursor_glyph->pixel_width;
6034 cr.height = w->phys_cursor_height;
6035 return x_intersect_rectangles (&cr, r, &result);
6036 }
6037 else
6038 return 0;
dc6f92b8 6039}
dc6f92b8 6040
06a2c219 6041
a02f1be0
GM
6042/* Redraw the part of window W intersection rectangle FR. Pixel
6043 coordinates in FR are frame-relative. Call this function with
82f053ab
GM
6044 input blocked. Value is non-zero if the exposure overwrites
6045 mouse-face. */
dc6f92b8 6046
a39202f6 6047static int
a02f1be0 6048expose_window (w, fr)
06a2c219 6049 struct window *w;
a02f1be0 6050 XRectangle *fr;
dc6f92b8 6051{
a02f1be0 6052 struct frame *f = XFRAME (w->frame);
a02f1be0 6053 XRectangle wr, r;
82f053ab 6054 int mouse_face_overwritten_p = 0;
dc6f92b8 6055
80c32bcc
GM
6056 /* If window is not yet fully initialized, do nothing. This can
6057 happen when toolkit scroll bars are used and a window is split.
6058 Reconfiguring the scroll bar will generate an expose for a newly
6059 created window. */
a39202f6 6060 if (w->current_matrix == NULL)
82f053ab 6061 return 0;
a39202f6
GM
6062
6063 /* When we're currently updating the window, display and current
6064 matrix usually don't agree. Arrange for a thorough display
6065 later. */
6066 if (w == updated_window)
6067 {
6068 SET_FRAME_GARBAGED (f);
6069 return 0;
6070 }
80c32bcc 6071
a39202f6 6072 /* Frame-relative pixel rectangle of W. */
a02f1be0
GM
6073 wr.x = XFASTINT (w->left) * CANON_X_UNIT (f);
6074 wr.y = XFASTINT (w->top) * CANON_Y_UNIT (f);
6075 wr.width = XFASTINT (w->width) * CANON_X_UNIT (f);
6076 wr.height = XFASTINT (w->height) * CANON_Y_UNIT (f);
6077
a39202f6
GM
6078 if (x_intersect_rectangles (fr, &wr, &r))
6079 {
6080 int yb = window_text_bottom_y (w);
6081 struct glyph_row *row;
6082 int cursor_cleared_p;
a02f1be0 6083
a39202f6
GM
6084 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
6085 r.x, r.y, r.width, r.height));
dc6f92b8 6086
a39202f6
GM
6087 /* Convert to window coordinates. */
6088 r.x = FRAME_TO_WINDOW_PIXEL_X (w, r.x);
6089 r.y = FRAME_TO_WINDOW_PIXEL_Y (w, r.y);
dc6f92b8 6090
a39202f6
GM
6091 /* Turn off the cursor. */
6092 if (!w->pseudo_window_p
6093 && x_phys_cursor_in_rect_p (w, &r))
6094 {
6095 x_clear_cursor (w);
6096 cursor_cleared_p = 1;
6097 }
6098 else
6099 cursor_cleared_p = 0;
06a2c219 6100
a39202f6
GM
6101 /* Find the first row intersecting the rectangle R. */
6102 for (row = w->current_matrix->rows;
6103 row->enabled_p;
6104 ++row)
6105 {
6106 int y0 = row->y;
6107 int y1 = MATRIX_ROW_BOTTOM_Y (row);
6108
6109 if ((y0 >= r.y && y0 < r.y + r.height)
6110 || (y1 > r.y && y1 < r.y + r.height)
6111 || (r.y >= y0 && r.y < y1)
6112 || (r.y + r.height > y0 && r.y + r.height < y1))
82f053ab
GM
6113 {
6114 if (expose_line (w, row, &r))
6115 mouse_face_overwritten_p = 1;
6116 }
6117
a39202f6
GM
6118 if (y1 >= yb)
6119 break;
6120 }
dc6f92b8 6121
a39202f6
GM
6122 /* Display the mode line if there is one. */
6123 if (WINDOW_WANTS_MODELINE_P (w)
6124 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
6125 row->enabled_p)
6126 && row->y < r.y + r.height)
82f053ab
GM
6127 {
6128 if (expose_line (w, row, &r))
6129 mouse_face_overwritten_p = 1;
6130 }
a39202f6
GM
6131
6132 if (!w->pseudo_window_p)
6133 {
6134 /* Draw border between windows. */
6135 x_draw_vertical_border (w);
06a2c219 6136
a39202f6
GM
6137 /* Turn the cursor on again. */
6138 if (cursor_cleared_p)
6139 x_update_window_cursor (w, 1);
6140 }
06a2c219 6141 }
82f053ab
GM
6142
6143 return mouse_face_overwritten_p;
06a2c219 6144}
dc6f92b8 6145
dc6f92b8 6146
06a2c219
GM
6147/* Determine the intersection of two rectangles R1 and R2. Return
6148 the intersection in *RESULT. Value is non-zero if RESULT is not
6149 empty. */
6150
6151static int
6152x_intersect_rectangles (r1, r2, result)
6153 XRectangle *r1, *r2, *result;
6154{
6155 XRectangle *left, *right;
6156 XRectangle *upper, *lower;
6157 int intersection_p = 0;
6158
6159 /* Rearrange so that R1 is the left-most rectangle. */
6160 if (r1->x < r2->x)
6161 left = r1, right = r2;
6162 else
6163 left = r2, right = r1;
6164
6165 /* X0 of the intersection is right.x0, if this is inside R1,
6166 otherwise there is no intersection. */
6167 if (right->x <= left->x + left->width)
6168 {
6169 result->x = right->x;
6170
6171 /* The right end of the intersection is the minimum of the
6172 the right ends of left and right. */
6173 result->width = (min (left->x + left->width, right->x + right->width)
6174 - result->x);
6175
6176 /* Same game for Y. */
6177 if (r1->y < r2->y)
6178 upper = r1, lower = r2;
6179 else
6180 upper = r2, lower = r1;
6181
6182 /* The upper end of the intersection is lower.y0, if this is inside
6183 of upper. Otherwise, there is no intersection. */
6184 if (lower->y <= upper->y + upper->height)
dc43ef94 6185 {
06a2c219
GM
6186 result->y = lower->y;
6187
6188 /* The lower end of the intersection is the minimum of the lower
6189 ends of upper and lower. */
6190 result->height = (min (lower->y + lower->height,
6191 upper->y + upper->height)
6192 - result->y);
6193 intersection_p = 1;
dc43ef94 6194 }
dc6f92b8
JB
6195 }
6196
06a2c219 6197 return intersection_p;
dc6f92b8 6198}
06a2c219
GM
6199
6200
6201
6202
dc6f92b8 6203\f
dc6f92b8 6204static void
334208b7
RS
6205frame_highlight (f)
6206 struct frame *f;
dc6f92b8 6207{
b3e1e05c
JB
6208 /* We used to only do this if Vx_no_window_manager was non-nil, but
6209 the ICCCM (section 4.1.6) says that the window's border pixmap
6210 and border pixel are window attributes which are "private to the
6211 client", so we can always change it to whatever we want. */
6212 BLOCK_INPUT;
334208b7 6213 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6214 f->output_data.x->border_pixel);
b3e1e05c 6215 UNBLOCK_INPUT;
5d46f928 6216 x_update_cursor (f, 1);
dc6f92b8
JB
6217}
6218
6219static void
334208b7
RS
6220frame_unhighlight (f)
6221 struct frame *f;
dc6f92b8 6222{
b3e1e05c
JB
6223 /* We used to only do this if Vx_no_window_manager was non-nil, but
6224 the ICCCM (section 4.1.6) says that the window's border pixmap
6225 and border pixel are window attributes which are "private to the
6226 client", so we can always change it to whatever we want. */
6227 BLOCK_INPUT;
334208b7 6228 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6229 f->output_data.x->border_tile);
b3e1e05c 6230 UNBLOCK_INPUT;
5d46f928 6231 x_update_cursor (f, 1);
dc6f92b8 6232}
dc6f92b8 6233
f676886a
JB
6234/* The focus has changed. Update the frames as necessary to reflect
6235 the new situation. Note that we can't change the selected frame
c5acd733 6236 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 6237 Each event gets marked with the frame in which it occurred, so the
c5acd733 6238 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 6239
6d4238f3 6240static void
0f941935
KH
6241x_new_focus_frame (dpyinfo, frame)
6242 struct x_display_info *dpyinfo;
f676886a 6243 struct frame *frame;
dc6f92b8 6244{
0f941935 6245 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 6246
0f941935 6247 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 6248 {
58769bee 6249 /* Set this before calling other routines, so that they see
f676886a 6250 the correct value of x_focus_frame. */
0f941935 6251 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
6252
6253 if (old_focus && old_focus->auto_lower)
f676886a 6254 x_lower_frame (old_focus);
dc6f92b8
JB
6255
6256#if 0
f676886a 6257 selected_frame = frame;
e0c1aef2
KH
6258 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6259 selected_frame);
f676886a
JB
6260 Fselect_window (selected_frame->selected_window);
6261 choose_minibuf_frame ();
c118dd06 6262#endif /* ! 0 */
dc6f92b8 6263
0f941935
KH
6264 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6265 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
6266 else
6267 pending_autoraise_frame = 0;
6d4238f3 6268 }
dc6f92b8 6269
0f941935 6270 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
6271}
6272
37c2c98b
RS
6273/* Handle an event saying the mouse has moved out of an Emacs frame. */
6274
6275void
0f941935
KH
6276x_mouse_leave (dpyinfo)
6277 struct x_display_info *dpyinfo;
37c2c98b 6278{
0f941935 6279 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 6280}
6d4238f3 6281
f451eb13
JB
6282/* The focus has changed, or we have redirected a frame's focus to
6283 another frame (this happens when a frame uses a surrogate
06a2c219 6284 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
6285
6286 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 6287 frame is being highlighted or un-highlighted; we only use it to find
0f941935 6288 the appropriate X display info. */
06a2c219 6289
6d4238f3 6290static void
0f941935
KH
6291XTframe_rehighlight (frame)
6292 struct frame *frame;
6d4238f3 6293{
0f941935
KH
6294 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6295}
6d4238f3 6296
0f941935
KH
6297static void
6298x_frame_rehighlight (dpyinfo)
6299 struct x_display_info *dpyinfo;
6300{
6301 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6302
6303 if (dpyinfo->x_focus_frame)
6d4238f3 6304 {
0f941935
KH
6305 dpyinfo->x_highlight_frame
6306 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6307 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6308 : dpyinfo->x_focus_frame);
6309 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 6310 {
0f941935
KH
6311 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6312 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 6313 }
dc6f92b8 6314 }
6d4238f3 6315 else
0f941935 6316 dpyinfo->x_highlight_frame = 0;
dc6f92b8 6317
0f941935 6318 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
6319 {
6320 if (old_highlight)
f676886a 6321 frame_unhighlight (old_highlight);
0f941935
KH
6322 if (dpyinfo->x_highlight_frame)
6323 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 6324 }
dc6f92b8 6325}
06a2c219
GM
6326
6327
dc6f92b8 6328\f
06a2c219 6329/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 6330
28430d3c
JB
6331/* Initialize mode_switch_bit and modifier_meaning. */
6332static void
334208b7
RS
6333x_find_modifier_meanings (dpyinfo)
6334 struct x_display_info *dpyinfo;
28430d3c 6335{
f689eb05 6336 int min_code, max_code;
28430d3c
JB
6337 KeySym *syms;
6338 int syms_per_code;
6339 XModifierKeymap *mods;
6340
334208b7
RS
6341 dpyinfo->meta_mod_mask = 0;
6342 dpyinfo->shift_lock_mask = 0;
6343 dpyinfo->alt_mod_mask = 0;
6344 dpyinfo->super_mod_mask = 0;
6345 dpyinfo->hyper_mod_mask = 0;
58769bee 6346
9658a521 6347#ifdef HAVE_X11R4
334208b7 6348 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 6349#else
4a60f8c5
RS
6350 min_code = dpyinfo->display->min_keycode;
6351 max_code = dpyinfo->display->max_keycode;
9658a521
JB
6352#endif
6353
334208b7 6354 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
6355 min_code, max_code - min_code + 1,
6356 &syms_per_code);
334208b7 6357 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 6358
58769bee 6359 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 6360 Alt keysyms are on. */
28430d3c 6361 {
06a2c219 6362 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
6363
6364 for (row = 3; row < 8; row++)
6365 for (col = 0; col < mods->max_keypermod; col++)
6366 {
0299d313
RS
6367 KeyCode code
6368 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 6369
af92970c
KH
6370 /* Zeroes are used for filler. Skip them. */
6371 if (code == 0)
6372 continue;
6373
28430d3c
JB
6374 /* Are any of this keycode's keysyms a meta key? */
6375 {
6376 int code_col;
6377
6378 for (code_col = 0; code_col < syms_per_code; code_col++)
6379 {
f689eb05 6380 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 6381
f689eb05 6382 switch (sym)
28430d3c 6383 {
f689eb05
JB
6384 case XK_Meta_L:
6385 case XK_Meta_R:
334208b7 6386 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 6387 break;
f689eb05
JB
6388
6389 case XK_Alt_L:
6390 case XK_Alt_R:
334208b7 6391 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
6392 break;
6393
6394 case XK_Hyper_L:
6395 case XK_Hyper_R:
334208b7 6396 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
6397 break;
6398
6399 case XK_Super_L:
6400 case XK_Super_R:
334208b7 6401 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 6402 break;
11edeb03
JB
6403
6404 case XK_Shift_Lock:
6405 /* Ignore this if it's not on the lock modifier. */
6406 if ((1 << row) == LockMask)
334208b7 6407 dpyinfo->shift_lock_mask = LockMask;
11edeb03 6408 break;
28430d3c
JB
6409 }
6410 }
6411 }
6412 }
6413 }
6414
f689eb05 6415 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 6416 if (! dpyinfo->meta_mod_mask)
a3c44b14 6417 {
334208b7
RS
6418 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6419 dpyinfo->alt_mod_mask = 0;
a3c44b14 6420 }
f689eb05 6421
148c4b70
RS
6422 /* If some keys are both alt and meta,
6423 make them just meta, not alt. */
334208b7 6424 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 6425 {
334208b7 6426 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 6427 }
58769bee 6428
28430d3c 6429 XFree ((char *) syms);
f689eb05 6430 XFreeModifiermap (mods);
28430d3c
JB
6431}
6432
dfeccd2d
JB
6433/* Convert between the modifier bits X uses and the modifier bits
6434 Emacs uses. */
06a2c219 6435
7c5283e4 6436static unsigned int
334208b7
RS
6437x_x_to_emacs_modifiers (dpyinfo, state)
6438 struct x_display_info *dpyinfo;
dc6f92b8
JB
6439 unsigned int state;
6440{
334208b7
RS
6441 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
6442 | ((state & ControlMask) ? ctrl_modifier : 0)
6443 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
6444 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
6445 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
6446 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
6447}
6448
dfeccd2d 6449static unsigned int
334208b7
RS
6450x_emacs_to_x_modifiers (dpyinfo, state)
6451 struct x_display_info *dpyinfo;
dfeccd2d
JB
6452 unsigned int state;
6453{
334208b7
RS
6454 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
6455 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6456 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6457 | ((state & shift_modifier) ? ShiftMask : 0)
6458 | ((state & ctrl_modifier) ? ControlMask : 0)
6459 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6460}
d047c4eb
KH
6461
6462/* Convert a keysym to its name. */
6463
6464char *
6465x_get_keysym_name (keysym)
6466 KeySym keysym;
6467{
6468 char *value;
6469
6470 BLOCK_INPUT;
6471 value = XKeysymToString (keysym);
6472 UNBLOCK_INPUT;
6473
6474 return value;
6475}
06a2c219
GM
6476
6477
e4571a43
JB
6478\f
6479/* Mouse clicks and mouse movement. Rah. */
e4571a43 6480
06a2c219
GM
6481/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6482 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6483 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6484 not force the value into range. */
69388238 6485
c8dba240 6486void
69388238 6487pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6488 FRAME_PTR f;
69388238 6489 register int pix_x, pix_y;
e4571a43
JB
6490 register int *x, *y;
6491 XRectangle *bounds;
69388238 6492 int noclip;
e4571a43 6493{
06a2c219 6494 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6495 even for negative values. */
6496 if (pix_x < 0)
7556890b 6497 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6498 if (pix_y < 0)
7556890b 6499 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6500
e4571a43
JB
6501 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6502 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6503
6504 if (bounds)
6505 {
7556890b
RS
6506 bounds->width = FONT_WIDTH (f->output_data.x->font);
6507 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6508 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6509 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6510 }
6511
69388238
RS
6512 if (!noclip)
6513 {
6514 if (pix_x < 0)
6515 pix_x = 0;
3cbd2e0b
RS
6516 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6517 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6518
6519 if (pix_y < 0)
6520 pix_y = 0;
6521 else if (pix_y > f->height)
6522 pix_y = f->height;
6523 }
e4571a43
JB
6524
6525 *x = pix_x;
6526 *y = pix_y;
6527}
6528
06a2c219
GM
6529
6530/* Given HPOS/VPOS in the current matrix of W, return corresponding
6531 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6532 can't tell the positions because W's display is not up to date,
6533 return 0. */
6534
6535int
6536glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6537 struct window *w;
6538 int hpos, vpos;
6539 int *frame_x, *frame_y;
2b5c9e71 6540{
06a2c219
GM
6541 int success_p;
6542
6543 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6544 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6545
6546 if (display_completed)
6547 {
6548 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6549 struct glyph *glyph = row->glyphs[TEXT_AREA];
6550 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6551
6552 *frame_y = row->y;
6553 *frame_x = row->x;
6554 while (glyph < end)
6555 {
6556 *frame_x += glyph->pixel_width;
6557 ++glyph;
6558 }
6559
6560 success_p = 1;
6561 }
6562 else
6563 {
6564 *frame_y = *frame_x = 0;
6565 success_p = 0;
6566 }
6567
6568 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6569 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6570 return success_p;
2b5c9e71
RS
6571}
6572
06a2c219 6573
dc6f92b8
JB
6574/* Prepare a mouse-event in *RESULT for placement in the input queue.
6575
6576 If the event is a button press, then note that we have grabbed
f451eb13 6577 the mouse. */
dc6f92b8
JB
6578
6579static Lisp_Object
f451eb13 6580construct_mouse_click (result, event, f)
dc6f92b8
JB
6581 struct input_event *result;
6582 XButtonEvent *event;
f676886a 6583 struct frame *f;
dc6f92b8 6584{
f451eb13 6585 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6586 otherwise. */
f451eb13 6587 result->kind = mouse_click;
69388238 6588 result->code = event->button - Button1;
1113d9db 6589 result->timestamp = event->time;
334208b7
RS
6590 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6591 event->state)
f689eb05 6592 | (event->type == ButtonRelease
58769bee 6593 ? up_modifier
f689eb05 6594 : down_modifier));
dc6f92b8 6595
06a2c219
GM
6596 XSETINT (result->x, event->x);
6597 XSETINT (result->y, event->y);
6598 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6599 result->arg = Qnil;
06a2c219 6600 return Qnil;
dc6f92b8 6601}
b849c413 6602
69388238 6603\f
90e65f07
JB
6604/* Function to report a mouse movement to the mainstream Emacs code.
6605 The input handler calls this.
6606
6607 We have received a mouse movement event, which is given in *event.
6608 If the mouse is over a different glyph than it was last time, tell
6609 the mainstream emacs code by setting mouse_moved. If not, ask for
6610 another motion event, so we can check again the next time it moves. */
b8009dd1 6611
06a2c219
GM
6612static XMotionEvent last_mouse_motion_event;
6613static Lisp_Object last_mouse_motion_frame;
6614
90e65f07 6615static void
12ba150f 6616note_mouse_movement (frame, event)
f676886a 6617 FRAME_PTR frame;
90e65f07 6618 XMotionEvent *event;
90e65f07 6619{
e5d77022 6620 last_mouse_movement_time = event->time;
06a2c219
GM
6621 last_mouse_motion_event = *event;
6622 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6623
27f338af
RS
6624 if (event->window != FRAME_X_WINDOW (frame))
6625 {
39d8bb4d 6626 frame->mouse_moved = 1;
27f338af 6627 last_mouse_scroll_bar = Qnil;
27f338af 6628 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6629 }
6630
90e65f07 6631 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6632 else if (event->x < last_mouse_glyph.x
6633 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6634 || event->y < last_mouse_glyph.y
6635 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6636 {
39d8bb4d 6637 frame->mouse_moved = 1;
ab648270 6638 last_mouse_scroll_bar = Qnil;
b8009dd1 6639 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6640 }
6641}
6642
bf1c0ba1 6643/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6644
06a2c219
GM
6645 int disable_mouse_highlight;
6646
6647
6648\f
6649/************************************************************************
6650 Mouse Face
6651 ************************************************************************/
6652
6653/* Find the glyph under window-relative coordinates X/Y in window W.
6654 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6655 strings. Return in *HPOS and *VPOS the row and column number of
6656 the glyph found. Return in *AREA the glyph area containing X.
6657 Value is a pointer to the glyph found or null if X/Y is not on
6658 text, or we can't tell because W's current matrix is not up to
6659 date. */
6660
6661static struct glyph *
f9db2310 6662x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
06a2c219
GM
6663 struct window *w;
6664 int x, y;
6665 int *hpos, *vpos, *area;
f9db2310 6666 int buffer_only_p;
06a2c219
GM
6667{
6668 struct glyph *glyph, *end;
3e71d8f2 6669 struct glyph_row *row = NULL;
06a2c219
GM
6670 int x0, i, left_area_width;
6671
6672 /* Find row containing Y. Give up if some row is not enabled. */
6673 for (i = 0; i < w->current_matrix->nrows; ++i)
6674 {
6675 row = MATRIX_ROW (w->current_matrix, i);
6676 if (!row->enabled_p)
6677 return NULL;
6678 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6679 break;
6680 }
6681
6682 *vpos = i;
6683 *hpos = 0;
6684
6685 /* Give up if Y is not in the window. */
6686 if (i == w->current_matrix->nrows)
6687 return NULL;
6688
6689 /* Get the glyph area containing X. */
6690 if (w->pseudo_window_p)
6691 {
6692 *area = TEXT_AREA;
6693 x0 = 0;
6694 }
6695 else
6696 {
6697 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6698 if (x < left_area_width)
6699 {
6700 *area = LEFT_MARGIN_AREA;
6701 x0 = 0;
6702 }
6703 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6704 {
6705 *area = TEXT_AREA;
6706 x0 = row->x + left_area_width;
6707 }
6708 else
6709 {
6710 *area = RIGHT_MARGIN_AREA;
6711 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6712 }
6713 }
6714
6715 /* Find glyph containing X. */
6716 glyph = row->glyphs[*area];
6717 end = glyph + row->used[*area];
6718 while (glyph < end)
6719 {
6720 if (x < x0 + glyph->pixel_width)
6721 {
6722 if (w->pseudo_window_p)
6723 break;
f9db2310 6724 else if (!buffer_only_p || BUFFERP (glyph->object))
06a2c219
GM
6725 break;
6726 }
6727
6728 x0 += glyph->pixel_width;
6729 ++glyph;
6730 }
6731
6732 if (glyph == end)
6733 return NULL;
6734
6735 *hpos = glyph - row->glyphs[*area];
6736 return glyph;
6737}
6738
6739
6740/* Convert frame-relative x/y to coordinates relative to window W.
6741 Takes pseudo-windows into account. */
6742
6743static void
6744frame_to_window_pixel_xy (w, x, y)
6745 struct window *w;
6746 int *x, *y;
6747{
6748 if (w->pseudo_window_p)
6749 {
6750 /* A pseudo-window is always full-width, and starts at the
6751 left edge of the frame, plus a frame border. */
6752 struct frame *f = XFRAME (w->frame);
6753 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6754 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6755 }
6756 else
6757 {
6758 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6759 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6760 }
6761}
6762
6763
e371a781 6764/* Take proper action when mouse has moved to the mode or header line of
06a2c219
GM
6765 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6766 mode line. X is relative to the start of the text display area of
6767 W, so the width of bitmap areas and scroll bars must be subtracted
6768 to get a position relative to the start of the mode line. */
6769
6770static void
6771note_mode_line_highlight (w, x, mode_line_p)
6772 struct window *w;
6773 int x, mode_line_p;
6774{
6775 struct frame *f = XFRAME (w->frame);
6776 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6777 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6778 struct glyph_row *row;
6779
6780 if (mode_line_p)
6781 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6782 else
045dee35 6783 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
e371a781 6784
06a2c219
GM
6785 if (row->enabled_p)
6786 {
6787 struct glyph *glyph, *end;
6788 Lisp_Object help, map;
6789 int x0;
6790
6791 /* Find the glyph under X. */
6792 glyph = row->glyphs[TEXT_AREA];
6793 end = glyph + row->used[TEXT_AREA];
6794 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
110859fc 6795 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
e371a781 6796
06a2c219
GM
6797 while (glyph < end
6798 && x >= x0 + glyph->pixel_width)
6799 {
6800 x0 += glyph->pixel_width;
6801 ++glyph;
6802 }
6803
6804 if (glyph < end
6805 && STRINGP (glyph->object)
6806 && XSTRING (glyph->object)->intervals
6807 && glyph->charpos >= 0
6808 && glyph->charpos < XSTRING (glyph->object)->size)
6809 {
6810 /* If we're on a string with `help-echo' text property,
6811 arrange for the help to be displayed. This is done by
6812 setting the global variable help_echo to the help string. */
6813 help = Fget_text_property (make_number (glyph->charpos),
6814 Qhelp_echo, glyph->object);
b7e80413 6815 if (!NILP (help))
be010514
GM
6816 {
6817 help_echo = help;
7cea38bc 6818 XSETWINDOW (help_echo_window, w);
be010514
GM
6819 help_echo_object = glyph->object;
6820 help_echo_pos = glyph->charpos;
6821 }
06a2c219
GM
6822
6823 /* Change the mouse pointer according to what is under X/Y. */
6824 map = Fget_text_property (make_number (glyph->charpos),
6825 Qlocal_map, glyph->object);
02067692 6826 if (KEYMAPP (map))
06a2c219 6827 cursor = f->output_data.x->nontext_cursor;
be010514
GM
6828 else
6829 {
6830 map = Fget_text_property (make_number (glyph->charpos),
6831 Qkeymap, glyph->object);
02067692 6832 if (KEYMAPP (map))
be010514
GM
6833 cursor = f->output_data.x->nontext_cursor;
6834 }
06a2c219
GM
6835 }
6836 }
6837
6838 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6839}
6840
6841
6842/* Take proper action when the mouse has moved to position X, Y on
6843 frame F as regards highlighting characters that have mouse-face
6844 properties. Also de-highlighting chars where the mouse was before.
27f338af 6845 X and Y can be negative or out of range. */
b8009dd1
RS
6846
6847static void
6848note_mouse_highlight (f, x, y)
06a2c219 6849 struct frame *f;
c32cdd9a 6850 int x, y;
b8009dd1 6851{
06a2c219
GM
6852 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6853 int portion;
b8009dd1
RS
6854 Lisp_Object window;
6855 struct window *w;
0d487c52
GM
6856 Cursor cursor = None;
6857 struct buffer *b;
b8009dd1 6858
06a2c219
GM
6859 /* When a menu is active, don't highlight because this looks odd. */
6860#ifdef USE_X_TOOLKIT
6861 if (popup_activated ())
6862 return;
6863#endif
6864
04fff9c0
GM
6865 if (disable_mouse_highlight
6866 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6867 return;
6868
06a2c219
GM
6869 dpyinfo->mouse_face_mouse_x = x;
6870 dpyinfo->mouse_face_mouse_y = y;
6871 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6872
06a2c219 6873 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6874 return;
6875
514e4681
RS
6876 if (gc_in_progress)
6877 {
06a2c219 6878 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6879 return;
6880 }
6881
b8009dd1 6882 /* Which window is that in? */
06a2c219 6883 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6884
6885 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6886 if (! EQ (window, dpyinfo->mouse_face_window))
6887 clear_mouse_face (dpyinfo);
6888
6889 /* Not on a window -> return. */
6890 if (!WINDOWP (window))
6891 return;
6892
6893 /* Convert to window-relative pixel coordinates. */
6894 w = XWINDOW (window);
6895 frame_to_window_pixel_xy (w, &x, &y);
6896
9ea173e8 6897 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6898 buffer. */
9ea173e8 6899 if (EQ (window, f->tool_bar_window))
06a2c219 6900 {
9ea173e8 6901 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6902 return;
6903 }
6904
0d487c52 6905 /* Mouse is on the mode or header line? */
06a2c219
GM
6906 if (portion == 1 || portion == 3)
6907 {
06a2c219
GM
6908 note_mode_line_highlight (w, x, portion == 1);
6909 return;
6910 }
0d487c52
GM
6911
6912 if (portion == 2)
6913 cursor = f->output_data.x->horizontal_drag_cursor;
06a2c219 6914 else
0d487c52 6915 cursor = f->output_data.x->text_cursor;
b8009dd1 6916
0cdd0c9f
RS
6917 /* Are we in a window whose display is up to date?
6918 And verify the buffer's text has not changed. */
0d487c52 6919 b = XBUFFER (w->buffer);
06a2c219
GM
6920 if (/* Within text portion of the window. */
6921 portion == 0
0cdd0c9f 6922 && EQ (w->window_end_valid, w->buffer)
0d487c52
GM
6923 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
6924 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
b8009dd1 6925 {
06a2c219
GM
6926 int hpos, vpos, pos, i, area;
6927 struct glyph *glyph;
f9db2310 6928 Lisp_Object object;
0d487c52
GM
6929 Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
6930 Lisp_Object *overlay_vec = NULL;
6931 int len, noverlays;
6932 struct buffer *obuf;
6933 int obegv, ozv, same_region;
b8009dd1 6934
06a2c219 6935 /* Find the glyph under X/Y. */
f9db2310 6936 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
06a2c219
GM
6937
6938 /* Clear mouse face if X/Y not over text. */
6939 if (glyph == NULL
6940 || area != TEXT_AREA
6941 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6942 {
fa262c07
GM
6943 if (clear_mouse_face (dpyinfo))
6944 cursor = None;
6945 goto set_cursor;
06a2c219
GM
6946 }
6947
6948 pos = glyph->charpos;
f9db2310
GM
6949 object = glyph->object;
6950 if (!STRINGP (object) && !BUFFERP (object))
fa262c07 6951 goto set_cursor;
06a2c219 6952
0d487c52
GM
6953 /* If we get an out-of-range value, return now; avoid an error. */
6954 if (BUFFERP (object) && pos > BUF_Z (b))
fa262c07 6955 goto set_cursor;
06a2c219 6956
0d487c52
GM
6957 /* Make the window's buffer temporarily current for
6958 overlays_at and compute_char_face. */
6959 obuf = current_buffer;
6960 current_buffer = b;
6961 obegv = BEGV;
6962 ozv = ZV;
6963 BEGV = BEG;
6964 ZV = Z;
06a2c219 6965
0d487c52
GM
6966 /* Is this char mouse-active or does it have help-echo? */
6967 position = make_number (pos);
f9db2310 6968
0d487c52
GM
6969 if (BUFFERP (object))
6970 {
6971 /* Put all the overlays we want in a vector in overlay_vec.
6972 Store the length in len. If there are more than 10, make
6973 enough space for all, and try again. */
6974 len = 10;
6975 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6976 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
6977 if (noverlays > len)
6978 {
6979 len = noverlays;
6980 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6981 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
6982 }
f8349001 6983
0d487c52
GM
6984 /* Sort overlays into increasing priority order. */
6985 noverlays = sort_overlays (overlay_vec, noverlays, w);
6986 }
6987 else
6988 noverlays = 0;
6989
6990 same_region = (EQ (window, dpyinfo->mouse_face_window)
6991 && vpos >= dpyinfo->mouse_face_beg_row
6992 && vpos <= dpyinfo->mouse_face_end_row
6993 && (vpos > dpyinfo->mouse_face_beg_row
6994 || hpos >= dpyinfo->mouse_face_beg_col)
6995 && (vpos < dpyinfo->mouse_face_end_row
6996 || hpos < dpyinfo->mouse_face_end_col
6997 || dpyinfo->mouse_face_past_end));
6998
6999 if (same_region)
7000 cursor = None;
7001
7002 /* Check mouse-face highlighting. */
7003 if (! same_region
7004 /* If there exists an overlay with mouse-face overlapping
7005 the one we are currently highlighting, we have to
7006 check if we enter the overlapping overlay, and then
7007 highlight only that. */
7008 || (OVERLAYP (dpyinfo->mouse_face_overlay)
7009 && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
7010 {
0d487c52
GM
7011 /* Find the highest priority overlay that has a mouse-face
7012 property. */
7013 overlay = Qnil;
7014 for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
7015 {
7016 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
7017 if (!NILP (mouse_face))
7018 overlay = overlay_vec[i];
7019 }
8bd189fb
GM
7020
7021 /* If we're actually highlighting the same overlay as
7022 before, there's no need to do that again. */
7023 if (!NILP (overlay)
7024 && EQ (overlay, dpyinfo->mouse_face_overlay))
7025 goto check_help_echo;
f9db2310 7026
8bd189fb
GM
7027 dpyinfo->mouse_face_overlay = overlay;
7028
7029 /* Clear the display of the old active region, if any. */
7030 if (clear_mouse_face (dpyinfo))
7031 cursor = None;
7032
0d487c52
GM
7033 /* If no overlay applies, get a text property. */
7034 if (NILP (overlay))
7035 mouse_face = Fget_text_property (position, Qmouse_face, object);
06a2c219 7036
0d487c52
GM
7037 /* Handle the overlay case. */
7038 if (!NILP (overlay))
7039 {
7040 /* Find the range of text around this char that
7041 should be active. */
7042 Lisp_Object before, after;
7043 int ignore;
7044
7045 before = Foverlay_start (overlay);
7046 after = Foverlay_end (overlay);
7047 /* Record this as the current active region. */
7048 fast_find_position (w, XFASTINT (before),
7049 &dpyinfo->mouse_face_beg_col,
7050 &dpyinfo->mouse_face_beg_row,
7051 &dpyinfo->mouse_face_beg_x,
7e376260
GM
7052 &dpyinfo->mouse_face_beg_y, Qnil);
7053
0d487c52
GM
7054 dpyinfo->mouse_face_past_end
7055 = !fast_find_position (w, XFASTINT (after),
7056 &dpyinfo->mouse_face_end_col,
7057 &dpyinfo->mouse_face_end_row,
7058 &dpyinfo->mouse_face_end_x,
7e376260 7059 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7060 dpyinfo->mouse_face_window = window;
7061 dpyinfo->mouse_face_face_id
7062 = face_at_buffer_position (w, pos, 0, 0,
7063 &ignore, pos + 1, 1);
7064
7065 /* Display it as active. */
7066 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7067 cursor = None;
0d487c52
GM
7068 }
7069 /* Handle the text property case. */
7070 else if (!NILP (mouse_face) && BUFFERP (object))
7071 {
7072 /* Find the range of text around this char that
7073 should be active. */
7074 Lisp_Object before, after, beginning, end;
7075 int ignore;
7076
7077 beginning = Fmarker_position (w->start);
7078 end = make_number (BUF_Z (XBUFFER (object))
7079 - XFASTINT (w->window_end_pos));
7080 before
7081 = Fprevious_single_property_change (make_number (pos + 1),
7082 Qmouse_face,
7083 object, beginning);
7084 after
7085 = Fnext_single_property_change (position, Qmouse_face,
7086 object, end);
7087
7088 /* Record this as the current active region. */
7089 fast_find_position (w, XFASTINT (before),
7090 &dpyinfo->mouse_face_beg_col,
7091 &dpyinfo->mouse_face_beg_row,
7092 &dpyinfo->mouse_face_beg_x,
7e376260 7093 &dpyinfo->mouse_face_beg_y, Qnil);
0d487c52
GM
7094 dpyinfo->mouse_face_past_end
7095 = !fast_find_position (w, XFASTINT (after),
7096 &dpyinfo->mouse_face_end_col,
7097 &dpyinfo->mouse_face_end_row,
7098 &dpyinfo->mouse_face_end_x,
7e376260 7099 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7100 dpyinfo->mouse_face_window = window;
7101
7102 if (BUFFERP (object))
06a2c219
GM
7103 dpyinfo->mouse_face_face_id
7104 = face_at_buffer_position (w, pos, 0, 0,
7105 &ignore, pos + 1, 1);
7106
0d487c52
GM
7107 /* Display it as active. */
7108 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7109 cursor = None;
0d487c52
GM
7110 }
7111 else if (!NILP (mouse_face) && STRINGP (object))
7112 {
7113 Lisp_Object b, e;
7114 int ignore;
f9db2310 7115
0d487c52
GM
7116 b = Fprevious_single_property_change (make_number (pos + 1),
7117 Qmouse_face,
7118 object, Qnil);
7119 e = Fnext_single_property_change (position, Qmouse_face,
7120 object, Qnil);
7121 if (NILP (b))
7122 b = make_number (0);
7123 if (NILP (e))
7124 e = make_number (XSTRING (object)->size - 1);
7125 fast_find_string_pos (w, XINT (b), object,
06a2c219
GM
7126 &dpyinfo->mouse_face_beg_col,
7127 &dpyinfo->mouse_face_beg_row,
7128 &dpyinfo->mouse_face_beg_x,
0d487c52
GM
7129 &dpyinfo->mouse_face_beg_y, 0);
7130 fast_find_string_pos (w, XINT (e), object,
7131 &dpyinfo->mouse_face_end_col,
7132 &dpyinfo->mouse_face_end_row,
7133 &dpyinfo->mouse_face_end_x,
7134 &dpyinfo->mouse_face_end_y, 1);
7135 dpyinfo->mouse_face_past_end = 0;
7136 dpyinfo->mouse_face_window = window;
7137 dpyinfo->mouse_face_face_id
7138 = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
7139 glyph->face_id, 1);
7140 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7141 cursor = None;
0d487c52 7142 }
7e376260
GM
7143 else if (STRINGP (object) && NILP (mouse_face))
7144 {
7145 /* A string which doesn't have mouse-face, but
7146 the text ``under'' it might have. */
7147 struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
7148 int start = MATRIX_ROW_START_CHARPOS (r);
7149
7150 pos = string_buffer_position (w, object, start);
7151 if (pos > 0)
7152 mouse_face = get_char_property_and_overlay (make_number (pos),
7153 Qmouse_face,
7154 w->buffer,
7155 &overlay);
7156 if (!NILP (mouse_face) && !NILP (overlay))
7157 {
7158 Lisp_Object before = Foverlay_start (overlay);
7159 Lisp_Object after = Foverlay_end (overlay);
7160 Lisp_Object ignore;
7161
7162 /* Note that we might not be able to find position
7163 BEFORE in the glyph matrix if the overlay is
7164 entirely covered by a `display' property. In
7165 this case, we overshoot. So let's stop in
7166 the glyph matrix before glyphs for OBJECT. */
7167 fast_find_position (w, XFASTINT (before),
7168 &dpyinfo->mouse_face_beg_col,
7169 &dpyinfo->mouse_face_beg_row,
7170 &dpyinfo->mouse_face_beg_x,
7171 &dpyinfo->mouse_face_beg_y,
7172 object);
7173
7174 dpyinfo->mouse_face_past_end
7175 = !fast_find_position (w, XFASTINT (after),
7176 &dpyinfo->mouse_face_end_col,
7177 &dpyinfo->mouse_face_end_row,
7178 &dpyinfo->mouse_face_end_x,
7179 &dpyinfo->mouse_face_end_y,
7180 Qnil);
7181 dpyinfo->mouse_face_window = window;
7182 dpyinfo->mouse_face_face_id
7183 = face_at_buffer_position (w, pos, 0, 0,
7184 &ignore, pos + 1, 1);
7185
7186 /* Display it as active. */
7187 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
7188 cursor = None;
7189 }
7190 }
0d487c52 7191 }
06a2c219 7192
8bd189fb
GM
7193 check_help_echo:
7194
0d487c52
GM
7195 /* Look for a `help-echo' property. */
7196 {
7197 Lisp_Object help, overlay;
06a2c219 7198
0d487c52
GM
7199 /* Check overlays first. */
7200 help = overlay = Qnil;
7201 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
7202 {
7203 overlay = overlay_vec[i];
7204 help = Foverlay_get (overlay, Qhelp_echo);
7205 }
be010514 7206
0d487c52
GM
7207 if (!NILP (help))
7208 {
7209 help_echo = help;
7210 help_echo_window = window;
7211 help_echo_object = overlay;
7212 help_echo_pos = pos;
7213 }
7214 else
7215 {
7216 Lisp_Object object = glyph->object;
7217 int charpos = glyph->charpos;
7177d86b 7218
0d487c52
GM
7219 /* Try text properties. */
7220 if (STRINGP (object)
7221 && charpos >= 0
7222 && charpos < XSTRING (object)->size)
7223 {
7224 help = Fget_text_property (make_number (charpos),
7225 Qhelp_echo, object);
7226 if (NILP (help))
7227 {
7228 /* If the string itself doesn't specify a help-echo,
7229 see if the buffer text ``under'' it does. */
7230 struct glyph_row *r
7231 = MATRIX_ROW (w->current_matrix, vpos);
7232 int start = MATRIX_ROW_START_CHARPOS (r);
7233 int pos = string_buffer_position (w, object, start);
7234 if (pos > 0)
7235 {
7e376260 7236 help = Fget_char_property (make_number (pos),
0d487c52
GM
7237 Qhelp_echo, w->buffer);
7238 if (!NILP (help))
7239 {
7240 charpos = pos;
7241 object = w->buffer;
7242 }
7243 }
7244 }
7245 }
7246 else if (BUFFERP (object)
7247 && charpos >= BEGV
7248 && charpos < ZV)
7249 help = Fget_text_property (make_number (charpos), Qhelp_echo,
7250 object);
06a2c219 7251
0d487c52
GM
7252 if (!NILP (help))
7253 {
7254 help_echo = help;
7255 help_echo_window = window;
7256 help_echo_object = object;
7257 help_echo_pos = charpos;
7258 }
7259 }
06a2c219 7260 }
0d487c52
GM
7261
7262 BEGV = obegv;
7263 ZV = ozv;
7264 current_buffer = obuf;
06a2c219 7265 }
0d487c52 7266
fa262c07
GM
7267 set_cursor:
7268
0d487c52
GM
7269 if (cursor != None)
7270 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
06a2c219
GM
7271}
7272
7273static void
7274redo_mouse_highlight ()
7275{
7276 if (!NILP (last_mouse_motion_frame)
7277 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
7278 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
7279 last_mouse_motion_event.x,
7280 last_mouse_motion_event.y);
7281}
7282
7283
7284\f
7285/***********************************************************************
9ea173e8 7286 Tool-bars
06a2c219
GM
7287 ***********************************************************************/
7288
9ea173e8
GM
7289static int x_tool_bar_item P_ ((struct frame *, int, int,
7290 struct glyph **, int *, int *, int *));
06a2c219 7291
9ea173e8 7292/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
7293 or -1. */
7294
9ea173e8 7295static int last_tool_bar_item;
06a2c219
GM
7296
7297
9ea173e8
GM
7298/* Get information about the tool-bar item at position X/Y on frame F.
7299 Return in *GLYPH a pointer to the glyph of the tool-bar item in
7300 the current matrix of the tool-bar window of F, or NULL if not
7301 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
8daf1204 7302 item in F->tool_bar_items. Value is
06a2c219 7303
9ea173e8 7304 -1 if X/Y is not on a tool-bar item
06a2c219
GM
7305 0 if X/Y is on the same item that was highlighted before.
7306 1 otherwise. */
7307
7308static int
9ea173e8 7309x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
7310 struct frame *f;
7311 int x, y;
7312 struct glyph **glyph;
7313 int *hpos, *vpos, *prop_idx;
7314{
7315 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7316 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7317 int area;
7318
7319 /* Find the glyph under X/Y. */
f9db2310 7320 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
06a2c219
GM
7321 if (*glyph == NULL)
7322 return -1;
7323
9ea173e8 7324 /* Get the start of this tool-bar item's properties in
8daf1204 7325 f->tool_bar_items. */
9ea173e8 7326 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
7327 return -1;
7328
7329 /* Is mouse on the highlighted item? */
9ea173e8 7330 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
7331 && *vpos >= dpyinfo->mouse_face_beg_row
7332 && *vpos <= dpyinfo->mouse_face_end_row
7333 && (*vpos > dpyinfo->mouse_face_beg_row
7334 || *hpos >= dpyinfo->mouse_face_beg_col)
7335 && (*vpos < dpyinfo->mouse_face_end_row
7336 || *hpos < dpyinfo->mouse_face_end_col
7337 || dpyinfo->mouse_face_past_end))
7338 return 0;
7339
7340 return 1;
7341}
7342
7343
9ea173e8 7344/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
7345 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
7346 or ButtonRelase. */
7347
7348static void
9ea173e8 7349x_handle_tool_bar_click (f, button_event)
06a2c219
GM
7350 struct frame *f;
7351 XButtonEvent *button_event;
7352{
7353 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7354 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7355 int hpos, vpos, prop_idx;
7356 struct glyph *glyph;
7357 Lisp_Object enabled_p;
7358 int x = button_event->x;
7359 int y = button_event->y;
7360
9ea173e8 7361 /* If not on the highlighted tool-bar item, return. */
06a2c219 7362 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 7363 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
7364 return;
7365
7366 /* If item is disabled, do nothing. */
8daf1204 7367 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7368 if (NILP (enabled_p))
7369 return;
7370
7371 if (button_event->type == ButtonPress)
7372 {
7373 /* Show item in pressed state. */
7374 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
7375 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 7376 last_tool_bar_item = prop_idx;
06a2c219
GM
7377 }
7378 else
7379 {
7380 Lisp_Object key, frame;
7381 struct input_event event;
7382
7383 /* Show item in released state. */
7384 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
7385 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
7386
8daf1204 7387 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
06a2c219
GM
7388
7389 XSETFRAME (frame, f);
9ea173e8 7390 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7391 event.frame_or_window = frame;
7392 event.arg = frame;
06a2c219
GM
7393 kbd_buffer_store_event (&event);
7394
9ea173e8 7395 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7396 event.frame_or_window = frame;
7397 event.arg = key;
06a2c219
GM
7398 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7399 button_event->state);
7400 kbd_buffer_store_event (&event);
9ea173e8 7401 last_tool_bar_item = -1;
06a2c219
GM
7402 }
7403}
7404
7405
9ea173e8
GM
7406/* Possibly highlight a tool-bar item on frame F when mouse moves to
7407 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
7408 note_mouse_highlight. */
7409
7410static void
9ea173e8 7411note_tool_bar_highlight (f, x, y)
06a2c219
GM
7412 struct frame *f;
7413 int x, y;
7414{
9ea173e8 7415 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
7416 struct window *w = XWINDOW (window);
7417 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7418 int hpos, vpos;
7419 struct glyph *glyph;
7420 struct glyph_row *row;
5c187dee 7421 int i;
06a2c219
GM
7422 Lisp_Object enabled_p;
7423 int prop_idx;
140330de 7424 enum draw_glyphs_face draw;
5c187dee 7425 int mouse_down_p, rc;
06a2c219
GM
7426
7427 /* Function note_mouse_highlight is called with negative x(y
7428 values when mouse moves outside of the frame. */
7429 if (x <= 0 || y <= 0)
7430 {
7431 clear_mouse_face (dpyinfo);
7432 return;
7433 }
7434
9ea173e8 7435 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
7436 if (rc < 0)
7437 {
9ea173e8 7438 /* Not on tool-bar item. */
06a2c219
GM
7439 clear_mouse_face (dpyinfo);
7440 return;
7441 }
7442 else if (rc == 0)
06a2c219 7443 goto set_help_echo;
b8009dd1 7444
06a2c219
GM
7445 clear_mouse_face (dpyinfo);
7446
9ea173e8 7447 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
7448 mouse_down_p = (dpyinfo->grabbed
7449 && f == last_mouse_frame
7450 && FRAME_LIVE_P (f));
7451 if (mouse_down_p
9ea173e8 7452 && last_tool_bar_item != prop_idx)
06a2c219
GM
7453 return;
7454
7455 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7456 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7457
9ea173e8 7458 /* If tool-bar item is not enabled, don't highlight it. */
8daf1204 7459 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7460 if (!NILP (enabled_p))
7461 {
7462 /* Compute the x-position of the glyph. In front and past the
7463 image is a space. We include this is the highlighted area. */
7464 row = MATRIX_ROW (w->current_matrix, vpos);
7465 for (i = x = 0; i < hpos; ++i)
7466 x += row->glyphs[TEXT_AREA][i].pixel_width;
7467
7468 /* Record this as the current active region. */
7469 dpyinfo->mouse_face_beg_col = hpos;
7470 dpyinfo->mouse_face_beg_row = vpos;
7471 dpyinfo->mouse_face_beg_x = x;
7472 dpyinfo->mouse_face_beg_y = row->y;
7473 dpyinfo->mouse_face_past_end = 0;
7474
7475 dpyinfo->mouse_face_end_col = hpos + 1;
7476 dpyinfo->mouse_face_end_row = vpos;
7477 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7478 dpyinfo->mouse_face_end_y = row->y;
7479 dpyinfo->mouse_face_window = window;
9ea173e8 7480 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
7481
7482 /* Display it as active. */
7483 show_mouse_face (dpyinfo, draw);
7484 dpyinfo->mouse_face_image_state = draw;
b8009dd1 7485 }
06a2c219
GM
7486
7487 set_help_echo:
7488
9ea173e8 7489 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 7490 XTread_socket does the rest. */
7cea38bc 7491 help_echo_object = help_echo_window = Qnil;
be010514 7492 help_echo_pos = -1;
8daf1204 7493 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
b7e80413 7494 if (NILP (help_echo))
8daf1204 7495 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
b8009dd1 7496}
4d73d038 7497
06a2c219
GM
7498
7499\f
9f8531e5
GM
7500/* Find the glyph matrix position of buffer position CHARPOS in window
7501 *W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7502 current glyphs must be up to date. If CHARPOS is above window
7503 start return (0, 0, 0, 0). If CHARPOS is after end of W, return end
7504 of last line in W. In the row containing CHARPOS, stop before glyphs
7e376260 7505 having STOP as object. */
b8009dd1 7506
9f8531e5
GM
7507#if 0 /* This is a version of fast_find_position that's more correct
7508 in the presence of hscrolling, for example. I didn't install
7509 it right away because the problem fixed is minor, it failed
7510 in 20.x as well, and I think it's too risky to install
7511 so near the release of 21.1. 2001-09-25 gerd. */
7512
7513static int
7514fast_find_position (w, charpos, hpos, vpos, x, y, stop)
7515 struct window *w;
7516 int charpos;
7517 int *hpos, *vpos, *x, *y;
7518 Lisp_Object stop;
7519{
7520 struct glyph_row *row, *first;
7521 struct glyph *glyph, *end;
7522 int i, past_end = 0;
7523
7524 first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7525 row = row_containing_pos (w, charpos, first, NULL);
7526 if (row == NULL)
7527 {
7528 if (charpos < MATRIX_ROW_START_CHARPOS (first))
7529 {
7530 *x = *y = *hpos = *vpos = 0;
7531 return 0;
7532 }
7533 else
7534 {
7535 row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
7536 past_end = 1;
7537 }
7538 }
7539
7540 *x = row->x;
7541 *y = row->y;
7542 *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7543
7544 glyph = row->glyphs[TEXT_AREA];
7545 end = glyph + row->used[TEXT_AREA];
7546
7547 /* Skip over glyphs not having an object at the start of the row.
7548 These are special glyphs like truncation marks on terminal
7549 frames. */
7550 if (row->displays_text_p)
7551 while (glyph < end
7552 && INTEGERP (glyph->object)
7553 && !EQ (stop, glyph->object)
7554 && glyph->charpos < 0)
7555 {
7556 *x += glyph->pixel_width;
7557 ++glyph;
7558 }
7559
7560 while (glyph < end
7561 && !INTEGERP (glyph->object)
7562 && !EQ (stop, glyph->object)
7563 && (!BUFFERP (glyph->object)
7564 || glyph->charpos < charpos))
7565 {
7566 *x += glyph->pixel_width;
7567 ++glyph;
7568 }
7569
7570 *hpos = glyph - row->glyphs[TEXT_AREA];
7571 return past_end;
7572}
7573
7574#else /* not 0 */
7575
b8009dd1 7576static int
7e376260 7577fast_find_position (w, pos, hpos, vpos, x, y, stop)
06a2c219 7578 struct window *w;
b8009dd1 7579 int pos;
06a2c219 7580 int *hpos, *vpos, *x, *y;
7e376260 7581 Lisp_Object stop;
b8009dd1 7582{
b8009dd1 7583 int i;
bf1c0ba1 7584 int lastcol;
06a2c219
GM
7585 int maybe_next_line_p = 0;
7586 int line_start_position;
7587 int yb = window_text_bottom_y (w);
03d1a189
GM
7588 struct glyph_row *row, *best_row;
7589 int row_vpos, best_row_vpos;
06a2c219
GM
7590 int current_x;
7591
03d1a189
GM
7592 row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7593 row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7594
06a2c219 7595 while (row->y < yb)
b8009dd1 7596 {
06a2c219
GM
7597 if (row->used[TEXT_AREA])
7598 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7599 else
7600 line_start_position = 0;
7601
7602 if (line_start_position > pos)
b8009dd1 7603 break;
77b68646
RS
7604 /* If the position sought is the end of the buffer,
7605 don't include the blank lines at the bottom of the window. */
06a2c219
GM
7606 else if (line_start_position == pos
7607 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 7608 {
06a2c219 7609 maybe_next_line_p = 1;
77b68646
RS
7610 break;
7611 }
06a2c219
GM
7612 else if (line_start_position > 0)
7613 {
7614 best_row = row;
7615 best_row_vpos = row_vpos;
7616 }
4b0bb6f3
GM
7617
7618 if (row->y + row->height >= yb)
7619 break;
06a2c219
GM
7620
7621 ++row;
7622 ++row_vpos;
b8009dd1 7623 }
06a2c219
GM
7624
7625 /* Find the right column within BEST_ROW. */
7626 lastcol = 0;
7627 current_x = best_row->x;
7628 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 7629 {
06a2c219 7630 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7e376260 7631 int charpos = glyph->charpos;
06a2c219 7632
7e376260 7633 if (BUFFERP (glyph->object))
bf1c0ba1 7634 {
7e376260
GM
7635 if (charpos == pos)
7636 {
7637 *hpos = i;
7638 *vpos = best_row_vpos;
7639 *x = current_x;
7640 *y = best_row->y;
7641 return 1;
7642 }
7643 else if (charpos > pos)
7644 break;
bf1c0ba1 7645 }
7e376260 7646 else if (EQ (glyph->object, stop))
4d73d038 7647 break;
06a2c219 7648
7e376260
GM
7649 if (charpos > 0)
7650 lastcol = i;
06a2c219 7651 current_x += glyph->pixel_width;
bf1c0ba1 7652 }
b8009dd1 7653
77b68646
RS
7654 /* If we're looking for the end of the buffer,
7655 and we didn't find it in the line we scanned,
7656 use the start of the following line. */
06a2c219 7657 if (maybe_next_line_p)
77b68646 7658 {
06a2c219
GM
7659 ++best_row;
7660 ++best_row_vpos;
7661 lastcol = 0;
7662 current_x = best_row->x;
77b68646
RS
7663 }
7664
06a2c219
GM
7665 *vpos = best_row_vpos;
7666 *hpos = lastcol + 1;
7667 *x = current_x;
7668 *y = best_row->y;
b8009dd1
RS
7669 return 0;
7670}
7671
9f8531e5
GM
7672#endif /* not 0 */
7673
06a2c219 7674
f9db2310
GM
7675/* Find the position of the the glyph for position POS in OBJECT in
7676 window W's current matrix, and return in *X/*Y the pixel
7677 coordinates, and return in *HPOS/*VPOS the column/row of the glyph.
7678
7679 RIGHT_P non-zero means return the position of the right edge of the
7680 glyph, RIGHT_P zero means return the left edge position.
7681
7682 If no glyph for POS exists in the matrix, return the position of
7683 the glyph with the next smaller position that is in the matrix, if
7684 RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS
7685 exists in the matrix, return the position of the glyph with the
7686 next larger position in OBJECT.
7687
7688 Value is non-zero if a glyph was found. */
7689
7690static int
7691fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
7692 struct window *w;
7693 int pos;
7694 Lisp_Object object;
7695 int *hpos, *vpos, *x, *y;
7696 int right_p;
7697{
7698 int yb = window_text_bottom_y (w);
7699 struct glyph_row *r;
7700 struct glyph *best_glyph = NULL;
7701 struct glyph_row *best_row = NULL;
7702 int best_x = 0;
7703
7704 for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7705 r->enabled_p && r->y < yb;
7706 ++r)
7707 {
7708 struct glyph *g = r->glyphs[TEXT_AREA];
7709 struct glyph *e = g + r->used[TEXT_AREA];
7710 int gx;
7711
7712 for (gx = r->x; g < e; gx += g->pixel_width, ++g)
7713 if (EQ (g->object, object))
7714 {
7715 if (g->charpos == pos)
7716 {
7717 best_glyph = g;
7718 best_x = gx;
7719 best_row = r;
7720 goto found;
7721 }
7722 else if (best_glyph == NULL
7723 || ((abs (g->charpos - pos)
7724 < abs (best_glyph->charpos - pos))
7725 && (right_p
7726 ? g->charpos < pos
7727 : g->charpos > pos)))
7728 {
7729 best_glyph = g;
7730 best_x = gx;
7731 best_row = r;
7732 }
7733 }
7734 }
7735
7736 found:
7737
7738 if (best_glyph)
7739 {
7740 *x = best_x;
7741 *hpos = best_glyph - best_row->glyphs[TEXT_AREA];
7742
7743 if (right_p)
7744 {
7745 *x += best_glyph->pixel_width;
7746 ++*hpos;
7747 }
7748
7749 *y = best_row->y;
7750 *vpos = best_row - w->current_matrix->rows;
7751 }
7752
7753 return best_glyph != NULL;
7754}
7755
7756
b8009dd1
RS
7757/* Display the active region described by mouse_face_*
7758 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7759
7760static void
06a2c219 7761show_mouse_face (dpyinfo, draw)
7a13e894 7762 struct x_display_info *dpyinfo;
06a2c219 7763 enum draw_glyphs_face draw;
b8009dd1 7764{
7a13e894 7765 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7766 struct frame *f = XFRAME (WINDOW_FRAME (w));
b8009dd1 7767 int i;
06a2c219
GM
7768 int cursor_off_p = 0;
7769 struct cursor_pos saved_cursor;
7770
7771 saved_cursor = output_cursor;
7772
7773 /* If window is in the process of being destroyed, don't bother
7774 to do anything. */
7775 if (w->current_matrix == NULL)
7776 goto set_x_cursor;
7777
7778 /* Recognize when we are called to operate on rows that don't exist
7779 anymore. This can happen when a window is split. */
7780 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
7781 goto set_x_cursor;
7782
7783 set_output_cursor (&w->phys_cursor);
7784
7785 /* Note that mouse_face_beg_row etc. are window relative. */
7786 for (i = dpyinfo->mouse_face_beg_row;
7787 i <= dpyinfo->mouse_face_end_row;
7788 i++)
7789 {
7790 int start_hpos, end_hpos, start_x;
7791 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
7792
7793 /* Don't do anything if row doesn't have valid contents. */
7794 if (!row->enabled_p)
7795 continue;
7796
7797 /* For all but the first row, the highlight starts at column 0. */
7798 if (i == dpyinfo->mouse_face_beg_row)
7799 {
7800 start_hpos = dpyinfo->mouse_face_beg_col;
7801 start_x = dpyinfo->mouse_face_beg_x;
7802 }
7803 else
7804 {
7805 start_hpos = 0;
7806 start_x = 0;
7807 }
7808
7809 if (i == dpyinfo->mouse_face_end_row)
7810 end_hpos = dpyinfo->mouse_face_end_col;
7811 else
7812 end_hpos = row->used[TEXT_AREA];
7813
7814 /* If the cursor's in the text we are about to rewrite, turn the
7815 cursor off. */
7816 if (!w->pseudo_window_p
7817 && i == output_cursor.vpos
7818 && output_cursor.hpos >= start_hpos - 1
7819 && output_cursor.hpos <= end_hpos)
514e4681 7820 {
06a2c219
GM
7821 x_update_window_cursor (w, 0);
7822 cursor_off_p = 1;
514e4681 7823 }
b8009dd1 7824
06a2c219 7825 if (end_hpos > start_hpos)
64f26cf5 7826 {
64f26cf5
GM
7827 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7828 start_hpos, end_hpos, draw, NULL, NULL, 0);
7b0870b2 7829 row->mouse_face_p = draw == DRAW_MOUSE_FACE || DRAW_IMAGE_RAISED;
64f26cf5 7830 }
b8009dd1
RS
7831 }
7832
514e4681 7833 /* If we turned the cursor off, turn it back on. */
06a2c219
GM
7834 if (cursor_off_p)
7835 x_display_cursor (w, 1,
7836 output_cursor.hpos, output_cursor.vpos,
7837 output_cursor.x, output_cursor.y);
2729a2b5 7838
06a2c219 7839 output_cursor = saved_cursor;
fb3b7de5 7840
06a2c219
GM
7841 set_x_cursor:
7842
7843 /* Change the mouse cursor. */
7844 if (draw == DRAW_NORMAL_TEXT)
7845 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7846 f->output_data.x->text_cursor);
7847 else if (draw == DRAW_MOUSE_FACE)
334208b7 7848 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7849 f->output_data.x->cross_cursor);
27ead1d5 7850 else
334208b7 7851 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7852 f->output_data.x->nontext_cursor);
b8009dd1
RS
7853}
7854
7855/* Clear out the mouse-highlighted active region.
fa262c07
GM
7856 Redraw it un-highlighted first. Value is non-zero if mouse
7857 face was actually drawn unhighlighted. */
b8009dd1 7858
fa262c07 7859static int
7a13e894
RS
7860clear_mouse_face (dpyinfo)
7861 struct x_display_info *dpyinfo;
b8009dd1 7862{
fa262c07 7863 int cleared = 0;
06a2c219 7864
fa262c07
GM
7865 if (!NILP (dpyinfo->mouse_face_window))
7866 {
7867 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
7868 cleared = 1;
7869 }
b8009dd1 7870
7a13e894
RS
7871 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7872 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7873 dpyinfo->mouse_face_window = Qnil;
1b85dc1c 7874 dpyinfo->mouse_face_overlay = Qnil;
fa262c07 7875 return cleared;
b8009dd1 7876}
e687d06e 7877
71b8321e
GM
7878
7879/* Clear any mouse-face on window W. This function is part of the
7880 redisplay interface, and is called from try_window_id and similar
7881 functions to ensure the mouse-highlight is off. */
7882
7883static void
7884x_clear_mouse_face (w)
7885 struct window *w;
7886{
7887 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7888 Lisp_Object window;
7889
2e636f9d 7890 BLOCK_INPUT;
71b8321e
GM
7891 XSETWINDOW (window, w);
7892 if (EQ (window, dpyinfo->mouse_face_window))
7893 clear_mouse_face (dpyinfo);
2e636f9d 7894 UNBLOCK_INPUT;
71b8321e
GM
7895}
7896
7897
e687d06e
RS
7898/* Just discard the mouse face information for frame F, if any.
7899 This is used when the size of F is changed. */
7900
dfcf069d 7901void
e687d06e
RS
7902cancel_mouse_face (f)
7903 FRAME_PTR f;
7904{
7905 Lisp_Object window;
7906 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7907
7908 window = dpyinfo->mouse_face_window;
7909 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7910 {
7911 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7912 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7913 dpyinfo->mouse_face_window = Qnil;
7914 }
7915}
b52b65bd 7916
b8009dd1 7917\f
b52b65bd
GM
7918static int glyph_rect P_ ((struct frame *f, int, int, XRectangle *));
7919
7920
7921/* Try to determine frame pixel position and size of the glyph under
7922 frame pixel coordinates X/Y on frame F . Return the position and
7923 size in *RECT. Value is non-zero if we could compute these
7924 values. */
7925
7926static int
7927glyph_rect (f, x, y, rect)
7928 struct frame *f;
7929 int x, y;
7930 XRectangle *rect;
7931{
7932 Lisp_Object window;
7933 int part, found = 0;
7934
7935 window = window_from_coordinates (f, x, y, &part, 0);
7936 if (!NILP (window))
7937 {
7938 struct window *w = XWINDOW (window);
7939 struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7940 struct glyph_row *end = r + w->current_matrix->nrows - 1;
7941 int area;
7942
7943 frame_to_window_pixel_xy (w, &x, &y);
7944
7945 for (; !found && r < end && r->enabled_p; ++r)
7946 if (r->y >= y)
7947 {
7948 struct glyph *g = r->glyphs[TEXT_AREA];
7949 struct glyph *end = g + r->used[TEXT_AREA];
7950 int gx;
7951
7952 for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
7953 if (gx >= x)
7954 {
7955 rect->width = g->pixel_width;
7956 rect->height = r->height;
7957 rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
7958 rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
7959 found = 1;
7960 }
7961 }
7962 }
7963
7964 return found;
7965}
7966
12ba150f 7967
90e65f07 7968/* Return the current position of the mouse.
b52b65bd 7969 *FP should be a frame which indicates which display to ask about.
90e65f07 7970
b52b65bd
GM
7971 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
7972 and *PART to the frame, window, and scroll bar part that the mouse
7973 is over. Set *X and *Y to the portion and whole of the mouse's
ab648270 7974 position on the scroll bar.
12ba150f 7975
b52b65bd
GM
7976 If the mouse movement started elsewhere, set *FP to the frame the
7977 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
12ba150f
JB
7978 the mouse is over.
7979
b52b65bd 7980 Set *TIME to the server time-stamp for the time at which the mouse
12ba150f
JB
7981 was at this position.
7982
a135645a
RS
7983 Don't store anything if we don't have a valid set of values to report.
7984
90e65f07 7985 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7986 movement. */
90e65f07
JB
7987
7988static void
1cf412ec 7989XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7990 FRAME_PTR *fp;
1cf412ec 7991 int insist;
12ba150f 7992 Lisp_Object *bar_window;
ab648270 7993 enum scroll_bar_part *part;
90e65f07 7994 Lisp_Object *x, *y;
e5d77022 7995 unsigned long *time;
90e65f07 7996{
a135645a
RS
7997 FRAME_PTR f1;
7998
90e65f07
JB
7999 BLOCK_INPUT;
8000
8bcee03e 8001 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 8002 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
8003 else
8004 {
12ba150f
JB
8005 Window root;
8006 int root_x, root_y;
90e65f07 8007
12ba150f
JB
8008 Window dummy_window;
8009 int dummy;
8010
39d8bb4d
KH
8011 Lisp_Object frame, tail;
8012
8013 /* Clear the mouse-moved flag for every frame on this display. */
8014 FOR_EACH_FRAME (tail, frame)
8015 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
8016 XFRAME (frame)->mouse_moved = 0;
8017
ab648270 8018 last_mouse_scroll_bar = Qnil;
12ba150f
JB
8019
8020 /* Figure out which root window we're on. */
334208b7
RS
8021 XQueryPointer (FRAME_X_DISPLAY (*fp),
8022 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
8023
8024 /* The root window which contains the pointer. */
8025 &root,
8026
8027 /* Trash which we can't trust if the pointer is on
8028 a different screen. */
8029 &dummy_window,
8030
8031 /* The position on that root window. */
58769bee 8032 &root_x, &root_y,
12ba150f
JB
8033
8034 /* More trash we can't trust. */
8035 &dummy, &dummy,
8036
8037 /* Modifier keys and pointer buttons, about which
8038 we don't care. */
8039 (unsigned int *) &dummy);
8040
8041 /* Now we have a position on the root; find the innermost window
8042 containing the pointer. */
8043 {
8044 Window win, child;
8045 int win_x, win_y;
06a2c219 8046 int parent_x = 0, parent_y = 0;
e99db5a1 8047 int count;
12ba150f
JB
8048
8049 win = root;
69388238 8050
2d7fc7e8
RS
8051 /* XTranslateCoordinates can get errors if the window
8052 structure is changing at the same time this function
8053 is running. So at least we must not crash from them. */
8054
e99db5a1 8055 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 8056
334208b7 8057 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 8058 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 8059 {
69388238
RS
8060 /* If mouse was grabbed on a frame, give coords for that frame
8061 even if the mouse is now outside it. */
334208b7 8062 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 8063
12ba150f 8064 /* From-window, to-window. */
69388238 8065 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
8066
8067 /* From-position, to-position. */
8068 root_x, root_y, &win_x, &win_y,
8069
8070 /* Child of win. */
8071 &child);
69388238
RS
8072 f1 = last_mouse_frame;
8073 }
8074 else
8075 {
8076 while (1)
8077 {
334208b7 8078 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 8079
69388238
RS
8080 /* From-window, to-window. */
8081 root, win,
12ba150f 8082
69388238
RS
8083 /* From-position, to-position. */
8084 root_x, root_y, &win_x, &win_y,
8085
8086 /* Child of win. */
8087 &child);
8088
9af3143a 8089 if (child == None || child == win)
69388238
RS
8090 break;
8091
8092 win = child;
8093 parent_x = win_x;
8094 parent_y = win_y;
8095 }
12ba150f 8096
69388238
RS
8097 /* Now we know that:
8098 win is the innermost window containing the pointer
8099 (XTC says it has no child containing the pointer),
8100 win_x and win_y are the pointer's position in it
8101 (XTC did this the last time through), and
8102 parent_x and parent_y are the pointer's position in win's parent.
8103 (They are what win_x and win_y were when win was child.
8104 If win is the root window, it has no parent, and
8105 parent_{x,y} are invalid, but that's okay, because we'll
8106 never use them in that case.) */
8107
8108 /* Is win one of our frames? */
19126e11 8109 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
aad0f6ab
GM
8110
8111#ifdef USE_X_TOOLKIT
8112 /* If we end up with the menu bar window, say it's not
8113 on the frame. */
8114 if (f1 != NULL
8115 && f1->output_data.x->menubar_widget
8116 && win == XtWindow (f1->output_data.x->menubar_widget))
8117 f1 = NULL;
8118#endif /* USE_X_TOOLKIT */
69388238 8119 }
58769bee 8120
2d7fc7e8
RS
8121 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
8122 f1 = 0;
8123
e99db5a1 8124 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 8125
ab648270 8126 /* If not, is it one of our scroll bars? */
a135645a 8127 if (! f1)
12ba150f 8128 {
ab648270 8129 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
8130
8131 if (bar)
8132 {
a135645a 8133 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
8134 win_x = parent_x;
8135 win_y = parent_y;
8136 }
8137 }
90e65f07 8138
8bcee03e 8139 if (f1 == 0 && insist > 0)
b86bd3dd 8140 f1 = SELECTED_FRAME ();
1cf412ec 8141
a135645a 8142 if (f1)
12ba150f 8143 {
06a2c219
GM
8144 /* Ok, we found a frame. Store all the values.
8145 last_mouse_glyph is a rectangle used to reduce the
8146 generation of mouse events. To not miss any motion
8147 events, we must divide the frame into rectangles of the
8148 size of the smallest character that could be displayed
8149 on it, i.e. into the same rectangles that matrices on
8150 the frame are divided into. */
8151
b52b65bd
GM
8152 int width, height, gx, gy;
8153 XRectangle rect;
8154
8155 if (glyph_rect (f1, win_x, win_y, &rect))
8156 last_mouse_glyph = rect;
8157 else
8158 {
8159 width = FRAME_SMALLEST_CHAR_WIDTH (f1);
8160 height = FRAME_SMALLEST_FONT_HEIGHT (f1);
8161 gx = win_x;
8162 gy = win_y;
06a2c219 8163
b52b65bd
GM
8164 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
8165 round down even for negative values. */
8166 if (gx < 0)
8167 gx -= width - 1;
4f00e84d 8168 if (gy < 0)
b52b65bd
GM
8169 gy -= height - 1;
8170 gx = (gx + width - 1) / width * width;
8171 gy = (gy + height - 1) / height * height;
8172
8173 last_mouse_glyph.width = width;
8174 last_mouse_glyph.height = height;
8175 last_mouse_glyph.x = gx;
8176 last_mouse_glyph.y = gy;
8177 }
12ba150f
JB
8178
8179 *bar_window = Qnil;
8180 *part = 0;
334208b7 8181 *fp = f1;
e0c1aef2
KH
8182 XSETINT (*x, win_x);
8183 XSETINT (*y, win_y);
12ba150f
JB
8184 *time = last_mouse_movement_time;
8185 }
8186 }
8187 }
90e65f07
JB
8188
8189 UNBLOCK_INPUT;
8190}
f451eb13 8191
06a2c219 8192
06a2c219 8193#ifdef USE_X_TOOLKIT
bffcfca9
GM
8194
8195/* Atimer callback function for TIMER. Called every 0.1s to process
8196 Xt timeouts, if needed. We must avoid calling XtAppPending as
8197 much as possible because that function does an implicit XFlush
8198 that slows us down. */
8199
8200static void
8201x_process_timeouts (timer)
8202 struct atimer *timer;
8203{
8204 if (toolkit_scroll_bar_interaction || popup_activated_flag)
8205 {
8206 BLOCK_INPUT;
8207 while (XtAppPending (Xt_app_con) & XtIMTimer)
8208 XtAppProcessEvent (Xt_app_con, XtIMTimer);
8209 UNBLOCK_INPUT;
8210 }
06a2c219
GM
8211}
8212
bffcfca9 8213#endif /* USE_X_TOOLKIT */
06a2c219
GM
8214
8215\f
8216/* Scroll bar support. */
8217
8218/* Given an X window ID, find the struct scroll_bar which manages it.
8219 This can be called in GC, so we have to make sure to strip off mark
8220 bits. */
bffcfca9 8221
06a2c219
GM
8222static struct scroll_bar *
8223x_window_to_scroll_bar (window_id)
8224 Window window_id;
8225{
8226 Lisp_Object tail;
8227
8228 for (tail = Vframe_list;
8229 XGCTYPE (tail) == Lisp_Cons;
8e713be6 8230 tail = XCDR (tail))
06a2c219
GM
8231 {
8232 Lisp_Object frame, bar, condemned;
8233
8e713be6 8234 frame = XCAR (tail);
06a2c219
GM
8235 /* All elements of Vframe_list should be frames. */
8236 if (! GC_FRAMEP (frame))
8237 abort ();
8238
8239 /* Scan this frame's scroll bar list for a scroll bar with the
8240 right window ID. */
8241 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
8242 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
8243 /* This trick allows us to search both the ordinary and
8244 condemned scroll bar lists with one loop. */
8245 ! GC_NILP (bar) || (bar = condemned,
8246 condemned = Qnil,
8247 ! GC_NILP (bar));
8248 bar = XSCROLL_BAR (bar)->next)
8249 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
8250 return XSCROLL_BAR (bar);
8251 }
8252
8253 return 0;
8254}
8255
8256
01f67d2c 8257#if defined USE_LUCID
c95fc5f1
GM
8258
8259/* Return the Lucid menu bar WINDOW is part of. Return null
8260 if WINDOW is not part of a menu bar. */
8261
8262static Widget
8263x_window_to_menu_bar (window)
8264 Window window;
8265{
8266 Lisp_Object tail;
8267
8268 for (tail = Vframe_list;
8269 XGCTYPE (tail) == Lisp_Cons;
8270 tail = XCDR (tail))
8271 {
8272 Lisp_Object frame = XCAR (tail);
8273 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
8274
8275 if (menu_bar && xlwmenu_window_p (menu_bar, window))
8276 return menu_bar;
8277 }
8278
8279 return NULL;
8280}
8281
01f67d2c 8282#endif /* USE_LUCID */
c95fc5f1 8283
06a2c219
GM
8284\f
8285/************************************************************************
8286 Toolkit scroll bars
8287 ************************************************************************/
8288
eccc05db 8289#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8290
8291static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
8292static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
8293static void x_create_toolkit_scroll_bar P_ ((struct frame *,
8294 struct scroll_bar *));
8295static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
8296 int, int, int));
8297
8298
8299/* Id of action hook installed for scroll bars. */
8300
8301static XtActionHookId action_hook_id;
8302
8303/* Lisp window being scrolled. Set when starting to interact with
8304 a toolkit scroll bar, reset to nil when ending the interaction. */
8305
8306static Lisp_Object window_being_scrolled;
8307
8308/* Last scroll bar part sent in xm_scroll_callback. */
8309
8310static int last_scroll_bar_part;
8311
ec18280f
SM
8312/* Whether this is an Xaw with arrow-scrollbars. This should imply
8313 that movements of 1/20 of the screen size are mapped to up/down. */
8314
8315static Boolean xaw3d_arrow_scroll;
8316
8317/* Whether the drag scrolling maintains the mouse at the top of the
8318 thumb. If not, resizing the thumb needs to be done more carefully
8319 to avoid jerkyness. */
8320
8321static Boolean xaw3d_pick_top;
8322
06a2c219
GM
8323
8324/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 8325 bars are used.. The hook is responsible for detecting when
06a2c219
GM
8326 the user ends an interaction with the scroll bar, and generates
8327 a `end-scroll' scroll_bar_click' event if so. */
8328
8329static void
8330xt_action_hook (widget, client_data, action_name, event, params,
8331 num_params)
8332 Widget widget;
8333 XtPointer client_data;
8334 String action_name;
8335 XEvent *event;
8336 String *params;
8337 Cardinal *num_params;
8338{
8339 int scroll_bar_p;
8340 char *end_action;
8341
8342#ifdef USE_MOTIF
8343 scroll_bar_p = XmIsScrollBar (widget);
8344 end_action = "Release";
ec18280f 8345#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8346 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
8347 end_action = "EndScroll";
ec18280f 8348#endif /* USE_MOTIF */
06a2c219 8349
06a2c219
GM
8350 if (scroll_bar_p
8351 && strcmp (action_name, end_action) == 0
8352 && WINDOWP (window_being_scrolled))
8353 {
8354 struct window *w;
8355
8356 x_send_scroll_bar_event (window_being_scrolled,
8357 scroll_bar_end_scroll, 0, 0);
8358 w = XWINDOW (window_being_scrolled);
8359 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
8360 window_being_scrolled = Qnil;
8361 last_scroll_bar_part = -1;
bffcfca9
GM
8362
8363 /* Xt timeouts no longer needed. */
8364 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
8365 }
8366}
8367
07b3d16e
GM
8368/* A vector of windows used for communication between
8369 x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
8370
8371static struct window **scroll_bar_windows;
8372static int scroll_bar_windows_size;
8373
06a2c219
GM
8374
8375/* Send a client message with message type Xatom_Scrollbar for a
8376 scroll action to the frame of WINDOW. PART is a value identifying
8377 the part of the scroll bar that was clicked on. PORTION is the
8378 amount to scroll of a whole of WHOLE. */
8379
8380static void
8381x_send_scroll_bar_event (window, part, portion, whole)
8382 Lisp_Object window;
8383 int part, portion, whole;
8384{
8385 XEvent event;
8386 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
07b3d16e
GM
8387 struct window *w = XWINDOW (window);
8388 struct frame *f = XFRAME (w->frame);
8389 int i;
06a2c219 8390
07b3d16e
GM
8391 BLOCK_INPUT;
8392
06a2c219
GM
8393 /* Construct a ClientMessage event to send to the frame. */
8394 ev->type = ClientMessage;
8395 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
8396 ev->display = FRAME_X_DISPLAY (f);
8397 ev->window = FRAME_X_WINDOW (f);
8398 ev->format = 32;
07b3d16e
GM
8399
8400 /* We can only transfer 32 bits in the XClientMessageEvent, which is
8401 not enough to store a pointer or Lisp_Object on a 64 bit system.
8402 So, store the window in scroll_bar_windows and pass the index
8403 into that array in the event. */
8404 for (i = 0; i < scroll_bar_windows_size; ++i)
8405 if (scroll_bar_windows[i] == NULL)
8406 break;
8407
8408 if (i == scroll_bar_windows_size)
8409 {
8410 int new_size = max (10, 2 * scroll_bar_windows_size);
8411 size_t nbytes = new_size * sizeof *scroll_bar_windows;
8412 size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows;
8413
8414 scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
8415 nbytes);
8416 bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
8417 scroll_bar_windows_size = new_size;
8418 }
8419
8420 scroll_bar_windows[i] = w;
8421 ev->data.l[0] = (long) i;
06a2c219
GM
8422 ev->data.l[1] = (long) part;
8423 ev->data.l[2] = (long) 0;
8424 ev->data.l[3] = (long) portion;
8425 ev->data.l[4] = (long) whole;
8426
bffcfca9
GM
8427 /* Make Xt timeouts work while the scroll bar is active. */
8428 toolkit_scroll_bar_interaction = 1;
8429
06a2c219
GM
8430 /* Setting the event mask to zero means that the message will
8431 be sent to the client that created the window, and if that
8432 window no longer exists, no event will be sent. */
06a2c219
GM
8433 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
8434 UNBLOCK_INPUT;
8435}
8436
8437
8438/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
8439 in *IEVENT. */
8440
8441static void
8442x_scroll_bar_to_input_event (event, ievent)
8443 XEvent *event;
8444 struct input_event *ievent;
8445{
8446 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
8447 Lisp_Object window;
8448 struct frame *f;
07b3d16e
GM
8449 struct window *w;
8450
8451 w = scroll_bar_windows[ev->data.l[0]];
8452 scroll_bar_windows[ev->data.l[0]] = NULL;
52e386c2 8453
07b3d16e
GM
8454 XSETWINDOW (window, w);
8455 f = XFRAME (w->frame);
06a2c219
GM
8456
8457 ievent->kind = scroll_bar_click;
8458 ievent->frame_or_window = window;
0f8aabe9 8459 ievent->arg = Qnil;
06a2c219
GM
8460 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
8461 ievent->part = ev->data.l[1];
8462 ievent->code = ev->data.l[2];
8463 ievent->x = make_number ((int) ev->data.l[3]);
8464 ievent->y = make_number ((int) ev->data.l[4]);
8465 ievent->modifiers = 0;
8466}
8467
8468
8469#ifdef USE_MOTIF
8470
8471/* Minimum and maximum values used for Motif scroll bars. */
8472
8473#define XM_SB_MIN 1
8474#define XM_SB_MAX 10000000
8475#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
8476
8477
8478/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
8479 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
8480 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
8481
8482static void
8483xm_scroll_callback (widget, client_data, call_data)
8484 Widget widget;
8485 XtPointer client_data, call_data;
8486{
8487 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8488 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
06a2c219
GM
8489 int part = -1, whole = 0, portion = 0;
8490
8491 switch (cs->reason)
8492 {
8493 case XmCR_DECREMENT:
8494 bar->dragging = Qnil;
8495 part = scroll_bar_up_arrow;
8496 break;
8497
8498 case XmCR_INCREMENT:
8499 bar->dragging = Qnil;
8500 part = scroll_bar_down_arrow;
8501 break;
8502
8503 case XmCR_PAGE_DECREMENT:
8504 bar->dragging = Qnil;
8505 part = scroll_bar_above_handle;
8506 break;
8507
8508 case XmCR_PAGE_INCREMENT:
8509 bar->dragging = Qnil;
8510 part = scroll_bar_below_handle;
8511 break;
8512
8513 case XmCR_TO_TOP:
8514 bar->dragging = Qnil;
8515 part = scroll_bar_to_top;
8516 break;
8517
8518 case XmCR_TO_BOTTOM:
8519 bar->dragging = Qnil;
8520 part = scroll_bar_to_bottom;
8521 break;
8522
8523 case XmCR_DRAG:
8524 {
8525 int slider_size;
8526 int dragging_down_p = (INTEGERP (bar->dragging)
8527 && XINT (bar->dragging) <= cs->value);
8528
8529 /* Get the slider size. */
8530 BLOCK_INPUT;
8531 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
8532 UNBLOCK_INPUT;
8533
8534 /* At the max position of the scroll bar, do a line-wise
23442ae4
GM
8535 movement. Without doing anything, we would be called with
8536 the same cs->value again and again. If we want to make
8537 sure that we can reach the end of the buffer, we have to do
8538 something.
06a2c219
GM
8539
8540 Implementation note: setting bar->dragging always to
8541 cs->value gives a smoother movement at the max position.
8542 Setting it to nil when doing line-wise movement gives
8543 a better slider behavior. */
8544
8545 if (cs->value + slider_size == XM_SB_MAX
8546 || (dragging_down_p
8547 && last_scroll_bar_part == scroll_bar_down_arrow))
8548 {
8549 part = scroll_bar_down_arrow;
8550 bar->dragging = Qnil;
8551 }
8552 else
8553 {
8554 whole = XM_SB_RANGE;
8555 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
8556 part = scroll_bar_handle;
8557 bar->dragging = make_number (cs->value);
8558 }
8559 }
8560 break;
8561
8562 case XmCR_VALUE_CHANGED:
8563 break;
8564 };
8565
8566 if (part >= 0)
8567 {
8568 window_being_scrolled = bar->window;
8569 last_scroll_bar_part = part;
8570 x_send_scroll_bar_event (bar->window, part, portion, whole);
8571 }
8572}
8573
8574
ec18280f 8575#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
8576
8577
ec18280f 8578/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
8579 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
8580 scroll bar struct. CALL_DATA is a pointer to a float saying where
8581 the thumb is. */
8582
8583static void
ec18280f 8584xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
8585 Widget widget;
8586 XtPointer client_data, call_data;
8587{
8588 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8589 float top = *(float *) call_data;
8590 float shown;
ec18280f
SM
8591 int whole, portion, height;
8592 int part;
06a2c219
GM
8593
8594 /* Get the size of the thumb, a value between 0 and 1. */
8595 BLOCK_INPUT;
ec18280f 8596 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
8597 UNBLOCK_INPUT;
8598
8599 whole = 10000000;
8600 portion = shown < 1 ? top * whole : 0;
06a2c219 8601
ec18280f
SM
8602 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
8603 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
8604 the bottom, so we force the scrolling whenever we see that we're
8605 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
8606 we try to ensure that we always stay two pixels away from the
8607 bottom). */
06a2c219
GM
8608 part = scroll_bar_down_arrow;
8609 else
8610 part = scroll_bar_handle;
8611
8612 window_being_scrolled = bar->window;
8613 bar->dragging = make_number (portion);
8614 last_scroll_bar_part = part;
8615 x_send_scroll_bar_event (bar->window, part, portion, whole);
8616}
8617
8618
ec18280f
SM
8619/* Xaw scroll bar callback. Invoked for incremental scrolling.,
8620 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
8621 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
8622 the scroll bar. CALL_DATA is an integer specifying the action that
8623 has taken place. It's magnitude is in the range 0..height of the
8624 scroll bar. Negative values mean scroll towards buffer start.
8625 Values < height of scroll bar mean line-wise movement. */
8626
8627static void
ec18280f 8628xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
8629 Widget widget;
8630 XtPointer client_data, call_data;
8631{
8632 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8633 int position = (int) call_data;
8634 Dimension height;
8635 int part;
8636
8637 /* Get the height of the scroll bar. */
8638 BLOCK_INPUT;
8639 XtVaGetValues (widget, XtNheight, &height, NULL);
8640 UNBLOCK_INPUT;
8641
ec18280f
SM
8642 if (abs (position) >= height)
8643 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
8644
8645 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
8646 it maps line-movement to call_data = max(5, height/20). */
8647 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
8648 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 8649 else
ec18280f 8650 part = scroll_bar_move_ratio;
06a2c219
GM
8651
8652 window_being_scrolled = bar->window;
8653 bar->dragging = Qnil;
8654 last_scroll_bar_part = part;
ec18280f 8655 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
8656}
8657
8658
8659#endif /* not USE_MOTIF */
8660
8661
8662/* Create the widget for scroll bar BAR on frame F. Record the widget
8663 and X window of the scroll bar in BAR. */
8664
8665static void
8666x_create_toolkit_scroll_bar (f, bar)
8667 struct frame *f;
8668 struct scroll_bar *bar;
8669{
8670 Window xwindow;
8671 Widget widget;
8672 Arg av[20];
8673 int ac = 0;
8674 char *scroll_bar_name = "verticalScrollBar";
8675 unsigned long pixel;
8676
8677 BLOCK_INPUT;
8678
8679#ifdef USE_MOTIF
06a2c219
GM
8680 /* Set resources. Create the widget. */
8681 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8682 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
8683 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
8684 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
8685 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
8686 XtSetArg (av[ac], XmNincrement, 1); ++ac;
8687 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
8688
8689 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8690 if (pixel != -1)
8691 {
8692 XtSetArg (av[ac], XmNforeground, pixel);
8693 ++ac;
8694 }
8695
8696 pixel = f->output_data.x->scroll_bar_background_pixel;
8697 if (pixel != -1)
8698 {
8699 XtSetArg (av[ac], XmNbackground, pixel);
8700 ++ac;
8701 }
8702
8703 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
8704 scroll_bar_name, av, ac);
8705
8706 /* Add one callback for everything that can happen. */
8707 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
8708 (XtPointer) bar);
8709 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
8710 (XtPointer) bar);
8711 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
8712 (XtPointer) bar);
8713 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
8714 (XtPointer) bar);
8715 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
8716 (XtPointer) bar);
8717 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
8718 (XtPointer) bar);
8719 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
8720 (XtPointer) bar);
8721
8722 /* Realize the widget. Only after that is the X window created. */
8723 XtRealizeWidget (widget);
8724
8725 /* Set the cursor to an arrow. I didn't find a resource to do that.
8726 And I'm wondering why it hasn't an arrow cursor by default. */
8727 XDefineCursor (XtDisplay (widget), XtWindow (widget),
8728 f->output_data.x->nontext_cursor);
8729
ec18280f 8730#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8731
8732 /* Set resources. Create the widget. The background of the
8733 Xaw3d scroll bar widget is a little bit light for my taste.
8734 We don't alter it here to let users change it according
8735 to their taste with `emacs*verticalScrollBar.background: xxx'. */
8736 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8737 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
8738 /* For smoother scrolling with Xaw3d -sm */
8739 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
06a2c219
GM
8740
8741 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8742 if (pixel != -1)
8743 {
8744 XtSetArg (av[ac], XtNforeground, pixel);
8745 ++ac;
8746 }
8747
8748 pixel = f->output_data.x->scroll_bar_background_pixel;
8749 if (pixel != -1)
8750 {
8751 XtSetArg (av[ac], XtNbackground, pixel);
8752 ++ac;
8753 }
7c1bef7a
MB
8754
8755 /* Top/bottom shadow colors. */
8756
8757 /* Allocate them, if necessary. */
8758 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
8759 {
8760 pixel = f->output_data.x->scroll_bar_background_pixel;
8761 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8762 &pixel, 1.2, 0x8000))
8763 pixel = -1;
8764 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
8765 }
8766 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8767 {
8768 pixel = f->output_data.x->scroll_bar_background_pixel;
8769 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8770 &pixel, 0.6, 0x4000))
8771 pixel = -1;
8772 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
8773 }
8774
8775 /* Tell the toolkit about them. */
8776 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
8777 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8778 /* We tried to allocate a color for the top/bottom shadow, and
8779 failed, so tell Xaw3d to use dithering instead. */
8780 {
8781 XtSetArg (av[ac], XtNbeNiceToColormap, True);
8782 ++ac;
8783 }
8784 else
8785 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
8786 be more consistent with other emacs 3d colors, and since Xaw3d is
8787 not good at dealing with allocation failure. */
8788 {
8789 /* This tells Xaw3d to use real colors instead of dithering for
8790 the shadows. */
8791 XtSetArg (av[ac], XtNbeNiceToColormap, False);
8792 ++ac;
8793
8794 /* Specify the colors. */
8795 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
8796 if (pixel != -1)
8797 {
8798 XtSetArg (av[ac], "topShadowPixel", pixel);
8799 ++ac;
8800 }
8801 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
8802 if (pixel != -1)
8803 {
8804 XtSetArg (av[ac], "bottomShadowPixel", pixel);
8805 ++ac;
8806 }
8807 }
8808
06a2c219
GM
8809 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
8810 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
8811
8812 {
8813 char *initial = "";
8814 char *val = initial;
8815 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
8816 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
8817 if (val == initial)
8818 { /* ARROW_SCROLL */
8819 xaw3d_arrow_scroll = True;
8820 /* Isn't that just a personal preference ? -sm */
8821 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
8822 }
8823 }
06a2c219
GM
8824
8825 /* Define callbacks. */
ec18280f
SM
8826 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
8827 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
8828 (XtPointer) bar);
8829
8830 /* Realize the widget. Only after that is the X window created. */
8831 XtRealizeWidget (widget);
8832
ec18280f 8833#endif /* !USE_MOTIF */
06a2c219
GM
8834
8835 /* Install an action hook that let's us detect when the user
8836 finishes interacting with a scroll bar. */
8837 if (action_hook_id == 0)
8838 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
8839
8840 /* Remember X window and widget in the scroll bar vector. */
8841 SET_SCROLL_BAR_X_WIDGET (bar, widget);
8842 xwindow = XtWindow (widget);
8843 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
8844
8845 UNBLOCK_INPUT;
8846}
8847
8848
8849/* Set the thumb size and position of scroll bar BAR. We are currently
8850 displaying PORTION out of a whole WHOLE, and our position POSITION. */
8851
8852static void
8853x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
8854 struct scroll_bar *bar;
8855 int portion, position, whole;
f451eb13 8856{
e83dc917
GM
8857 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8858 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
06a2c219 8859 float top, shown;
f451eb13 8860
06a2c219
GM
8861 if (whole == 0)
8862 top = 0, shown = 1;
8863 else
f451eb13 8864 {
06a2c219
GM
8865 top = (float) position / whole;
8866 shown = (float) portion / whole;
8867 }
f451eb13 8868
06a2c219 8869 BLOCK_INPUT;
f451eb13 8870
06a2c219
GM
8871#ifdef USE_MOTIF
8872 {
8873 int size, value;
06a2c219 8874
ec18280f 8875 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
8876 is the scroll bar's maximum and MIN is the scroll bar's minimum
8877 value. */
8878 size = shown * XM_SB_RANGE;
8879 size = min (size, XM_SB_RANGE);
8880 size = max (size, 1);
8881
8882 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
8883 value = top * XM_SB_RANGE;
8884 value = min (value, XM_SB_MAX - size);
8885 value = max (value, XM_SB_MIN);
8886
06a2c219
GM
8887 if (NILP (bar->dragging))
8888 XmScrollBarSetValues (widget, value, size, 0, 0, False);
8889 else if (last_scroll_bar_part == scroll_bar_down_arrow)
8890 /* This has the negative side effect that the slider value is
ec18280f 8891 not what it would be if we scrolled here using line-wise or
06a2c219
GM
8892 page-wise movement. */
8893 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
8894 else
8895 {
8896 /* If currently dragging, only update the slider size.
8897 This reduces flicker effects. */
8898 int old_value, old_size, increment, page_increment;
8899
8900 XmScrollBarGetValues (widget, &old_value, &old_size,
8901 &increment, &page_increment);
8902 XmScrollBarSetValues (widget, old_value,
8903 min (size, XM_SB_RANGE - old_value),
8904 0, 0, False);
8905 }
06a2c219 8906 }
ec18280f 8907#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 8908 {
ec18280f
SM
8909 float old_top, old_shown;
8910 Dimension height;
8911 XtVaGetValues (widget,
8912 XtNtopOfThumb, &old_top,
8913 XtNshown, &old_shown,
8914 XtNheight, &height,
8915 NULL);
8916
8917 /* Massage the top+shown values. */
8918 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8919 top = max (0, min (1, top));
8920 else
8921 top = old_top;
8922 /* Keep two pixels available for moving the thumb down. */
8923 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8924
8925 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8926 check that your system's configuration file contains a define
8927 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8928 if (top != old_top || shown != old_shown)
eb393530 8929 {
ec18280f 8930 if (NILP (bar->dragging))
eb393530 8931 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8932 else
8933 {
ec18280f
SM
8934#ifdef HAVE_XAW3D
8935 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8936 int scroll_mode = 0;
ec18280f
SM
8937
8938 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8939 if (xaw3d_arrow_scroll)
8940 {
8941 /* Xaw3d stupidly ignores resize requests while dragging
8942 so we have to make it believe it's not in dragging mode. */
8943 scroll_mode = sb->scrollbar.scroll_mode;
8944 if (scroll_mode == 2)
8945 sb->scrollbar.scroll_mode = 0;
8946 }
8947#endif
8948 /* Try to make the scrolling a tad smoother. */
8949 if (!xaw3d_pick_top)
8950 shown = min (shown, old_shown);
8951
8952 XawScrollbarSetThumb (widget, top, shown);
8953
8954#ifdef HAVE_XAW3D
8955 if (xaw3d_arrow_scroll && scroll_mode == 2)
8956 sb->scrollbar.scroll_mode = scroll_mode;
8957#endif
06a2c219 8958 }
06a2c219
GM
8959 }
8960 }
ec18280f 8961#endif /* !USE_MOTIF */
06a2c219
GM
8962
8963 UNBLOCK_INPUT;
f451eb13
JB
8964}
8965
06a2c219
GM
8966#endif /* USE_TOOLKIT_SCROLL_BARS */
8967
8968
8969\f
8970/************************************************************************
8971 Scroll bars, general
8972 ************************************************************************/
8973
8974/* Create a scroll bar and return the scroll bar vector for it. W is
8975 the Emacs window on which to create the scroll bar. TOP, LEFT,
8976 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8977 scroll bar. */
8978
ab648270 8979static struct scroll_bar *
06a2c219
GM
8980x_scroll_bar_create (w, top, left, width, height)
8981 struct window *w;
f451eb13
JB
8982 int top, left, width, height;
8983{
06a2c219 8984 struct frame *f = XFRAME (w->frame);
334208b7
RS
8985 struct scroll_bar *bar
8986 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8987
8988 BLOCK_INPUT;
8989
eccc05db 8990#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8991 x_create_toolkit_scroll_bar (f, bar);
8992#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8993 {
8994 XSetWindowAttributes a;
8995 unsigned long mask;
5c187dee 8996 Window window;
06a2c219
GM
8997
8998 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8999 if (a.background_pixel == -1)
9000 a.background_pixel = f->output_data.x->background_pixel;
9001
12ba150f 9002 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 9003 | ButtonMotionMask | PointerMotionHintMask
12ba150f 9004 | ExposureMask);
7a13e894 9005 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 9006
dbc4e1c1 9007 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 9008
06a2c219
GM
9009 /* Clear the area of W that will serve as a scroll bar. This is
9010 for the case that a window has been split horizontally. In
9011 this case, no clear_frame is generated to reduce flickering. */
c5e6e06b
GM
9012 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9013 left, top, width,
9014 window_box_height (w), False);
06a2c219
GM
9015
9016 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9017 /* Position and size of scroll bar. */
9018 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9019 top,
9020 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
9021 height,
9022 /* Border width, depth, class, and visual. */
9023 0,
9024 CopyFromParent,
9025 CopyFromParent,
9026 CopyFromParent,
9027 /* Attributes. */
9028 mask, &a);
9029 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 9030 }
06a2c219 9031#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9032
06a2c219 9033 XSETWINDOW (bar->window, w);
e0c1aef2
KH
9034 XSETINT (bar->top, top);
9035 XSETINT (bar->left, left);
9036 XSETINT (bar->width, width);
9037 XSETINT (bar->height, height);
9038 XSETINT (bar->start, 0);
9039 XSETINT (bar->end, 0);
12ba150f 9040 bar->dragging = Qnil;
f451eb13
JB
9041
9042 /* Add bar to its frame's list of scroll bars. */
334208b7 9043 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 9044 bar->prev = Qnil;
334208b7 9045 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 9046 if (!NILP (bar->next))
e0c1aef2 9047 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 9048
06a2c219 9049 /* Map the window/widget. */
eccc05db 9050#ifdef USE_TOOLKIT_SCROLL_BARS
f964b4d7
GM
9051 {
9052 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
9053 XtConfigureWidget (scroll_bar,
9054 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9055 top,
9056 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
9057 max (height, 1), 0);
9058 XtMapWidget (scroll_bar);
9059 }
06a2c219 9060#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 9061 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 9062#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9063
9064 UNBLOCK_INPUT;
12ba150f 9065 return bar;
f451eb13
JB
9066}
9067
06a2c219 9068
12ba150f 9069/* Draw BAR's handle in the proper position.
06a2c219 9070
12ba150f
JB
9071 If the handle is already drawn from START to END, don't bother
9072 redrawing it, unless REBUILD is non-zero; in that case, always
9073 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 9074 events.)
12ba150f
JB
9075
9076 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
9077 fit inside its rectangle, but if the user is dragging the scroll
9078 bar handle, we want to let them drag it down all the way, so that
9079 the bar's top is as far down as it goes; otherwise, there's no way
9080 to move to the very end of the buffer. */
9081
5c187dee
GM
9082#ifndef USE_TOOLKIT_SCROLL_BARS
9083
f451eb13 9084static void
ab648270
JB
9085x_scroll_bar_set_handle (bar, start, end, rebuild)
9086 struct scroll_bar *bar;
f451eb13 9087 int start, end;
12ba150f 9088 int rebuild;
f451eb13 9089{
12ba150f 9090 int dragging = ! NILP (bar->dragging);
ab648270 9091 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9092 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9093 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
9094
9095 /* If the display is already accurate, do nothing. */
9096 if (! rebuild
9097 && start == XINT (bar->start)
9098 && end == XINT (bar->end))
9099 return;
9100
f451eb13
JB
9101 BLOCK_INPUT;
9102
9103 {
d9cdbb3d
RS
9104 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
9105 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
9106 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
9107
9108 /* Make sure the values are reasonable, and try to preserve
9109 the distance between start and end. */
12ba150f
JB
9110 {
9111 int length = end - start;
9112
9113 if (start < 0)
9114 start = 0;
9115 else if (start > top_range)
9116 start = top_range;
9117 end = start + length;
9118
9119 if (end < start)
9120 end = start;
9121 else if (end > top_range && ! dragging)
9122 end = top_range;
9123 }
f451eb13 9124
ab648270 9125 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
9126 XSETINT (bar->start, start);
9127 XSETINT (bar->end, end);
f451eb13 9128
12ba150f
JB
9129 /* Clip the end position, just for display. */
9130 if (end > top_range)
9131 end = top_range;
f451eb13 9132
ab648270 9133 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
9134 below top positions, to make sure the handle is always at least
9135 that many pixels tall. */
ab648270 9136 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 9137
12ba150f
JB
9138 /* Draw the empty space above the handle. Note that we can't clear
9139 zero-height areas; that means "clear to end of window." */
9140 if (0 < start)
c5e6e06b
GM
9141 x_clear_area (FRAME_X_DISPLAY (f), w,
9142 /* x, y, width, height, and exposures. */
9143 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9144 VERTICAL_SCROLL_BAR_TOP_BORDER,
9145 inside_width, start,
9146 False);
f451eb13 9147
06a2c219
GM
9148 /* Change to proper foreground color if one is specified. */
9149 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9150 XSetForeground (FRAME_X_DISPLAY (f), gc,
9151 f->output_data.x->scroll_bar_foreground_pixel);
9152
12ba150f 9153 /* Draw the handle itself. */
334208b7 9154 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
12ba150f 9155 /* x, y, width, height */
ab648270
JB
9156 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9157 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 9158 inside_width, end - start);
f451eb13 9159
06a2c219
GM
9160 /* Restore the foreground color of the GC if we changed it above. */
9161 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9162 XSetForeground (FRAME_X_DISPLAY (f), gc,
9163 f->output_data.x->foreground_pixel);
f451eb13 9164
12ba150f
JB
9165 /* Draw the empty space below the handle. Note that we can't
9166 clear zero-height areas; that means "clear to end of window." */
9167 if (end < inside_height)
c5e6e06b
GM
9168 x_clear_area (FRAME_X_DISPLAY (f), w,
9169 /* x, y, width, height, and exposures. */
9170 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9171 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
9172 inside_width, inside_height - end,
9173 False);
f451eb13 9174
f451eb13
JB
9175 }
9176
f451eb13
JB
9177 UNBLOCK_INPUT;
9178}
9179
5c187dee 9180#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 9181
06a2c219
GM
9182/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
9183 nil. */
58769bee 9184
12ba150f 9185static void
ab648270
JB
9186x_scroll_bar_remove (bar)
9187 struct scroll_bar *bar;
12ba150f 9188{
e83dc917 9189 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
9190 BLOCK_INPUT;
9191
eccc05db 9192#ifdef USE_TOOLKIT_SCROLL_BARS
e83dc917
GM
9193 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
9194#else
9195 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
9196#endif
06a2c219 9197
ab648270
JB
9198 /* Disassociate this scroll bar from its window. */
9199 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
9200
9201 UNBLOCK_INPUT;
9202}
9203
06a2c219 9204
12ba150f
JB
9205/* Set the handle of the vertical scroll bar for WINDOW to indicate
9206 that we are displaying PORTION characters out of a total of WHOLE
ab648270 9207 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 9208 create one. */
06a2c219 9209
12ba150f 9210static void
06a2c219
GM
9211XTset_vertical_scroll_bar (w, portion, whole, position)
9212 struct window *w;
f451eb13
JB
9213 int portion, whole, position;
9214{
06a2c219 9215 struct frame *f = XFRAME (w->frame);
ab648270 9216 struct scroll_bar *bar;
3c6ede7b 9217 int top, height, left, sb_left, width, sb_width;
06a2c219 9218 int window_x, window_y, window_width, window_height;
06a2c219 9219
3c6ede7b 9220 /* Get window dimensions. */
06a2c219 9221 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
9222 top = window_y;
9223 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9224 height = window_height;
06a2c219 9225
3c6ede7b 9226 /* Compute the left edge of the scroll bar area. */
06a2c219 9227 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
9228 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
9229 else
9230 left = XFASTINT (w->left);
9231 left *= CANON_X_UNIT (f);
9232 left += FRAME_INTERNAL_BORDER_WIDTH (f);
9233
9234 /* Compute the width of the scroll bar which might be less than
9235 the width of the area reserved for the scroll bar. */
9236 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
9237 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 9238 else
3c6ede7b 9239 sb_width = width;
12ba150f 9240
3c6ede7b
GM
9241 /* Compute the left edge of the scroll bar. */
9242#ifdef USE_TOOLKIT_SCROLL_BARS
9243 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9244 sb_left = left + width - sb_width - (width - sb_width) / 2;
9245 else
9246 sb_left = left + (width - sb_width) / 2;
9247#else
9248 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9249 sb_left = left + width - sb_width;
9250 else
9251 sb_left = left;
9252#endif
9253
ab648270 9254 /* Does the scroll bar exist yet? */
06a2c219 9255 if (NILP (w->vertical_scroll_bar))
3c6ede7b 9256 {
80c32bcc 9257 BLOCK_INPUT;
f964b4d7
GM
9258 if (width && height)
9259 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9260 left, top, width, height, False);
80c32bcc 9261 UNBLOCK_INPUT;
3c6ede7b
GM
9262 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
9263 }
f451eb13 9264 else
12ba150f
JB
9265 {
9266 /* It may just need to be moved and resized. */
06a2c219
GM
9267 unsigned int mask = 0;
9268
9269 bar = XSCROLL_BAR (w->vertical_scroll_bar);
9270
9271 BLOCK_INPUT;
9272
3c6ede7b 9273 if (sb_left != XINT (bar->left))
06a2c219 9274 mask |= CWX;
3c6ede7b 9275 if (top != XINT (bar->top))
06a2c219 9276 mask |= CWY;
3c6ede7b 9277 if (sb_width != XINT (bar->width))
06a2c219 9278 mask |= CWWidth;
3c6ede7b 9279 if (height != XINT (bar->height))
06a2c219
GM
9280 mask |= CWHeight;
9281
9282#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
9283
9284 /* Since toolkit scroll bars are smaller than the space reserved
9285 for them on the frame, we have to clear "under" them. */
f964b4d7
GM
9286 if (width && height)
9287 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9288 left, top, width, height, False);
06a2c219
GM
9289
9290 /* Move/size the scroll bar widget. */
9291 if (mask)
e83dc917 9292 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
3c6ede7b
GM
9293 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9294 top,
9295 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
f964b4d7 9296 max (height, 1), 0);
06a2c219
GM
9297
9298#else /* not USE_TOOLKIT_SCROLL_BARS */
9299
357e7376
GM
9300 /* Clear areas not covered by the scroll bar because of
9301 VERTICAL_SCROLL_BAR_WIDTH_TRIM. */
e1f6572f
RS
9302 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
9303 {
c5e6e06b
GM
9304 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9305 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9306 height, False);
9307 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9308 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9309 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9310 height, False);
e1f6572f 9311 }
357e7376
GM
9312
9313 /* Clear areas not covered by the scroll bar because it's not as
9314 wide as the area reserved for it . This makes sure a
9315 previous mode line display is cleared after C-x 2 C-x 1, for
9316 example. */
9317 {
9318 int area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9319 int rest = area_width - sb_width;
9320 if (rest > 0)
9321 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9322 left + area_width - rest, 0,
9323 rest, max (height, 1), False);
9324 }
06a2c219
GM
9325
9326 /* Move/size the scroll bar window. */
9327 if (mask)
9328 {
9329 XWindowChanges wc;
9330
3c6ede7b
GM
9331 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
9332 wc.y = top;
9333 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
9334 wc.height = height;
06a2c219
GM
9335 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
9336 mask, &wc);
9337 }
9338
9339#endif /* not USE_TOOLKIT_SCROLL_BARS */
9340
9341 /* Remember new settings. */
3c6ede7b
GM
9342 XSETINT (bar->left, sb_left);
9343 XSETINT (bar->top, top);
9344 XSETINT (bar->width, sb_width);
9345 XSETINT (bar->height, height);
06a2c219
GM
9346
9347 UNBLOCK_INPUT;
12ba150f 9348 }
f451eb13 9349
eccc05db 9350#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
9351 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
9352#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 9353 /* Set the scroll bar's current state, unless we're currently being
f451eb13 9354 dragged. */
12ba150f 9355 if (NILP (bar->dragging))
f451eb13 9356 {
92857db0 9357 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 9358
12ba150f 9359 if (whole == 0)
ab648270 9360 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
9361 else
9362 {
43f868f5
JB
9363 int start = ((double) position * top_range) / whole;
9364 int end = ((double) (position + portion) * top_range) / whole;
ab648270 9365 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 9366 }
f451eb13 9367 }
06a2c219 9368#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9369
06a2c219 9370 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
9371}
9372
12ba150f 9373
f451eb13 9374/* The following three hooks are used when we're doing a thorough
ab648270 9375 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 9376 are going to be deleted, because keeping track of when windows go
12ba150f
JB
9377 away is a real pain - "Can you say set-window-configuration, boys
9378 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 9379 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 9380 from the fiery pit when we actually redisplay its window. */
f451eb13 9381
ab648270
JB
9382/* Arrange for all scroll bars on FRAME to be removed at the next call
9383 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
9384 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
9385
58769bee 9386static void
ab648270 9387XTcondemn_scroll_bars (frame)
f451eb13
JB
9388 FRAME_PTR frame;
9389{
f9e24cb9
RS
9390 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
9391 while (! NILP (FRAME_SCROLL_BARS (frame)))
9392 {
9393 Lisp_Object bar;
9394 bar = FRAME_SCROLL_BARS (frame);
9395 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
9396 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
9397 XSCROLL_BAR (bar)->prev = Qnil;
9398 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
9399 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
9400 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
9401 }
f451eb13
JB
9402}
9403
fa2dfc30 9404
06a2c219 9405/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 9406 Note that WINDOW isn't necessarily condemned at all. */
fa2dfc30 9407
f451eb13 9408static void
ab648270 9409XTredeem_scroll_bar (window)
12ba150f 9410 struct window *window;
f451eb13 9411{
ab648270 9412 struct scroll_bar *bar;
fa2dfc30 9413 struct frame *f;
12ba150f 9414
ab648270
JB
9415 /* We can't redeem this window's scroll bar if it doesn't have one. */
9416 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
9417 abort ();
9418
ab648270 9419 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
9420
9421 /* Unlink it from the condemned list. */
fa2dfc30
GM
9422 f = XFRAME (WINDOW_FRAME (window));
9423 if (NILP (bar->prev))
9424 {
9425 /* If the prev pointer is nil, it must be the first in one of
9426 the lists. */
9427 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
9428 /* It's not condemned. Everything's fine. */
9429 return;
9430 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
9431 window->vertical_scroll_bar))
9432 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
9433 else
9434 /* If its prev pointer is nil, it must be at the front of
9435 one or the other! */
9436 abort ();
9437 }
9438 else
9439 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f 9440
fa2dfc30
GM
9441 if (! NILP (bar->next))
9442 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 9443
fa2dfc30
GM
9444 bar->next = FRAME_SCROLL_BARS (f);
9445 bar->prev = Qnil;
9446 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
9447 if (! NILP (bar->next))
9448 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13
JB
9449}
9450
ab648270
JB
9451/* Remove all scroll bars on FRAME that haven't been saved since the
9452 last call to `*condemn_scroll_bars_hook'. */
06a2c219 9453
f451eb13 9454static void
ab648270 9455XTjudge_scroll_bars (f)
12ba150f 9456 FRAME_PTR f;
f451eb13 9457{
12ba150f 9458 Lisp_Object bar, next;
f451eb13 9459
ab648270 9460 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
9461
9462 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
9463 more events on the hapless scroll bars. */
9464 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
9465
9466 for (; ! NILP (bar); bar = next)
f451eb13 9467 {
ab648270 9468 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 9469
ab648270 9470 x_scroll_bar_remove (b);
12ba150f
JB
9471
9472 next = b->next;
9473 b->next = b->prev = Qnil;
f451eb13 9474 }
12ba150f 9475
ab648270 9476 /* Now there should be no references to the condemned scroll bars,
12ba150f 9477 and they should get garbage-collected. */
f451eb13
JB
9478}
9479
9480
06a2c219
GM
9481/* Handle an Expose or GraphicsExpose event on a scroll bar. This
9482 is a no-op when using toolkit scroll bars.
ab648270
JB
9483
9484 This may be called from a signal handler, so we have to ignore GC
9485 mark bits. */
06a2c219 9486
f451eb13 9487static void
ab648270
JB
9488x_scroll_bar_expose (bar, event)
9489 struct scroll_bar *bar;
f451eb13
JB
9490 XEvent *event;
9491{
06a2c219
GM
9492#ifndef USE_TOOLKIT_SCROLL_BARS
9493
ab648270 9494 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9495 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9496 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 9497 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 9498
f451eb13
JB
9499 BLOCK_INPUT;
9500
ab648270 9501 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 9502
06a2c219 9503 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 9504 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
9505
9506 /* x, y, width, height */
d9cdbb3d 9507 0, 0,
3cbd2e0b 9508 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
9509 XINT (bar->height) - 1);
9510
f451eb13 9511 UNBLOCK_INPUT;
06a2c219
GM
9512
9513#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9514}
9515
ab648270
JB
9516/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
9517 is set to something other than no_event, it is enqueued.
9518
9519 This may be called from a signal handler, so we have to ignore GC
9520 mark bits. */
06a2c219 9521
5c187dee
GM
9522#ifndef USE_TOOLKIT_SCROLL_BARS
9523
f451eb13 9524static void
ab648270
JB
9525x_scroll_bar_handle_click (bar, event, emacs_event)
9526 struct scroll_bar *bar;
f451eb13
JB
9527 XEvent *event;
9528 struct input_event *emacs_event;
9529{
0299d313 9530 if (! GC_WINDOWP (bar->window))
12ba150f
JB
9531 abort ();
9532
ab648270 9533 emacs_event->kind = scroll_bar_click;
69388238 9534 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
9535 emacs_event->modifiers
9536 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
9537 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
9538 event->xbutton.state)
9539 | (event->type == ButtonRelease
9540 ? up_modifier
9541 : down_modifier));
12ba150f 9542 emacs_event->frame_or_window = bar->window;
0f8aabe9 9543 emacs_event->arg = Qnil;
f451eb13 9544 emacs_event->timestamp = event->xbutton.time;
12ba150f 9545 {
06a2c219 9546#if 0
d9cdbb3d 9547 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 9548 int internal_height
d9cdbb3d 9549 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9550#endif
0299d313 9551 int top_range
d9cdbb3d 9552 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 9553 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
9554
9555 if (y < 0) y = 0;
9556 if (y > top_range) y = top_range;
9557
9558 if (y < XINT (bar->start))
ab648270
JB
9559 emacs_event->part = scroll_bar_above_handle;
9560 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9561 emacs_event->part = scroll_bar_handle;
12ba150f 9562 else
ab648270 9563 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
9564
9565 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
9566 they want to drag it. Lisp code needs to be able to decide
9567 whether or not we're dragging. */
929787e1 9568#if 0
12ba150f
JB
9569 /* If the user has just clicked on the handle, record where they're
9570 holding it. */
9571 if (event->type == ButtonPress
ab648270 9572 && emacs_event->part == scroll_bar_handle)
e0c1aef2 9573 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 9574#endif
12ba150f
JB
9575
9576 /* If the user has released the handle, set it to its final position. */
9577 if (event->type == ButtonRelease
9578 && ! NILP (bar->dragging))
9579 {
9580 int new_start = y - XINT (bar->dragging);
9581 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 9582
ab648270 9583 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
9584 bar->dragging = Qnil;
9585 }
f451eb13 9586
5116f055
JB
9587 /* Same deal here as the other #if 0. */
9588#if 0
58769bee 9589 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 9590 the handle. */
ab648270 9591 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
9592 emacs_event->x = bar->start;
9593 else
e0c1aef2 9594 XSETINT (emacs_event->x, y);
5116f055 9595#else
e0c1aef2 9596 XSETINT (emacs_event->x, y);
5116f055 9597#endif
f451eb13 9598
e0c1aef2 9599 XSETINT (emacs_event->y, top_range);
12ba150f
JB
9600 }
9601}
f451eb13 9602
ab648270
JB
9603/* Handle some mouse motion while someone is dragging the scroll bar.
9604
9605 This may be called from a signal handler, so we have to ignore GC
9606 mark bits. */
06a2c219 9607
f451eb13 9608static void
ab648270
JB
9609x_scroll_bar_note_movement (bar, event)
9610 struct scroll_bar *bar;
f451eb13
JB
9611 XEvent *event;
9612{
39d8bb4d
KH
9613 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
9614
f451eb13
JB
9615 last_mouse_movement_time = event->xmotion.time;
9616
39d8bb4d 9617 f->mouse_moved = 1;
e0c1aef2 9618 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
9619
9620 /* If we're dragging the bar, display it. */
ab648270 9621 if (! GC_NILP (bar->dragging))
f451eb13
JB
9622 {
9623 /* Where should the handle be now? */
12ba150f 9624 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 9625
12ba150f 9626 if (new_start != XINT (bar->start))
f451eb13 9627 {
12ba150f 9628 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 9629
ab648270 9630 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
9631 }
9632 }
f451eb13
JB
9633}
9634
5c187dee
GM
9635#endif /* !USE_TOOLKIT_SCROLL_BARS */
9636
12ba150f 9637/* Return information to the user about the current position of the mouse
ab648270 9638 on the scroll bar. */
06a2c219 9639
12ba150f 9640static void
334208b7
RS
9641x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
9642 FRAME_PTR *fp;
12ba150f 9643 Lisp_Object *bar_window;
ab648270 9644 enum scroll_bar_part *part;
12ba150f
JB
9645 Lisp_Object *x, *y;
9646 unsigned long *time;
9647{
ab648270 9648 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
9649 Window w = SCROLL_BAR_X_WINDOW (bar);
9650 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 9651 int win_x, win_y;
559cb2fb
JB
9652 Window dummy_window;
9653 int dummy_coord;
9654 unsigned int dummy_mask;
12ba150f 9655
cf7cb199
JB
9656 BLOCK_INPUT;
9657
ab648270 9658 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 9659 report that. */
334208b7 9660 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 9661
559cb2fb
JB
9662 /* Root, child, root x and root y. */
9663 &dummy_window, &dummy_window,
9664 &dummy_coord, &dummy_coord,
12ba150f 9665
559cb2fb
JB
9666 /* Position relative to scroll bar. */
9667 &win_x, &win_y,
12ba150f 9668
559cb2fb
JB
9669 /* Mouse buttons and modifier keys. */
9670 &dummy_mask))
7a13e894 9671 ;
559cb2fb
JB
9672 else
9673 {
06a2c219 9674#if 0
559cb2fb 9675 int inside_height
d9cdbb3d 9676 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9677#endif
559cb2fb 9678 int top_range
d9cdbb3d 9679 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
9680
9681 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
9682
9683 if (! NILP (bar->dragging))
9684 win_y -= XINT (bar->dragging);
9685
9686 if (win_y < 0)
9687 win_y = 0;
9688 if (win_y > top_range)
9689 win_y = top_range;
9690
334208b7 9691 *fp = f;
7a13e894 9692 *bar_window = bar->window;
559cb2fb
JB
9693
9694 if (! NILP (bar->dragging))
9695 *part = scroll_bar_handle;
9696 else if (win_y < XINT (bar->start))
9697 *part = scroll_bar_above_handle;
9698 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9699 *part = scroll_bar_handle;
9700 else
9701 *part = scroll_bar_below_handle;
12ba150f 9702
e0c1aef2
KH
9703 XSETINT (*x, win_y);
9704 XSETINT (*y, top_range);
12ba150f 9705
39d8bb4d 9706 f->mouse_moved = 0;
559cb2fb
JB
9707 last_mouse_scroll_bar = Qnil;
9708 }
12ba150f 9709
559cb2fb 9710 *time = last_mouse_movement_time;
cf7cb199 9711
cf7cb199 9712 UNBLOCK_INPUT;
12ba150f
JB
9713}
9714
f451eb13 9715
dbc4e1c1 9716/* The screen has been cleared so we may have changed foreground or
ab648270
JB
9717 background colors, and the scroll bars may need to be redrawn.
9718 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
9719 redraw them. */
9720
dfcf069d 9721void
ab648270 9722x_scroll_bar_clear (f)
dbc4e1c1
JB
9723 FRAME_PTR f;
9724{
06a2c219 9725#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
9726 Lisp_Object bar;
9727
b80c363e
RS
9728 /* We can have scroll bars even if this is 0,
9729 if we just turned off scroll bar mode.
9730 But in that case we should not clear them. */
9731 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
9732 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
9733 bar = XSCROLL_BAR (bar)->next)
c5e6e06b
GM
9734 XClearArea (FRAME_X_DISPLAY (f),
9735 SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
b80c363e 9736 0, 0, 0, 0, True);
06a2c219 9737#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
9738}
9739
06a2c219 9740/* This processes Expose events from the menu-bar specific X event
19126e11 9741 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 9742 when handling menu-bar or pop-up items. */
3afe33e7 9743
06a2c219 9744int
3afe33e7
RS
9745process_expose_from_menu (event)
9746 XEvent event;
9747{
9748 FRAME_PTR f;
19126e11 9749 struct x_display_info *dpyinfo;
06a2c219 9750 int frame_exposed_p = 0;
3afe33e7 9751
f94397b5
KH
9752 BLOCK_INPUT;
9753
19126e11
KH
9754 dpyinfo = x_display_info_for_display (event.xexpose.display);
9755 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
9756 if (f)
9757 {
9758 if (f->async_visible == 0)
9759 {
9760 f->async_visible = 1;
9761 f->async_iconified = 0;
06c488fd 9762 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
9763 SET_FRAME_GARBAGED (f);
9764 }
9765 else
9766 {
06a2c219
GM
9767 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
9768 event.xexpose.x, event.xexpose.y,
9769 event.xexpose.width, event.xexpose.height);
9770 frame_exposed_p = 1;
3afe33e7
RS
9771 }
9772 }
9773 else
9774 {
9775 struct scroll_bar *bar
9776 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9777
3afe33e7
RS
9778 if (bar)
9779 x_scroll_bar_expose (bar, &event);
9780 }
f94397b5
KH
9781
9782 UNBLOCK_INPUT;
06a2c219 9783 return frame_exposed_p;
3afe33e7 9784}
09756a85
RS
9785\f
9786/* Define a queue to save up SelectionRequest events for later handling. */
9787
9788struct selection_event_queue
9789 {
9790 XEvent event;
9791 struct selection_event_queue *next;
9792 };
9793
9794static struct selection_event_queue *queue;
9795
9796/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 9797
09756a85
RS
9798static int x_queue_selection_requests;
9799
9800/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 9801
09756a85 9802static void
334208b7
RS
9803x_queue_event (f, event)
9804 FRAME_PTR f;
09756a85
RS
9805 XEvent *event;
9806{
9807 struct selection_event_queue *queue_tmp
06a2c219 9808 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 9809
58769bee 9810 if (queue_tmp != NULL)
09756a85
RS
9811 {
9812 queue_tmp->event = *event;
9813 queue_tmp->next = queue;
9814 queue = queue_tmp;
9815 }
9816}
9817
9818/* Take all the queued events and put them back
9819 so that they get processed afresh. */
9820
9821static void
db3906fd
RS
9822x_unqueue_events (display)
9823 Display *display;
09756a85 9824{
58769bee 9825 while (queue != NULL)
09756a85
RS
9826 {
9827 struct selection_event_queue *queue_tmp = queue;
db3906fd 9828 XPutBackEvent (display, &queue_tmp->event);
09756a85 9829 queue = queue_tmp->next;
06a2c219 9830 xfree ((char *)queue_tmp);
09756a85
RS
9831 }
9832}
9833
9834/* Start queuing SelectionRequest events. */
9835
9836void
db3906fd
RS
9837x_start_queuing_selection_requests (display)
9838 Display *display;
09756a85
RS
9839{
9840 x_queue_selection_requests++;
9841}
9842
9843/* Stop queuing SelectionRequest events. */
9844
9845void
db3906fd
RS
9846x_stop_queuing_selection_requests (display)
9847 Display *display;
09756a85
RS
9848{
9849 x_queue_selection_requests--;
db3906fd 9850 x_unqueue_events (display);
09756a85 9851}
f451eb13
JB
9852\f
9853/* The main X event-reading loop - XTread_socket. */
dc6f92b8 9854
06a2c219 9855/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
9856 but we have to put it out here, since static variables within functions
9857 sometimes don't work. */
06a2c219 9858
dc6f92b8
JB
9859static Time enter_timestamp;
9860
11edeb03 9861/* This holds the state XLookupString needs to implement dead keys
58769bee 9862 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
9863 says that a portable program can't use this, but Stephen Gildea assures
9864 me that letting the compiler initialize it to zeros will work okay.
9865
9866 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
9867 given for enter_time stamp, above. */
9868
11edeb03
JB
9869static XComposeStatus compose_status;
9870
10e6549c
RS
9871/* Record the last 100 characters stored
9872 to help debug the loss-of-chars-during-GC problem. */
06a2c219 9873
2224b905
RS
9874static int temp_index;
9875static short temp_buffer[100];
10e6549c 9876
7a13e894
RS
9877/* Set this to nonzero to fake an "X I/O error"
9878 on a particular display. */
06a2c219 9879
7a13e894
RS
9880struct x_display_info *XTread_socket_fake_io_error;
9881
2224b905
RS
9882/* When we find no input here, we occasionally do a no-op command
9883 to verify that the X server is still running and we can still talk with it.
9884 We try all the open displays, one by one.
9885 This variable is used for cycling thru the displays. */
06a2c219 9886
2224b905
RS
9887static struct x_display_info *next_noop_dpyinfo;
9888
06a2c219
GM
9889#define SET_SAVED_MENU_EVENT(size) \
9890 do \
9891 { \
9892 if (f->output_data.x->saved_menu_event == 0) \
9893 f->output_data.x->saved_menu_event \
9894 = (XEvent *) xmalloc (sizeof (XEvent)); \
9895 bcopy (&event, f->output_data.x->saved_menu_event, size); \
9896 if (numchars >= 1) \
9897 { \
9898 bufp->kind = menu_bar_activate_event; \
9899 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 9900 bufp->arg = Qnil; \
06a2c219
GM
9901 bufp++; \
9902 count++; \
9903 numchars--; \
9904 } \
9905 } \
9906 while (0)
9907
8805890a 9908#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 9909#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 9910
dc6f92b8
JB
9911/* Read events coming from the X server.
9912 This routine is called by the SIGIO handler.
9913 We return as soon as there are no more events to be read.
9914
9915 Events representing keys are stored in buffer BUFP,
9916 which can hold up to NUMCHARS characters.
9917 We return the number of characters stored into the buffer,
9918 thus pretending to be `read'.
9919
dc6f92b8
JB
9920 EXPECTED is nonzero if the caller knows input is available. */
9921
7c5283e4 9922int
f66868ba 9923XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 9924 register int sd;
8805890a
KH
9925 /* register */ struct input_event *bufp;
9926 /* register */ int numchars;
dc6f92b8
JB
9927 int expected;
9928{
9929 int count = 0;
9930 int nbytes = 0;
dc6f92b8 9931 XEvent event;
f676886a 9932 struct frame *f;
66f55a9d 9933 int event_found = 0;
334208b7 9934 struct x_display_info *dpyinfo;
379b5ac0 9935 struct coding_system coding;
dc6f92b8 9936
9ac0d9e0 9937 if (interrupt_input_blocked)
dc6f92b8 9938 {
9ac0d9e0 9939 interrupt_input_pending = 1;
dc6f92b8
JB
9940 return -1;
9941 }
9942
9ac0d9e0 9943 interrupt_input_pending = 0;
dc6f92b8 9944 BLOCK_INPUT;
c0a04927
RS
9945
9946 /* So people can tell when we have read the available input. */
9947 input_signal_count++;
9948
dc6f92b8 9949 if (numchars <= 0)
06a2c219 9950 abort (); /* Don't think this happens. */
dc6f92b8 9951
bde5503b
GM
9952 ++handling_signal;
9953
379b5ac0
KH
9954 /* The input should be decoded if it is from XIM. Currently the
9955 locale of XIM is the same as that of the system. So, we can use
9956 Vlocale_coding_system which is initialized properly at Emacs
9957 startup time. */
9958 setup_coding_system (Vlocale_coding_system, &coding);
9959 coding.src_multibyte = 0;
9960 coding.dst_multibyte = 1;
9961 /* The input is converted to events, thus we can't handle
9962 composition. Anyway, there's no XIM that gives us composition
9963 information. */
9964 coding.composing = COMPOSITION_DISABLED;
9965
7a13e894
RS
9966 /* Find the display we are supposed to read input for.
9967 It's the one communicating on descriptor SD. */
9968 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9969 {
9970#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9971#ifdef FIOSNBIO
7a13e894
RS
9972 /* If available, Xlib uses FIOSNBIO to make the socket
9973 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9974 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9975 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9976 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9977#endif /* ! defined (FIOSNBIO) */
7a13e894 9978#endif
dc6f92b8 9979
7a13e894
RS
9980#if 0 /* This code can't be made to work, with multiple displays,
9981 and appears not to be used on any system any more.
9982 Also keyboard.c doesn't turn O_NDELAY on and off
9983 for X connections. */
dc6f92b8
JB
9984#ifndef SIGIO
9985#ifndef HAVE_SELECT
7a13e894
RS
9986 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9987 {
9988 extern int read_alarm_should_throw;
9989 read_alarm_should_throw = 1;
9990 XPeekEvent (dpyinfo->display, &event);
9991 read_alarm_should_throw = 0;
9992 }
c118dd06
JB
9993#endif /* HAVE_SELECT */
9994#endif /* SIGIO */
7a13e894 9995#endif
dc6f92b8 9996
7a13e894
RS
9997 /* For debugging, this gives a way to fake an I/O error. */
9998 if (dpyinfo == XTread_socket_fake_io_error)
9999 {
10000 XTread_socket_fake_io_error = 0;
10001 x_io_error_quitter (dpyinfo->display);
10002 }
dc6f92b8 10003
06a2c219 10004 while (XPending (dpyinfo->display))
dc6f92b8 10005 {
7a13e894 10006 XNextEvent (dpyinfo->display, &event);
06a2c219 10007
531483fb 10008#ifdef HAVE_X_I18N
d1bc4182 10009 {
f2be1146
GM
10010 /* Filter events for the current X input method.
10011 XFilterEvent returns non-zero if the input method has
10012 consumed the event. We pass the frame's X window to
10013 XFilterEvent because that's the one for which the IC
10014 was created. */
f5d11644
GM
10015 struct frame *f1 = x_any_window_to_frame (dpyinfo,
10016 event.xclient.window);
10017 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
10018 break;
10019 }
0cd6403b 10020#endif
7a13e894
RS
10021 event_found = 1;
10022
10023 switch (event.type)
10024 {
10025 case ClientMessage:
c047688c 10026 {
7a13e894
RS
10027 if (event.xclient.message_type
10028 == dpyinfo->Xatom_wm_protocols
10029 && event.xclient.format == 32)
c047688c 10030 {
7a13e894
RS
10031 if (event.xclient.data.l[0]
10032 == dpyinfo->Xatom_wm_take_focus)
c047688c 10033 {
8c1a6a84
RS
10034 /* Use x_any_window_to_frame because this
10035 could be the shell widget window
10036 if the frame has no title bar. */
10037 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
10038#ifdef HAVE_X_I18N
10039 /* Not quite sure this is needed -pd */
8c1a6a84 10040 if (f && FRAME_XIC (f))
6c183ba5
RS
10041 XSetICFocus (FRAME_XIC (f));
10042#endif
f1da8f06
GM
10043#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
10044 instructs the WM to set the input focus automatically for
10045 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
10046 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
10047 it has set the focus. So, XSetInputFocus below is not
10048 needed.
10049
10050 The call to XSetInputFocus below has also caused trouble. In
10051 cases where the XSetInputFocus done by the WM and the one
10052 below are temporally close (on a fast machine), the call
10053 below can generate additional FocusIn events which confuse
10054 Emacs. */
10055
bf7253f4
RS
10056 /* Since we set WM_TAKE_FOCUS, we must call
10057 XSetInputFocus explicitly. But not if f is null,
10058 since that might be an event for a deleted frame. */
7a13e894 10059 if (f)
bf7253f4
RS
10060 {
10061 Display *d = event.xclient.display;
10062 /* Catch and ignore errors, in case window has been
10063 iconified by a window manager such as GWM. */
10064 int count = x_catch_errors (d);
10065 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
10066 /* The ICCCM says this is
10067 the only valid choice. */
10068 RevertToParent,
bf7253f4
RS
10069 event.xclient.data.l[1]);
10070 /* This is needed to detect the error
10071 if there is an error. */
10072 XSync (d, False);
10073 x_uncatch_errors (d, count);
10074 }
7a13e894 10075 /* Not certain about handling scroll bars here */
f1da8f06 10076#endif /* 0 */
c047688c 10077 }
7a13e894
RS
10078 else if (event.xclient.data.l[0]
10079 == dpyinfo->Xatom_wm_save_yourself)
10080 {
10081 /* Save state modify the WM_COMMAND property to
06a2c219 10082 something which can reinstate us. This notifies
7a13e894
RS
10083 the session manager, who's looking for such a
10084 PropertyNotify. Can restart processing when
06a2c219 10085 a keyboard or mouse event arrives. */
7a13e894
RS
10086 if (numchars > 0)
10087 {
19126e11
KH
10088 f = x_top_window_to_frame (dpyinfo,
10089 event.xclient.window);
7a13e894
RS
10090
10091 /* This is just so we only give real data once
10092 for a single Emacs process. */
b86bd3dd 10093 if (f == SELECTED_FRAME ())
7a13e894
RS
10094 XSetCommand (FRAME_X_DISPLAY (f),
10095 event.xclient.window,
10096 initial_argv, initial_argc);
f000f5c5 10097 else if (f)
7a13e894
RS
10098 XSetCommand (FRAME_X_DISPLAY (f),
10099 event.xclient.window,
10100 0, 0);
10101 }
10102 }
10103 else if (event.xclient.data.l[0]
10104 == dpyinfo->Xatom_wm_delete_window)
1fb20991 10105 {
19126e11
KH
10106 struct frame *f
10107 = x_any_window_to_frame (dpyinfo,
10108 event.xclient.window);
1fb20991 10109
7a13e894
RS
10110 if (f)
10111 {
10112 if (numchars == 0)
10113 abort ();
1fb20991 10114
7a13e894
RS
10115 bufp->kind = delete_window_event;
10116 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10117 bufp->arg = Qnil;
7a13e894
RS
10118 bufp++;
10119
10120 count += 1;
10121 numchars -= 1;
10122 }
1fb20991 10123 }
c047688c 10124 }
7a13e894
RS
10125 else if (event.xclient.message_type
10126 == dpyinfo->Xatom_wm_configure_denied)
10127 {
10128 }
10129 else if (event.xclient.message_type
10130 == dpyinfo->Xatom_wm_window_moved)
10131 {
10132 int new_x, new_y;
19126e11
KH
10133 struct frame *f
10134 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 10135
7a13e894
RS
10136 new_x = event.xclient.data.s[0];
10137 new_y = event.xclient.data.s[1];
1fb20991 10138
7a13e894
RS
10139 if (f)
10140 {
7556890b
RS
10141 f->output_data.x->left_pos = new_x;
10142 f->output_data.x->top_pos = new_y;
7a13e894 10143 }
1fb20991 10144 }
0fdff6bb 10145#ifdef HACK_EDITRES
7a13e894
RS
10146 else if (event.xclient.message_type
10147 == dpyinfo->Xatom_editres)
10148 {
19126e11
KH
10149 struct frame *f
10150 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 10151 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 10152 &event, NULL);
7a13e894 10153 }
0fdff6bb 10154#endif /* HACK_EDITRES */
06a2c219
GM
10155 else if ((event.xclient.message_type
10156 == dpyinfo->Xatom_DONE)
10157 || (event.xclient.message_type
10158 == dpyinfo->Xatom_PAGE))
10159 {
10160 /* Ghostview job completed. Kill it. We could
10161 reply with "Next" if we received "Page", but we
10162 currently never do because we are interested in
10163 images, only, which should have 1 page. */
06a2c219
GM
10164 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
10165 struct frame *f
10166 = x_window_to_frame (dpyinfo, event.xclient.window);
10167 x_kill_gs_process (pixmap, f);
10168 expose_frame (f, 0, 0, 0, 0);
10169 }
10170#ifdef USE_TOOLKIT_SCROLL_BARS
10171 /* Scroll bar callbacks send a ClientMessage from which
10172 we construct an input_event. */
10173 else if (event.xclient.message_type
10174 == dpyinfo->Xatom_Scrollbar)
10175 {
10176 x_scroll_bar_to_input_event (&event, bufp);
10177 ++bufp, ++count, --numchars;
10178 goto out;
10179 }
10180#endif /* USE_TOOLKIT_SCROLL_BARS */
10181 else
10182 goto OTHER;
7a13e894
RS
10183 }
10184 break;
dc6f92b8 10185
7a13e894 10186 case SelectionNotify:
3afe33e7 10187#ifdef USE_X_TOOLKIT
19126e11 10188 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 10189 goto OTHER;
3afe33e7 10190#endif /* not USE_X_TOOLKIT */
dfcf069d 10191 x_handle_selection_notify (&event.xselection);
7a13e894 10192 break;
d56a553a 10193
06a2c219 10194 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 10195#ifdef USE_X_TOOLKIT
19126e11 10196 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 10197 goto OTHER;
3afe33e7 10198#endif /* USE_X_TOOLKIT */
7a13e894
RS
10199 {
10200 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 10201
7a13e894
RS
10202 if (numchars == 0)
10203 abort ();
d56a553a 10204
7a13e894
RS
10205 bufp->kind = selection_clear_event;
10206 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10207 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10208 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10209 bufp->frame_or_window = Qnil;
0f8aabe9 10210 bufp->arg = Qnil;
7a13e894 10211 bufp++;
d56a553a 10212
7a13e894
RS
10213 count += 1;
10214 numchars -= 1;
10215 }
10216 break;
dc6f92b8 10217
06a2c219 10218 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 10219#ifdef USE_X_TOOLKIT
19126e11 10220 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 10221 goto OTHER;
3afe33e7 10222#endif /* USE_X_TOOLKIT */
7a13e894 10223 if (x_queue_selection_requests)
19126e11 10224 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
10225 &event);
10226 else
10227 {
1d2b2268
GM
10228 XSelectionRequestEvent *eventp
10229 = (XSelectionRequestEvent *) &event;
dc6f92b8 10230
7a13e894
RS
10231 if (numchars == 0)
10232 abort ();
10233
10234 bufp->kind = selection_request_event;
10235 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10236 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
10237 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10238 SELECTION_EVENT_TARGET (bufp) = eventp->target;
10239 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
10240 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10241 bufp->frame_or_window = Qnil;
0f8aabe9 10242 bufp->arg = Qnil;
7a13e894
RS
10243 bufp++;
10244
10245 count += 1;
10246 numchars -= 1;
10247 }
10248 break;
10249
10250 case PropertyNotify:
1d2b2268
GM
10251#if 0 /* This is plain wrong. In the case that we are waiting for a
10252 PropertyNotify used as an ACK in incremental selection
10253 transfer, the property will be on the receiver's window. */
10254#if defined USE_X_TOOLKIT
19126e11 10255 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 10256 goto OTHER;
1d2b2268
GM
10257#endif
10258#endif
dfcf069d 10259 x_handle_property_notify (&event.xproperty);
1d2b2268 10260 goto OTHER;
dc6f92b8 10261
7a13e894 10262 case ReparentNotify:
19126e11 10263 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
10264 if (f)
10265 {
10266 int x, y;
7556890b 10267 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 10268 x_real_positions (f, &x, &y);
7556890b
RS
10269 f->output_data.x->left_pos = x;
10270 f->output_data.x->top_pos = y;
7a13e894
RS
10271 }
10272 break;
3bd330d4 10273
7a13e894 10274 case Expose:
19126e11 10275 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 10276 if (f)
dc6f92b8 10277 {
7a13e894
RS
10278 if (f->async_visible == 0)
10279 {
10280 f->async_visible = 1;
10281 f->async_iconified = 0;
06c488fd 10282 f->output_data.x->has_been_visible = 1;
7a13e894
RS
10283 SET_FRAME_GARBAGED (f);
10284 }
10285 else
06a2c219
GM
10286 expose_frame (x_window_to_frame (dpyinfo,
10287 event.xexpose.window),
10288 event.xexpose.x, event.xexpose.y,
10289 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
10290 }
10291 else
7a13e894 10292 {
12949a7f
EZ
10293#ifndef USE_TOOLKIT_SCROLL_BARS
10294 struct scroll_bar *bar;
10295#endif
01f67d2c 10296#if defined USE_LUCID
c95fc5f1
GM
10297 /* Submenus of the Lucid menu bar aren't widgets
10298 themselves, so there's no way to dispatch events
10299 to them. Recognize this case separately. */
10300 {
10301 Widget widget
10302 = x_window_to_menu_bar (event.xexpose.window);
10303 if (widget)
10304 xlwmenu_redisplay (widget);
10305 }
01f67d2c
PJ
10306#endif /* USE_LUCID */
10307
06a2c219
GM
10308#ifdef USE_TOOLKIT_SCROLL_BARS
10309 /* Dispatch event to the widget. */
10310 goto OTHER;
10311#else /* not USE_TOOLKIT_SCROLL_BARS */
12949a7f 10312 bar = x_window_to_scroll_bar (event.xexpose.window);
58769bee 10313
7a13e894
RS
10314 if (bar)
10315 x_scroll_bar_expose (bar, &event);
3afe33e7 10316#ifdef USE_X_TOOLKIT
7a13e894
RS
10317 else
10318 goto OTHER;
3afe33e7 10319#endif /* USE_X_TOOLKIT */
06a2c219 10320#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10321 }
10322 break;
dc6f92b8 10323
7a13e894 10324 case GraphicsExpose: /* This occurs when an XCopyArea's
d624284c
PJ
10325 source area was obscured or not
10326 available. */
19126e11 10327 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
10328 if (f)
10329 {
06a2c219
GM
10330 expose_frame (f,
10331 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
10332 event.xgraphicsexpose.width,
10333 event.xgraphicsexpose.height);
7a13e894 10334 }
3afe33e7 10335#ifdef USE_X_TOOLKIT
7a13e894
RS
10336 else
10337 goto OTHER;
3afe33e7 10338#endif /* USE_X_TOOLKIT */
7a13e894 10339 break;
dc6f92b8 10340
7a13e894 10341 case NoExpose: /* This occurs when an XCopyArea's
06a2c219 10342 source area was completely
d624284c 10343 available. */
7a13e894 10344 break;
dc6f92b8 10345
7a13e894 10346 case UnmapNotify:
06a2c219
GM
10347 /* Redo the mouse-highlight after the tooltip has gone. */
10348 if (event.xmap.window == tip_window)
10349 {
10350 tip_window = 0;
10351 redo_mouse_highlight ();
10352 }
10353
91ea2a7a 10354 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894 10355 if (f) /* F may no longer exist if
d624284c 10356 the frame was deleted. */
7a13e894
RS
10357 {
10358 /* While a frame is unmapped, display generation is
10359 disabled; you don't want to spend time updating a
10360 display that won't ever be seen. */
10361 f->async_visible = 0;
10362 /* We can't distinguish, from the event, whether the window
10363 has become iconified or invisible. So assume, if it
10364 was previously visible, than now it is iconified.
1aa6072f
RS
10365 But x_make_frame_invisible clears both
10366 the visible flag and the iconified flag;
10367 and that way, we know the window is not iconified now. */
7a13e894 10368 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
10369 {
10370 f->async_iconified = 1;
bddd097c 10371
1aa6072f
RS
10372 bufp->kind = iconify_event;
10373 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10374 bufp->arg = Qnil;
1aa6072f
RS
10375 bufp++;
10376 count++;
10377 numchars--;
10378 }
7a13e894 10379 }
7a13e894 10380 goto OTHER;
dc6f92b8 10381
7a13e894 10382 case MapNotify:
06a2c219
GM
10383 if (event.xmap.window == tip_window)
10384 /* The tooltip has been drawn already. Avoid
10385 the SET_FRAME_GARBAGED below. */
10386 goto OTHER;
10387
10388 /* We use x_top_window_to_frame because map events can
10389 come for sub-windows and they don't mean that the
10390 frame is visible. */
19126e11 10391 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
10392 if (f)
10393 {
10394 f->async_visible = 1;
10395 f->async_iconified = 0;
06c488fd 10396 f->output_data.x->has_been_visible = 1;
dc6f92b8 10397
7a13e894
RS
10398 /* wait_reading_process_input will notice this and update
10399 the frame's display structures. */
10400 SET_FRAME_GARBAGED (f);
bddd097c 10401
d806e720
RS
10402 if (f->iconified)
10403 {
10404 bufp->kind = deiconify_event;
10405 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10406 bufp->arg = Qnil;
d806e720
RS
10407 bufp++;
10408 count++;
10409 numchars--;
10410 }
e73ec6fa 10411 else if (! NILP (Vframe_list)
8e713be6 10412 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
10413 /* Force a redisplay sooner or later
10414 to update the frame titles
10415 in case this is the second frame. */
10416 record_asynch_buffer_change ();
7a13e894 10417 }
7a13e894 10418 goto OTHER;
dc6f92b8 10419
7a13e894 10420 case KeyPress:
19126e11 10421 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 10422
eccc05db 10423#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
10424 if (f == 0)
10425 {
2564ea1b
GM
10426 /* Scroll bars consume key events, but we want
10427 the keys to go to the scroll bar's frame. */
06a2c219
GM
10428 Widget widget = XtWindowToWidget (dpyinfo->display,
10429 event.xkey.window);
10430 if (widget && XmIsScrollBar (widget))
10431 {
10432 widget = XtParent (widget);
10433 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
10434 }
10435 }
eccc05db 10436#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
06a2c219 10437
7a13e894
RS
10438 if (f != 0)
10439 {
10440 KeySym keysym, orig_keysym;
379b5ac0
KH
10441 /* al%imercury@uunet.uu.net says that making this 81
10442 instead of 80 fixed a bug whereby meta chars made
10443 his Emacs hang.
10444
10445 It seems that some version of XmbLookupString has
10446 a bug of not returning XBufferOverflow in
10447 status_return even if the input is too long to
10448 fit in 81 bytes. So, we must prepare sufficient
10449 bytes for copy_buffer. 513 bytes (256 chars for
10450 two-byte character set) seems to be a faily good
10451 approximation. -- 2000.8.10 handa@etl.go.jp */
10452 unsigned char copy_buffer[513];
10453 unsigned char *copy_bufptr = copy_buffer;
10454 int copy_bufsiz = sizeof (copy_buffer);
7a13e894 10455 int modifiers;
64bb1782 10456
7a13e894
RS
10457 event.xkey.state
10458 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
10459 extra_keyboard_modifiers);
10460 modifiers = event.xkey.state;
3a2712f9 10461
7a13e894 10462 /* This will have to go some day... */
752a043f 10463
7a13e894
RS
10464 /* make_lispy_event turns chars into control chars.
10465 Don't do it here because XLookupString is too eager. */
10466 event.xkey.state &= ~ControlMask;
5d46f928
RS
10467 event.xkey.state &= ~(dpyinfo->meta_mod_mask
10468 | dpyinfo->super_mod_mask
10469 | dpyinfo->hyper_mod_mask
10470 | dpyinfo->alt_mod_mask);
10471
1cf4a0d1
RS
10472 /* In case Meta is ComposeCharacter,
10473 clear its status. According to Markus Ehrnsperger
10474 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
10475 this enables ComposeCharacter to work whether or
10476 not it is combined with Meta. */
10477 if (modifiers & dpyinfo->meta_mod_mask)
10478 bzero (&compose_status, sizeof (compose_status));
10479
6c183ba5
RS
10480#ifdef HAVE_X_I18N
10481 if (FRAME_XIC (f))
10482 {
f5d11644
GM
10483 Status status_return;
10484
6c183ba5 10485 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
10486 &event.xkey, copy_bufptr,
10487 copy_bufsiz, &keysym,
6c183ba5 10488 &status_return);
f5d11644
GM
10489 if (status_return == XBufferOverflow)
10490 {
10491 copy_bufsiz = nbytes + 1;
10492 copy_bufptr = (char *) alloca (copy_bufsiz);
10493 nbytes = XmbLookupString (FRAME_XIC (f),
10494 &event.xkey, copy_bufptr,
10495 copy_bufsiz, &keysym,
10496 &status_return);
10497 }
10498
1decb680
PE
10499 if (status_return == XLookupNone)
10500 break;
10501 else if (status_return == XLookupChars)
fdd9d55e
GM
10502 {
10503 keysym = NoSymbol;
10504 modifiers = 0;
10505 }
1decb680
PE
10506 else if (status_return != XLookupKeySym
10507 && status_return != XLookupBoth)
10508 abort ();
6c183ba5
RS
10509 }
10510 else
379b5ac0
KH
10511 nbytes = XLookupString (&event.xkey, copy_bufptr,
10512 copy_bufsiz, &keysym,
10513 &compose_status);
6c183ba5 10514#else
379b5ac0
KH
10515 nbytes = XLookupString (&event.xkey, copy_bufptr,
10516 copy_bufsiz, &keysym,
10517 &compose_status);
6c183ba5 10518#endif
dc6f92b8 10519
7a13e894 10520 orig_keysym = keysym;
55123275 10521
7a13e894
RS
10522 if (numchars > 1)
10523 {
10524 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
10525 || keysym == XK_Delete
1097aea0 10526#ifdef XK_ISO_Left_Tab
441affdb 10527 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 10528#endif
852bff8f 10529 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
10530 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
10531 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 10532#ifdef HPUX
7a13e894
RS
10533 /* This recognizes the "extended function keys".
10534 It seems there's no cleaner way.
10535 Test IsModifierKey to avoid handling mode_switch
10536 incorrectly. */
10537 || ((unsigned) (keysym) >= XK_Select
10538 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
10539#endif
10540#ifdef XK_dead_circumflex
7a13e894 10541 || orig_keysym == XK_dead_circumflex
69388238
RS
10542#endif
10543#ifdef XK_dead_grave
7a13e894 10544 || orig_keysym == XK_dead_grave
69388238
RS
10545#endif
10546#ifdef XK_dead_tilde
7a13e894 10547 || orig_keysym == XK_dead_tilde
69388238
RS
10548#endif
10549#ifdef XK_dead_diaeresis
7a13e894 10550 || orig_keysym == XK_dead_diaeresis
69388238
RS
10551#endif
10552#ifdef XK_dead_macron
7a13e894 10553 || orig_keysym == XK_dead_macron
69388238
RS
10554#endif
10555#ifdef XK_dead_degree
7a13e894 10556 || orig_keysym == XK_dead_degree
69388238
RS
10557#endif
10558#ifdef XK_dead_acute
7a13e894 10559 || orig_keysym == XK_dead_acute
69388238
RS
10560#endif
10561#ifdef XK_dead_cedilla
7a13e894 10562 || orig_keysym == XK_dead_cedilla
69388238
RS
10563#endif
10564#ifdef XK_dead_breve
7a13e894 10565 || orig_keysym == XK_dead_breve
69388238
RS
10566#endif
10567#ifdef XK_dead_ogonek
7a13e894 10568 || orig_keysym == XK_dead_ogonek
69388238
RS
10569#endif
10570#ifdef XK_dead_caron
7a13e894 10571 || orig_keysym == XK_dead_caron
69388238
RS
10572#endif
10573#ifdef XK_dead_doubleacute
7a13e894 10574 || orig_keysym == XK_dead_doubleacute
69388238
RS
10575#endif
10576#ifdef XK_dead_abovedot
7a13e894 10577 || orig_keysym == XK_dead_abovedot
c34790e0 10578#endif
7a13e894
RS
10579 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
10580 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
10581 /* Any "vendor-specific" key is ok. */
f0e299de
GM
10582 || (orig_keysym & (1 << 28))
10583 || (keysym != NoSymbol && nbytes == 0))
7a13e894 10584 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
10585#ifndef HAVE_X11R5
10586#ifdef XK_Mode_switch
7a13e894 10587 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
10588#endif
10589#ifdef XK_Num_Lock
7a13e894 10590 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
10591#endif
10592#endif /* not HAVE_X11R5 */
7a13e894 10593 ))
dc6f92b8 10594 {
10e6549c
RS
10595 if (temp_index == sizeof temp_buffer / sizeof (short))
10596 temp_index = 0;
7a13e894
RS
10597 temp_buffer[temp_index++] = keysym;
10598 bufp->kind = non_ascii_keystroke;
10599 bufp->code = keysym;
e0c1aef2 10600 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10601 bufp->arg = Qnil;
334208b7
RS
10602 bufp->modifiers
10603 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10604 modifiers);
1113d9db 10605 bufp->timestamp = event.xkey.time;
dc6f92b8 10606 bufp++;
7a13e894
RS
10607 count++;
10608 numchars--;
dc6f92b8 10609 }
7a13e894
RS
10610 else if (numchars > nbytes)
10611 {
10612 register int i;
379b5ac0 10613 register int c;
379b5ac0 10614 int nchars, len;
7a13e894
RS
10615
10616 for (i = 0; i < nbytes; i++)
10617 {
379b5ac0
KH
10618 if (temp_index == (sizeof temp_buffer
10619 / sizeof (short)))
7a13e894 10620 temp_index = 0;
379b5ac0
KH
10621 temp_buffer[temp_index++] = copy_bufptr[i];
10622 }
10623
10624 if (/* If the event is not from XIM, */
10625 event.xkey.keycode != 0
10626 /* or the current locale doesn't request
10627 decoding of the intup data, ... */
10628 || coding.type == coding_type_raw_text
10629 || coding.type == coding_type_no_conversion)
10630 {
10631 /* ... we can use the input data as is. */
10632 nchars = nbytes;
10633 }
10634 else
10635 {
10636 /* We have to decode the input data. */
10637 int require;
10638 unsigned char *p;
10639
10640 require = decoding_buffer_size (&coding, nbytes);
10641 p = (unsigned char *) alloca (require);
10642 coding.mode |= CODING_MODE_LAST_BLOCK;
10643 decode_coding (&coding, copy_bufptr, p,
10644 nbytes, require);
10645 nbytes = coding.produced;
10646 nchars = coding.produced_char;
10647 copy_bufptr = p;
10648 }
10649
10650 /* Convert the input data to a sequence of
10651 character events. */
10652 for (i = 0; i < nbytes; i += len)
10653 {
10654 c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
10655 nbytes - i, len);
10656 bufp->kind = (SINGLE_BYTE_CHAR_P (c)
10657 ? ascii_keystroke
10658 : multibyte_char_keystroke);
10659 bufp->code = c;
7a13e894 10660 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10661 bufp->arg = Qnil;
7a13e894
RS
10662 bufp->modifiers
10663 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10664 modifiers);
10665 bufp->timestamp = event.xkey.time;
10666 bufp++;
10667 }
10668
379b5ac0
KH
10669 count += nchars;
10670 numchars -= nchars;
1decb680
PE
10671
10672 if (keysym == NoSymbol)
10673 break;
7a13e894
RS
10674 }
10675 else
10676 abort ();
dc6f92b8 10677 }
10e6549c
RS
10678 else
10679 abort ();
dc6f92b8 10680 }
59ddecde
GM
10681#ifdef HAVE_X_I18N
10682 /* Don't dispatch this event since XtDispatchEvent calls
10683 XFilterEvent, and two calls in a row may freeze the
10684 client. */
10685 break;
10686#else
717ca130 10687 goto OTHER;
59ddecde 10688#endif
f451eb13 10689
f5d11644 10690 case KeyRelease:
59ddecde
GM
10691#ifdef HAVE_X_I18N
10692 /* Don't dispatch this event since XtDispatchEvent calls
10693 XFilterEvent, and two calls in a row may freeze the
10694 client. */
10695 break;
10696#else
f5d11644 10697 goto OTHER;
59ddecde 10698#endif
f5d11644 10699
7a13e894 10700 /* Here's a possible interpretation of the whole
06a2c219
GM
10701 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
10702 you get a FocusIn event, you have to get a FocusOut
10703 event before you relinquish the focus. If you
10704 haven't received a FocusIn event, then a mere
10705 LeaveNotify is enough to free you. */
f451eb13 10706
7a13e894 10707 case EnterNotify:
06a2c219 10708 {
06a2c219
GM
10709 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
10710
582c60f8 10711 if (event.xcrossing.focus)
06a2c219
GM
10712 {
10713 /* Avoid nasty pop/raise loops. */
10714 if (f && (!(f->auto_raise)
10715 || !(f->auto_lower)
10716 || (event.xcrossing.time - enter_timestamp) > 500))
10717 {
10718 x_new_focus_frame (dpyinfo, f);
10719 enter_timestamp = event.xcrossing.time;
10720 }
10721 }
10722 else if (f == dpyinfo->x_focus_frame)
10723 x_new_focus_frame (dpyinfo, 0);
10724
10725 /* EnterNotify counts as mouse movement,
10726 so update things that depend on mouse position. */
2533c408 10727 if (f && !f->output_data.x->hourglass_p)
06a2c219
GM
10728 note_mouse_movement (f, &event.xmotion);
10729 goto OTHER;
10730 }
dc6f92b8 10731
7a13e894 10732 case FocusIn:
19126e11 10733 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10734 if (event.xfocus.detail != NotifyPointer)
0f941935 10735 dpyinfo->x_focus_event_frame = f;
7a13e894 10736 if (f)
eb72635f
GM
10737 {
10738 x_new_focus_frame (dpyinfo, f);
10739
10740 /* Don't stop displaying the initial startup message
10741 for a switch-frame event we don't need. */
10742 if (GC_NILP (Vterminal_frame)
10743 && GC_CONSP (Vframe_list)
10744 && !GC_NILP (XCDR (Vframe_list)))
10745 {
10746 bufp->kind = FOCUS_IN_EVENT;
10747 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10748 bufp->arg = Qnil;
eb72635f
GM
10749 ++bufp, ++count, --numchars;
10750 }
10751 }
f9e24cb9 10752
6c183ba5
RS
10753#ifdef HAVE_X_I18N
10754 if (f && FRAME_XIC (f))
10755 XSetICFocus (FRAME_XIC (f));
10756#endif
10757
7a13e894 10758 goto OTHER;
10c5e63d 10759
7a13e894 10760 case LeaveNotify:
19126e11 10761 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 10762 if (f)
10c5e63d 10763 {
7a13e894 10764 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
10765 {
10766 /* If we move outside the frame, then we're
10767 certainly no longer on any text in the frame. */
10768 clear_mouse_face (dpyinfo);
10769 dpyinfo->mouse_face_mouse_frame = 0;
10770 }
10771
10772 /* Generate a nil HELP_EVENT to cancel a help-echo.
10773 Do it only if there's something to cancel.
10774 Otherwise, the startup message is cleared when
10775 the mouse leaves the frame. */
10776 if (any_help_event_p)
10777 {
be010514
GM
10778 Lisp_Object frame;
10779 int n;
10780
06a2c219 10781 XSETFRAME (frame, f);
82c5d67a 10782 help_echo = Qnil;
5ab2570d
GM
10783 n = gen_help_event (bufp, numchars,
10784 Qnil, frame, Qnil, Qnil, 0);
be010514 10785 bufp += n, count += n, numchars -= n;
06a2c219 10786 }
7a13e894 10787
582c60f8 10788 if (event.xcrossing.focus)
0f941935 10789 x_mouse_leave (dpyinfo);
10c5e63d 10790 else
7a13e894 10791 {
0f941935
KH
10792 if (f == dpyinfo->x_focus_event_frame)
10793 dpyinfo->x_focus_event_frame = 0;
10794 if (f == dpyinfo->x_focus_frame)
10795 x_new_focus_frame (dpyinfo, 0);
7a13e894 10796 }
10c5e63d 10797 }
7a13e894 10798 goto OTHER;
dc6f92b8 10799
7a13e894 10800 case FocusOut:
19126e11 10801 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10802 if (event.xfocus.detail != NotifyPointer
0f941935
KH
10803 && f == dpyinfo->x_focus_event_frame)
10804 dpyinfo->x_focus_event_frame = 0;
10805 if (f && f == dpyinfo->x_focus_frame)
10806 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 10807
6c183ba5
RS
10808#ifdef HAVE_X_I18N
10809 if (f && FRAME_XIC (f))
10810 XUnsetICFocus (FRAME_XIC (f));
10811#endif
10812
7a13e894 10813 goto OTHER;
dc6f92b8 10814
7a13e894 10815 case MotionNotify:
dc6f92b8 10816 {
06a2c219 10817 previous_help_echo = help_echo;
7cea38bc 10818 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 10819 help_echo_pos = -1;
06a2c219 10820
7a13e894
RS
10821 if (dpyinfo->grabbed && last_mouse_frame
10822 && FRAME_LIVE_P (last_mouse_frame))
10823 f = last_mouse_frame;
10824 else
19126e11 10825 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 10826
7a13e894
RS
10827 if (f)
10828 note_mouse_movement (f, &event.xmotion);
10829 else
10830 {
e88b3c50 10831#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10832 struct scroll_bar *bar
10833 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 10834
7a13e894
RS
10835 if (bar)
10836 x_scroll_bar_note_movement (bar, &event);
e88b3c50 10837#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 10838
06a2c219
GM
10839 /* If we move outside the frame, then we're
10840 certainly no longer on any text in the frame. */
7a13e894
RS
10841 clear_mouse_face (dpyinfo);
10842 }
06a2c219
GM
10843
10844 /* If the contents of the global variable help_echo
10845 has changed, generate a HELP_EVENT. */
b7e80413
SM
10846 if (!NILP (help_echo)
10847 || !NILP (previous_help_echo))
06a2c219
GM
10848 {
10849 Lisp_Object frame;
be010514 10850 int n;
06a2c219
GM
10851
10852 if (f)
10853 XSETFRAME (frame, f);
10854 else
10855 frame = Qnil;
10856
10857 any_help_event_p = 1;
5ab2570d 10858 n = gen_help_event (bufp, numchars, help_echo, frame,
7cea38bc
GM
10859 help_echo_window, help_echo_object,
10860 help_echo_pos);
be010514 10861 bufp += n, count += n, numchars -= n;
06a2c219
GM
10862 }
10863
10864 goto OTHER;
dc6f92b8 10865 }
dc6f92b8 10866
7a13e894 10867 case ConfigureNotify:
9829ddba
RS
10868 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
10869 if (f)
af395ec1 10870 {
5c187dee 10871#ifndef USE_X_TOOLKIT
bf1b7b30
KH
10872 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
10873 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 10874
2d7fc7e8
RS
10875 /* In the toolkit version, change_frame_size
10876 is called by the code that handles resizing
10877 of the EmacsFrame widget. */
7a13e894 10878
7a13e894
RS
10879 /* Even if the number of character rows and columns has
10880 not changed, the font size may have changed, so we need
10881 to check the pixel dimensions as well. */
10882 if (columns != f->width
10883 || rows != f->height
7556890b
RS
10884 || event.xconfigure.width != f->output_data.x->pixel_width
10885 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 10886 {
7d1e984f 10887 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 10888 SET_FRAME_GARBAGED (f);
e687d06e 10889 cancel_mouse_face (f);
7a13e894 10890 }
2d7fc7e8 10891#endif
af395ec1 10892
7556890b
RS
10893 f->output_data.x->pixel_width = event.xconfigure.width;
10894 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
10895
10896 /* What we have now is the position of Emacs's own window.
10897 Convert that to the position of the window manager window. */
dcb07ae9
RS
10898 x_real_positions (f, &f->output_data.x->left_pos,
10899 &f->output_data.x->top_pos);
10900
f5d11644
GM
10901#ifdef HAVE_X_I18N
10902 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
10903 xic_set_statusarea (f);
10904#endif
10905
dcb07ae9
RS
10906 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
10907 {
10908 /* Since the WM decorations come below top_pos now,
10909 we must put them below top_pos in the future. */
10910 f->output_data.x->win_gravity = NorthWestGravity;
10911 x_wm_set_size_hint (f, (long) 0, 0);
10912 }
8f08dc93
KH
10913#ifdef USE_MOTIF
10914 /* Some window managers pass (0,0) as the location of
10915 the window, and the Motif event handler stores it
10916 in the emacs widget, which messes up Motif menus. */
10917 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
10918 {
10919 event.xconfigure.x = f->output_data.x->widget->core.x;
10920 event.xconfigure.y = f->output_data.x->widget->core.y;
10921 }
06a2c219 10922#endif /* USE_MOTIF */
7a13e894 10923 }
2d7fc7e8 10924 goto OTHER;
dc6f92b8 10925
7a13e894
RS
10926 case ButtonPress:
10927 case ButtonRelease:
10928 {
10929 /* If we decide we want to generate an event to be seen
10930 by the rest of Emacs, we put it here. */
10931 struct input_event emacs_event;
9ea173e8 10932 int tool_bar_p = 0;
06a2c219 10933
7a13e894 10934 emacs_event.kind = no_event;
7a13e894 10935 bzero (&compose_status, sizeof (compose_status));
9b07615b 10936
06a2c219
GM
10937 if (dpyinfo->grabbed
10938 && last_mouse_frame
9f67f20b
RS
10939 && FRAME_LIVE_P (last_mouse_frame))
10940 f = last_mouse_frame;
10941 else
2224b905 10942 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 10943
06a2c219
GM
10944 if (f)
10945 {
9ea173e8
GM
10946 /* Is this in the tool-bar? */
10947 if (WINDOWP (f->tool_bar_window)
10948 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
10949 {
10950 Lisp_Object window;
10951 int p, x, y;
10952
10953 x = event.xbutton.x;
10954 y = event.xbutton.y;
10955
10956 /* Set x and y. */
10957 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 10958 if (EQ (window, f->tool_bar_window))
06a2c219 10959 {
9ea173e8
GM
10960 x_handle_tool_bar_click (f, &event.xbutton);
10961 tool_bar_p = 1;
06a2c219
GM
10962 }
10963 }
10964
9ea173e8 10965 if (!tool_bar_p)
06a2c219
GM
10966 if (!dpyinfo->x_focus_frame
10967 || f == dpyinfo->x_focus_frame)
10968 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
10969 }
10970 else
10971 {
06a2c219 10972#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10973 struct scroll_bar *bar
10974 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 10975
7a13e894
RS
10976 if (bar)
10977 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 10978#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10979 }
10980
10981 if (event.type == ButtonPress)
10982 {
10983 dpyinfo->grabbed |= (1 << event.xbutton.button);
10984 last_mouse_frame = f;
edad46f6
KH
10985 /* Ignore any mouse motion that happened
10986 before this event; any subsequent mouse-movement
10987 Emacs events should reflect only motion after
10988 the ButtonPress. */
a00e91cd
KH
10989 if (f != 0)
10990 f->mouse_moved = 0;
06a2c219 10991
9ea173e8
GM
10992 if (!tool_bar_p)
10993 last_tool_bar_item = -1;
7a13e894 10994 }
3afe33e7
RS
10995 else
10996 {
7a13e894 10997 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10998 }
23faf38f 10999
7a13e894
RS
11000 if (numchars >= 1 && emacs_event.kind != no_event)
11001 {
11002 bcopy (&emacs_event, bufp, sizeof (struct input_event));
11003 bufp++;
11004 count++;
11005 numchars--;
11006 }
3afe33e7
RS
11007
11008#ifdef USE_X_TOOLKIT
2224b905
RS
11009 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
11010 /* For a down-event in the menu bar,
11011 don't pass it to Xt right now.
11012 Instead, save it away
11013 and we will pass it to Xt from kbd_buffer_get_event.
11014 That way, we can run some Lisp code first. */
91375f8f
RS
11015 if (f && event.type == ButtonPress
11016 /* Verify the event is really within the menu bar
11017 and not just sent to it due to grabbing. */
11018 && event.xbutton.x >= 0
11019 && event.xbutton.x < f->output_data.x->pixel_width
11020 && event.xbutton.y >= 0
11021 && event.xbutton.y < f->output_data.x->menubar_height
11022 && event.xbutton.same_screen)
2224b905 11023 {
8805890a 11024 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
11025 XSETFRAME (last_mouse_press_frame, f);
11026 }
11027 else if (event.type == ButtonPress)
11028 {
11029 last_mouse_press_frame = Qnil;
30e671c3 11030 goto OTHER;
ce89ef46 11031 }
06a2c219 11032
2237cac9
RS
11033#ifdef USE_MOTIF /* This should do not harm for Lucid,
11034 but I am trying to be cautious. */
ce89ef46
RS
11035 else if (event.type == ButtonRelease)
11036 {
2237cac9 11037 if (!NILP (last_mouse_press_frame))
f10ded1c 11038 {
2237cac9
RS
11039 f = XFRAME (last_mouse_press_frame);
11040 if (f->output_data.x)
06a2c219 11041 SET_SAVED_BUTTON_EVENT;
f10ded1c 11042 }
06a2c219 11043 else
30e671c3 11044 goto OTHER;
2224b905 11045 }
2237cac9 11046#endif /* USE_MOTIF */
2224b905
RS
11047 else
11048 goto OTHER;
3afe33e7 11049#endif /* USE_X_TOOLKIT */
7a13e894
RS
11050 }
11051 break;
dc6f92b8 11052
7a13e894 11053 case CirculateNotify:
06a2c219
GM
11054 goto OTHER;
11055
7a13e894 11056 case CirculateRequest:
06a2c219
GM
11057 goto OTHER;
11058
11059 case VisibilityNotify:
11060 goto OTHER;
dc6f92b8 11061
7a13e894
RS
11062 case MappingNotify:
11063 /* Someone has changed the keyboard mapping - update the
11064 local cache. */
11065 switch (event.xmapping.request)
11066 {
11067 case MappingModifier:
11068 x_find_modifier_meanings (dpyinfo);
11069 /* This is meant to fall through. */
11070 case MappingKeyboard:
11071 XRefreshKeyboardMapping (&event.xmapping);
11072 }
7a13e894 11073 goto OTHER;
dc6f92b8 11074
7a13e894 11075 default:
7a13e894 11076 OTHER:
717ca130 11077#ifdef USE_X_TOOLKIT
7a13e894
RS
11078 BLOCK_INPUT;
11079 XtDispatchEvent (&event);
11080 UNBLOCK_INPUT;
3afe33e7 11081#endif /* USE_X_TOOLKIT */
7a13e894
RS
11082 break;
11083 }
dc6f92b8
JB
11084 }
11085 }
11086
06a2c219
GM
11087 out:;
11088
9a5196d0
RS
11089 /* On some systems, an X bug causes Emacs to get no more events
11090 when the window is destroyed. Detect that. (1994.) */
58769bee 11091 if (! event_found)
ef2a22d0 11092 {
ef2a22d0
RS
11093 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
11094 One XNOOP in 100 loops will make Emacs terminate.
11095 B. Bretthauer, 1994 */
11096 x_noop_count++;
58769bee 11097 if (x_noop_count >= 100)
ef2a22d0
RS
11098 {
11099 x_noop_count=0;
2224b905
RS
11100
11101 if (next_noop_dpyinfo == 0)
11102 next_noop_dpyinfo = x_display_list;
11103
11104 XNoOp (next_noop_dpyinfo->display);
11105
11106 /* Each time we get here, cycle through the displays now open. */
11107 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
11108 }
11109 }
502add23 11110
06a2c219 11111 /* If the focus was just given to an auto-raising frame,
0134a210 11112 raise it now. */
7a13e894 11113 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
11114 if (pending_autoraise_frame)
11115 {
11116 x_raise_frame (pending_autoraise_frame);
11117 pending_autoraise_frame = 0;
11118 }
0134a210 11119
dc6f92b8 11120 UNBLOCK_INPUT;
bde5503b 11121 --handling_signal;
dc6f92b8
JB
11122 return count;
11123}
06a2c219
GM
11124
11125
11126
dc6f92b8 11127\f
06a2c219
GM
11128/***********************************************************************
11129 Text Cursor
11130 ***********************************************************************/
11131
78a9a4c5 11132/* Notice if the text cursor of window W has been overwritten by a
06a2c219 11133 drawing operation that outputs N glyphs starting at HPOS in the
78a9a4c5
GM
11134 line given by output_cursor.vpos.
11135
11136 N < 0 means all the rest of the line after HPOS has been
11137 written. */
06a2c219
GM
11138
11139static void
78a9a4c5 11140notice_overwritten_cursor (w, hpos, n)
06a2c219
GM
11141 struct window *w;
11142 int hpos, n;
11143{
11144 if (updated_area == TEXT_AREA
11145 && output_cursor.vpos == w->phys_cursor.vpos
78a9a4c5
GM
11146 && output_cursor.x <= w->phys_cursor.x
11147 && w->phys_cursor_on_p)
11148 {
11149 if (n < 0)
11150 w->phys_cursor_on_p = 0;
11151 else
11152 {
11153 /* It depends on the width of the N glyphs written at HPOS
11154 if the cursor has been overwritten or not. */
11155 struct glyph *glyph = &updated_row->glyphs[TEXT_AREA][hpos];
11156 struct glyph *end = glyph + n;
11157 int width = 0;
11158
11159 for (; glyph < end; ++glyph)
11160 width += glyph->pixel_width;
11161
11162 if (output_cursor.x + width > w->phys_cursor.x)
11163 w->phys_cursor_on_p = 0;
11164 }
11165 }
06a2c219 11166}
f451eb13
JB
11167
11168
06a2c219
GM
11169/* Set clipping for output in glyph row ROW. W is the window in which
11170 we operate. GC is the graphics context to set clipping in.
11171 WHOLE_LINE_P non-zero means include the areas used for truncation
11172 mark display and alike in the clipping rectangle.
11173
11174 ROW may be a text row or, e.g., a mode line. Text rows must be
11175 clipped to the interior of the window dedicated to text display,
11176 mode lines must be clipped to the whole window. */
dc6f92b8
JB
11177
11178static void
06a2c219
GM
11179x_clip_to_row (w, row, gc, whole_line_p)
11180 struct window *w;
11181 struct glyph_row *row;
11182 GC gc;
11183 int whole_line_p;
dc6f92b8 11184{
06a2c219
GM
11185 struct frame *f = XFRAME (WINDOW_FRAME (w));
11186 XRectangle clip_rect;
11187 int window_x, window_y, window_width, window_height;
dc6f92b8 11188
06a2c219 11189 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 11190
06a2c219
GM
11191 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
11192 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
11193 clip_rect.y = max (clip_rect.y, window_y);
11194 clip_rect.width = window_width;
11195 clip_rect.height = row->visible_height;
5c1aae96 11196
06a2c219
GM
11197 /* If clipping to the whole line, including trunc marks, extend
11198 the rectangle to the left and increase its width. */
11199 if (whole_line_p)
11200 {
110859fc
GM
11201 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
11202 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 11203 }
5c1aae96 11204
06a2c219 11205 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
11206}
11207
06a2c219
GM
11208
11209/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
11210
11211static void
06a2c219
GM
11212x_draw_hollow_cursor (w, row)
11213 struct window *w;
11214 struct glyph_row *row;
dc6f92b8 11215{
06a2c219
GM
11216 struct frame *f = XFRAME (WINDOW_FRAME (w));
11217 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11218 Display *dpy = FRAME_X_DISPLAY (f);
11219 int x, y, wd, h;
11220 XGCValues xgcv;
11221 struct glyph *cursor_glyph;
11222 GC gc;
11223
11224 /* Compute frame-relative coordinates from window-relative
11225 coordinates. */
11226 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11227 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
11228 + row->ascent - w->phys_cursor_ascent);
11229 h = row->height - 1;
11230
11231 /* Get the glyph the cursor is on. If we can't tell because
11232 the current matrix is invalid or such, give up. */
11233 cursor_glyph = get_phys_cursor_glyph (w);
11234 if (cursor_glyph == NULL)
dc6f92b8
JB
11235 return;
11236
06a2c219
GM
11237 /* Compute the width of the rectangle to draw. If on a stretch
11238 glyph, and `x-stretch-block-cursor' is nil, don't draw a
11239 rectangle as wide as the glyph, but use a canonical character
11240 width instead. */
11241 wd = cursor_glyph->pixel_width - 1;
11242 if (cursor_glyph->type == STRETCH_GLYPH
11243 && !x_stretch_cursor_p)
11244 wd = min (CANON_X_UNIT (f), wd);
11245
11246 /* The foreground of cursor_gc is typically the same as the normal
11247 background color, which can cause the cursor box to be invisible. */
11248 xgcv.foreground = f->output_data.x->cursor_pixel;
11249 if (dpyinfo->scratch_cursor_gc)
11250 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
11251 else
11252 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
11253 GCForeground, &xgcv);
11254 gc = dpyinfo->scratch_cursor_gc;
11255
11256 /* Set clipping, draw the rectangle, and reset clipping again. */
11257 x_clip_to_row (w, row, gc, 0);
11258 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
11259 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
11260}
11261
06a2c219
GM
11262
11263/* Draw a bar cursor on window W in glyph row ROW.
11264
11265 Implementation note: One would like to draw a bar cursor with an
11266 angle equal to the one given by the font property XA_ITALIC_ANGLE.
11267 Unfortunately, I didn't find a font yet that has this property set.
11268 --gerd. */
dc6f92b8
JB
11269
11270static void
f02d8aa0 11271x_draw_bar_cursor (w, row, width)
06a2c219
GM
11272 struct window *w;
11273 struct glyph_row *row;
f02d8aa0 11274 int width;
dc6f92b8 11275{
92f424df
GM
11276 struct frame *f = XFRAME (w->frame);
11277 struct glyph *cursor_glyph;
11278 GC gc;
11279 int x;
11280 unsigned long mask;
11281 XGCValues xgcv;
11282 Display *dpy;
11283 Window window;
06a2c219 11284
92f424df
GM
11285 /* If cursor is out of bounds, don't draw garbage. This can happen
11286 in mini-buffer windows when switching between echo area glyphs
11287 and mini-buffer. */
11288 cursor_glyph = get_phys_cursor_glyph (w);
11289 if (cursor_glyph == NULL)
11290 return;
06a2c219 11291
92f424df
GM
11292 /* If on an image, draw like a normal cursor. That's usually better
11293 visible than drawing a bar, esp. if the image is large so that
11294 the bar might not be in the window. */
11295 if (cursor_glyph->type == IMAGE_GLYPH)
11296 {
11297 struct glyph_row *row;
11298 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
11299 x_draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
11300 }
11301 else
11302 {
06a2c219
GM
11303 xgcv.background = f->output_data.x->cursor_pixel;
11304 xgcv.foreground = f->output_data.x->cursor_pixel;
11305 xgcv.graphics_exposures = 0;
11306 mask = GCForeground | GCBackground | GCGraphicsExposures;
11307 dpy = FRAME_X_DISPLAY (f);
11308 window = FRAME_X_WINDOW (f);
11309 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
92f424df 11310
06a2c219
GM
11311 if (gc)
11312 XChangeGC (dpy, gc, mask, &xgcv);
11313 else
11314 {
11315 gc = XCreateGC (dpy, window, mask, &xgcv);
11316 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
11317 }
92f424df 11318
f02d8aa0
GM
11319 if (width < 0)
11320 width = f->output_data.x->cursor_width;
92f424df 11321
06a2c219
GM
11322 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11323 x_clip_to_row (w, row, gc, 0);
11324 XFillRectangle (dpy, window, gc,
11325 x,
11326 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
f02d8aa0 11327 min (cursor_glyph->pixel_width, width),
06a2c219
GM
11328 row->height);
11329 XSetClipMask (dpy, gc, None);
11330 }
dc6f92b8
JB
11331}
11332
06a2c219
GM
11333
11334/* Clear the cursor of window W to background color, and mark the
11335 cursor as not shown. This is used when the text where the cursor
11336 is is about to be rewritten. */
11337
dc6f92b8 11338static void
06a2c219
GM
11339x_clear_cursor (w)
11340 struct window *w;
dc6f92b8 11341{
06a2c219
GM
11342 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
11343 x_update_window_cursor (w, 0);
11344}
90e65f07 11345
dbc4e1c1 11346
06a2c219
GM
11347/* Draw the cursor glyph of window W in glyph row ROW. See the
11348 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 11349
06a2c219
GM
11350static void
11351x_draw_phys_cursor_glyph (w, row, hl)
11352 struct window *w;
11353 struct glyph_row *row;
11354 enum draw_glyphs_face hl;
11355{
11356 /* If cursor hpos is out of bounds, don't draw garbage. This can
11357 happen in mini-buffer windows when switching between echo area
11358 glyphs and mini-buffer. */
11359 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e
GM
11360 {
11361 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
11362 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
11363 hl, 0, 0, 0);
11364
11365 /* When we erase the cursor, and ROW is overlapped by other
11366 rows, make sure that these overlapping parts of other rows
11367 are redrawn. */
11368 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
11369 {
11370 if (row > w->current_matrix->rows
11371 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
11372 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
11373
11374 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
11375 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
11376 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
11377 }
11378 }
06a2c219 11379}
dbc4e1c1 11380
eea6af04 11381
06a2c219 11382/* Erase the image of a cursor of window W from the screen. */
eea6af04 11383
06a2c219
GM
11384static void
11385x_erase_phys_cursor (w)
11386 struct window *w;
11387{
11388 struct frame *f = XFRAME (w->frame);
11389 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11390 int hpos = w->phys_cursor.hpos;
11391 int vpos = w->phys_cursor.vpos;
11392 int mouse_face_here_p = 0;
11393 struct glyph_matrix *active_glyphs = w->current_matrix;
11394 struct glyph_row *cursor_row;
11395 struct glyph *cursor_glyph;
11396 enum draw_glyphs_face hl;
11397
11398 /* No cursor displayed or row invalidated => nothing to do on the
11399 screen. */
11400 if (w->phys_cursor_type == NO_CURSOR)
11401 goto mark_cursor_off;
11402
11403 /* VPOS >= active_glyphs->nrows means that window has been resized.
11404 Don't bother to erase the cursor. */
11405 if (vpos >= active_glyphs->nrows)
11406 goto mark_cursor_off;
11407
11408 /* If row containing cursor is marked invalid, there is nothing we
11409 can do. */
11410 cursor_row = MATRIX_ROW (active_glyphs, vpos);
11411 if (!cursor_row->enabled_p)
11412 goto mark_cursor_off;
11413
11414 /* This can happen when the new row is shorter than the old one.
11415 In this case, either x_draw_glyphs or clear_end_of_line
11416 should have cleared the cursor. Note that we wouldn't be
11417 able to erase the cursor in this case because we don't have a
11418 cursor glyph at hand. */
11419 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
11420 goto mark_cursor_off;
11421
11422 /* If the cursor is in the mouse face area, redisplay that when
11423 we clear the cursor. */
8801a864
KR
11424 if (! NILP (dpyinfo->mouse_face_window)
11425 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
11426 && (vpos > dpyinfo->mouse_face_beg_row
11427 || (vpos == dpyinfo->mouse_face_beg_row
11428 && hpos >= dpyinfo->mouse_face_beg_col))
11429 && (vpos < dpyinfo->mouse_face_end_row
11430 || (vpos == dpyinfo->mouse_face_end_row
11431 && hpos < dpyinfo->mouse_face_end_col))
11432 /* Don't redraw the cursor's spot in mouse face if it is at the
11433 end of a line (on a newline). The cursor appears there, but
11434 mouse highlighting does not. */
11435 && cursor_row->used[TEXT_AREA] > hpos)
11436 mouse_face_here_p = 1;
11437
11438 /* Maybe clear the display under the cursor. */
11439 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
11440 {
11441 int x;
045dee35 11442 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 11443
06a2c219
GM
11444 cursor_glyph = get_phys_cursor_glyph (w);
11445 if (cursor_glyph == NULL)
11446 goto mark_cursor_off;
dbc4e1c1 11447
e0300d33 11448 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
06a2c219 11449
c5e6e06b
GM
11450 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11451 x,
11452 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
11453 cursor_row->y)),
11454 cursor_glyph->pixel_width,
11455 cursor_row->visible_height,
11456 False);
dbc4e1c1 11457 }
06a2c219
GM
11458
11459 /* Erase the cursor by redrawing the character underneath it. */
11460 if (mouse_face_here_p)
11461 hl = DRAW_MOUSE_FACE;
11462 else if (cursor_row->inverse_p)
11463 hl = DRAW_INVERSE_VIDEO;
11464 else
11465 hl = DRAW_NORMAL_TEXT;
11466 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 11467
06a2c219
GM
11468 mark_cursor_off:
11469 w->phys_cursor_on_p = 0;
11470 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
11471}
11472
11473
b7f83f9e
GM
11474/* Non-zero if physical cursor of window W is within mouse face. */
11475
11476static int
11477cursor_in_mouse_face_p (w)
11478 struct window *w;
11479{
11480 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
11481 int in_mouse_face = 0;
11482
11483 if (WINDOWP (dpyinfo->mouse_face_window)
11484 && XWINDOW (dpyinfo->mouse_face_window) == w)
11485 {
11486 int hpos = w->phys_cursor.hpos;
11487 int vpos = w->phys_cursor.vpos;
11488
11489 if (vpos >= dpyinfo->mouse_face_beg_row
11490 && vpos <= dpyinfo->mouse_face_end_row
11491 && (vpos > dpyinfo->mouse_face_beg_row
11492 || hpos >= dpyinfo->mouse_face_beg_col)
11493 && (vpos < dpyinfo->mouse_face_end_row
11494 || hpos < dpyinfo->mouse_face_end_col
11495 || dpyinfo->mouse_face_past_end))
11496 in_mouse_face = 1;
11497 }
11498
11499 return in_mouse_face;
11500}
11501
11502
06a2c219
GM
11503/* Display or clear cursor of window W. If ON is zero, clear the
11504 cursor. If it is non-zero, display the cursor. If ON is nonzero,
11505 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 11506
06a2c219
GM
11507void
11508x_display_and_set_cursor (w, on, hpos, vpos, x, y)
11509 struct window *w;
11510 int on, hpos, vpos, x, y;
dbc4e1c1 11511{
06a2c219
GM
11512 struct frame *f = XFRAME (w->frame);
11513 int new_cursor_type;
f02d8aa0 11514 int new_cursor_width;
06a2c219
GM
11515 struct glyph_matrix *current_glyphs;
11516 struct glyph_row *glyph_row;
11517 struct glyph *glyph;
dbc4e1c1 11518
49d838ea 11519 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
11520 windows and frames; in the latter case, the frame or window may
11521 be in the midst of changing its size, and x and y may be off the
11522 window. */
11523 if (! FRAME_VISIBLE_P (f)
11524 || FRAME_GARBAGED_P (f)
11525 || vpos >= w->current_matrix->nrows
11526 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
11527 return;
11528
11529 /* If cursor is off and we want it off, return quickly. */
06a2c219 11530 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
11531 return;
11532
06a2c219
GM
11533 current_glyphs = w->current_matrix;
11534 glyph_row = MATRIX_ROW (current_glyphs, vpos);
11535 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
11536
11537 /* If cursor row is not enabled, we don't really know where to
11538 display the cursor. */
11539 if (!glyph_row->enabled_p)
11540 {
11541 w->phys_cursor_on_p = 0;
11542 return;
11543 }
11544
11545 xassert (interrupt_input_blocked);
11546
11547 /* Set new_cursor_type to the cursor we want to be displayed. In a
11548 mini-buffer window, we want the cursor only to appear if we are
11549 reading input from this window. For the selected window, we want
11550 the cursor type given by the frame parameter. If explicitly
11551 marked off, draw no cursor. In all other cases, we want a hollow
11552 box cursor. */
f02d8aa0 11553 new_cursor_width = -1;
9b4a7047
GM
11554 if (cursor_in_echo_area
11555 && FRAME_HAS_MINIBUF_P (f)
11556 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 11557 {
9b4a7047
GM
11558 if (w == XWINDOW (echo_area_window))
11559 new_cursor_type = FRAME_DESIRED_CURSOR (f);
06a2c219
GM
11560 else
11561 new_cursor_type = HOLLOW_BOX_CURSOR;
11562 }
06a2c219 11563 else
9b4a7047 11564 {
7a58ab59
GM
11565 if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
11566 || w != XWINDOW (f->selected_window))
9b4a7047 11567 {
e55a0b79
GM
11568 extern int cursor_in_non_selected_windows;
11569
5cefa566
GM
11570 if (MINI_WINDOW_P (w)
11571 || !cursor_in_non_selected_windows
11572 || NILP (XBUFFER (w->buffer)->cursor_type))
9b4a7047
GM
11573 new_cursor_type = NO_CURSOR;
11574 else
11575 new_cursor_type = HOLLOW_BOX_CURSOR;
11576 }
11577 else if (w->cursor_off_p)
11578 new_cursor_type = NO_CURSOR;
11579 else
f02d8aa0
GM
11580 {
11581 struct buffer *b = XBUFFER (w->buffer);
11582
11583 if (EQ (b->cursor_type, Qt))
11584 new_cursor_type = FRAME_DESIRED_CURSOR (f);
11585 else
11586 new_cursor_type = x_specified_cursor_type (b->cursor_type,
11587 &new_cursor_width);
11588 }
9b4a7047 11589 }
06a2c219
GM
11590
11591 /* If cursor is currently being shown and we don't want it to be or
11592 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 11593 erase it. */
06a2c219 11594 if (w->phys_cursor_on_p
dc6f92b8 11595 && (!on
06a2c219
GM
11596 || w->phys_cursor.x != x
11597 || w->phys_cursor.y != y
11598 || new_cursor_type != w->phys_cursor_type))
11599 x_erase_phys_cursor (w);
11600
11601 /* If the cursor is now invisible and we want it to be visible,
11602 display it. */
11603 if (on && !w->phys_cursor_on_p)
11604 {
11605 w->phys_cursor_ascent = glyph_row->ascent;
11606 w->phys_cursor_height = glyph_row->height;
11607
11608 /* Set phys_cursor_.* before x_draw_.* is called because some
11609 of them may need the information. */
11610 w->phys_cursor.x = x;
11611 w->phys_cursor.y = glyph_row->y;
11612 w->phys_cursor.hpos = hpos;
11613 w->phys_cursor.vpos = vpos;
11614 w->phys_cursor_type = new_cursor_type;
11615 w->phys_cursor_on_p = 1;
11616
11617 switch (new_cursor_type)
dc6f92b8 11618 {
06a2c219
GM
11619 case HOLLOW_BOX_CURSOR:
11620 x_draw_hollow_cursor (w, glyph_row);
11621 break;
11622
11623 case FILLED_BOX_CURSOR:
11624 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
11625 break;
11626
11627 case BAR_CURSOR:
f02d8aa0 11628 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
11629 break;
11630
11631 case NO_CURSOR:
11632 break;
dc6f92b8 11633
06a2c219
GM
11634 default:
11635 abort ();
11636 }
59ddecde
GM
11637
11638#ifdef HAVE_X_I18N
11639 if (w == XWINDOW (f->selected_window))
11640 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
11641 xic_set_preeditarea (w, x, y);
11642#endif
dc6f92b8
JB
11643 }
11644
06a2c219 11645#ifndef XFlush
f676886a 11646 if (updating_frame != f)
334208b7 11647 XFlush (FRAME_X_DISPLAY (f));
06a2c219 11648#endif
dc6f92b8
JB
11649}
11650
06a2c219
GM
11651
11652/* Display the cursor on window W, or clear it. X and Y are window
11653 relative pixel coordinates. HPOS and VPOS are glyph matrix
11654 positions. If W is not the selected window, display a hollow
11655 cursor. ON non-zero means display the cursor at X, Y which
11656 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 11657
dfcf069d 11658void
06a2c219
GM
11659x_display_cursor (w, on, hpos, vpos, x, y)
11660 struct window *w;
11661 int on, hpos, vpos, x, y;
dc6f92b8 11662{
f94397b5 11663 BLOCK_INPUT;
06a2c219 11664 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
11665 UNBLOCK_INPUT;
11666}
11667
06a2c219
GM
11668
11669/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
11670 Don't change the cursor's position. */
11671
dfcf069d 11672void
06a2c219 11673x_update_cursor (f, on_p)
5d46f928 11674 struct frame *f;
5d46f928 11675{
06a2c219
GM
11676 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
11677}
11678
11679
11680/* Call x_update_window_cursor with parameter ON_P on all leaf windows
11681 in the window tree rooted at W. */
11682
11683static void
11684x_update_cursor_in_window_tree (w, on_p)
11685 struct window *w;
11686 int on_p;
11687{
11688 while (w)
11689 {
11690 if (!NILP (w->hchild))
11691 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
11692 else if (!NILP (w->vchild))
11693 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
11694 else
11695 x_update_window_cursor (w, on_p);
11696
11697 w = NILP (w->next) ? 0 : XWINDOW (w->next);
11698 }
11699}
5d46f928 11700
f94397b5 11701
06a2c219
GM
11702/* Switch the display of W's cursor on or off, according to the value
11703 of ON. */
11704
11705static void
11706x_update_window_cursor (w, on)
11707 struct window *w;
11708 int on;
11709{
16b5d424
GM
11710 /* Don't update cursor in windows whose frame is in the process
11711 of being deleted. */
11712 if (w->current_matrix)
11713 {
11714 BLOCK_INPUT;
11715 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
11716 w->phys_cursor.x, w->phys_cursor.y);
11717 UNBLOCK_INPUT;
11718 }
dc6f92b8 11719}
06a2c219
GM
11720
11721
11722
dc6f92b8
JB
11723\f
11724/* Icons. */
11725
dbc4e1c1 11726/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
11727
11728int
990ba854 11729x_bitmap_icon (f, file)
f676886a 11730 struct frame *f;
990ba854 11731 Lisp_Object file;
dc6f92b8 11732{
06a2c219 11733 int bitmap_id;
dc6f92b8 11734
c118dd06 11735 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11736 return 1;
11737
990ba854 11738 /* Free up our existing icon bitmap if any. */
7556890b
RS
11739 if (f->output_data.x->icon_bitmap > 0)
11740 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11741 f->output_data.x->icon_bitmap = 0;
990ba854
RS
11742
11743 if (STRINGP (file))
7f2ae036
RS
11744 bitmap_id = x_create_bitmap_from_file (f, file);
11745 else
11746 {
990ba854 11747 /* Create the GNU bitmap if necessary. */
5bf01b68 11748 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
11749 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
11750 = x_create_bitmap_from_data (f, gnu_bits,
11751 gnu_width, gnu_height);
990ba854
RS
11752
11753 /* The first time we create the GNU bitmap,
06a2c219 11754 this increments the ref-count one extra time.
990ba854
RS
11755 As a result, the GNU bitmap is never freed.
11756 That way, we don't have to worry about allocating it again. */
334208b7 11757 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 11758
334208b7 11759 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
11760 }
11761
11762 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 11763 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
11764
11765 return 0;
11766}
11767
11768
1be2d067
KH
11769/* Make the x-window of frame F use a rectangle with text.
11770 Use ICON_NAME as the text. */
dc6f92b8
JB
11771
11772int
f676886a
JB
11773x_text_icon (f, icon_name)
11774 struct frame *f;
dc6f92b8
JB
11775 char *icon_name;
11776{
c118dd06 11777 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11778 return 1;
11779
1be2d067
KH
11780#ifdef HAVE_X11R4
11781 {
11782 XTextProperty text;
11783 text.value = (unsigned char *) icon_name;
11784 text.encoding = XA_STRING;
11785 text.format = 8;
11786 text.nitems = strlen (icon_name);
11787#ifdef USE_X_TOOLKIT
7556890b 11788 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
11789 &text);
11790#else /* not USE_X_TOOLKIT */
11791 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
11792#endif /* not USE_X_TOOLKIT */
11793 }
11794#else /* not HAVE_X11R4 */
11795 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
11796#endif /* not HAVE_X11R4 */
58769bee 11797
7556890b
RS
11798 if (f->output_data.x->icon_bitmap > 0)
11799 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11800 f->output_data.x->icon_bitmap = 0;
b1c884c3 11801 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
11802
11803 return 0;
11804}
11805\f
e99db5a1
RS
11806#define X_ERROR_MESSAGE_SIZE 200
11807
11808/* If non-nil, this should be a string.
11809 It means catch X errors and store the error message in this string. */
11810
11811static Lisp_Object x_error_message_string;
11812
11813/* An X error handler which stores the error message in
11814 x_error_message_string. This is called from x_error_handler if
11815 x_catch_errors is in effect. */
11816
06a2c219 11817static void
e99db5a1
RS
11818x_error_catcher (display, error)
11819 Display *display;
11820 XErrorEvent *error;
11821{
11822 XGetErrorText (display, error->error_code,
11823 XSTRING (x_error_message_string)->data,
11824 X_ERROR_MESSAGE_SIZE);
11825}
11826
11827/* Begin trapping X errors for display DPY. Actually we trap X errors
11828 for all displays, but DPY should be the display you are actually
11829 operating on.
11830
11831 After calling this function, X protocol errors no longer cause
11832 Emacs to exit; instead, they are recorded in the string
11833 stored in x_error_message_string.
11834
11835 Calling x_check_errors signals an Emacs error if an X error has
11836 occurred since the last call to x_catch_errors or x_check_errors.
11837
11838 Calling x_uncatch_errors resumes the normal error handling. */
11839
11840void x_check_errors ();
11841static Lisp_Object x_catch_errors_unwind ();
11842
11843int
11844x_catch_errors (dpy)
11845 Display *dpy;
11846{
11847 int count = specpdl_ptr - specpdl;
11848
11849 /* Make sure any errors from previous requests have been dealt with. */
11850 XSync (dpy, False);
11851
11852 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
11853
11854 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
11855 XSTRING (x_error_message_string)->data[0] = 0;
11856
11857 return count;
11858}
11859
11860/* Unbind the binding that we made to check for X errors. */
11861
11862static Lisp_Object
11863x_catch_errors_unwind (old_val)
11864 Lisp_Object old_val;
11865{
11866 x_error_message_string = old_val;
11867 return Qnil;
11868}
11869
11870/* If any X protocol errors have arrived since the last call to
11871 x_catch_errors or x_check_errors, signal an Emacs error using
11872 sprintf (a buffer, FORMAT, the x error message text) as the text. */
11873
11874void
11875x_check_errors (dpy, format)
11876 Display *dpy;
11877 char *format;
11878{
11879 /* Make sure to catch any errors incurred so far. */
11880 XSync (dpy, False);
11881
11882 if (XSTRING (x_error_message_string)->data[0])
11883 error (format, XSTRING (x_error_message_string)->data);
11884}
11885
9829ddba
RS
11886/* Nonzero if we had any X protocol errors
11887 since we did x_catch_errors on DPY. */
e99db5a1
RS
11888
11889int
11890x_had_errors_p (dpy)
11891 Display *dpy;
11892{
11893 /* Make sure to catch any errors incurred so far. */
11894 XSync (dpy, False);
11895
11896 return XSTRING (x_error_message_string)->data[0] != 0;
11897}
11898
9829ddba
RS
11899/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
11900
06a2c219 11901void
9829ddba
RS
11902x_clear_errors (dpy)
11903 Display *dpy;
11904{
11905 XSTRING (x_error_message_string)->data[0] = 0;
11906}
11907
e99db5a1
RS
11908/* Stop catching X protocol errors and let them make Emacs die.
11909 DPY should be the display that was passed to x_catch_errors.
11910 COUNT should be the value that was returned by
11911 the corresponding call to x_catch_errors. */
11912
11913void
11914x_uncatch_errors (dpy, count)
11915 Display *dpy;
11916 int count;
11917{
11918 unbind_to (count, Qnil);
11919}
11920
11921#if 0
11922static unsigned int x_wire_count;
11923x_trace_wire ()
11924{
11925 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
11926}
11927#endif /* ! 0 */
11928
11929\f
11930/* Handle SIGPIPE, which can happen when the connection to a server
11931 simply goes away. SIGPIPE is handled by x_connection_signal.
11932 Don't need to do anything, because the write which caused the
11933 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 11934 which will do the appropriate cleanup for us. */
e99db5a1
RS
11935
11936static SIGTYPE
11937x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 11938 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
11939{
11940#ifdef USG
11941 /* USG systems forget handlers when they are used;
11942 must reestablish each time */
11943 signal (signalnum, x_connection_signal);
11944#endif /* USG */
11945}
0da1ab50 11946
e99db5a1 11947\f
0da1ab50
GM
11948/************************************************************************
11949 Handling X errors
11950 ************************************************************************/
4746118a 11951
f0e299de
GM
11952/* Error message passed to x_connection_closed. */
11953
11954static char *error_msg;
11955
11956/* Function installed as fatal_error_signal_hook.in
11957 x_connection_closed. Print the X error message, and exit normally,
11958 instead of dumping core when XtCloseDisplay fails. */
11959
11960static void
11961x_fatal_error_signal ()
11962{
11963 fprintf (stderr, "%s\n", error_msg);
11964 exit (70);
11965}
11966
0da1ab50
GM
11967/* Handle the loss of connection to display DPY. ERROR_MESSAGE is
11968 the text of an error message that lead to the connection loss. */
16bd92ea 11969
4746118a 11970static SIGTYPE
5978125e
GM
11971x_connection_closed (dpy, error_message)
11972 Display *dpy;
7a13e894 11973 char *error_message;
4746118a 11974{
5978125e 11975 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
7a13e894 11976 Lisp_Object frame, tail;
0da1ab50 11977 int count;
0da1ab50 11978
f0e299de
GM
11979 error_msg = (char *) alloca (strlen (error_message) + 1);
11980 strcpy (error_msg, error_message);
1a532e54
GM
11981 handling_signal = 0;
11982
0da1ab50
GM
11983 /* Prevent being called recursively because of an error condition
11984 below. Otherwise, we might end up with printing ``can't find per
11985 display information'' in the recursive call instead of printing
11986 the original message here. */
11987 count = x_catch_errors (dpy);
11988
8a4f36cc
GM
11989 /* We have to close the display to inform Xt that it doesn't
11990 exist anymore. If we don't, Xt will continue to wait for
11991 events from the display. As a consequence, a sequence of
11992
11993 M-x make-frame-on-display RET :1 RET
11994 ...kill the new frame, so that we get an IO error...
11995 M-x make-frame-on-display RET :1 RET
11996
11997 will indefinitely wait in Xt for events for display `:1', opened
11998 in the first class to make-frame-on-display.
6186a4a0 11999
8a4f36cc
GM
12000 Closing the display is reported to lead to a bus error on
12001 OpenWindows in certain situations. I suspect that is a bug
12002 in OpenWindows. I don't know how to cicumvent it here. */
12003
f613a4c8 12004#ifdef USE_X_TOOLKIT
ae24cb3b
GM
12005 /* If DPYINFO is null, this means we didn't open the display
12006 in the first place, so don't try to close it. */
12007 if (dpyinfo)
f0e299de
GM
12008 {
12009 extern void (*fatal_error_signal_hook) P_ ((void));
12010 fatal_error_signal_hook = x_fatal_error_signal;
12011 XtCloseDisplay (dpy);
12012 fatal_error_signal_hook = NULL;
12013 }
f613a4c8 12014#endif
adabc3a9 12015
8a4f36cc 12016 /* Indicate that this display is dead. */
9e80b57d
KR
12017 if (dpyinfo)
12018 dpyinfo->display = 0;
6186a4a0 12019
06a2c219 12020 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
12021 that are on the dead display. */
12022 FOR_EACH_FRAME (tail, frame)
12023 {
12024 Lisp_Object minibuf_frame;
12025 minibuf_frame
12026 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
12027 if (FRAME_X_P (XFRAME (frame))
12028 && FRAME_X_P (XFRAME (minibuf_frame))
12029 && ! EQ (frame, minibuf_frame)
12030 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
12031 Fdelete_frame (frame, Qt);
12032 }
12033
12034 /* Now delete all remaining frames on the dead display.
06a2c219 12035 We are now sure none of these is used as the mini-buffer
7a13e894
RS
12036 for another frame that we need to delete. */
12037 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
12038 if (FRAME_X_P (XFRAME (frame))
12039 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
12040 {
12041 /* Set this to t so that Fdelete_frame won't get confused
12042 trying to find a replacement. */
12043 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
12044 Fdelete_frame (frame, Qt);
12045 }
7a13e894 12046
482a1bd2
KH
12047 if (dpyinfo)
12048 x_delete_display (dpyinfo);
7a13e894 12049
0da1ab50
GM
12050 x_uncatch_errors (dpy, count);
12051
7a13e894
RS
12052 if (x_display_list == 0)
12053 {
f0e299de 12054 fprintf (stderr, "%s\n", error_msg);
7a13e894
RS
12055 shut_down_emacs (0, 0, Qnil);
12056 exit (70);
12057 }
12ba150f 12058
7a13e894
RS
12059 /* Ordinary stack unwind doesn't deal with these. */
12060#ifdef SIGIO
12061 sigunblock (sigmask (SIGIO));
12062#endif
12063 sigunblock (sigmask (SIGALRM));
12064 TOTALLY_UNBLOCK_INPUT;
12065
aa4d9a9e 12066 clear_waiting_for_input ();
f0e299de 12067 error ("%s", error_msg);
4746118a
JB
12068}
12069
0da1ab50 12070
7a13e894
RS
12071/* This is the usual handler for X protocol errors.
12072 It kills all frames on the display that we got the error for.
12073 If that was the only one, it prints an error message and kills Emacs. */
12074
06a2c219 12075static void
c118dd06
JB
12076x_error_quitter (display, error)
12077 Display *display;
12078 XErrorEvent *error;
12079{
7a13e894 12080 char buf[256], buf1[356];
dc6f92b8 12081
58769bee 12082 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 12083 original error handler. */
dc6f92b8 12084
c118dd06 12085 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 12086 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 12087 buf, error->request_code);
7a13e894 12088 x_connection_closed (display, buf1);
dc6f92b8
JB
12089}
12090
0da1ab50 12091
e99db5a1
RS
12092/* This is the first-level handler for X protocol errors.
12093 It calls x_error_quitter or x_error_catcher. */
7a13e894 12094
8922af5f 12095static int
e99db5a1 12096x_error_handler (display, error)
8922af5f 12097 Display *display;
e99db5a1 12098 XErrorEvent *error;
8922af5f 12099{
e99db5a1
RS
12100 if (! NILP (x_error_message_string))
12101 x_error_catcher (display, error);
12102 else
12103 x_error_quitter (display, error);
06a2c219 12104 return 0;
f9e24cb9 12105}
c118dd06 12106
e99db5a1
RS
12107/* This is the handler for X IO errors, always.
12108 It kills all frames on the display that we lost touch with.
12109 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 12110
c118dd06 12111static int
e99db5a1 12112x_io_error_quitter (display)
c118dd06 12113 Display *display;
c118dd06 12114{
e99db5a1 12115 char buf[256];
dc6f92b8 12116
e99db5a1
RS
12117 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
12118 x_connection_closed (display, buf);
06a2c219 12119 return 0;
dc6f92b8 12120}
dc6f92b8 12121\f
f451eb13
JB
12122/* Changing the font of the frame. */
12123
76bcdf39
RS
12124/* Give frame F the font named FONTNAME as its default font, and
12125 return the full name of that font. FONTNAME may be a wildcard
12126 pattern; in that case, we choose some font that fits the pattern.
12127 The return value shows which font we chose. */
12128
b5cf7a0e 12129Lisp_Object
f676886a
JB
12130x_new_font (f, fontname)
12131 struct frame *f;
dc6f92b8
JB
12132 register char *fontname;
12133{
dc43ef94 12134 struct font_info *fontp
ee569018 12135 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 12136
dc43ef94
KH
12137 if (!fontp)
12138 return Qnil;
2224a5fc 12139
dc43ef94 12140 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 12141 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
12142 f->output_data.x->fontset = -1;
12143
b2cad826
KH
12144 /* Compute the scroll bar width in character columns. */
12145 if (f->scroll_bar_pixel_width > 0)
12146 {
7556890b 12147 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
12148 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
12149 }
12150 else
4e61bddf
RS
12151 {
12152 int wid = FONT_WIDTH (f->output_data.x->font);
12153 f->scroll_bar_cols = (14 + wid - 1) / wid;
12154 }
b2cad826 12155
f676886a 12156 /* Now make the frame display the given font. */
c118dd06 12157 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 12158 {
7556890b
RS
12159 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
12160 f->output_data.x->font->fid);
12161 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
12162 f->output_data.x->font->fid);
12163 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
12164 f->output_data.x->font->fid);
f676886a 12165
a27f9f86 12166 frame_update_line_height (f);
3497f73e
GM
12167
12168 /* Don't change the size of a tip frame; there's no point in
12169 doing it because it's done in Fx_show_tip, and it leads to
12170 problems because the tip frame has no widget. */
12171 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
12172 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 12173 }
a27f9f86
RS
12174 else
12175 /* If we are setting a new frame's font for the first time,
12176 there are no faces yet, so this font's height is the line height. */
7556890b 12177 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 12178
dc43ef94
KH
12179 return build_string (fontp->full_name);
12180}
12181
12182/* Give frame F the fontset named FONTSETNAME as its default font, and
12183 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
12184 pattern; in that case, we choose some fontset that fits the pattern.
12185 The return value shows which fontset we chose. */
b5cf7a0e 12186
dc43ef94
KH
12187Lisp_Object
12188x_new_fontset (f, fontsetname)
12189 struct frame *f;
12190 char *fontsetname;
12191{
ee569018 12192 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 12193 Lisp_Object result;
b5cf7a0e 12194
dc43ef94
KH
12195 if (fontset < 0)
12196 return Qnil;
b5cf7a0e 12197
2da424f1
KH
12198 if (f->output_data.x->fontset == fontset)
12199 /* This fontset is already set in frame F. There's nothing more
12200 to do. */
ee569018 12201 return fontset_name (fontset);
dc43ef94 12202
ee569018 12203 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
12204
12205 if (!STRINGP (result))
12206 /* Can't load ASCII font. */
12207 return Qnil;
12208
12209 /* Since x_new_font doesn't update any fontset information, do it now. */
12210 f->output_data.x->fontset = fontset;
dc43ef94 12211
f5d11644
GM
12212#ifdef HAVE_X_I18N
12213 if (FRAME_XIC (f)
12214 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 12215 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
12216#endif
12217
dc43ef94 12218 return build_string (fontsetname);
dc6f92b8 12219}
f5d11644
GM
12220
12221\f
12222/***********************************************************************
12223 X Input Methods
12224 ***********************************************************************/
12225
12226#ifdef HAVE_X_I18N
12227
12228#ifdef HAVE_X11R6
12229
12230/* XIM destroy callback function, which is called whenever the
12231 connection to input method XIM dies. CLIENT_DATA contains a
12232 pointer to the x_display_info structure corresponding to XIM. */
12233
12234static void
12235xim_destroy_callback (xim, client_data, call_data)
12236 XIM xim;
12237 XPointer client_data;
12238 XPointer call_data;
12239{
12240 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
12241 Lisp_Object frame, tail;
12242
12243 BLOCK_INPUT;
12244
12245 /* No need to call XDestroyIC.. */
12246 FOR_EACH_FRAME (tail, frame)
12247 {
12248 struct frame *f = XFRAME (frame);
12249 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
12250 {
12251 FRAME_XIC (f) = NULL;
12252 if (FRAME_XIC_FONTSET (f))
12253 {
12254 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
12255 FRAME_XIC_FONTSET (f) = NULL;
12256 }
12257 }
12258 }
12259
12260 /* No need to call XCloseIM. */
12261 dpyinfo->xim = NULL;
12262 XFree (dpyinfo->xim_styles);
12263 UNBLOCK_INPUT;
12264}
12265
12266#endif /* HAVE_X11R6 */
12267
12268/* Open the connection to the XIM server on display DPYINFO.
12269 RESOURCE_NAME is the resource name Emacs uses. */
12270
12271static void
12272xim_open_dpy (dpyinfo, resource_name)
12273 struct x_display_info *dpyinfo;
12274 char *resource_name;
12275{
287f7dd6 12276#ifdef USE_XIM
f5d11644
GM
12277 XIM xim;
12278
12279 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
12280 dpyinfo->xim = xim;
12281
12282 if (xim)
12283 {
f5d11644
GM
12284#ifdef HAVE_X11R6
12285 XIMCallback destroy;
12286#endif
12287
12288 /* Get supported styles and XIM values. */
12289 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
12290
12291#ifdef HAVE_X11R6
12292 destroy.callback = xim_destroy_callback;
12293 destroy.client_data = (XPointer)dpyinfo;
cea2ad76 12294 /* This isn't prototyped in OSF 5.0. */
f5d11644
GM
12295 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
12296#endif
12297 }
287f7dd6
GM
12298
12299#else /* not USE_XIM */
12300 dpyinfo->xim = NULL;
12301#endif /* not USE_XIM */
f5d11644
GM
12302}
12303
12304
b9de836c 12305#ifdef HAVE_X11R6_XIM
f5d11644
GM
12306
12307struct xim_inst_t
12308{
12309 struct x_display_info *dpyinfo;
12310 char *resource_name;
12311};
12312
12313/* XIM instantiate callback function, which is called whenever an XIM
12314 server is available. DISPLAY is teh display of the XIM.
12315 CLIENT_DATA contains a pointer to an xim_inst_t structure created
12316 when the callback was registered. */
12317
12318static void
12319xim_instantiate_callback (display, client_data, call_data)
12320 Display *display;
12321 XPointer client_data;
12322 XPointer call_data;
12323{
12324 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
12325 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
12326
12327 /* We don't support multiple XIM connections. */
12328 if (dpyinfo->xim)
12329 return;
12330
12331 xim_open_dpy (dpyinfo, xim_inst->resource_name);
12332
12333 /* Create XIC for the existing frames on the same display, as long
12334 as they have no XIC. */
12335 if (dpyinfo->xim && dpyinfo->reference_count > 0)
12336 {
12337 Lisp_Object tail, frame;
12338
12339 BLOCK_INPUT;
12340 FOR_EACH_FRAME (tail, frame)
12341 {
12342 struct frame *f = XFRAME (frame);
12343
12344 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
12345 if (FRAME_XIC (f) == NULL)
12346 {
12347 create_frame_xic (f);
12348 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
12349 xic_set_statusarea (f);
12350 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
12351 {
12352 struct window *w = XWINDOW (f->selected_window);
12353 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
12354 }
12355 }
12356 }
12357
12358 UNBLOCK_INPUT;
12359 }
12360}
12361
b9de836c 12362#endif /* HAVE_X11R6_XIM */
f5d11644
GM
12363
12364
12365/* Open a connection to the XIM server on display DPYINFO.
12366 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
12367 connection only at the first time. On X11R6, open the connection
12368 in the XIM instantiate callback function. */
12369
12370static void
12371xim_initialize (dpyinfo, resource_name)
12372 struct x_display_info *dpyinfo;
12373 char *resource_name;
12374{
287f7dd6 12375#ifdef USE_XIM
b9de836c 12376#ifdef HAVE_X11R6_XIM
f5d11644
GM
12377 struct xim_inst_t *xim_inst;
12378 int len;
12379
12380 dpyinfo->xim = NULL;
12381 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
12382 xim_inst->dpyinfo = dpyinfo;
12383 len = strlen (resource_name);
12384 xim_inst->resource_name = (char *) xmalloc (len + 1);
12385 bcopy (resource_name, xim_inst->resource_name, len + 1);
12386 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12387 resource_name, EMACS_CLASS,
12388 xim_instantiate_callback,
2ebb2f8b
DL
12389 /* Fixme: This is XPointer in
12390 XFree86 but (XPointer *) on
12391 Tru64, at least. */
12392 (XPointer) xim_inst);
b9de836c 12393#else /* not HAVE_X11R6_XIM */
f5d11644
GM
12394 dpyinfo->xim = NULL;
12395 xim_open_dpy (dpyinfo, resource_name);
b9de836c 12396#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
12397
12398#else /* not USE_XIM */
12399 dpyinfo->xim = NULL;
12400#endif /* not USE_XIM */
f5d11644
GM
12401}
12402
12403
12404/* Close the connection to the XIM server on display DPYINFO. */
12405
12406static void
12407xim_close_dpy (dpyinfo)
12408 struct x_display_info *dpyinfo;
12409{
287f7dd6 12410#ifdef USE_XIM
b9de836c 12411#ifdef HAVE_X11R6_XIM
8a4f36cc
GM
12412 if (dpyinfo->display)
12413 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12414 NULL, EMACS_CLASS,
12415 xim_instantiate_callback, NULL);
b9de836c 12416#endif /* not HAVE_X11R6_XIM */
8a4f36cc
GM
12417 if (dpyinfo->display)
12418 XCloseIM (dpyinfo->xim);
f5d11644
GM
12419 dpyinfo->xim = NULL;
12420 XFree (dpyinfo->xim_styles);
287f7dd6 12421#endif /* USE_XIM */
f5d11644
GM
12422}
12423
b9de836c 12424#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
12425
12426
dc6f92b8 12427\f
2e365682
RS
12428/* Calculate the absolute position in frame F
12429 from its current recorded position values and gravity. */
12430
dfcf069d 12431void
43bca5d5 12432x_calc_absolute_position (f)
f676886a 12433 struct frame *f;
dc6f92b8 12434{
06a2c219 12435 Window child;
6dba1858 12436 int win_x = 0, win_y = 0;
7556890b 12437 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
12438 int this_window;
12439
9829ddba
RS
12440 /* We have nothing to do if the current position
12441 is already for the top-left corner. */
12442 if (! ((flags & XNegative) || (flags & YNegative)))
12443 return;
12444
c81412a0 12445#ifdef USE_X_TOOLKIT
7556890b 12446 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
12447#else
12448 this_window = FRAME_X_WINDOW (f);
12449#endif
6dba1858
RS
12450
12451 /* Find the position of the outside upper-left corner of
9829ddba
RS
12452 the inner window, with respect to the outer window.
12453 But do this only if we will need the results. */
7556890b 12454 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 12455 {
9829ddba
RS
12456 int count;
12457
6dba1858 12458 BLOCK_INPUT;
9829ddba
RS
12459 count = x_catch_errors (FRAME_X_DISPLAY (f));
12460 while (1)
12461 {
12462 x_clear_errors (FRAME_X_DISPLAY (f));
12463 XTranslateCoordinates (FRAME_X_DISPLAY (f),
12464
12465 /* From-window, to-window. */
12466 this_window,
12467 f->output_data.x->parent_desc,
12468
12469 /* From-position, to-position. */
12470 0, 0, &win_x, &win_y,
12471
12472 /* Child of win. */
12473 &child);
12474 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12475 {
12476 Window newroot, newparent = 0xdeadbeef;
12477 Window *newchildren;
2ebb2f8b 12478 unsigned int nchildren;
9829ddba
RS
12479
12480 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
12481 &newparent, &newchildren, &nchildren))
12482 break;
58769bee 12483
7c3c78a3 12484 XFree ((char *) newchildren);
6dba1858 12485
9829ddba
RS
12486 f->output_data.x->parent_desc = newparent;
12487 }
12488 else
12489 break;
12490 }
6dba1858 12491
9829ddba 12492 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
12493 UNBLOCK_INPUT;
12494 }
12495
12496 /* Treat negative positions as relative to the leftmost bottommost
12497 position that fits on the screen. */
20f55f9a 12498 if (flags & XNegative)
7556890b 12499 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
12500 - 2 * f->output_data.x->border_width - win_x
12501 - PIXEL_WIDTH (f)
12502 + f->output_data.x->left_pos);
dc6f92b8 12503
7708ced0
GM
12504 {
12505 int height = PIXEL_HEIGHT (f);
06a2c219 12506
7708ced0
GM
12507#if defined USE_X_TOOLKIT && defined USE_MOTIF
12508 /* Something is fishy here. When using Motif, starting Emacs with
12509 `-g -0-0', the frame appears too low by a few pixels.
12510
12511 This seems to be so because initially, while Emacs is starting,
12512 the column widget's height and the frame's pixel height are
12513 different. The column widget's height is the right one. In
12514 later invocations, when Emacs is up, the frame's pixel height
12515 is right, though.
12516
12517 It's not obvious where the initial small difference comes from.
12518 2000-12-01, gerd. */
12519
12520 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
06a2c219 12521#endif
2e365682 12522
7708ced0
GM
12523 if (flags & YNegative)
12524 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
12525 - 2 * f->output_data.x->border_width
12526 - win_y
12527 - height
12528 + f->output_data.x->top_pos);
12529 }
12530
3a35ab44
RS
12531 /* The left_pos and top_pos
12532 are now relative to the top and left screen edges,
12533 so the flags should correspond. */
7556890b 12534 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
12535}
12536
3a35ab44
RS
12537/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
12538 to really change the position, and 0 when calling from
12539 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
12540 position values). It is -1 when calling from x_set_frame_parameters,
12541 which means, do adjust for borders but don't change the gravity. */
3a35ab44 12542
dfcf069d 12543void
dc05a16b 12544x_set_offset (f, xoff, yoff, change_gravity)
f676886a 12545 struct frame *f;
dc6f92b8 12546 register int xoff, yoff;
dc05a16b 12547 int change_gravity;
dc6f92b8 12548{
4a4cbdd5
KH
12549 int modified_top, modified_left;
12550
aa3ff7c9 12551 if (change_gravity > 0)
3a35ab44 12552 {
7556890b
RS
12553 f->output_data.x->top_pos = yoff;
12554 f->output_data.x->left_pos = xoff;
12555 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 12556 if (xoff < 0)
7556890b 12557 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 12558 if (yoff < 0)
7556890b
RS
12559 f->output_data.x->size_hint_flags |= YNegative;
12560 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 12561 }
43bca5d5 12562 x_calc_absolute_position (f);
dc6f92b8
JB
12563
12564 BLOCK_INPUT;
c32cdd9a 12565 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 12566
7556890b
RS
12567 modified_left = f->output_data.x->left_pos;
12568 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
12569#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
12570 this seems to be unnecessary and incorrect. rms, 4/17/97. */
12571 /* It is a mystery why we need to add the border_width here
12572 when the frame is already visible, but experiment says we do. */
aa3ff7c9 12573 if (change_gravity != 0)
4a4cbdd5 12574 {
7556890b
RS
12575 modified_left += f->output_data.x->border_width;
12576 modified_top += f->output_data.x->border_width;
4a4cbdd5 12577 }
e73ec6fa 12578#endif
4a4cbdd5 12579
3afe33e7 12580#ifdef USE_X_TOOLKIT
7556890b 12581 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 12582 modified_left, modified_top);
3afe33e7 12583#else /* not USE_X_TOOLKIT */
334208b7 12584 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 12585 modified_left, modified_top);
3afe33e7 12586#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12587 UNBLOCK_INPUT;
12588}
12589
dc6f92b8 12590
499b1844
GM
12591/* Change the size of frame F's X window to COLS/ROWS in the case F
12592 doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
12593 top-left-corner window gravity for this size change and subsequent
12594 size changes. Otherwise we leave the window gravity unchanged. */
12595
12596static void
12597x_set_window_size_1 (f, change_gravity, cols, rows)
f676886a 12598 struct frame *f;
bc20ebbf 12599 int change_gravity;
b1c884c3 12600 int cols, rows;
dc6f92b8
JB
12601{
12602 int pixelwidth, pixelheight;
80fd1fe2 12603
b1c884c3 12604 check_frame_size (f, &rows, &cols);
7556890b 12605 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
12606 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
12607 ? 0
12608 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 12609 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 12610 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 12611 f->output_data.x->flags_areas_extra
110859fc 12612 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
12613 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
12614 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 12615
7556890b 12616 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 12617 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 12618
334208b7
RS
12619 XSync (FRAME_X_DISPLAY (f), False);
12620 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12621 pixelwidth, pixelheight);
b1c884c3
JB
12622
12623 /* Now, strictly speaking, we can't be sure that this is accurate,
12624 but the window manager will get around to dealing with the size
12625 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
12626 ConfigureNotify event gets here.
12627
12628 We could just not bother storing any of this information here,
12629 and let the ConfigureNotify event set everything up, but that
fddd5ceb 12630 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 12631 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
12632 point in the future when the ConfigureNotify event arrives.
12633
12634 We pass 1 for DELAY since we can't run Lisp code inside of
12635 a BLOCK_INPUT. */
7d1e984f 12636 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
12637 PIXEL_WIDTH (f) = pixelwidth;
12638 PIXEL_HEIGHT (f) = pixelheight;
12639
aee9a898
RS
12640 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
12641 receive in the ConfigureNotify event; if we get what we asked
12642 for, then the event won't cause the screen to become garbaged, so
12643 we have to make sure to do it here. */
12644 SET_FRAME_GARBAGED (f);
12645
12646 XFlush (FRAME_X_DISPLAY (f));
499b1844
GM
12647}
12648
12649
12650/* Call this to change the size of frame F's x-window.
12651 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
12652 for this size change and subsequent size changes.
12653 Otherwise we leave the window gravity unchanged. */
aee9a898 12654
499b1844
GM
12655void
12656x_set_window_size (f, change_gravity, cols, rows)
12657 struct frame *f;
12658 int change_gravity;
12659 int cols, rows;
12660{
12661 BLOCK_INPUT;
12662
12663#ifdef USE_X_TOOLKIT
12664
f1f4d345 12665 if (f->output_data.x->widget != NULL)
499b1844
GM
12666 {
12667 /* The x and y position of the widget is clobbered by the
12668 call to XtSetValues within EmacsFrameSetCharSize.
12669 This is a real kludge, but I don't understand Xt so I can't
12670 figure out a correct fix. Can anyone else tell me? -- rms. */
12671 int xpos = f->output_data.x->widget->core.x;
12672 int ypos = f->output_data.x->widget->core.y;
12673 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
12674 f->output_data.x->widget->core.x = xpos;
12675 f->output_data.x->widget->core.y = ypos;
12676 }
12677 else
12678 x_set_window_size_1 (f, change_gravity, cols, rows);
12679
12680#else /* not USE_X_TOOLKIT */
12681
12682 x_set_window_size_1 (f, change_gravity, cols, rows);
12683
aee9a898
RS
12684#endif /* not USE_X_TOOLKIT */
12685
4d73d038 12686 /* If cursor was outside the new size, mark it as off. */
06a2c219 12687 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 12688
aee9a898
RS
12689 /* Clear out any recollection of where the mouse highlighting was,
12690 since it might be in a place that's outside the new frame size.
12691 Actually checking whether it is outside is a pain in the neck,
12692 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 12693 cancel_mouse_face (f);
dbc4e1c1 12694
dc6f92b8
JB
12695 UNBLOCK_INPUT;
12696}
dc6f92b8 12697\f
d047c4eb 12698/* Mouse warping. */
dc6f92b8 12699
9b378208 12700void
f676886a
JB
12701x_set_mouse_position (f, x, y)
12702 struct frame *f;
dc6f92b8
JB
12703 int x, y;
12704{
12705 int pix_x, pix_y;
12706
7556890b
RS
12707 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
12708 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
12709
12710 if (pix_x < 0) pix_x = 0;
12711 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
12712
12713 if (pix_y < 0) pix_y = 0;
12714 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
12715
12716 BLOCK_INPUT;
dc6f92b8 12717
334208b7
RS
12718 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12719 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
12720 UNBLOCK_INPUT;
12721}
12722
9b378208
RS
12723/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
12724
12725void
12726x_set_mouse_pixel_position (f, pix_x, pix_y)
12727 struct frame *f;
12728 int pix_x, pix_y;
12729{
12730 BLOCK_INPUT;
12731
334208b7
RS
12732 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12733 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
12734 UNBLOCK_INPUT;
12735}
d047c4eb
KH
12736\f
12737/* focus shifting, raising and lowering. */
9b378208 12738
dfcf069d 12739void
f676886a
JB
12740x_focus_on_frame (f)
12741 struct frame *f;
dc6f92b8 12742{
1fb20991 12743#if 0 /* This proves to be unpleasant. */
f676886a 12744 x_raise_frame (f);
1fb20991 12745#endif
6d4238f3
JB
12746#if 0
12747 /* I don't think that the ICCCM allows programs to do things like this
12748 without the interaction of the window manager. Whatever you end up
f676886a 12749 doing with this code, do it to x_unfocus_frame too. */
334208b7 12750 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 12751 RevertToPointerRoot, CurrentTime);
c118dd06 12752#endif /* ! 0 */
dc6f92b8
JB
12753}
12754
dfcf069d 12755void
f676886a
JB
12756x_unfocus_frame (f)
12757 struct frame *f;
dc6f92b8 12758{
6d4238f3 12759#if 0
f676886a 12760 /* Look at the remarks in x_focus_on_frame. */
0f941935 12761 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 12762 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 12763 RevertToPointerRoot, CurrentTime);
c118dd06 12764#endif /* ! 0 */
dc6f92b8
JB
12765}
12766
f676886a 12767/* Raise frame F. */
dc6f92b8 12768
dfcf069d 12769void
f676886a
JB
12770x_raise_frame (f)
12771 struct frame *f;
dc6f92b8 12772{
3a88c238 12773 if (f->async_visible)
dc6f92b8
JB
12774 {
12775 BLOCK_INPUT;
3afe33e7 12776#ifdef USE_X_TOOLKIT
7556890b 12777 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12778#else /* not USE_X_TOOLKIT */
334208b7 12779 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12780#endif /* not USE_X_TOOLKIT */
334208b7 12781 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12782 UNBLOCK_INPUT;
12783 }
12784}
12785
f676886a 12786/* Lower frame F. */
dc6f92b8 12787
dfcf069d 12788void
f676886a
JB
12789x_lower_frame (f)
12790 struct frame *f;
dc6f92b8 12791{
3a88c238 12792 if (f->async_visible)
dc6f92b8
JB
12793 {
12794 BLOCK_INPUT;
3afe33e7 12795#ifdef USE_X_TOOLKIT
7556890b 12796 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12797#else /* not USE_X_TOOLKIT */
334208b7 12798 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12799#endif /* not USE_X_TOOLKIT */
334208b7 12800 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12801 UNBLOCK_INPUT;
12802 }
12803}
12804
dbc4e1c1 12805static void
6b0442dc 12806XTframe_raise_lower (f, raise_flag)
dbc4e1c1 12807 FRAME_PTR f;
6b0442dc 12808 int raise_flag;
dbc4e1c1 12809{
6b0442dc 12810 if (raise_flag)
dbc4e1c1
JB
12811 x_raise_frame (f);
12812 else
12813 x_lower_frame (f);
12814}
d047c4eb
KH
12815\f
12816/* Change of visibility. */
dc6f92b8 12817
9382638d
KH
12818/* This tries to wait until the frame is really visible.
12819 However, if the window manager asks the user where to position
12820 the frame, this will return before the user finishes doing that.
12821 The frame will not actually be visible at that time,
12822 but it will become visible later when the window manager
12823 finishes with it. */
12824
dfcf069d 12825void
f676886a
JB
12826x_make_frame_visible (f)
12827 struct frame *f;
dc6f92b8 12828{
990ba854 12829 Lisp_Object type;
1aa6072f 12830 int original_top, original_left;
31be9251
GM
12831 int retry_count = 2;
12832
12833 retry:
dc6f92b8 12834
dc6f92b8 12835 BLOCK_INPUT;
dc6f92b8 12836
990ba854
RS
12837 type = x_icon_type (f);
12838 if (!NILP (type))
12839 x_bitmap_icon (f, type);
bdcd49ba 12840
f676886a 12841 if (! FRAME_VISIBLE_P (f))
90e65f07 12842 {
1aa6072f
RS
12843 /* We test FRAME_GARBAGED_P here to make sure we don't
12844 call x_set_offset a second time
12845 if we get to x_make_frame_visible a second time
12846 before the window gets really visible. */
12847 if (! FRAME_ICONIFIED_P (f)
12848 && ! f->output_data.x->asked_for_visible)
12849 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
12850
12851 f->output_data.x->asked_for_visible = 1;
12852
90e65f07 12853 if (! EQ (Vx_no_window_manager, Qt))
f676886a 12854 x_wm_set_window_state (f, NormalState);
3afe33e7 12855#ifdef USE_X_TOOLKIT
d7a38a2e 12856 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 12857 XtMapWidget (f->output_data.x->widget);
3afe33e7 12858#else /* not USE_X_TOOLKIT */
7f9c7f94 12859 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12860#endif /* not USE_X_TOOLKIT */
0134a210
RS
12861#if 0 /* This seems to bring back scroll bars in the wrong places
12862 if the window configuration has changed. They seem
12863 to come back ok without this. */
ab648270 12864 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 12865 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 12866#endif
90e65f07 12867 }
dc6f92b8 12868
334208b7 12869 XFlush (FRAME_X_DISPLAY (f));
90e65f07 12870
0dacf791
RS
12871 /* Synchronize to ensure Emacs knows the frame is visible
12872 before we do anything else. We do this loop with input not blocked
12873 so that incoming events are handled. */
12874 {
12875 Lisp_Object frame;
12ce2351 12876 int count;
28c01ffe
RS
12877 /* This must be before UNBLOCK_INPUT
12878 since events that arrive in response to the actions above
12879 will set it when they are handled. */
12880 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
12881
12882 original_left = f->output_data.x->left_pos;
12883 original_top = f->output_data.x->top_pos;
c0a04927
RS
12884
12885 /* This must come after we set COUNT. */
12886 UNBLOCK_INPUT;
12887
2745e6c4 12888 /* We unblock here so that arriving X events are processed. */
1aa6072f 12889
dcb07ae9
RS
12890 /* Now move the window back to where it was "supposed to be".
12891 But don't do it if the gravity is negative.
12892 When the gravity is negative, this uses a position
28c01ffe
RS
12893 that is 3 pixels too low. Perhaps that's really the border width.
12894
12895 Don't do this if the window has never been visible before,
12896 because the window manager may choose the position
12897 and we don't want to override it. */
1aa6072f 12898
4d3f5d9a 12899 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 12900 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 12901 && previously_visible)
1aa6072f 12902 {
2745e6c4
RS
12903 Drawable rootw;
12904 int x, y;
12905 unsigned int width, height, border, depth;
06a2c219 12906
1aa6072f 12907 BLOCK_INPUT;
9829ddba 12908
06a2c219
GM
12909 /* On some window managers (such as FVWM) moving an existing
12910 window, even to the same place, causes the window manager
12911 to introduce an offset. This can cause the window to move
12912 to an unexpected location. Check the geometry (a little
12913 slow here) and then verify that the window is in the right
12914 place. If the window is not in the right place, move it
12915 there, and take the potential window manager hit. */
2745e6c4
RS
12916 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12917 &rootw, &x, &y, &width, &height, &border, &depth);
12918
12919 if (original_left != x || original_top != y)
12920 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12921 original_left, original_top);
12922
1aa6072f
RS
12923 UNBLOCK_INPUT;
12924 }
9829ddba 12925
e0c1aef2 12926 XSETFRAME (frame, f);
c0a04927 12927
12ce2351
GM
12928 /* Wait until the frame is visible. Process X events until a
12929 MapNotify event has been seen, or until we think we won't get a
12930 MapNotify at all.. */
12931 for (count = input_signal_count + 10;
12932 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 12933 {
12ce2351 12934 /* Force processing of queued events. */
334208b7 12935 x_sync (f);
12ce2351
GM
12936
12937 /* Machines that do polling rather than SIGIO have been
12938 observed to go into a busy-wait here. So we'll fake an
12939 alarm signal to let the handler know that there's something
12940 to be read. We used to raise a real alarm, but it seems
12941 that the handler isn't always enabled here. This is
12942 probably a bug. */
8b2f8d4e 12943 if (input_polling_used ())
3b2fa4e6 12944 {
12ce2351
GM
12945 /* It could be confusing if a real alarm arrives while
12946 processing the fake one. Turn it off and let the
12947 handler reset it. */
3e71d8f2 12948 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
12949 int old_poll_suppress_count = poll_suppress_count;
12950 poll_suppress_count = 1;
12951 poll_for_input_1 ();
12952 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 12953 }
12ce2351
GM
12954
12955 /* See if a MapNotify event has been processed. */
12956 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 12957 }
31be9251
GM
12958
12959 /* 2000-09-28: In
12960
12961 (let ((f (selected-frame)))
12962 (iconify-frame f)
12963 (raise-frame f))
12964
12965 the frame is not raised with various window managers on
12966 FreeBSD, Linux and Solaris. It turns out that, for some
12967 unknown reason, the call to XtMapWidget is completely ignored.
12968 Mapping the widget a second time works. */
12969
12970 if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
12971 goto retry;
0dacf791 12972 }
dc6f92b8
JB
12973}
12974
06a2c219 12975/* Change from mapped state to withdrawn state. */
dc6f92b8 12976
d047c4eb
KH
12977/* Make the frame visible (mapped and not iconified). */
12978
dfcf069d 12979void
f676886a
JB
12980x_make_frame_invisible (f)
12981 struct frame *f;
dc6f92b8 12982{
546e6d5b
RS
12983 Window window;
12984
12985#ifdef USE_X_TOOLKIT
12986 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 12987 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
12988#else /* not USE_X_TOOLKIT */
12989 window = FRAME_X_WINDOW (f);
12990#endif /* not USE_X_TOOLKIT */
dc6f92b8 12991
9319ae23 12992 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
12993 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
12994 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 12995
5627c40e 12996#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 12997 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 12998 return;
5627c40e 12999#endif
dc6f92b8
JB
13000
13001 BLOCK_INPUT;
c118dd06 13002
af31d76f
RS
13003 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
13004 that the current position of the window is user-specified, rather than
13005 program-specified, so that when the window is mapped again, it will be
13006 placed at the same location, without forcing the user to position it
13007 by hand again (they have already done that once for this window.) */
c32cdd9a 13008 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 13009
c118dd06
JB
13010#ifdef HAVE_X11R4
13011
334208b7
RS
13012 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
13013 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
13014 {
13015 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13016 error ("Can't notify window manager of window withdrawal");
c118dd06 13017 }
c118dd06 13018#else /* ! defined (HAVE_X11R4) */
16bd92ea 13019
c118dd06 13020 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
13021 if (! EQ (Vx_no_window_manager, Qt))
13022 {
16bd92ea 13023 XEvent unmap;
dc6f92b8 13024
16bd92ea 13025 unmap.xunmap.type = UnmapNotify;
546e6d5b 13026 unmap.xunmap.window = window;
334208b7 13027 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 13028 unmap.xunmap.from_configure = False;
334208b7
RS
13029 if (! XSendEvent (FRAME_X_DISPLAY (f),
13030 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 13031 False,
06a2c219 13032 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
13033 &unmap))
13034 {
13035 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13036 error ("Can't notify window manager of withdrawal");
16bd92ea 13037 }
dc6f92b8
JB
13038 }
13039
16bd92ea 13040 /* Unmap the window ourselves. Cheeky! */
334208b7 13041 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 13042#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 13043
5627c40e
RS
13044 /* We can't distinguish this from iconification
13045 just by the event that we get from the server.
13046 So we can't win using the usual strategy of letting
13047 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
13048 and synchronize with the server to make sure we agree. */
13049 f->visible = 0;
13050 FRAME_ICONIFIED_P (f) = 0;
13051 f->async_visible = 0;
13052 f->async_iconified = 0;
13053
334208b7 13054 x_sync (f);
5627c40e 13055
dc6f92b8
JB
13056 UNBLOCK_INPUT;
13057}
13058
06a2c219 13059/* Change window state from mapped to iconified. */
dc6f92b8 13060
dfcf069d 13061void
f676886a
JB
13062x_iconify_frame (f)
13063 struct frame *f;
dc6f92b8 13064{
3afe33e7 13065 int result;
990ba854 13066 Lisp_Object type;
dc6f92b8 13067
9319ae23 13068 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
13069 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
13070 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 13071
3a88c238 13072 if (f->async_iconified)
dc6f92b8
JB
13073 return;
13074
3afe33e7 13075 BLOCK_INPUT;
546e6d5b 13076
9af3143a
RS
13077 FRAME_SAMPLE_VISIBILITY (f);
13078
990ba854
RS
13079 type = x_icon_type (f);
13080 if (!NILP (type))
13081 x_bitmap_icon (f, type);
bdcd49ba
RS
13082
13083#ifdef USE_X_TOOLKIT
13084
546e6d5b
RS
13085 if (! FRAME_VISIBLE_P (f))
13086 {
13087 if (! EQ (Vx_no_window_manager, Qt))
13088 x_wm_set_window_state (f, IconicState);
13089 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 13090 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
13091 /* The server won't give us any event to indicate
13092 that an invisible frame was changed to an icon,
13093 so we have to record it here. */
13094 f->iconified = 1;
1e6bc770 13095 f->visible = 1;
9cf30a30 13096 f->async_iconified = 1;
1e6bc770 13097 f->async_visible = 0;
546e6d5b
RS
13098 UNBLOCK_INPUT;
13099 return;
13100 }
13101
334208b7 13102 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 13103 XtWindow (f->output_data.x->widget),
334208b7 13104 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
13105 UNBLOCK_INPUT;
13106
13107 if (!result)
546e6d5b 13108 error ("Can't notify window manager of iconification");
3afe33e7
RS
13109
13110 f->async_iconified = 1;
1e6bc770
RS
13111 f->async_visible = 0;
13112
8c002a25
KH
13113
13114 BLOCK_INPUT;
334208b7 13115 XFlush (FRAME_X_DISPLAY (f));
8c002a25 13116 UNBLOCK_INPUT;
3afe33e7
RS
13117#else /* not USE_X_TOOLKIT */
13118
fd13dbb2
RS
13119 /* Make sure the X server knows where the window should be positioned,
13120 in case the user deiconifies with the window manager. */
13121 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 13122 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 13123
16bd92ea
JB
13124 /* Since we don't know which revision of X we're running, we'll use both
13125 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
13126
13127 /* X11R4: send a ClientMessage to the window manager using the
13128 WM_CHANGE_STATE type. */
13129 {
13130 XEvent message;
58769bee 13131
c118dd06 13132 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 13133 message.xclient.type = ClientMessage;
334208b7 13134 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
13135 message.xclient.format = 32;
13136 message.xclient.data.l[0] = IconicState;
13137
334208b7
RS
13138 if (! XSendEvent (FRAME_X_DISPLAY (f),
13139 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
13140 False,
13141 SubstructureRedirectMask | SubstructureNotifyMask,
13142 &message))
dc6f92b8
JB
13143 {
13144 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13145 error ("Can't notify window manager of iconification");
dc6f92b8 13146 }
16bd92ea 13147 }
dc6f92b8 13148
58769bee 13149 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
13150 IconicState. */
13151 x_wm_set_window_state (f, IconicState);
dc6f92b8 13152
a9c00105
RS
13153 if (!FRAME_VISIBLE_P (f))
13154 {
13155 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 13156 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
13157 }
13158
3a88c238 13159 f->async_iconified = 1;
1e6bc770 13160 f->async_visible = 0;
dc6f92b8 13161
334208b7 13162 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 13163 UNBLOCK_INPUT;
8c002a25 13164#endif /* not USE_X_TOOLKIT */
dc6f92b8 13165}
19f71add 13166
d047c4eb 13167\f
19f71add 13168/* Free X resources of frame F. */
dc6f92b8 13169
dfcf069d 13170void
19f71add 13171x_free_frame_resources (f)
f676886a 13172 struct frame *f;
dc6f92b8 13173{
7f9c7f94
RS
13174 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13175
dc6f92b8 13176 BLOCK_INPUT;
c0ff3fab 13177
6186a4a0
RS
13178 /* If a display connection is dead, don't try sending more
13179 commands to the X server. */
19f71add 13180 if (dpyinfo->display)
6186a4a0 13181 {
19f71add 13182 if (f->output_data.x->icon_desc)
6186a4a0 13183 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
19f71add 13184
31f41daf 13185#ifdef HAVE_X_I18N
f5d11644
GM
13186 if (FRAME_XIC (f))
13187 free_frame_xic (f);
31f41daf 13188#endif
19f71add 13189
2662734b 13190 if (FRAME_X_WINDOW (f))
19f71add
GM
13191 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13192
3afe33e7 13193#ifdef USE_X_TOOLKIT
06a2c219 13194 if (f->output_data.x->widget)
30ca89f5
GM
13195 {
13196 XtDestroyWidget (f->output_data.x->widget);
13197 f->output_data.x->widget = NULL;
13198 }
6186a4a0 13199 free_frame_menubar (f);
3afe33e7
RS
13200#endif /* USE_X_TOOLKIT */
13201
3e71d8f2
GM
13202 unload_color (f, f->output_data.x->foreground_pixel);
13203 unload_color (f, f->output_data.x->background_pixel);
13204 unload_color (f, f->output_data.x->cursor_pixel);
13205 unload_color (f, f->output_data.x->cursor_foreground_pixel);
13206 unload_color (f, f->output_data.x->border_pixel);
13207 unload_color (f, f->output_data.x->mouse_pixel);
19f71add 13208
3e71d8f2
GM
13209 if (f->output_data.x->scroll_bar_background_pixel != -1)
13210 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
13211 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
13212 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
7c1bef7a
MB
13213#ifdef USE_TOOLKIT_SCROLL_BARS
13214 /* Scrollbar shadow colors. */
13215 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
13216 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
13217 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
13218 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
13219#endif /* USE_TOOLKIT_SCROLL_BARS */
3e71d8f2
GM
13220 if (f->output_data.x->white_relief.allocated_p)
13221 unload_color (f, f->output_data.x->white_relief.pixel);
13222 if (f->output_data.x->black_relief.allocated_p)
13223 unload_color (f, f->output_data.x->black_relief.pixel);
4ca78676 13224
19f71add
GM
13225 if (FRAME_FACE_CACHE (f))
13226 free_frame_faces (f);
13227
4ca78676 13228 x_free_gcs (f);
6186a4a0
RS
13229 XFlush (FRAME_X_DISPLAY (f));
13230 }
dc6f92b8 13231
df89d8a4 13232 if (f->output_data.x->saved_menu_event)
06a2c219 13233 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 13234
7556890b 13235 xfree (f->output_data.x);
19f71add
GM
13236 f->output_data.x = NULL;
13237
0f941935
KH
13238 if (f == dpyinfo->x_focus_frame)
13239 dpyinfo->x_focus_frame = 0;
13240 if (f == dpyinfo->x_focus_event_frame)
13241 dpyinfo->x_focus_event_frame = 0;
13242 if (f == dpyinfo->x_highlight_frame)
13243 dpyinfo->x_highlight_frame = 0;
c0ff3fab 13244
7f9c7f94 13245 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 13246 {
7f9c7f94
RS
13247 dpyinfo->mouse_face_beg_row
13248 = dpyinfo->mouse_face_beg_col = -1;
13249 dpyinfo->mouse_face_end_row
13250 = dpyinfo->mouse_face_end_col = -1;
13251 dpyinfo->mouse_face_window = Qnil;
21323706
RS
13252 dpyinfo->mouse_face_deferred_gc = 0;
13253 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 13254 }
0134a210 13255
c0ff3fab 13256 UNBLOCK_INPUT;
dc6f92b8 13257}
19f71add
GM
13258
13259
13260/* Destroy the X window of frame F. */
13261
13262void
13263x_destroy_window (f)
13264 struct frame *f;
13265{
13266 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13267
13268 /* If a display connection is dead, don't try sending more
13269 commands to the X server. */
13270 if (dpyinfo->display != 0)
13271 x_free_frame_resources (f);
13272
13273 dpyinfo->reference_count--;
13274}
13275
dc6f92b8 13276\f
f451eb13
JB
13277/* Setting window manager hints. */
13278
af31d76f
RS
13279/* Set the normal size hints for the window manager, for frame F.
13280 FLAGS is the flags word to use--or 0 meaning preserve the flags
13281 that the window now has.
13282 If USER_POSITION is nonzero, we set the USPosition
13283 flag (this is useful when FLAGS is 0). */
6dba1858 13284
dfcf069d 13285void
af31d76f 13286x_wm_set_size_hint (f, flags, user_position)
f676886a 13287 struct frame *f;
af31d76f
RS
13288 long flags;
13289 int user_position;
dc6f92b8
JB
13290{
13291 XSizeHints size_hints;
3afe33e7
RS
13292
13293#ifdef USE_X_TOOLKIT
7e4f2521
FP
13294 Arg al[2];
13295 int ac = 0;
13296 Dimension widget_width, widget_height;
7556890b 13297 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 13298#else /* not USE_X_TOOLKIT */
c118dd06 13299 Window window = FRAME_X_WINDOW (f);
3afe33e7 13300#endif /* not USE_X_TOOLKIT */
dc6f92b8 13301
b72a58fd
RS
13302 /* Setting PMaxSize caused various problems. */
13303 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 13304
7556890b
RS
13305 size_hints.x = f->output_data.x->left_pos;
13306 size_hints.y = f->output_data.x->top_pos;
7553a6b7 13307
7e4f2521
FP
13308#ifdef USE_X_TOOLKIT
13309 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
13310 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 13311 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
13312 size_hints.height = widget_height;
13313 size_hints.width = widget_width;
13314#else /* not USE_X_TOOLKIT */
f676886a
JB
13315 size_hints.height = PIXEL_HEIGHT (f);
13316 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 13317#endif /* not USE_X_TOOLKIT */
7553a6b7 13318
7556890b
RS
13319 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
13320 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
13321 size_hints.max_width
13322 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
13323 size_hints.max_height
13324 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 13325
d067ea8b
KH
13326 /* Calculate the base and minimum sizes.
13327
13328 (When we use the X toolkit, we don't do it here.
13329 Instead we copy the values that the widgets are using, below.) */
13330#ifndef USE_X_TOOLKIT
b1c884c3 13331 {
b0342f17 13332 int base_width, base_height;
0134a210 13333 int min_rows = 0, min_cols = 0;
b0342f17 13334
f451eb13
JB
13335 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
13336 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 13337
0134a210 13338 check_frame_size (f, &min_rows, &min_cols);
b0342f17 13339
0134a210
RS
13340 /* The window manager uses the base width hints to calculate the
13341 current number of rows and columns in the frame while
13342 resizing; min_width and min_height aren't useful for this
13343 purpose, since they might not give the dimensions for a
13344 zero-row, zero-column frame.
58769bee 13345
0134a210
RS
13346 We use the base_width and base_height members if we have
13347 them; otherwise, we set the min_width and min_height members
13348 to the size for a zero x zero frame. */
b0342f17
JB
13349
13350#ifdef HAVE_X11R4
0134a210
RS
13351 size_hints.flags |= PBaseSize;
13352 size_hints.base_width = base_width;
13353 size_hints.base_height = base_height;
13354 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
13355 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 13356#else
0134a210
RS
13357 size_hints.min_width = base_width;
13358 size_hints.min_height = base_height;
b0342f17 13359#endif
b1c884c3 13360 }
dc6f92b8 13361
d067ea8b 13362 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 13363 if (flags)
dc6f92b8 13364 {
d067ea8b
KH
13365 size_hints.flags |= flags;
13366 goto no_read;
13367 }
13368#endif /* not USE_X_TOOLKIT */
13369
13370 {
13371 XSizeHints hints; /* Sometimes I hate X Windows... */
13372 long supplied_return;
13373 int value;
af31d76f
RS
13374
13375#ifdef HAVE_X11R4
d067ea8b
KH
13376 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
13377 &supplied_return);
af31d76f 13378#else
d067ea8b 13379 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 13380#endif
58769bee 13381
d067ea8b
KH
13382#ifdef USE_X_TOOLKIT
13383 size_hints.base_height = hints.base_height;
13384 size_hints.base_width = hints.base_width;
13385 size_hints.min_height = hints.min_height;
13386 size_hints.min_width = hints.min_width;
13387#endif
13388
13389 if (flags)
13390 size_hints.flags |= flags;
13391 else
13392 {
13393 if (value == 0)
13394 hints.flags = 0;
13395 if (hints.flags & PSize)
13396 size_hints.flags |= PSize;
13397 if (hints.flags & PPosition)
13398 size_hints.flags |= PPosition;
13399 if (hints.flags & USPosition)
13400 size_hints.flags |= USPosition;
13401 if (hints.flags & USSize)
13402 size_hints.flags |= USSize;
13403 }
13404 }
13405
06a2c219 13406#ifndef USE_X_TOOLKIT
d067ea8b 13407 no_read:
06a2c219 13408#endif
0134a210 13409
af31d76f 13410#ifdef PWinGravity
7556890b 13411 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 13412 size_hints.flags |= PWinGravity;
dc05a16b 13413
af31d76f 13414 if (user_position)
6dba1858 13415 {
af31d76f
RS
13416 size_hints.flags &= ~ PPosition;
13417 size_hints.flags |= USPosition;
6dba1858 13418 }
2554751d 13419#endif /* PWinGravity */
6dba1858 13420
b0342f17 13421#ifdef HAVE_X11R4
334208b7 13422 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13423#else
334208b7 13424 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13425#endif
dc6f92b8
JB
13426}
13427
13428/* Used for IconicState or NormalState */
06a2c219 13429
dfcf069d 13430void
f676886a
JB
13431x_wm_set_window_state (f, state)
13432 struct frame *f;
dc6f92b8
JB
13433 int state;
13434{
3afe33e7 13435#ifdef USE_X_TOOLKIT
546e6d5b
RS
13436 Arg al[1];
13437
13438 XtSetArg (al[0], XtNinitialState, state);
7556890b 13439 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 13440#else /* not USE_X_TOOLKIT */
c118dd06 13441 Window window = FRAME_X_WINDOW (f);
dc6f92b8 13442
7556890b
RS
13443 f->output_data.x->wm_hints.flags |= StateHint;
13444 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 13445
7556890b 13446 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 13447#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13448}
13449
dfcf069d 13450void
7f2ae036 13451x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 13452 struct frame *f;
7f2ae036 13453 int pixmap_id;
dc6f92b8 13454{
d2bd6bc4
RS
13455 Pixmap icon_pixmap;
13456
06a2c219 13457#ifndef USE_X_TOOLKIT
c118dd06 13458 Window window = FRAME_X_WINDOW (f);
75231bad 13459#endif
dc6f92b8 13460
7f2ae036 13461 if (pixmap_id > 0)
dbc4e1c1 13462 {
d2bd6bc4 13463 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 13464 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
13465 }
13466 else
68568555
RS
13467 {
13468 /* It seems there is no way to turn off use of an icon pixmap.
13469 The following line does it, only if no icon has yet been created,
13470 for some window managers. But with mwm it crashes.
13471 Some people say it should clear the IconPixmapHint bit in this case,
13472 but that doesn't work, and the X consortium said it isn't the
13473 right thing at all. Since there is no way to win,
13474 best to explicitly give up. */
13475#if 0
13476 f->output_data.x->wm_hints.icon_pixmap = None;
13477#else
13478 return;
13479#endif
13480 }
b1c884c3 13481
d2bd6bc4
RS
13482#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
13483
13484 {
13485 Arg al[1];
13486 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
13487 XtSetValues (f->output_data.x->widget, al, 1);
13488 }
13489
13490#else /* not USE_X_TOOLKIT */
13491
7556890b
RS
13492 f->output_data.x->wm_hints.flags |= IconPixmapHint;
13493 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
13494
13495#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13496}
13497
dfcf069d 13498void
f676886a
JB
13499x_wm_set_icon_position (f, icon_x, icon_y)
13500 struct frame *f;
dc6f92b8
JB
13501 int icon_x, icon_y;
13502{
75231bad 13503#ifdef USE_X_TOOLKIT
7556890b 13504 Window window = XtWindow (f->output_data.x->widget);
75231bad 13505#else
c118dd06 13506 Window window = FRAME_X_WINDOW (f);
75231bad 13507#endif
dc6f92b8 13508
7556890b
RS
13509 f->output_data.x->wm_hints.flags |= IconPositionHint;
13510 f->output_data.x->wm_hints.icon_x = icon_x;
13511 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 13512
7556890b 13513 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
13514}
13515
13516\f
06a2c219
GM
13517/***********************************************************************
13518 Fonts
13519 ***********************************************************************/
dc43ef94
KH
13520
13521/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 13522
dc43ef94
KH
13523struct font_info *
13524x_get_font_info (f, font_idx)
13525 FRAME_PTR f;
13526 int font_idx;
13527{
13528 return (FRAME_X_FONT_TABLE (f) + font_idx);
13529}
13530
13531
9c11f79e
GM
13532/* Return a list of names of available fonts matching PATTERN on frame F.
13533
13534 If SIZE is > 0, it is the size (maximum bounds width) of fonts
13535 to be listed.
13536
13537 SIZE < 0 means include scalable fonts.
13538
13539 Frame F null means we have not yet created any frame on X, and
13540 consult the first display in x_display_list. MAXNAMES sets a limit
13541 on how many fonts to match. */
dc43ef94
KH
13542
13543Lisp_Object
13544x_list_fonts (f, pattern, size, maxnames)
9c11f79e 13545 struct frame *f;
dc43ef94
KH
13546 Lisp_Object pattern;
13547 int size;
13548 int maxnames;
13549{
06a2c219
GM
13550 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
13551 Lisp_Object tem, second_best;
9c11f79e
GM
13552 struct x_display_info *dpyinfo
13553 = f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
13554 Display *dpy = dpyinfo->display;
09c6077f 13555 int try_XLoadQueryFont = 0;
53ca4657 13556 int count;
9c11f79e
GM
13557 int allow_scalable_fonts_p = 0;
13558
13559 if (size < 0)
13560 {
13561 allow_scalable_fonts_p = 1;
13562 size = 0;
13563 }
dc43ef94 13564
6b0efe73 13565 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
13566 if (NILP (patterns))
13567 patterns = Fcons (pattern, Qnil);
81ba44e5 13568
09c6077f
KH
13569 if (maxnames == 1 && !size)
13570 /* We can return any single font matching PATTERN. */
13571 try_XLoadQueryFont = 1;
9a32686f 13572
8e713be6 13573 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 13574 {
dc43ef94 13575 int num_fonts;
3e71d8f2 13576 char **names = NULL;
dc43ef94 13577
8e713be6 13578 pattern = XCAR (patterns);
536f4067
RS
13579 /* See if we cached the result for this particular query.
13580 The cache is an alist of the form:
9c11f79e
GM
13581 ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */
13582 tem = XCDR (dpyinfo->name_list_element);
13583 key = Fcons (Fcons (pattern, make_number (maxnames)),
13584 allow_scalable_fonts_p ? Qt : Qnil);
13585 list = Fassoc (key, tem);
13586 if (!NILP (list))
b5210ea7
KH
13587 {
13588 list = Fcdr_safe (list);
13589 /* We have a cashed list. Don't have to get the list again. */
13590 goto label_cached;
13591 }
13592
13593 /* At first, put PATTERN in the cache. */
09c6077f 13594
dc43ef94 13595 BLOCK_INPUT;
17d85edc
KH
13596 count = x_catch_errors (dpy);
13597
09c6077f
KH
13598 if (try_XLoadQueryFont)
13599 {
13600 XFontStruct *font;
13601 unsigned long value;
13602
13603 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
13604 if (x_had_errors_p (dpy))
13605 {
13606 /* This error is perhaps due to insufficient memory on X
13607 server. Let's just ignore it. */
13608 font = NULL;
13609 x_clear_errors (dpy);
13610 }
13611
09c6077f
KH
13612 if (font
13613 && XGetFontProperty (font, XA_FONT, &value))
13614 {
13615 char *name = (char *) XGetAtomName (dpy, (Atom) value);
13616 int len = strlen (name);
01c752b5 13617 char *tmp;
09c6077f 13618
6f6512e8
KH
13619 /* If DXPC (a Differential X Protocol Compressor)
13620 Ver.3.7 is running, XGetAtomName will return null
13621 string. We must avoid such a name. */
13622 if (len == 0)
13623 try_XLoadQueryFont = 0;
13624 else
13625 {
13626 num_fonts = 1;
13627 names = (char **) alloca (sizeof (char *));
13628 /* Some systems only allow alloca assigned to a
13629 simple var. */
13630 tmp = (char *) alloca (len + 1); names[0] = tmp;
13631 bcopy (name, names[0], len + 1);
13632 XFree (name);
13633 }
09c6077f
KH
13634 }
13635 else
13636 try_XLoadQueryFont = 0;
a083fd23
RS
13637
13638 if (font)
13639 XFreeFont (dpy, font);
09c6077f
KH
13640 }
13641
13642 if (!try_XLoadQueryFont)
17d85edc
KH
13643 {
13644 /* We try at least 10 fonts because XListFonts will return
13645 auto-scaled fonts at the head. */
13646 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
13647 &num_fonts);
13648 if (x_had_errors_p (dpy))
13649 {
13650 /* This error is perhaps due to insufficient memory on X
13651 server. Let's just ignore it. */
13652 names = NULL;
13653 x_clear_errors (dpy);
13654 }
13655 }
13656
13657 x_uncatch_errors (dpy, count);
dc43ef94
KH
13658 UNBLOCK_INPUT;
13659
13660 if (names)
13661 {
13662 int i;
dc43ef94
KH
13663
13664 /* Make a list of all the fonts we got back.
13665 Store that in the font cache for the display. */
13666 for (i = 0; i < num_fonts; i++)
13667 {
06a2c219 13668 int width = 0;
dc43ef94 13669 char *p = names[i];
06a2c219
GM
13670 int average_width = -1, dashes = 0;
13671
dc43ef94 13672 /* Count the number of dashes in NAMES[I]. If there are
9c11f79e
GM
13673 14 dashes, and the field value following 12th dash
13674 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
13675 is usually too ugly to be used for editing. Let's
13676 ignore it. */
dc43ef94
KH
13677 while (*p)
13678 if (*p++ == '-')
13679 {
13680 dashes++;
13681 if (dashes == 7) /* PIXEL_SIZE field */
13682 width = atoi (p);
13683 else if (dashes == 12) /* AVERAGE_WIDTH field */
13684 average_width = atoi (p);
13685 }
9c11f79e
GM
13686
13687 if (allow_scalable_fonts_p
13688 || dashes < 14 || average_width != 0)
dc43ef94
KH
13689 {
13690 tem = build_string (names[i]);
13691 if (NILP (Fassoc (tem, list)))
13692 {
13693 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
13694 && ((fast_c_string_match_ignore_case
13695 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
13696 >= 0))
13697 /* We can set the value of PIXEL_SIZE to the
b5210ea7 13698 width of this font. */
dc43ef94
KH
13699 list = Fcons (Fcons (tem, make_number (width)), list);
13700 else
13701 /* For the moment, width is not known. */
13702 list = Fcons (Fcons (tem, Qnil), list);
13703 }
13704 }
13705 }
e38f4136 13706
09c6077f 13707 if (!try_XLoadQueryFont)
e38f4136
GM
13708 {
13709 BLOCK_INPUT;
13710 XFreeFontNames (names);
13711 UNBLOCK_INPUT;
13712 }
dc43ef94
KH
13713 }
13714
b5210ea7 13715 /* Now store the result in the cache. */
f3fbd155
KR
13716 XSETCDR (dpyinfo->name_list_element,
13717 Fcons (Fcons (key, list), XCDR (dpyinfo->name_list_element)));
dc43ef94 13718
b5210ea7
KH
13719 label_cached:
13720 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 13721
b5210ea7
KH
13722 newlist = second_best = Qnil;
13723 /* Make a list of the fonts that have the right width. */
8e713be6 13724 for (; CONSP (list); list = XCDR (list))
b5210ea7 13725 {
536f4067
RS
13726 int found_size;
13727
8e713be6 13728 tem = XCAR (list);
dc43ef94 13729
8e713be6 13730 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
13731 continue;
13732 if (!size)
13733 {
8e713be6 13734 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
13735 continue;
13736 }
dc43ef94 13737
8e713be6 13738 if (!INTEGERP (XCDR (tem)))
dc43ef94 13739 {
b5210ea7 13740 /* Since we have not yet known the size of this font, we
9c11f79e 13741 must try slow function call XLoadQueryFont. */
dc43ef94
KH
13742 XFontStruct *thisinfo;
13743
13744 BLOCK_INPUT;
17d85edc 13745 count = x_catch_errors (dpy);
dc43ef94 13746 thisinfo = XLoadQueryFont (dpy,
8e713be6 13747 XSTRING (XCAR (tem))->data);
17d85edc
KH
13748 if (x_had_errors_p (dpy))
13749 {
13750 /* This error is perhaps due to insufficient memory on X
13751 server. Let's just ignore it. */
13752 thisinfo = NULL;
13753 x_clear_errors (dpy);
13754 }
13755 x_uncatch_errors (dpy, count);
dc43ef94
KH
13756 UNBLOCK_INPUT;
13757
13758 if (thisinfo)
13759 {
f3fbd155
KR
13760 XSETCDR (tem,
13761 (thisinfo->min_bounds.width == 0
13762 ? make_number (0)
13763 : make_number (thisinfo->max_bounds.width)));
e38f4136 13764 BLOCK_INPUT;
dc43ef94 13765 XFreeFont (dpy, thisinfo);
e38f4136 13766 UNBLOCK_INPUT;
dc43ef94
KH
13767 }
13768 else
b5210ea7 13769 /* For unknown reason, the previous call of XListFont had
06a2c219 13770 returned a font which can't be opened. Record the size
b5210ea7 13771 as 0 not to try to open it again. */
f3fbd155 13772 XSETCDR (tem, make_number (0));
dc43ef94 13773 }
536f4067 13774
8e713be6 13775 found_size = XINT (XCDR (tem));
536f4067 13776 if (found_size == size)
8e713be6 13777 newlist = Fcons (XCAR (tem), newlist);
536f4067 13778 else if (found_size > 0)
b5210ea7 13779 {
536f4067 13780 if (NILP (second_best))
b5210ea7 13781 second_best = tem;
536f4067
RS
13782 else if (found_size < size)
13783 {
8e713be6
KR
13784 if (XINT (XCDR (second_best)) > size
13785 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
13786 second_best = tem;
13787 }
13788 else
13789 {
8e713be6
KR
13790 if (XINT (XCDR (second_best)) > size
13791 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
13792 second_best = tem;
13793 }
b5210ea7
KH
13794 }
13795 }
13796 if (!NILP (newlist))
13797 break;
13798 else if (!NILP (second_best))
13799 {
8e713be6 13800 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 13801 break;
dc43ef94 13802 }
dc43ef94
KH
13803 }
13804
13805 return newlist;
13806}
13807
06a2c219
GM
13808
13809#if GLYPH_DEBUG
13810
13811/* Check that FONT is valid on frame F. It is if it can be found in F's
13812 font table. */
13813
13814static void
13815x_check_font (f, font)
13816 struct frame *f;
13817 XFontStruct *font;
13818{
13819 int i;
13820 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13821
13822 xassert (font != NULL);
13823
13824 for (i = 0; i < dpyinfo->n_fonts; i++)
13825 if (dpyinfo->font_table[i].name
13826 && font == dpyinfo->font_table[i].font)
13827 break;
13828
13829 xassert (i < dpyinfo->n_fonts);
13830}
13831
13832#endif /* GLYPH_DEBUG != 0 */
13833
13834/* Set *W to the minimum width, *H to the minimum font height of FONT.
13835 Note: There are (broken) X fonts out there with invalid XFontStruct
13836 min_bounds contents. For example, handa@etl.go.jp reports that
13837 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
13838 have font->min_bounds.width == 0. */
13839
13840static INLINE void
13841x_font_min_bounds (font, w, h)
13842 XFontStruct *font;
13843 int *w, *h;
13844{
13845 *h = FONT_HEIGHT (font);
13846 *w = font->min_bounds.width;
13847
13848 /* Try to handle the case where FONT->min_bounds has invalid
13849 contents. Since the only font known to have invalid min_bounds
13850 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
13851 if (*w <= 0)
13852 *w = font->max_bounds.width;
13853}
13854
13855
13856/* Compute the smallest character width and smallest font height over
13857 all fonts available on frame F. Set the members smallest_char_width
13858 and smallest_font_height in F's x_display_info structure to
13859 the values computed. Value is non-zero if smallest_font_height or
13860 smallest_char_width become smaller than they were before. */
13861
13862static int
13863x_compute_min_glyph_bounds (f)
13864 struct frame *f;
13865{
13866 int i;
13867 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13868 XFontStruct *font;
13869 int old_width = dpyinfo->smallest_char_width;
13870 int old_height = dpyinfo->smallest_font_height;
13871
13872 dpyinfo->smallest_font_height = 100000;
13873 dpyinfo->smallest_char_width = 100000;
13874
13875 for (i = 0; i < dpyinfo->n_fonts; ++i)
13876 if (dpyinfo->font_table[i].name)
13877 {
13878 struct font_info *fontp = dpyinfo->font_table + i;
13879 int w, h;
13880
13881 font = (XFontStruct *) fontp->font;
13882 xassert (font != (XFontStruct *) ~0);
13883 x_font_min_bounds (font, &w, &h);
13884
13885 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
13886 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
13887 }
13888
13889 xassert (dpyinfo->smallest_char_width > 0
13890 && dpyinfo->smallest_font_height > 0);
13891
13892 return (dpyinfo->n_fonts == 1
13893 || dpyinfo->smallest_char_width < old_width
13894 || dpyinfo->smallest_font_height < old_height);
13895}
13896
13897
dc43ef94
KH
13898/* Load font named FONTNAME of the size SIZE for frame F, and return a
13899 pointer to the structure font_info while allocating it dynamically.
13900 If SIZE is 0, load any size of font.
13901 If loading is failed, return NULL. */
13902
13903struct font_info *
13904x_load_font (f, fontname, size)
13905 struct frame *f;
13906 register char *fontname;
13907 int size;
13908{
13909 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13910 Lisp_Object font_names;
d645aaa4 13911 int count;
dc43ef94
KH
13912
13913 /* Get a list of all the fonts that match this name. Once we
13914 have a list of matching fonts, we compare them against the fonts
13915 we already have by comparing names. */
09c6077f 13916 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
13917
13918 if (!NILP (font_names))
13919 {
13920 Lisp_Object tail;
13921 int i;
13922
13923 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 13924 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
13925 if (dpyinfo->font_table[i].name
13926 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 13927 XSTRING (XCAR (tail))->data)
06a2c219 13928 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 13929 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
13930 return (dpyinfo->font_table + i);
13931 }
13932
13933 /* Load the font and add it to the table. */
13934 {
13935 char *full_name;
13936 XFontStruct *font;
13937 struct font_info *fontp;
13938 unsigned long value;
06a2c219 13939 int i;
dc43ef94 13940
2da424f1
KH
13941 /* If we have found fonts by x_list_font, load one of them. If
13942 not, we still try to load a font by the name given as FONTNAME
13943 because XListFonts (called in x_list_font) of some X server has
13944 a bug of not finding a font even if the font surely exists and
13945 is loadable by XLoadQueryFont. */
e1d6d5b9 13946 if (size > 0 && !NILP (font_names))
8e713be6 13947 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
13948
13949 BLOCK_INPUT;
d645aaa4 13950 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 13951 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
13952 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
13953 {
13954 /* This error is perhaps due to insufficient memory on X
13955 server. Let's just ignore it. */
13956 font = NULL;
13957 x_clear_errors (FRAME_X_DISPLAY (f));
13958 }
13959 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 13960 UNBLOCK_INPUT;
b5210ea7 13961 if (!font)
dc43ef94
KH
13962 return NULL;
13963
06a2c219
GM
13964 /* Find a free slot in the font table. */
13965 for (i = 0; i < dpyinfo->n_fonts; ++i)
13966 if (dpyinfo->font_table[i].name == NULL)
13967 break;
13968
13969 /* If no free slot found, maybe enlarge the font table. */
13970 if (i == dpyinfo->n_fonts
13971 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 13972 {
06a2c219
GM
13973 int sz;
13974 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
13975 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 13976 dpyinfo->font_table
06a2c219 13977 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
13978 }
13979
06a2c219
GM
13980 fontp = dpyinfo->font_table + i;
13981 if (i == dpyinfo->n_fonts)
13982 ++dpyinfo->n_fonts;
dc43ef94
KH
13983
13984 /* Now fill in the slots of *FONTP. */
13985 BLOCK_INPUT;
13986 fontp->font = font;
06a2c219 13987 fontp->font_idx = i;
dc43ef94
KH
13988 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
13989 bcopy (fontname, fontp->name, strlen (fontname) + 1);
13990
13991 /* Try to get the full name of FONT. Put it in FULL_NAME. */
13992 full_name = 0;
13993 if (XGetFontProperty (font, XA_FONT, &value))
13994 {
13995 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
13996 char *p = name;
13997 int dashes = 0;
13998
13999 /* Count the number of dashes in the "full name".
14000 If it is too few, this isn't really the font's full name,
14001 so don't use it.
14002 In X11R4, the fonts did not come with their canonical names
14003 stored in them. */
14004 while (*p)
14005 {
14006 if (*p == '-')
14007 dashes++;
14008 p++;
14009 }
14010
14011 if (dashes >= 13)
14012 {
14013 full_name = (char *) xmalloc (p - name + 1);
14014 bcopy (name, full_name, p - name + 1);
14015 }
14016
14017 XFree (name);
14018 }
14019
14020 if (full_name != 0)
14021 fontp->full_name = full_name;
14022 else
14023 fontp->full_name = fontp->name;
14024
14025 fontp->size = font->max_bounds.width;
d5749adb 14026 fontp->height = FONT_HEIGHT (font);
dc43ef94 14027
2da424f1
KH
14028 if (NILP (font_names))
14029 {
14030 /* We come here because of a bug of XListFonts mentioned at
14031 the head of this block. Let's store this information in
14032 the cache for x_list_fonts. */
14033 Lisp_Object lispy_name = build_string (fontname);
14034 Lisp_Object lispy_full_name = build_string (fontp->full_name);
9c11f79e
GM
14035 Lisp_Object key = Fcons (Fcons (lispy_name, make_number (256)),
14036 Qnil);
2da424f1 14037
f3fbd155
KR
14038 XSETCDR (dpyinfo->name_list_element,
14039 Fcons (Fcons (key,
14040 Fcons (Fcons (lispy_full_name,
14041 make_number (fontp->size)),
14042 Qnil)),
14043 XCDR (dpyinfo->name_list_element)));
2da424f1 14044 if (full_name)
9c11f79e
GM
14045 {
14046 key = Fcons (Fcons (lispy_full_name, make_number (256)),
14047 Qnil);
f3fbd155
KR
14048 XSETCDR (dpyinfo->name_list_element,
14049 Fcons (Fcons (key,
14050 Fcons (Fcons (lispy_full_name,
14051 make_number (fontp->size)),
14052 Qnil)),
14053 XCDR (dpyinfo->name_list_element)));
9c11f79e 14054 }
2da424f1
KH
14055 }
14056
dc43ef94
KH
14057 /* The slot `encoding' specifies how to map a character
14058 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
14059 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
14060 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 14061 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 14062 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
14063 which is never used by any charset. If mapping can't be
14064 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
14065 fontp->encoding[1]
14066 = (font->max_byte1 == 0
14067 /* 1-byte font */
14068 ? (font->min_char_or_byte2 < 0x80
14069 ? (font->max_char_or_byte2 < 0x80
14070 ? 0 /* 0x20..0x7F */
8ff102bd 14071 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
14072 : 1) /* 0xA0..0xFF */
14073 /* 2-byte font */
14074 : (font->min_byte1 < 0x80
14075 ? (font->max_byte1 < 0x80
14076 ? (font->min_char_or_byte2 < 0x80
14077 ? (font->max_char_or_byte2 < 0x80
14078 ? 0 /* 0x2020..0x7F7F */
8ff102bd 14079 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 14080 : 3) /* 0x20A0..0x7FFF */
8ff102bd 14081 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
14082 : (font->min_char_or_byte2 < 0x80
14083 ? (font->max_char_or_byte2 < 0x80
14084 ? 2 /* 0xA020..0xFF7F */
8ff102bd 14085 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
14086 : 1))); /* 0xA0A0..0xFFFF */
14087
14088 fontp->baseline_offset
14089 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
14090 ? (long) value : 0);
14091 fontp->relative_compose
14092 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
14093 ? (long) value : 0);
f78798df
KH
14094 fontp->default_ascent
14095 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
14096 ? (long) value : 0);
dc43ef94 14097
06a2c219
GM
14098 /* Set global flag fonts_changed_p to non-zero if the font loaded
14099 has a character with a smaller width than any other character
14100 before, or if the font loaded has a smalle>r height than any
14101 other font loaded before. If this happens, it will make a
14102 glyph matrix reallocation necessary. */
14103 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 14104 UNBLOCK_INPUT;
dc43ef94
KH
14105 return fontp;
14106 }
14107}
14108
06a2c219
GM
14109
14110/* Return a pointer to struct font_info of a font named FONTNAME for
14111 frame F. If no such font is loaded, return NULL. */
14112
dc43ef94
KH
14113struct font_info *
14114x_query_font (f, fontname)
14115 struct frame *f;
14116 register char *fontname;
14117{
14118 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14119 int i;
14120
14121 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
14122 if (dpyinfo->font_table[i].name
14123 && (!strcmp (dpyinfo->font_table[i].name, fontname)
14124 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
14125 return (dpyinfo->font_table + i);
14126 return NULL;
14127}
14128
06a2c219
GM
14129
14130/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
14131 `encoder' of the structure. */
14132
14133void
14134x_find_ccl_program (fontp)
14135 struct font_info *fontp;
14136{
a42f54e6 14137 Lisp_Object list, elt;
a6582676 14138
f9b5db02 14139 elt = Qnil;
8e713be6 14140 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 14141 {
8e713be6 14142 elt = XCAR (list);
a6582676 14143 if (CONSP (elt)
8e713be6 14144 && STRINGP (XCAR (elt))
9f2feff6
KH
14145 && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
14146 >= 0)
14147 || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
14148 >= 0)))
a42f54e6
KH
14149 break;
14150 }
f9b5db02 14151
a42f54e6
KH
14152 if (! NILP (list))
14153 {
d27f8ca7
KH
14154 struct ccl_program *ccl
14155 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 14156
8e713be6 14157 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
14158 xfree (ccl);
14159 else
14160 fontp->font_encoder = ccl;
a6582676
KH
14161 }
14162}
14163
06a2c219 14164
dc43ef94 14165\f
06a2c219
GM
14166/***********************************************************************
14167 Initialization
14168 ***********************************************************************/
f451eb13 14169
3afe33e7
RS
14170#ifdef USE_X_TOOLKIT
14171static XrmOptionDescRec emacs_options[] = {
14172 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
14173 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
14174
14175 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
14176 XrmoptionSepArg, NULL},
14177 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
14178
14179 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14180 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14181 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14182 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14183 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14184 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
14185 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
14186};
14187#endif /* USE_X_TOOLKIT */
14188
7a13e894
RS
14189static int x_initialized;
14190
29b38361
KH
14191#ifdef MULTI_KBOARD
14192/* Test whether two display-name strings agree up to the dot that separates
14193 the screen number from the server number. */
14194static int
14195same_x_server (name1, name2)
14196 char *name1, *name2;
14197{
14198 int seen_colon = 0;
cf591cc1
RS
14199 unsigned char *system_name = XSTRING (Vsystem_name)->data;
14200 int system_name_length = strlen (system_name);
14201 int length_until_period = 0;
14202
14203 while (system_name[length_until_period] != 0
14204 && system_name[length_until_period] != '.')
14205 length_until_period++;
14206
14207 /* Treat `unix' like an empty host name. */
14208 if (! strncmp (name1, "unix:", 5))
14209 name1 += 4;
14210 if (! strncmp (name2, "unix:", 5))
14211 name2 += 4;
14212 /* Treat this host's name like an empty host name. */
14213 if (! strncmp (name1, system_name, system_name_length)
14214 && name1[system_name_length] == ':')
14215 name1 += system_name_length;
14216 if (! strncmp (name2, system_name, system_name_length)
14217 && name2[system_name_length] == ':')
14218 name2 += system_name_length;
14219 /* Treat this host's domainless name like an empty host name. */
14220 if (! strncmp (name1, system_name, length_until_period)
14221 && name1[length_until_period] == ':')
14222 name1 += length_until_period;
14223 if (! strncmp (name2, system_name, length_until_period)
14224 && name2[length_until_period] == ':')
14225 name2 += length_until_period;
14226
29b38361
KH
14227 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
14228 {
14229 if (*name1 == ':')
14230 seen_colon++;
14231 if (seen_colon && *name1 == '.')
14232 return 1;
14233 }
14234 return (seen_colon
14235 && (*name1 == '.' || *name1 == '\0')
14236 && (*name2 == '.' || *name2 == '\0'));
14237}
14238#endif
14239
334208b7 14240struct x_display_info *
1f8255f2 14241x_term_init (display_name, xrm_option, resource_name)
334208b7 14242 Lisp_Object display_name;
1f8255f2
RS
14243 char *xrm_option;
14244 char *resource_name;
dc6f92b8 14245{
334208b7 14246 int connection;
7a13e894 14247 Display *dpy;
334208b7
RS
14248 struct x_display_info *dpyinfo;
14249 XrmDatabase xrdb;
14250
60439948
KH
14251 BLOCK_INPUT;
14252
7a13e894
RS
14253 if (!x_initialized)
14254 {
14255 x_initialize ();
14256 x_initialized = 1;
14257 }
dc6f92b8 14258
3afe33e7 14259#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
14260 /* weiner@footloose.sps.mot.com reports that this causes
14261 errors with X11R5:
14262 X protocol error: BadAtom (invalid Atom parameter)
14263 on protocol request 18skiloaf.
14264 So let's not use it until R6. */
14265#ifdef HAVE_X11XTR6
bdcd49ba
RS
14266 XtSetLanguageProc (NULL, NULL, NULL);
14267#endif
14268
7f9c7f94
RS
14269 {
14270 int argc = 0;
14271 char *argv[3];
14272
14273 argv[0] = "";
14274 argc = 1;
14275 if (xrm_option)
14276 {
14277 argv[argc++] = "-xrm";
14278 argv[argc++] = xrm_option;
14279 }
14280 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
14281 resource_name, EMACS_CLASS,
14282 emacs_options, XtNumber (emacs_options),
14283 &argc, argv);
39d8bb4d
KH
14284
14285#ifdef HAVE_X11XTR6
10537cb1 14286 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 14287 fixup_locale ();
39d8bb4d 14288#endif
7f9c7f94 14289 }
3afe33e7
RS
14290
14291#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
14292#ifdef HAVE_X11R5
14293 XSetLocaleModifiers ("");
14294#endif
7a13e894 14295 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 14296#endif /* not USE_X_TOOLKIT */
334208b7 14297
7a13e894
RS
14298 /* Detect failure. */
14299 if (dpy == 0)
60439948
KH
14300 {
14301 UNBLOCK_INPUT;
14302 return 0;
14303 }
7a13e894
RS
14304
14305 /* We have definitely succeeded. Record the new connection. */
14306
14307 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
f04e1297 14308 bzero (dpyinfo, sizeof *dpyinfo);
7a13e894 14309
29b38361
KH
14310#ifdef MULTI_KBOARD
14311 {
14312 struct x_display_info *share;
14313 Lisp_Object tail;
14314
14315 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
14316 share = share->next, tail = XCDR (tail))
14317 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
14318 XSTRING (display_name)->data))
14319 break;
14320 if (share)
14321 dpyinfo->kboard = share->kboard;
14322 else
14323 {
14324 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
14325 init_kboard (dpyinfo->kboard);
59e755be
KH
14326 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
14327 {
14328 char *vendor = ServerVendor (dpy);
9b6ed9f3 14329 UNBLOCK_INPUT;
59e755be
KH
14330 dpyinfo->kboard->Vsystem_key_alist
14331 = call1 (Qvendor_specific_keysyms,
14332 build_string (vendor ? vendor : ""));
9b6ed9f3 14333 BLOCK_INPUT;
59e755be
KH
14334 }
14335
29b38361
KH
14336 dpyinfo->kboard->next_kboard = all_kboards;
14337 all_kboards = dpyinfo->kboard;
0ad5446c
KH
14338 /* Don't let the initial kboard remain current longer than necessary.
14339 That would cause problems if a file loaded on startup tries to
06a2c219 14340 prompt in the mini-buffer. */
0ad5446c
KH
14341 if (current_kboard == initial_kboard)
14342 current_kboard = dpyinfo->kboard;
29b38361
KH
14343 }
14344 dpyinfo->kboard->reference_count++;
14345 }
b9737ad3
KH
14346#endif
14347
7a13e894
RS
14348 /* Put this display on the chain. */
14349 dpyinfo->next = x_display_list;
14350 x_display_list = dpyinfo;
14351
14352 /* Put it on x_display_name_list as well, to keep them parallel. */
14353 x_display_name_list = Fcons (Fcons (display_name, Qnil),
14354 x_display_name_list);
8e713be6 14355 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
14356
14357 dpyinfo->display = dpy;
dc6f92b8 14358
dc6f92b8 14359#if 0
7a13e894 14360 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 14361#endif /* ! 0 */
7a13e894
RS
14362
14363 dpyinfo->x_id_name
fc932ac6
RS
14364 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
14365 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
14366 + 2);
14367 sprintf (dpyinfo->x_id_name, "%s@%s",
14368 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
14369
14370 /* Figure out which modifier bits mean what. */
334208b7 14371 x_find_modifier_meanings (dpyinfo);
f451eb13 14372
ab648270 14373 /* Get the scroll bar cursor. */
7a13e894 14374 dpyinfo->vertical_scroll_bar_cursor
334208b7 14375 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 14376
334208b7
RS
14377 xrdb = x_load_resources (dpyinfo->display, xrm_option,
14378 resource_name, EMACS_CLASS);
14379#ifdef HAVE_XRMSETDATABASE
14380 XrmSetDatabase (dpyinfo->display, xrdb);
14381#else
14382 dpyinfo->display->db = xrdb;
14383#endif
547d9db8 14384 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
14385 all versions. */
14386 dpyinfo->xrdb = xrdb;
334208b7
RS
14387
14388 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
14389 DefaultScreen (dpyinfo->display));
5ff67d81 14390 select_visual (dpyinfo);
43bd1b2b 14391 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
14392 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
14393 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
14394 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
14395 dpyinfo->grabbed = 0;
14396 dpyinfo->reference_count = 0;
14397 dpyinfo->icon_bitmap_id = -1;
06a2c219 14398 dpyinfo->font_table = NULL;
7a13e894
RS
14399 dpyinfo->n_fonts = 0;
14400 dpyinfo->font_table_size = 0;
14401 dpyinfo->bitmaps = 0;
14402 dpyinfo->bitmaps_size = 0;
14403 dpyinfo->bitmaps_last = 0;
14404 dpyinfo->scratch_cursor_gc = 0;
14405 dpyinfo->mouse_face_mouse_frame = 0;
14406 dpyinfo->mouse_face_deferred_gc = 0;
14407 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
14408 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 14409 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894 14410 dpyinfo->mouse_face_window = Qnil;
0a61c667 14411 dpyinfo->mouse_face_overlay = Qnil;
7a13e894
RS
14412 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
14413 dpyinfo->mouse_face_defer = 0;
0f941935
KH
14414 dpyinfo->x_focus_frame = 0;
14415 dpyinfo->x_focus_event_frame = 0;
14416 dpyinfo->x_highlight_frame = 0;
06a2c219 14417 dpyinfo->image_cache = make_image_cache ();
334208b7 14418
43bd1b2b 14419 /* See if a private colormap is requested. */
5ff67d81
GM
14420 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
14421 {
14422 if (dpyinfo->visual->class == PseudoColor)
14423 {
14424 Lisp_Object value;
14425 value = display_x_get_resource (dpyinfo,
14426 build_string ("privateColormap"),
14427 build_string ("PrivateColormap"),
14428 Qnil, Qnil);
14429 if (STRINGP (value)
14430 && (!strcmp (XSTRING (value)->data, "true")
14431 || !strcmp (XSTRING (value)->data, "on")))
14432 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
14433 }
43bd1b2b 14434 }
5ff67d81
GM
14435 else
14436 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
14437 dpyinfo->visual, AllocNone);
43bd1b2b 14438
06a2c219
GM
14439 {
14440 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
14441 double pixels = DisplayHeight (dpyinfo->display, screen_number);
14442 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
14443 dpyinfo->resy = pixels * 25.4 / mm;
14444 pixels = DisplayWidth (dpyinfo->display, screen_number);
14445 mm = DisplayWidthMM (dpyinfo->display, screen_number);
14446 dpyinfo->resx = pixels * 25.4 / mm;
14447 }
14448
334208b7
RS
14449 dpyinfo->Xatom_wm_protocols
14450 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
14451 dpyinfo->Xatom_wm_take_focus
14452 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
14453 dpyinfo->Xatom_wm_save_yourself
14454 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
14455 dpyinfo->Xatom_wm_delete_window
14456 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
14457 dpyinfo->Xatom_wm_change_state
14458 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
14459 dpyinfo->Xatom_wm_configure_denied
14460 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
14461 dpyinfo->Xatom_wm_window_moved
14462 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
14463 dpyinfo->Xatom_editres
14464 = XInternAtom (dpyinfo->display, "Editres", False);
14465 dpyinfo->Xatom_CLIPBOARD
14466 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
14467 dpyinfo->Xatom_TIMESTAMP
14468 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
14469 dpyinfo->Xatom_TEXT
14470 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
14471 dpyinfo->Xatom_COMPOUND_TEXT
14472 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
14473 dpyinfo->Xatom_DELETE
14474 = XInternAtom (dpyinfo->display, "DELETE", False);
14475 dpyinfo->Xatom_MULTIPLE
14476 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
14477 dpyinfo->Xatom_INCR
14478 = XInternAtom (dpyinfo->display, "INCR", False);
14479 dpyinfo->Xatom_EMACS_TMP
14480 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
14481 dpyinfo->Xatom_TARGETS
14482 = XInternAtom (dpyinfo->display, "TARGETS", False);
14483 dpyinfo->Xatom_NULL
14484 = XInternAtom (dpyinfo->display, "NULL", False);
14485 dpyinfo->Xatom_ATOM_PAIR
14486 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
14487 /* For properties of font. */
14488 dpyinfo->Xatom_PIXEL_SIZE
14489 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
14490 dpyinfo->Xatom_MULE_BASELINE_OFFSET
14491 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
14492 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
14493 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
14494 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
14495 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 14496
06a2c219
GM
14497 /* Ghostscript support. */
14498 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
14499 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
14500
14501 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
14502 False);
14503
547d9db8
KH
14504 dpyinfo->cut_buffers_initialized = 0;
14505
334208b7
RS
14506 connection = ConnectionNumber (dpyinfo->display);
14507 dpyinfo->connection = connection;
14508
dc43ef94 14509 {
5d7cc324
RS
14510 char null_bits[1];
14511
14512 null_bits[0] = 0x00;
dc43ef94
KH
14513
14514 dpyinfo->null_pixel
14515 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14516 null_bits, 1, 1, (long) 0, (long) 0,
14517 1);
14518 }
14519
06a2c219
GM
14520 {
14521 extern int gray_bitmap_width, gray_bitmap_height;
10659c77 14522 extern char *gray_bitmap_bits;
06a2c219
GM
14523 dpyinfo->gray
14524 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14525 gray_bitmap_bits,
14526 gray_bitmap_width, gray_bitmap_height,
14527 (unsigned long) 1, (unsigned long) 0, 1);
14528 }
14529
f5d11644
GM
14530#ifdef HAVE_X_I18N
14531 xim_initialize (dpyinfo, resource_name);
14532#endif
14533
87485d6f
MW
14534#ifdef subprocesses
14535 /* This is only needed for distinguishing keyboard and process input. */
334208b7 14536 if (connection != 0)
7a13e894 14537 add_keyboard_wait_descriptor (connection);
87485d6f 14538#endif
6d4238f3 14539
041b69ac 14540#ifndef F_SETOWN_BUG
dc6f92b8 14541#ifdef F_SETOWN
dc6f92b8 14542#ifdef F_SETOWN_SOCK_NEG
61c3ce62 14543 /* stdin is a socket here */
334208b7 14544 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 14545#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 14546 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
14547#endif /* ! defined (F_SETOWN_SOCK_NEG) */
14548#endif /* ! defined (F_SETOWN) */
041b69ac 14549#endif /* F_SETOWN_BUG */
dc6f92b8
JB
14550
14551#ifdef SIGIO
eee20f6a
KH
14552 if (interrupt_input)
14553 init_sigio (connection);
c118dd06 14554#endif /* ! defined (SIGIO) */
dc6f92b8 14555
51b592fb 14556#ifdef USE_LUCID
f8c39f51 14557#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
14558 /* Make sure that we have a valid font for dialog boxes
14559 so that Xt does not crash. */
14560 {
14561 Display *dpy = dpyinfo->display;
14562 XrmValue d, fr, to;
14563 Font font;
e99db5a1 14564 int count;
51b592fb
RS
14565
14566 d.addr = (XPointer)&dpy;
14567 d.size = sizeof (Display *);
14568 fr.addr = XtDefaultFont;
14569 fr.size = sizeof (XtDefaultFont);
14570 to.size = sizeof (Font *);
14571 to.addr = (XPointer)&font;
e99db5a1 14572 count = x_catch_errors (dpy);
51b592fb
RS
14573 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
14574 abort ();
14575 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
14576 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 14577 x_uncatch_errors (dpy, count);
51b592fb
RS
14578 }
14579#endif
f8c39f51 14580#endif
51b592fb 14581
34e23e5a
GM
14582 /* See if we should run in synchronous mode. This is useful
14583 for debugging X code. */
14584 {
14585 Lisp_Object value;
14586 value = display_x_get_resource (dpyinfo,
14587 build_string ("synchronous"),
14588 build_string ("Synchronous"),
14589 Qnil, Qnil);
14590 if (STRINGP (value)
14591 && (!strcmp (XSTRING (value)->data, "true")
14592 || !strcmp (XSTRING (value)->data, "on")))
14593 XSynchronize (dpyinfo->display, True);
14594 }
14595
60439948
KH
14596 UNBLOCK_INPUT;
14597
7a13e894
RS
14598 return dpyinfo;
14599}
14600\f
14601/* Get rid of display DPYINFO, assuming all frames are already gone,
14602 and without sending any more commands to the X server. */
dc6f92b8 14603
7a13e894
RS
14604void
14605x_delete_display (dpyinfo)
14606 struct x_display_info *dpyinfo;
14607{
14608 delete_keyboard_wait_descriptor (dpyinfo->connection);
14609
14610 /* Discard this display from x_display_name_list and x_display_list.
14611 We can't use Fdelq because that can quit. */
14612 if (! NILP (x_display_name_list)
8e713be6
KR
14613 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
14614 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
14615 else
14616 {
14617 Lisp_Object tail;
14618
14619 tail = x_display_name_list;
8e713be6 14620 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 14621 {
bffcfca9 14622 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 14623 {
f3fbd155 14624 XSETCDR (tail, XCDR (XCDR (tail)));
7a13e894
RS
14625 break;
14626 }
8e713be6 14627 tail = XCDR (tail);
7a13e894
RS
14628 }
14629 }
14630
9bda743f
GM
14631 if (next_noop_dpyinfo == dpyinfo)
14632 next_noop_dpyinfo = dpyinfo->next;
14633
7a13e894
RS
14634 if (x_display_list == dpyinfo)
14635 x_display_list = dpyinfo->next;
7f9c7f94
RS
14636 else
14637 {
14638 struct x_display_info *tail;
7a13e894 14639
7f9c7f94
RS
14640 for (tail = x_display_list; tail; tail = tail->next)
14641 if (tail->next == dpyinfo)
14642 tail->next = tail->next->next;
14643 }
7a13e894 14644
0d777288
RS
14645#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
14646#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
14647 XrmDestroyDatabase (dpyinfo->xrdb);
14648#endif
0d777288 14649#endif
29b38361
KH
14650#ifdef MULTI_KBOARD
14651 if (--dpyinfo->kboard->reference_count == 0)
39f79001 14652 delete_kboard (dpyinfo->kboard);
b9737ad3 14653#endif
f5d11644
GM
14654#ifdef HAVE_X_I18N
14655 if (dpyinfo->xim)
14656 xim_close_dpy (dpyinfo);
14657#endif
14658
b9737ad3
KH
14659 xfree (dpyinfo->font_table);
14660 xfree (dpyinfo->x_id_name);
f04e1297 14661 xfree (dpyinfo->color_cells);
b9737ad3 14662 xfree (dpyinfo);
7a13e894 14663}
f04e1297 14664
7a13e894
RS
14665\f
14666/* Set up use of X before we make the first connection. */
14667
06a2c219
GM
14668static struct redisplay_interface x_redisplay_interface =
14669{
14670 x_produce_glyphs,
14671 x_write_glyphs,
14672 x_insert_glyphs,
14673 x_clear_end_of_line,
14674 x_scroll_run,
14675 x_after_update_window_line,
14676 x_update_window_begin,
14677 x_update_window_end,
14678 XTcursor_to,
14679 x_flush,
71b8321e 14680 x_clear_mouse_face,
66ac4b0e
GM
14681 x_get_glyph_overhangs,
14682 x_fix_overlapping_area
06a2c219
GM
14683};
14684
dfcf069d 14685void
7a13e894
RS
14686x_initialize ()
14687{
06a2c219
GM
14688 rif = &x_redisplay_interface;
14689
14690 clear_frame_hook = x_clear_frame;
14691 ins_del_lines_hook = x_ins_del_lines;
14692 change_line_highlight_hook = x_change_line_highlight;
14693 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
14694 ring_bell_hook = XTring_bell;
14695 reset_terminal_modes_hook = XTreset_terminal_modes;
14696 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
14697 update_begin_hook = x_update_begin;
14698 update_end_hook = x_update_end;
dc6f92b8
JB
14699 set_terminal_window_hook = XTset_terminal_window;
14700 read_socket_hook = XTread_socket;
b8009dd1 14701 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8 14702 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 14703 mouse_position_hook = XTmouse_position;
f451eb13 14704 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 14705 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
14706 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
14707 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
14708 redeem_scroll_bar_hook = XTredeem_scroll_bar;
14709 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 14710 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 14711
f676886a 14712 scroll_region_ok = 1; /* we'll scroll partial frames */
9017309f 14713 char_ins_del_ok = 1;
dc6f92b8
JB
14714 line_ins_del_ok = 1; /* we'll just blt 'em */
14715 fast_clear_end_of_line = 1; /* X does this well */
58769bee 14716 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
14717 off the bottom */
14718 baud_rate = 19200;
14719
7a13e894 14720 x_noop_count = 0;
9ea173e8 14721 last_tool_bar_item = -1;
06a2c219
GM
14722 any_help_event_p = 0;
14723
b30b24cb
RS
14724 /* Try to use interrupt input; if we can't, then start polling. */
14725 Fset_input_mode (Qt, Qnil, Qt, Qnil);
14726
7f9c7f94
RS
14727#ifdef USE_X_TOOLKIT
14728 XtToolkitInitialize ();
651f03b6 14729
7f9c7f94 14730 Xt_app_con = XtCreateApplicationContext ();
651f03b6
GM
14731
14732 /* Register a converter from strings to pixels, which uses
14733 Emacs' color allocation infrastructure. */
14734 XtAppSetTypeConverter (Xt_app_con,
14735 XtRString, XtRPixel, cvt_string_to_pixel,
14736 cvt_string_to_pixel_args,
14737 XtNumber (cvt_string_to_pixel_args),
14738 XtCacheByDisplay, cvt_pixel_dtor);
14739
665881ad 14740 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
14741
14742 /* Install an asynchronous timer that processes Xt timeout events
14743 every 0.1s. This is necessary because some widget sets use
14744 timeouts internally, for example the LessTif menu bar, or the
14745 Xaw3d scroll bar. When Xt timouts aren't processed, these
14746 widgets don't behave normally. */
14747 {
14748 EMACS_TIME interval;
14749 EMACS_SET_SECS_USECS (interval, 0, 100000);
14750 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
14751 }
db74249b 14752#endif
bffcfca9 14753
eccc05db 14754#ifdef USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
14755 xaw3d_arrow_scroll = False;
14756 xaw3d_pick_top = True;
7f9c7f94
RS
14757#endif
14758
58769bee 14759 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 14760 original error handler. */
e99db5a1 14761 XSetErrorHandler (x_error_handler);
334208b7 14762 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 14763
06a2c219 14764 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
14765#ifdef SIGWINCH
14766 signal (SIGWINCH, SIG_DFL);
c118dd06 14767#endif /* ! defined (SIGWINCH) */
dc6f92b8 14768
92e2441b 14769 signal (SIGPIPE, x_connection_signal);
dc6f92b8 14770}
55123275 14771
06a2c219 14772
55123275
JB
14773void
14774syms_of_xterm ()
14775{
e99db5a1
RS
14776 staticpro (&x_error_message_string);
14777 x_error_message_string = Qnil;
14778
7a13e894
RS
14779 staticpro (&x_display_name_list);
14780 x_display_name_list = Qnil;
334208b7 14781
ab648270 14782 staticpro (&last_mouse_scroll_bar);
e53cb100 14783 last_mouse_scroll_bar = Qnil;
59e755be
KH
14784
14785 staticpro (&Qvendor_specific_keysyms);
14786 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
14787
14788 staticpro (&last_mouse_press_frame);
14789 last_mouse_press_frame = Qnil;
06a2c219 14790
06a2c219 14791 help_echo = Qnil;
be010514
GM
14792 staticpro (&help_echo);
14793 help_echo_object = Qnil;
14794 staticpro (&help_echo_object);
7cea38bc
GM
14795 help_echo_window = Qnil;
14796 staticpro (&help_echo_window);
06a2c219 14797 previous_help_echo = Qnil;
be010514
GM
14798 staticpro (&previous_help_echo);
14799 help_echo_pos = -1;
06a2c219 14800
7ee72033
MB
14801 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
14802 doc: /* *Non-nil means draw block cursor as wide as the glyph under it.
228299fa
GM
14803For example, if a block cursor is over a tab, it will be drawn as
14804wide as that tab on the display. */);
06a2c219
GM
14805 x_stretch_cursor_p = 0;
14806
a72d5ce5 14807 DEFVAR_BOOL ("x-use-underline-position-properties",
7ee72033
MB
14808 &x_use_underline_position_properties,
14809 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
228299fa
GM
14810Nil means ignore them. If you encounter fonts with bogus
14811UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
14812to 4.1, set this to nil. */);
a72d5ce5
GM
14813 x_use_underline_position_properties = 1;
14814
7ee72033
MB
14815 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
14816 doc: /* What X toolkit scroll bars Emacs uses.
228299fa
GM
14817A value of nil means Emacs doesn't use X toolkit scroll bars.
14818Otherwise, value is a symbol describing the X toolkit. */);
eccc05db 14819#ifdef USE_TOOLKIT_SCROLL_BARS
5bf04520
GM
14820#ifdef USE_MOTIF
14821 Vx_toolkit_scroll_bars = intern ("motif");
14822#elif defined HAVE_XAW3D
14823 Vx_toolkit_scroll_bars = intern ("xaw3d");
14824#else
14825 Vx_toolkit_scroll_bars = intern ("xaw");
14826#endif
06a2c219 14827#else
5bf04520 14828 Vx_toolkit_scroll_bars = Qnil;
06a2c219
GM
14829#endif
14830
06a2c219
GM
14831 staticpro (&last_mouse_motion_frame);
14832 last_mouse_motion_frame = Qnil;
55123275 14833}
6cf0ae86 14834
1d6c120a 14835#endif /* HAVE_X_WINDOWS */