struct x_output): Add left_fringe_width, right_fringe_width,
[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
3f332ef3 158/* Fringe bitmaps. */
06a2c219 159
3f332ef3 160enum fringe_bitmap_type
06a2c219 161{
3f332ef3 162 NO_FRINGE_BITMAP,
06a2c219
GM
163 LEFT_TRUNCATION_BITMAP,
164 RIGHT_TRUNCATION_BITMAP,
165 OVERLAY_ARROW_BITMAP,
166 CONTINUED_LINE_BITMAP,
167 CONTINUATION_LINE_BITMAP,
168 ZV_LINE_BITMAP
169};
170
171/* Bitmap drawn to indicate lines not displaying text if
172 `indicate-empty-lines' is non-nil. */
173
174#define zv_width 8
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
06a2c219
GM
277/* This is a frame waiting to be auto-raised, within XTread_socket. */
278
0134a210
RS
279struct frame *pending_autoraise_frame;
280
7f9c7f94
RS
281#ifdef USE_X_TOOLKIT
282/* The application context for Xt use. */
283XtAppContext Xt_app_con;
06a2c219
GM
284static String Xt_default_resources[] = {0};
285#endif /* USE_X_TOOLKIT */
665881ad 286
06a2c219
GM
287/* Nominal cursor position -- where to draw output.
288 HPOS and VPOS are window relative glyph matrix coordinates.
289 X and Y are window relative pixel coordinates. */
dc6f92b8 290
06a2c219 291struct cursor_pos output_cursor;
dc6f92b8 292
bffcfca9
GM
293/* Non-zero means user is interacting with a toolkit scroll bar. */
294
295static int toolkit_scroll_bar_interaction;
dc6f92b8 296
69388238
RS
297/* Mouse movement.
298
06a2c219 299 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
300 so that we would have to call XQueryPointer after each MotionNotify
301 event to ask for another such event. However, this made mouse tracking
302 slow, and there was a bug that made it eventually stop.
303
304 Simply asking for MotionNotify all the time seems to work better.
305
69388238
RS
306 In order to avoid asking for motion events and then throwing most
307 of them away or busy-polling the server for mouse positions, we ask
308 the server for pointer motion hints. This means that we get only
309 one event per group of mouse movements. "Groups" are delimited by
310 other kinds of events (focus changes and button clicks, for
311 example), or by XQueryPointer calls; when one of these happens, we
312 get another MotionNotify event the next time the mouse moves. This
313 is at least as efficient as getting motion events when mouse
314 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 315 is off. */
69388238
RS
316
317/* Where the mouse was last time we reported a mouse event. */
69388238 318
06a2c219
GM
319FRAME_PTR last_mouse_frame;
320static XRectangle last_mouse_glyph;
2237cac9
RS
321static Lisp_Object last_mouse_press_frame;
322
69388238
RS
323/* The scroll bar in which the last X motion event occurred.
324
06a2c219
GM
325 If the last X motion event occurred in a scroll bar, we set this so
326 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
327 an ordinary motion.
328
06a2c219
GM
329 If the last X motion event didn't occur in a scroll bar, we set
330 this to Qnil, to tell XTmouse_position to return an ordinary motion
331 event. */
332
69388238
RS
333static Lisp_Object last_mouse_scroll_bar;
334
69388238
RS
335/* This is a hack. We would really prefer that XTmouse_position would
336 return the time associated with the position it returns, but there
06a2c219 337 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
338 along with the position query. So, we just keep track of the time
339 of the last movement we received, and return that in hopes that
340 it's somewhat accurate. */
06a2c219 341
69388238
RS
342static Time last_mouse_movement_time;
343
06a2c219
GM
344/* Incremented by XTread_socket whenever it really tries to read
345 events. */
346
c0a04927
RS
347#ifdef __STDC__
348static int volatile input_signal_count;
349#else
350static int input_signal_count;
351#endif
352
7a13e894 353/* Used locally within XTread_socket. */
06a2c219 354
7a13e894 355static int x_noop_count;
dc6f92b8 356
7a13e894 357/* Initial values of argv and argc. */
06a2c219 358
7a13e894
RS
359extern char **initial_argv;
360extern int initial_argc;
dc6f92b8 361
7a13e894 362extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 363
06a2c219 364/* Tells if a window manager is present or not. */
7a13e894
RS
365
366extern Lisp_Object Vx_no_window_manager;
dc6f92b8 367
c2df547c 368extern Lisp_Object Qface, Qmouse_face;
b8009dd1 369
dc6f92b8
JB
370extern int errno;
371
dfeccd2d 372/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 373
64bb1782
RS
374extern int extra_keyboard_modifiers;
375
59e755be
KH
376static Lisp_Object Qvendor_specific_keysyms;
377
952291d9
GM
378extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
379extern Lisp_Object x_icon_type P_ ((struct frame *));
c32cdd9a 380
7a13e894 381
06a2c219
GM
382/* Enumeration for overriding/changing the face to use for drawing
383 glyphs in x_draw_glyphs. */
384
385enum draw_glyphs_face
386{
387 DRAW_NORMAL_TEXT,
388 DRAW_INVERSE_VIDEO,
389 DRAW_CURSOR,
390 DRAW_MOUSE_FACE,
391 DRAW_IMAGE_RAISED,
392 DRAW_IMAGE_SUNKEN
393};
394
b7f83f9e 395static int cursor_in_mouse_face_p P_ ((struct window *));
fa262c07 396static int clear_mouse_face P_ ((struct x_display_info *));
651f03b6 397static int x_alloc_nearest_color_1 P_ ((Display *, Colormap, XColor *));
499b1844 398static void x_set_window_size_1 P_ ((struct frame *, int, int, int));
651f03b6 399static const XColor *x_color_cells P_ ((Display *, int *));
71b8321e 400static void x_update_window_end P_ ((struct window *, int, int));
06a2c219
GM
401static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
402void x_delete_display P_ ((struct x_display_info *));
403static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
404 unsigned));
405static int fast_find_position P_ ((struct window *, int, int *, int *,
7e376260 406 int *, int *, Lisp_Object));
f9db2310
GM
407static int fast_find_string_pos P_ ((struct window *, int, Lisp_Object,
408 int *, int *, int *, int *, int));
06a2c219
GM
409static void set_output_cursor P_ ((struct cursor_pos *));
410static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
f9db2310 411 int *, int *, int *, int));
06a2c219 412static void note_mode_line_highlight P_ ((struct window *, int, int));
06a2c219 413static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
414static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
415static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
416static void show_mouse_face P_ ((struct x_display_info *,
417 enum draw_glyphs_face));
418static int x_io_error_quitter P_ ((Display *));
419int x_catch_errors P_ ((Display *));
420void x_uncatch_errors P_ ((Display *, int));
421void x_lower_frame P_ ((struct frame *));
422void x_scroll_bar_clear P_ ((struct frame *));
423int x_had_errors_p P_ ((Display *));
424void x_wm_set_size_hint P_ ((struct frame *, long, int));
425void x_raise_frame P_ ((struct frame *));
426void x_set_window_size P_ ((struct frame *, int, int, int));
427void x_wm_set_window_state P_ ((struct frame *, int));
428void x_wm_set_icon_pixmap P_ ((struct frame *, int));
429void x_initialize P_ ((void));
430static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
431static int x_compute_min_glyph_bounds P_ ((struct frame *));
432static void x_draw_phys_cursor_glyph P_ ((struct window *,
433 struct glyph_row *,
434 enum draw_glyphs_face));
435static void x_update_end P_ ((struct frame *));
436static void XTframe_up_to_date P_ ((struct frame *));
06a2c219
GM
437static void XTset_terminal_modes P_ ((void));
438static void XTreset_terminal_modes P_ ((void));
439static void XTcursor_to P_ ((int, int, int, int));
440static void x_write_glyphs P_ ((struct glyph *, int));
441static void x_clear_end_of_line P_ ((int));
442static void x_clear_frame P_ ((void));
443static void x_clear_cursor P_ ((struct window *));
444static void frame_highlight P_ ((struct frame *));
445static void frame_unhighlight P_ ((struct frame *));
446static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
447static void XTframe_rehighlight P_ ((struct frame *));
448static void x_frame_rehighlight P_ ((struct x_display_info *));
449static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
f02d8aa0 450static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
06a2c219
GM
451static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
452 XRectangle *));
453static void expose_frame P_ ((struct frame *, int, int, int, int));
82f053ab 454static int expose_window_tree P_ ((struct window *, XRectangle *));
a39202f6 455static int expose_window P_ ((struct window *, XRectangle *));
06a2c219
GM
456static void expose_area P_ ((struct window *, struct glyph_row *,
457 XRectangle *, enum glyph_row_area));
82f053ab 458static int expose_line P_ ((struct window *, struct glyph_row *,
06a2c219
GM
459 XRectangle *));
460static void x_update_cursor_in_window_tree P_ ((struct window *, int));
461static void x_update_window_cursor P_ ((struct window *, int));
462static void x_erase_phys_cursor P_ ((struct window *));
463void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
3f332ef3
KS
464static void x_draw_fringe_bitmap P_ ((struct window *, struct glyph_row *,
465 enum fringe_bitmap_type));
06a2c219
GM
466
467static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
468 GC, int));
469static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
3f332ef3 470static void x_draw_row_fringe_bitmaps P_ ((struct window *, struct glyph_row *));
78a9a4c5 471static void notice_overwritten_cursor P_ ((struct window *, int, int));
06a2c219 472static void x_flush P_ ((struct frame *f));
952291d9
GM
473static void x_update_begin P_ ((struct frame *));
474static void x_update_window_begin P_ ((struct window *));
475static void x_draw_vertical_border P_ ((struct window *));
476static void x_after_update_window_line P_ ((struct glyph_row *));
477static INLINE void take_vertical_position_into_account P_ ((struct it *));
478static void x_produce_stretch_glyph P_ ((struct it *));
b52b65bd
GM
479static struct scroll_bar *x_window_to_scroll_bar P_ ((Window));
480static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
481 enum scroll_bar_part *,
482 Lisp_Object *, Lisp_Object *,
483 unsigned long *));
06a2c219
GM
484
485/* Flush display of frame F, or of all frames if F is null. */
486
487static void
488x_flush (f)
489 struct frame *f;
490{
491 BLOCK_INPUT;
492 if (f == NULL)
493 {
494 Lisp_Object rest, frame;
495 FOR_EACH_FRAME (rest, frame)
496 x_flush (XFRAME (frame));
497 }
498 else if (FRAME_X_P (f))
499 XFlush (FRAME_X_DISPLAY (f));
500 UNBLOCK_INPUT;
501}
502
dc6f92b8 503
06a2c219
GM
504/* Remove calls to XFlush by defining XFlush to an empty replacement.
505 Calls to XFlush should be unnecessary because the X output buffer
506 is flushed automatically as needed by calls to XPending,
507 XNextEvent, or XWindowEvent according to the XFlush man page.
508 XTread_socket calls XPending. Removing XFlush improves
509 performance. */
510
511#define XFlush(DISPLAY) (void) 0
b8009dd1 512
334208b7 513\f
06a2c219
GM
514/***********************************************************************
515 Debugging
516 ***********************************************************************/
517
9382638d 518#if 0
06a2c219
GM
519
520/* This is a function useful for recording debugging information about
521 the sequence of occurrences in this file. */
9382638d
KH
522
523struct record
524{
525 char *locus;
526 int type;
527};
528
529struct record event_record[100];
530
531int event_record_index;
532
533record_event (locus, type)
534 char *locus;
535 int type;
536{
537 if (event_record_index == sizeof (event_record) / sizeof (struct record))
538 event_record_index = 0;
539
540 event_record[event_record_index].locus = locus;
541 event_record[event_record_index].type = type;
542 event_record_index++;
543}
544
545#endif /* 0 */
06a2c219
GM
546
547
9382638d 548\f
334208b7
RS
549/* Return the struct x_display_info corresponding to DPY. */
550
551struct x_display_info *
552x_display_info_for_display (dpy)
553 Display *dpy;
554{
555 struct x_display_info *dpyinfo;
556
557 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
558 if (dpyinfo->display == dpy)
559 return dpyinfo;
16bd92ea 560
334208b7
RS
561 return 0;
562}
f451eb13 563
06a2c219
GM
564
565\f
566/***********************************************************************
567 Starting and ending an update
568 ***********************************************************************/
569
570/* Start an update of frame F. This function is installed as a hook
571 for update_begin, i.e. it is called when update_begin is called.
572 This function is called prior to calls to x_update_window_begin for
573 each window being updated. Currently, there is nothing to do here
574 because all interesting stuff is done on a window basis. */
dc6f92b8 575
dfcf069d 576static void
06a2c219 577x_update_begin (f)
f676886a 578 struct frame *f;
58769bee 579{
06a2c219
GM
580 /* Nothing to do. */
581}
dc6f92b8 582
dc6f92b8 583
06a2c219
GM
584/* Start update of window W. Set the global variable updated_window
585 to the window being updated and set output_cursor to the cursor
586 position of W. */
dc6f92b8 587
06a2c219
GM
588static void
589x_update_window_begin (w)
590 struct window *w;
591{
592 struct frame *f = XFRAME (WINDOW_FRAME (w));
593 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
594
595 updated_window = w;
596 set_output_cursor (&w->cursor);
b8009dd1 597
06a2c219 598 BLOCK_INPUT;
d1bc4182 599
06a2c219 600 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 601 {
514e4681 602 /* Don't do highlighting for mouse motion during the update. */
06a2c219 603 display_info->mouse_face_defer = 1;
37c2c98b 604
06a2c219
GM
605 /* If F needs to be redrawn, simply forget about any prior mouse
606 highlighting. */
9f67f20b 607 if (FRAME_GARBAGED_P (f))
06a2c219
GM
608 display_info->mouse_face_window = Qnil;
609
64f26cf5
GM
610#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
611 their mouse_face_p flag set, which means that they are always
612 unequal to rows in a desired matrix which never have that
613 flag set. So, rows containing mouse-face glyphs are never
614 scrolled, and we don't have to switch the mouse highlight off
615 here to prevent it from being scrolled. */
616
06a2c219
GM
617 /* Can we tell that this update does not affect the window
618 where the mouse highlight is? If so, no need to turn off.
619 Likewise, don't do anything if the frame is garbaged;
620 in that case, the frame's current matrix that we would use
621 is all wrong, and we will redisplay that line anyway. */
622 if (!NILP (display_info->mouse_face_window)
623 && w == XWINDOW (display_info->mouse_face_window))
514e4681 624 {
06a2c219 625 int i;
514e4681 626
06a2c219
GM
627 for (i = 0; i < w->desired_matrix->nrows; ++i)
628 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
629 break;
630
06a2c219
GM
631 if (i < w->desired_matrix->nrows)
632 clear_mouse_face (display_info);
514e4681 633 }
64f26cf5 634#endif /* 0 */
b8009dd1 635 }
6ccf47d1 636
dc6f92b8
JB
637 UNBLOCK_INPUT;
638}
639
06a2c219
GM
640
641/* Draw a vertical window border to the right of window W if W doesn't
642 have vertical scroll bars. */
643
dfcf069d 644static void
06a2c219
GM
645x_draw_vertical_border (w)
646 struct window *w;
58769bee 647{
06a2c219
GM
648 struct frame *f = XFRAME (WINDOW_FRAME (w));
649
650 /* Redraw borders between horizontally adjacent windows. Don't
651 do it for frames with vertical scroll bars because either the
652 right scroll bar of a window, or the left scroll bar of its
653 neighbor will suffice as a border. */
654 if (!WINDOW_RIGHTMOST_P (w)
655 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
656 {
657 int x0, x1, y0, y1;
dc6f92b8 658
06a2c219 659 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
3f332ef3 660 x1 += FRAME_X_RIGHT_FRINGE_WIDTH (f);
06a2c219
GM
661 y1 -= 1;
662
663 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
664 f->output_data.x->normal_gc, x1, y0, x1, y1);
665 }
666}
667
668
71b8321e
GM
669/* End update of window W (which is equal to updated_window).
670
671 Draw vertical borders between horizontally adjacent windows, and
672 display W's cursor if CURSOR_ON_P is non-zero.
673
674 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
675 glyphs in mouse-face were overwritten. In that case we have to
676 make sure that the mouse-highlight is properly redrawn.
677
678 W may be a menu bar pseudo-window in case we don't have X toolkit
679 support. Such windows don't have a cursor, so don't display it
680 here. */
06a2c219
GM
681
682static void
71b8321e 683x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 684 struct window *w;
71b8321e 685 int cursor_on_p, mouse_face_overwritten_p;
06a2c219 686{
140330de
GM
687 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
688
06a2c219
GM
689 if (!w->pseudo_window_p)
690 {
691 BLOCK_INPUT;
71b8321e 692
06a2c219
GM
693 if (cursor_on_p)
694 x_display_and_set_cursor (w, 1, output_cursor.hpos,
695 output_cursor.vpos,
696 output_cursor.x, output_cursor.y);
71b8321e 697
06a2c219
GM
698 x_draw_vertical_border (w);
699 UNBLOCK_INPUT;
700 }
701
140330de
GM
702 /* If a row with mouse-face was overwritten, arrange for
703 XTframe_up_to_date to redisplay the mouse highlight. */
704 if (mouse_face_overwritten_p)
705 {
706 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
707 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
708 dpyinfo->mouse_face_window = Qnil;
709 }
710
06a2c219
GM
711 updated_window = NULL;
712}
dc6f92b8 713
dc6f92b8 714
06a2c219
GM
715/* End update of frame F. This function is installed as a hook in
716 update_end. */
717
718static void
719x_update_end (f)
720 struct frame *f;
721{
722 /* Mouse highlight may be displayed again. */
aa8bff2e 723 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 724
06a2c219 725 BLOCK_INPUT;
334208b7 726 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
727 UNBLOCK_INPUT;
728}
b8009dd1 729
06a2c219
GM
730
731/* This function is called from various places in xdisp.c whenever a
732 complete update has been performed. The global variable
733 updated_window is not available here. */
b8009dd1 734
dfcf069d 735static void
b8009dd1 736XTframe_up_to_date (f)
06a2c219 737 struct frame *f;
b8009dd1 738{
06a2c219 739 if (FRAME_X_P (f))
514e4681 740 {
06a2c219 741 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 742
06a2c219
GM
743 if (dpyinfo->mouse_face_deferred_gc
744 || f == dpyinfo->mouse_face_mouse_frame)
745 {
746 BLOCK_INPUT;
747 if (dpyinfo->mouse_face_mouse_frame)
748 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
749 dpyinfo->mouse_face_mouse_x,
750 dpyinfo->mouse_face_mouse_y);
751 dpyinfo->mouse_face_deferred_gc = 0;
752 UNBLOCK_INPUT;
753 }
514e4681 754 }
b8009dd1 755}
06a2c219
GM
756
757
758/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
3f332ef3 759 arrow bitmaps, or clear the fringes if no bitmaps are required
06a2c219
GM
760 before DESIRED_ROW is made current. The window being updated is
761 found in updated_window. This function It is called from
762 update_window_line only if it is known that there are differences
763 between bitmaps to be drawn between current row and DESIRED_ROW. */
764
765static void
766x_after_update_window_line (desired_row)
767 struct glyph_row *desired_row;
768{
769 struct window *w = updated_window;
ef253080 770 struct frame *f;
259cf6bc 771 int width, height;
06a2c219
GM
772
773 xassert (w);
774
775 if (!desired_row->mode_line_p && !w->pseudo_window_p)
776 {
777 BLOCK_INPUT;
3f332ef3 778 x_draw_row_fringe_bitmaps (w, desired_row);
ef253080
GM
779 UNBLOCK_INPUT;
780 }
781
782 /* When a window has disappeared, make sure that no rest of
783 full-width rows stays visible in the internal border. Could
784 check here if updated_window is the leftmost/rightmost window,
785 but I guess it's not worth doing since vertically split windows
786 are almost never used, internal border is rarely set, and the
787 overhead is very small. */
788 if (windows_or_buffers_changed
789 && desired_row->full_width_p
790 && (f = XFRAME (w->frame),
791 width = FRAME_INTERNAL_BORDER_WIDTH (f),
259cf6bc
GM
792 width != 0)
793 && (height = desired_row->visible_height,
794 height > 0))
ef253080 795 {
ef253080 796 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
06a2c219 797
ef253080
GM
798 /* Internal border is drawn below the tool bar. */
799 if (WINDOWP (f->tool_bar_window)
800 && w == XWINDOW (f->tool_bar_window))
801 y -= width;
06a2c219 802
ef253080
GM
803 BLOCK_INPUT;
804 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
805 0, y, width, height, False);
806 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
807 f->output_data.x->pixel_width - width,
808 y, width, height, False);
06a2c219
GM
809 UNBLOCK_INPUT;
810 }
811}
812
813
3f332ef3 814/* Draw the bitmap WHICH in one of the left or right fringes of
06a2c219
GM
815 window W. ROW is the glyph row for which to display the bitmap; it
816 determines the vertical position at which the bitmap has to be
817 drawn. */
818
819static void
3f332ef3 820x_draw_fringe_bitmap (w, row, which)
06a2c219
GM
821 struct window *w;
822 struct glyph_row *row;
3f332ef3 823 enum fringe_bitmap_type which;
06a2c219
GM
824{
825 struct frame *f = XFRAME (WINDOW_FRAME (w));
826 Display *display = FRAME_X_DISPLAY (f);
827 Window window = FRAME_X_WINDOW (f);
828 int x, y, wd, h, dy;
829 unsigned char *bits;
830 Pixmap pixmap;
831 GC gc = f->output_data.x->normal_gc;
832 struct face *face;
833 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
834
835 /* Must clip because of partially visible lines. */
836 x_clip_to_row (w, row, gc, 1);
837
838 switch (which)
839 {
840 case LEFT_TRUNCATION_BITMAP:
841 wd = left_width;
842 h = left_height;
843 bits = left_bits;
844 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
845 - wd
3f332ef3 846 - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2);
06a2c219
GM
847 break;
848
849 case OVERLAY_ARROW_BITMAP:
850 wd = left_width;
851 h = left_height;
852 bits = ov_bits;
853 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
854 - wd
3f332ef3 855 - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2);
06a2c219
GM
856 break;
857
858 case RIGHT_TRUNCATION_BITMAP:
859 wd = right_width;
860 h = right_height;
861 bits = right_bits;
862 x = window_box_right (w, -1);
3f332ef3 863 x += (FRAME_X_RIGHT_FRINGE_WIDTH (f) - wd) / 2;
06a2c219
GM
864 break;
865
866 case CONTINUED_LINE_BITMAP:
867 wd = right_width;
868 h = right_height;
869 bits = continued_bits;
870 x = window_box_right (w, -1);
3f332ef3 871 x += (FRAME_X_RIGHT_FRINGE_WIDTH (f) - wd) / 2;
06a2c219
GM
872 break;
873
874 case CONTINUATION_LINE_BITMAP:
875 wd = continuation_width;
876 h = continuation_height;
877 bits = continuation_bits;
878 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
879 - wd
3f332ef3 880 - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2);
06a2c219
GM
881 break;
882
883 case ZV_LINE_BITMAP:
884 wd = zv_width;
885 h = zv_height;
886 bits = zv_bits;
887 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
888 - wd
3f332ef3 889 - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2);
06a2c219
GM
890 break;
891
892 default:
893 abort ();
894 }
895
896 /* Convert to frame coordinates. Set dy to the offset in the row to
897 start drawing the bitmap. */
898 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
899 dy = (row->height - h) / 2;
900
901 /* Draw the bitmap. I believe these small pixmaps can be cached
902 by the server. */
3f332ef3 903 face = FACE_FROM_ID (f, FRINGE_FACE_ID);
06a2c219
GM
904 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
905 face->foreground,
906 face->background, depth);
907 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
908 XFreePixmap (display, pixmap);
909 XSetClipMask (display, gc, None);
910}
911
912
3f332ef3 913/* Draw fringe bitmaps for glyph row ROW on window W. Call this
06a2c219
GM
914 function with input blocked. */
915
916static void
3f332ef3 917x_draw_row_fringe_bitmaps (w, row)
06a2c219
GM
918 struct window *w;
919 struct glyph_row *row;
920{
921 struct frame *f = XFRAME (w->frame);
3f332ef3 922 enum fringe_bitmap_type bitmap;
06a2c219 923 struct face *face;
045dee35 924 int header_line_height = -1;
06a2c219
GM
925
926 xassert (interrupt_input_blocked);
927
928 /* If row is completely invisible, because of vscrolling, we
929 don't have to draw anything. */
930 if (row->visible_height <= 0)
931 return;
932
3f332ef3 933 face = FACE_FROM_ID (f, FRINGE_FACE_ID);
06a2c219
GM
934 PREPARE_FACE_FOR_DISPLAY (f, face);
935
3f332ef3 936 /* Decide which bitmap to draw in the left fringe. */
06a2c219
GM
937 if (row->overlay_arrow_p)
938 bitmap = OVERLAY_ARROW_BITMAP;
939 else if (row->truncated_on_left_p)
940 bitmap = LEFT_TRUNCATION_BITMAP;
941 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
942 bitmap = CONTINUATION_LINE_BITMAP;
943 else if (row->indicate_empty_line_p)
944 bitmap = ZV_LINE_BITMAP;
945 else
3f332ef3 946 bitmap = NO_FRINGE_BITMAP;
06a2c219 947
3f332ef3
KS
948 /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill
949 the fringe. */
950 if (bitmap == NO_FRINGE_BITMAP
951 || FRAME_FRINGE_BITMAP_WIDTH (f) < FRAME_X_LEFT_FRINGE_WIDTH (f)
952 || row->height > FRAME_FRINGE_BITMAP_HEIGHT (f))
06a2c219
GM
953 {
954 /* If W has a vertical border to its left, don't draw over it. */
955 int border = ((XFASTINT (w->left) > 0
956 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
957 ? 1 : 0);
958 int left = window_box_left (w, -1);
959
045dee35
GM
960 if (header_line_height < 0)
961 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb 962
3f332ef3 963 /* In case the same realized face is used for fringes and
dcd08bfb
GM
964 for something displayed in the text (e.g. face `region' on
965 mono-displays, the fill style may have been changed to
966 FillSolid in x_draw_glyph_string_background. */
967 if (face->stipple)
968 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
969 else
970 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
971
06a2c219
GM
972 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
973 face->gc,
974 (left
3f332ef3 975 - FRAME_X_LEFT_FRINGE_WIDTH (f)
06a2c219 976 + border),
045dee35 977 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 978 row->y)),
3f332ef3 979 FRAME_X_LEFT_FRINGE_WIDTH (f) - border,
06a2c219 980 row->visible_height);
dcd08bfb
GM
981 if (!face->stipple)
982 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
983 }
984
985 /* Draw the left bitmap. */
3f332ef3
KS
986 if (bitmap != NO_FRINGE_BITMAP)
987 x_draw_fringe_bitmap (w, row, bitmap);
06a2c219 988
3f332ef3 989 /* Decide which bitmap to draw in the right fringe. */
06a2c219
GM
990 if (row->truncated_on_right_p)
991 bitmap = RIGHT_TRUNCATION_BITMAP;
992 else if (row->continued_p)
993 bitmap = CONTINUED_LINE_BITMAP;
994 else
3f332ef3 995 bitmap = NO_FRINGE_BITMAP;
06a2c219 996
3f332ef3
KS
997 /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill
998 the fringe. */
999 if (bitmap == NO_FRINGE_BITMAP
1000 || FRAME_FRINGE_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FRINGE_WIDTH (f)
1001 || row->height > FRAME_FRINGE_BITMAP_HEIGHT (f))
06a2c219
GM
1002 {
1003 int right = window_box_right (w, -1);
1004
045dee35
GM
1005 if (header_line_height < 0)
1006 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb 1007
3f332ef3 1008 /* In case the same realized face is used for fringes and
dcd08bfb
GM
1009 for something displayed in the text (e.g. face `region' on
1010 mono-displays, the fill style may have been changed to
1011 FillSolid in x_draw_glyph_string_background. */
1012 if (face->stipple)
1013 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
1014 else
1015 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
1016 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1017 face->gc,
1018 right,
045dee35 1019 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 1020 row->y)),
3f332ef3 1021 FRAME_X_RIGHT_FRINGE_WIDTH (f),
06a2c219 1022 row->visible_height);
dcd08bfb
GM
1023 if (!face->stipple)
1024 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
1025 }
1026
1027 /* Draw the right bitmap. */
3f332ef3
KS
1028 if (bitmap != NO_FRINGE_BITMAP)
1029 x_draw_fringe_bitmap (w, row, bitmap);
06a2c219
GM
1030}
1031
dc6f92b8 1032\f
06a2c219
GM
1033
1034/* This is called when starting Emacs and when restarting after
1035 suspend. When starting Emacs, no X window is mapped. And nothing
1036 must be done to Emacs's own window if it is suspended (though that
1037 rarely happens). */
dc6f92b8 1038
dfcf069d 1039static void
dc6f92b8
JB
1040XTset_terminal_modes ()
1041{
1042}
1043
06a2c219
GM
1044/* This is called when exiting or suspending Emacs. Exiting will make
1045 the X-windows go away, and suspending requires no action. */
dc6f92b8 1046
dfcf069d 1047static void
dc6f92b8
JB
1048XTreset_terminal_modes ()
1049{
dc6f92b8 1050}
06a2c219
GM
1051
1052
dc6f92b8 1053\f
06a2c219
GM
1054/***********************************************************************
1055 Output Cursor
1056 ***********************************************************************/
1057
1058/* Set the global variable output_cursor to CURSOR. All cursor
1059 positions are relative to updated_window. */
dc6f92b8 1060
dfcf069d 1061static void
06a2c219
GM
1062set_output_cursor (cursor)
1063 struct cursor_pos *cursor;
dc6f92b8 1064{
06a2c219
GM
1065 output_cursor.hpos = cursor->hpos;
1066 output_cursor.vpos = cursor->vpos;
1067 output_cursor.x = cursor->x;
1068 output_cursor.y = cursor->y;
1069}
1070
1071
1072/* Set a nominal cursor position.
dc6f92b8 1073
06a2c219
GM
1074 HPOS and VPOS are column/row positions in a window glyph matrix. X
1075 and Y are window text area relative pixel positions.
1076
1077 If this is done during an update, updated_window will contain the
1078 window that is being updated and the position is the future output
1079 cursor position for that window. If updated_window is null, use
1080 selected_window and display the cursor at the given position. */
1081
1082static void
1083XTcursor_to (vpos, hpos, y, x)
1084 int vpos, hpos, y, x;
1085{
1086 struct window *w;
1087
1088 /* If updated_window is not set, work on selected_window. */
1089 if (updated_window)
1090 w = updated_window;
1091 else
1092 w = XWINDOW (selected_window);
dbcb258a 1093
06a2c219
GM
1094 /* Set the output cursor. */
1095 output_cursor.hpos = hpos;
1096 output_cursor.vpos = vpos;
1097 output_cursor.x = x;
1098 output_cursor.y = y;
dc6f92b8 1099
06a2c219
GM
1100 /* If not called as part of an update, really display the cursor.
1101 This will also set the cursor position of W. */
1102 if (updated_window == NULL)
dc6f92b8
JB
1103 {
1104 BLOCK_INPUT;
06a2c219 1105 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1106 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1107 UNBLOCK_INPUT;
1108 }
1109}
dc43ef94 1110
06a2c219
GM
1111
1112\f
1113/***********************************************************************
1114 Display Iterator
1115 ***********************************************************************/
1116
1117/* Function prototypes of this page. */
1118
1119static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1120 struct glyph *,
ee569018
KH
1121 XChar2b *,
1122 int *));
06a2c219
GM
1123static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1124 int, XChar2b *, int));
1125static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1126static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1127static void x_append_glyph P_ ((struct it *));
b4192550 1128static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1129static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1130 int, int, double));
1131static void x_produce_glyphs P_ ((struct it *));
06a2c219 1132static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1133
1134
e2ef8ee6
GM
1135/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1136 is not contained in the font. */
dc43ef94 1137
06a2c219 1138static INLINE XCharStruct *
ee569018 1139x_per_char_metric (font, char2b)
06a2c219
GM
1140 XFontStruct *font;
1141 XChar2b *char2b;
1142{
1143 /* The result metric information. */
1144 XCharStruct *pcm = NULL;
dc6f92b8 1145
06a2c219 1146 xassert (font && char2b);
dc6f92b8 1147
06a2c219 1148 if (font->per_char != NULL)
dc6f92b8 1149 {
06a2c219 1150 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1151 {
06a2c219
GM
1152 /* min_char_or_byte2 specifies the linear character index
1153 corresponding to the first element of the per_char array,
1154 max_char_or_byte2 is the index of the last character. A
1155 character with non-zero CHAR2B->byte1 is not in the font.
1156 A character with byte2 less than min_char_or_byte2 or
1157 greater max_char_or_byte2 is not in the font. */
1158 if (char2b->byte1 == 0
1159 && char2b->byte2 >= font->min_char_or_byte2
1160 && char2b->byte2 <= font->max_char_or_byte2)
1161 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1162 }
06a2c219 1163 else
dc6f92b8 1164 {
06a2c219
GM
1165 /* If either min_byte1 or max_byte1 are nonzero, both
1166 min_char_or_byte2 and max_char_or_byte2 are less than
1167 256, and the 2-byte character index values corresponding
1168 to the per_char array element N (counting from 0) are:
1169
1170 byte1 = N/D + min_byte1
1171 byte2 = N\D + min_char_or_byte2
1172
1173 where:
1174
1175 D = max_char_or_byte2 - min_char_or_byte2 + 1
1176 / = integer division
1177 \ = integer modulus */
1178 if (char2b->byte1 >= font->min_byte1
1179 && char2b->byte1 <= font->max_byte1
1180 && char2b->byte2 >= font->min_char_or_byte2
1181 && char2b->byte2 <= font->max_char_or_byte2)
1182 {
1183 pcm = (font->per_char
1184 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1185 * (char2b->byte1 - font->min_byte1))
1186 + (char2b->byte2 - font->min_char_or_byte2));
1187 }
dc6f92b8 1188 }
06a2c219
GM
1189 }
1190 else
1191 {
1192 /* If the per_char pointer is null, all glyphs between the first
1193 and last character indexes inclusive have the same
1194 information, as given by both min_bounds and max_bounds. */
1195 if (char2b->byte2 >= font->min_char_or_byte2
1196 && char2b->byte2 <= font->max_char_or_byte2)
1197 pcm = &font->max_bounds;
1198 }
dc6f92b8 1199
ee569018 1200 return ((pcm == NULL
3e71d8f2 1201 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1202 ? NULL : pcm);
06a2c219 1203}
b73b6aaf 1204
57b03282 1205
06a2c219
GM
1206/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1207 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1208
06a2c219
GM
1209static INLINE void
1210x_encode_char (c, char2b, font_info)
1211 int c;
1212 XChar2b *char2b;
1213 struct font_info *font_info;
1214{
1215 int charset = CHAR_CHARSET (c);
1216 XFontStruct *font = font_info->font;
1217
1218 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1219 This may be either a program in a special encoder language or a
1220 fixed encoding. */
1221 if (font_info->font_encoder)
1222 {
1223 /* It's a program. */
1224 struct ccl_program *ccl = font_info->font_encoder;
1225
1226 if (CHARSET_DIMENSION (charset) == 1)
1227 {
1228 ccl->reg[0] = charset;
1229 ccl->reg[1] = char2b->byte2;
1230 }
1231 else
1232 {
1233 ccl->reg[0] = charset;
1234 ccl->reg[1] = char2b->byte1;
1235 ccl->reg[2] = char2b->byte2;
1236 }
1237
1238 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1239
1240 /* We assume that MSBs are appropriately set/reset by CCL
1241 program. */
1242 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1243 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1244 else
1245 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1246 }
1247 else if (font_info->encoding[charset])
1248 {
1249 /* Fixed encoding scheme. See fontset.h for the meaning of the
1250 encoding numbers. */
1251 int enc = font_info->encoding[charset];
1252
1253 if ((enc == 1 || enc == 2)
1254 && CHARSET_DIMENSION (charset) == 2)
1255 char2b->byte1 |= 0x80;
1256
1257 if (enc == 1 || enc == 3)
1258 char2b->byte2 |= 0x80;
1259 }
1260}
1261
1262
1263/* Get face and two-byte form of character C in face FACE_ID on frame
1264 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1265 means we want to display multibyte text. Value is a pointer to a
1266 realized face that is ready for display. */
1267
1268static INLINE struct face *
1269x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1270 struct frame *f;
1271 int c, face_id;
1272 XChar2b *char2b;
1273 int multibyte_p;
1274{
1275 struct face *face = FACE_FROM_ID (f, face_id);
1276
1277 if (!multibyte_p)
1278 {
1279 /* Unibyte case. We don't have to encode, but we have to make
1280 sure to use a face suitable for unibyte. */
1281 char2b->byte1 = 0;
1282 char2b->byte2 = c;
ee569018
KH
1283 face_id = FACE_FOR_CHAR (f, face, c);
1284 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1285 }
1286 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1287 {
1288 /* Case of ASCII in a face known to fit ASCII. */
1289 char2b->byte1 = 0;
1290 char2b->byte2 = c;
1291 }
1292 else
1293 {
1294 int c1, c2, charset;
1295
1296 /* Split characters into bytes. If c2 is -1 afterwards, C is
1297 really a one-byte character so that byte1 is zero. */
1298 SPLIT_CHAR (c, charset, c1, c2);
1299 if (c2 > 0)
1300 char2b->byte1 = c1, char2b->byte2 = c2;
1301 else
1302 char2b->byte1 = 0, char2b->byte2 = c1;
1303
06a2c219 1304 /* Maybe encode the character in *CHAR2B. */
ee569018 1305 if (face->font != NULL)
06a2c219
GM
1306 {
1307 struct font_info *font_info
1308 = FONT_INFO_FROM_ID (f, face->font_info_id);
1309 if (font_info)
ee569018 1310 x_encode_char (c, char2b, font_info);
06a2c219
GM
1311 }
1312 }
1313
1314 /* Make sure X resources of the face are allocated. */
1315 xassert (face != NULL);
1316 PREPARE_FACE_FOR_DISPLAY (f, face);
1317
1318 return face;
1319}
1320
1321
1322/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1323 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1324 a pointer to a realized face that is ready for display. */
1325
1326static INLINE struct face *
ee569018 1327x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1328 struct frame *f;
1329 struct glyph *glyph;
1330 XChar2b *char2b;
ee569018 1331 int *two_byte_p;
06a2c219
GM
1332{
1333 struct face *face;
1334
1335 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1336 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1337
ee569018
KH
1338 if (two_byte_p)
1339 *two_byte_p = 0;
1340
06a2c219
GM
1341 if (!glyph->multibyte_p)
1342 {
1343 /* Unibyte case. We don't have to encode, but we have to make
1344 sure to use a face suitable for unibyte. */
1345 char2b->byte1 = 0;
43d120d8 1346 char2b->byte2 = glyph->u.ch;
06a2c219 1347 }
43d120d8
KH
1348 else if (glyph->u.ch < 128
1349 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1350 {
1351 /* Case of ASCII in a face known to fit ASCII. */
1352 char2b->byte1 = 0;
43d120d8 1353 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1354 }
1355 else
1356 {
1357 int c1, c2, charset;
1358
1359 /* Split characters into bytes. If c2 is -1 afterwards, C is
1360 really a one-byte character so that byte1 is zero. */
43d120d8 1361 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1362 if (c2 > 0)
1363 char2b->byte1 = c1, char2b->byte2 = c2;
1364 else
1365 char2b->byte1 = 0, char2b->byte2 = c1;
1366
1367 /* Maybe encode the character in *CHAR2B. */
1368 if (charset != CHARSET_ASCII)
1369 {
1370 struct font_info *font_info
1371 = FONT_INFO_FROM_ID (f, face->font_info_id);
1372 if (font_info)
1373 {
43d120d8 1374 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1375 if (two_byte_p)
1376 *two_byte_p
1377 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1378 }
1379 }
1380 }
1381
1382 /* Make sure X resources of the face are allocated. */
1383 xassert (face != NULL);
1384 PREPARE_FACE_FOR_DISPLAY (f, face);
1385 return face;
1386}
1387
1388
1389/* Store one glyph for IT->char_to_display in IT->glyph_row.
1390 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1391
1392static INLINE void
1393x_append_glyph (it)
1394 struct it *it;
1395{
1396 struct glyph *glyph;
1397 enum glyph_row_area area = it->area;
1398
1399 xassert (it->glyph_row);
1400 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1401
1402 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1403 if (glyph < it->glyph_row->glyphs[area + 1])
1404 {
06a2c219
GM
1405 glyph->charpos = CHARPOS (it->position);
1406 glyph->object = it->object;
88d75730 1407 glyph->pixel_width = it->pixel_width;
06a2c219 1408 glyph->voffset = it->voffset;
88d75730 1409 glyph->type = CHAR_GLYPH;
06a2c219 1410 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1411 glyph->left_box_line_p = it->start_of_box_run_p;
1412 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1413 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1414 || it->phys_descent > it->descent);
88d75730 1415 glyph->padding_p = 0;
ee569018 1416 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1417 glyph->face_id = it->face_id;
1418 glyph->u.ch = it->char_to_display;
06a2c219
GM
1419 ++it->glyph_row->used[area];
1420 }
1421}
1422
b4192550
KH
1423/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1424 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1425
1426static INLINE void
1427x_append_composite_glyph (it)
1428 struct it *it;
1429{
1430 struct glyph *glyph;
1431 enum glyph_row_area area = it->area;
1432
1433 xassert (it->glyph_row);
1434
1435 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1436 if (glyph < it->glyph_row->glyphs[area + 1])
1437 {
b4192550
KH
1438 glyph->charpos = CHARPOS (it->position);
1439 glyph->object = it->object;
88d75730 1440 glyph->pixel_width = it->pixel_width;
b4192550 1441 glyph->voffset = it->voffset;
88d75730 1442 glyph->type = COMPOSITE_GLYPH;
b4192550 1443 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1444 glyph->left_box_line_p = it->start_of_box_run_p;
1445 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1446 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1447 || it->phys_descent > it->descent);
88d75730
GM
1448 glyph->padding_p = 0;
1449 glyph->glyph_not_available_p = 0;
1450 glyph->face_id = it->face_id;
1451 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1452 ++it->glyph_row->used[area];
1453 }
1454}
1455
06a2c219
GM
1456
1457/* Change IT->ascent and IT->height according to the setting of
1458 IT->voffset. */
1459
1460static INLINE void
1461take_vertical_position_into_account (it)
1462 struct it *it;
1463{
1464 if (it->voffset)
1465 {
1466 if (it->voffset < 0)
1467 /* Increase the ascent so that we can display the text higher
1468 in the line. */
1469 it->ascent += abs (it->voffset);
1470 else
1471 /* Increase the descent so that we can display the text lower
1472 in the line. */
1473 it->descent += it->voffset;
1474 }
1475}
1476
1477
1478/* Produce glyphs/get display metrics for the image IT is loaded with.
1479 See the description of struct display_iterator in dispextern.h for
1480 an overview of struct display_iterator. */
1481
1482static void
1483x_produce_image_glyph (it)
1484 struct it *it;
1485{
1486 struct image *img;
1487 struct face *face;
1488
1489 xassert (it->what == IT_IMAGE);
1490
1491 face = FACE_FROM_ID (it->f, it->face_id);
1492 img = IMAGE_FROM_ID (it->f, it->image_id);
1493 xassert (img);
1494
1495 /* Make sure X resources of the face and image are loaded. */
1496 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1497 prepare_image_for_display (it->f, img);
1498
95af8492 1499 it->ascent = it->phys_ascent = image_ascent (img, face);
22d650b8
GM
1500 it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
1501 it->pixel_width = img->width + 2 * img->hmargin;
06a2c219
GM
1502
1503 it->nglyphs = 1;
1504
1505 if (face->box != FACE_NO_BOX)
1506 {
ea2ba0d4
KH
1507 if (face->box_line_width > 0)
1508 {
1509 it->ascent += face->box_line_width;
1510 it->descent += face->box_line_width;
1511 }
06a2c219
GM
1512
1513 if (it->start_of_box_run_p)
ea2ba0d4 1514 it->pixel_width += abs (face->box_line_width);
06a2c219 1515 if (it->end_of_box_run_p)
ea2ba0d4 1516 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1517 }
1518
1519 take_vertical_position_into_account (it);
1520
1521 if (it->glyph_row)
1522 {
1523 struct glyph *glyph;
1524 enum glyph_row_area area = it->area;
1525
1526 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1527 if (glyph < it->glyph_row->glyphs[area + 1])
1528 {
06a2c219
GM
1529 glyph->charpos = CHARPOS (it->position);
1530 glyph->object = it->object;
88d75730 1531 glyph->pixel_width = it->pixel_width;
06a2c219 1532 glyph->voffset = it->voffset;
88d75730 1533 glyph->type = IMAGE_GLYPH;
06a2c219 1534 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1535 glyph->left_box_line_p = it->start_of_box_run_p;
1536 glyph->right_box_line_p = it->end_of_box_run_p;
1537 glyph->overlaps_vertically_p = 0;
1538 glyph->padding_p = 0;
1539 glyph->glyph_not_available_p = 0;
1540 glyph->face_id = it->face_id;
1541 glyph->u.img_id = img->id;
06a2c219
GM
1542 ++it->glyph_row->used[area];
1543 }
1544 }
1545}
1546
1547
1548/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1549 of the glyph, WIDTH and HEIGHT are the width and height of the
1550 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1551 ascent of the glyph (0 <= ASCENT <= 1). */
1552
1553static void
1554x_append_stretch_glyph (it, object, width, height, ascent)
1555 struct it *it;
1556 Lisp_Object object;
1557 int width, height;
1558 double ascent;
1559{
1560 struct glyph *glyph;
1561 enum glyph_row_area area = it->area;
1562
1563 xassert (ascent >= 0 && ascent <= 1);
1564
1565 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1566 if (glyph < it->glyph_row->glyphs[area + 1])
1567 {
06a2c219
GM
1568 glyph->charpos = CHARPOS (it->position);
1569 glyph->object = object;
88d75730 1570 glyph->pixel_width = width;
06a2c219 1571 glyph->voffset = it->voffset;
88d75730 1572 glyph->type = STRETCH_GLYPH;
06a2c219 1573 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1574 glyph->left_box_line_p = it->start_of_box_run_p;
1575 glyph->right_box_line_p = it->end_of_box_run_p;
1576 glyph->overlaps_vertically_p = 0;
1577 glyph->padding_p = 0;
1578 glyph->glyph_not_available_p = 0;
1579 glyph->face_id = it->face_id;
1580 glyph->u.stretch.ascent = height * ascent;
1581 glyph->u.stretch.height = height;
06a2c219
GM
1582 ++it->glyph_row->used[area];
1583 }
1584}
1585
1586
1587/* Produce a stretch glyph for iterator IT. IT->object is the value
1588 of the glyph property displayed. The value must be a list
1589 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1590 being recognized:
1591
1592 1. `:width WIDTH' specifies that the space should be WIDTH *
1593 canonical char width wide. WIDTH may be an integer or floating
1594 point number.
1595
1596 2. `:relative-width FACTOR' specifies that the width of the stretch
1597 should be computed from the width of the first character having the
1598 `glyph' property, and should be FACTOR times that width.
1599
1600 3. `:align-to HPOS' specifies that the space should be wide enough
1601 to reach HPOS, a value in canonical character units.
1602
1603 Exactly one of the above pairs must be present.
1604
1605 4. `:height HEIGHT' specifies that the height of the stretch produced
1606 should be HEIGHT, measured in canonical character units.
1607
1608 5. `:relative-height FACTOR' specifies that the height of the the
1609 stretch should be FACTOR times the height of the characters having
1610 the glyph property.
1611
1612 Either none or exactly one of 4 or 5 must be present.
1613
1614 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1615 of the stretch should be used for the ascent of the stretch.
1616 ASCENT must be in the range 0 <= ASCENT <= 100. */
1617
1618#define NUMVAL(X) \
1619 ((INTEGERP (X) || FLOATP (X)) \
1620 ? XFLOATINT (X) \
1621 : - 1)
1622
1623
1624static void
1625x_produce_stretch_glyph (it)
1626 struct it *it;
1627{
1628 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1629#if GLYPH_DEBUG
1630 extern Lisp_Object Qspace;
1631#endif
1632 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1633 extern Lisp_Object QCrelative_width, QCrelative_height;
1634 extern Lisp_Object QCalign_to;
1635 Lisp_Object prop, plist;
1636 double width = 0, height = 0, ascent = 0;
1637 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1638 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1639
1640 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1641
1642 /* List should start with `space'. */
1643 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1644 plist = XCDR (it->object);
1645
1646 /* Compute the width of the stretch. */
1647 if (prop = Fplist_get (plist, QCwidth),
1648 NUMVAL (prop) > 0)
1649 /* Absolute width `:width WIDTH' specified and valid. */
1650 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1651 else if (prop = Fplist_get (plist, QCrelative_width),
1652 NUMVAL (prop) > 0)
1653 {
1654 /* Relative width `:relative-width FACTOR' specified and valid.
1655 Compute the width of the characters having the `glyph'
1656 property. */
1657 struct it it2;
1658 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1659
1660 it2 = *it;
1661 if (it->multibyte_p)
1662 {
1663 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1664 - IT_BYTEPOS (*it));
1665 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1666 }
1667 else
1668 it2.c = *p, it2.len = 1;
1669
1670 it2.glyph_row = NULL;
1671 it2.what = IT_CHARACTER;
1672 x_produce_glyphs (&it2);
1673 width = NUMVAL (prop) * it2.pixel_width;
1674 }
1675 else if (prop = Fplist_get (plist, QCalign_to),
1676 NUMVAL (prop) > 0)
1677 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1678 else
1679 /* Nothing specified -> width defaults to canonical char width. */
1680 width = CANON_X_UNIT (it->f);
1681
1682 /* Compute height. */
1683 if (prop = Fplist_get (plist, QCheight),
1684 NUMVAL (prop) > 0)
1685 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1686 else if (prop = Fplist_get (plist, QCrelative_height),
1687 NUMVAL (prop) > 0)
1688 height = FONT_HEIGHT (font) * NUMVAL (prop);
1689 else
1690 height = FONT_HEIGHT (font);
1691
1692 /* Compute percentage of height used for ascent. If
1693 `:ascent ASCENT' is present and valid, use that. Otherwise,
1694 derive the ascent from the font in use. */
1695 if (prop = Fplist_get (plist, QCascent),
1696 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1697 ascent = NUMVAL (prop) / 100.0;
1698 else
1699 ascent = (double) font->ascent / FONT_HEIGHT (font);
1700
1701 if (width <= 0)
1702 width = 1;
1703 if (height <= 0)
1704 height = 1;
1705
1706 if (it->glyph_row)
1707 {
1708 Lisp_Object object = it->stack[it->sp - 1].string;
1709 if (!STRINGP (object))
1710 object = it->w->buffer;
1711 x_append_stretch_glyph (it, object, width, height, ascent);
1712 }
1713
1714 it->pixel_width = width;
66ac4b0e
GM
1715 it->ascent = it->phys_ascent = height * ascent;
1716 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1717 it->nglyphs = 1;
1718
1719 if (face->box != FACE_NO_BOX)
1720 {
ea2ba0d4
KH
1721 if (face->box_line_width > 0)
1722 {
1723 it->ascent += face->box_line_width;
1724 it->descent += face->box_line_width;
1725 }
06a2c219
GM
1726
1727 if (it->start_of_box_run_p)
ea2ba0d4 1728 it->pixel_width += abs (face->box_line_width);
06a2c219 1729 if (it->end_of_box_run_p)
ea2ba0d4 1730 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1731 }
1732
1733 take_vertical_position_into_account (it);
1734}
1735
b4192550
KH
1736/* Return proper value to be used as baseline offset of font that has
1737 ASCENT and DESCENT to draw characters by the font at the vertical
1738 center of the line of frame F.
1739
1740 Here, out task is to find the value of BOFF in the following figure;
1741
1742 -------------------------+-----------+-
1743 -+-+---------+-+ | |
1744 | | | | | |
1745 | | | | F_ASCENT F_HEIGHT
1746 | | | ASCENT | |
1747 HEIGHT | | | | |
1748 | | |-|-+------+-----------|------- baseline
1749 | | | | BOFF | |
1750 | |---------|-+-+ | |
1751 | | | DESCENT | |
1752 -+-+---------+-+ F_DESCENT |
1753 -------------------------+-----------+-
1754
1755 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1756 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1757 DESCENT = FONT->descent
1758 HEIGHT = FONT_HEIGHT (FONT)
1759 F_DESCENT = (F->output_data.x->font->descent
1760 - F->output_data.x->baseline_offset)
1761 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1762*/
1763
458f45fa
KH
1764#define VCENTER_BASELINE_OFFSET(FONT, F) \
1765 ((FONT)->descent \
1766 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT)) \
1767 + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \
1768 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1769
1770/* Produce glyphs/get display metrics for the display element IT is
1771 loaded with. See the description of struct display_iterator in
1772 dispextern.h for an overview of struct display_iterator. */
1773
1774static void
1775x_produce_glyphs (it)
1776 struct it *it;
1777{
ee569018
KH
1778 it->glyph_not_available_p = 0;
1779
06a2c219
GM
1780 if (it->what == IT_CHARACTER)
1781 {
1782 XChar2b char2b;
1783 XFontStruct *font;
ee569018 1784 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1785 XCharStruct *pcm;
06a2c219 1786 int font_not_found_p;
b4192550
KH
1787 struct font_info *font_info;
1788 int boff; /* baseline offset */
a4249304
KH
1789 /* We may change it->multibyte_p upon unibyte<->multibyte
1790 conversion. So, save the current value now and restore it
1791 later.
1792
1793 Note: It seems that we don't have to record multibyte_p in
1794 struct glyph because the character code itself tells if or
1795 not the character is multibyte. Thus, in the future, we must
1796 consider eliminating the field `multibyte_p' in the struct
c347a1c3 1797 glyph. */
a4249304 1798 int saved_multibyte_p = it->multibyte_p;
06a2c219 1799
ee569018
KH
1800 /* Maybe translate single-byte characters to multibyte, or the
1801 other way. */
06a2c219 1802 it->char_to_display = it->c;
ee569018 1803 if (!ASCII_BYTE_P (it->c))
06a2c219 1804 {
ee569018
KH
1805 if (unibyte_display_via_language_environment
1806 && SINGLE_BYTE_CHAR_P (it->c)
1807 && (it->c >= 0240
1808 || !NILP (Vnonascii_translation_table)))
1809 {
1810 it->char_to_display = unibyte_char_to_multibyte (it->c);
a4249304 1811 it->multibyte_p = 1;
ee569018
KH
1812 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1813 face = FACE_FROM_ID (it->f, it->face_id);
1814 }
1815 else if (!SINGLE_BYTE_CHAR_P (it->c)
1816 && !it->multibyte_p)
1817 {
c347a1c3 1818 it->multibyte_p = 1;
ee569018
KH
1819 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1820 face = FACE_FROM_ID (it->f, it->face_id);
1821 }
06a2c219
GM
1822 }
1823
ee569018
KH
1824 /* Get font to use. Encode IT->char_to_display. */
1825 x_get_char_face_and_encoding (it->f, it->char_to_display,
1826 it->face_id, &char2b,
1827 it->multibyte_p);
06a2c219
GM
1828 font = face->font;
1829
1830 /* When no suitable font found, use the default font. */
1831 font_not_found_p = font == NULL;
1832 if (font_not_found_p)
b4192550
KH
1833 {
1834 font = FRAME_FONT (it->f);
1835 boff = it->f->output_data.x->baseline_offset;
1836 font_info = NULL;
1837 }
1838 else
1839 {
1840 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1841 boff = font_info->baseline_offset;
1842 if (font_info->vertical_centering)
1843 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1844 }
06a2c219
GM
1845
1846 if (it->char_to_display >= ' '
1847 && (!it->multibyte_p || it->char_to_display < 128))
1848 {
1849 /* Either unibyte or ASCII. */
1850 int stretched_p;
1851
1852 it->nglyphs = 1;
06a2c219
GM
1853
1854 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1855 it->ascent = font->ascent + boff;
1856 it->descent = font->descent - boff;
474848ac
GM
1857
1858 if (pcm)
1859 {
1860 it->phys_ascent = pcm->ascent + boff;
1861 it->phys_descent = pcm->descent - boff;
1862 it->pixel_width = pcm->width;
1863 }
1864 else
1865 {
1866 it->glyph_not_available_p = 1;
1867 it->phys_ascent = font->ascent + boff;
1868 it->phys_descent = font->descent - boff;
1869 it->pixel_width = FONT_WIDTH (font);
1870 }
06a2c219
GM
1871
1872 /* If this is a space inside a region of text with
1873 `space-width' property, change its width. */
1874 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1875 if (stretched_p)
1876 it->pixel_width *= XFLOATINT (it->space_width);
1877
1878 /* If face has a box, add the box thickness to the character
1879 height. If character has a box line to the left and/or
1880 right, add the box line width to the character's width. */
1881 if (face->box != FACE_NO_BOX)
1882 {
1883 int thick = face->box_line_width;
1884
ea2ba0d4
KH
1885 if (thick > 0)
1886 {
1887 it->ascent += thick;
1888 it->descent += thick;
1889 }
1890 else
1891 thick = -thick;
1892
06a2c219
GM
1893 if (it->start_of_box_run_p)
1894 it->pixel_width += thick;
1895 if (it->end_of_box_run_p)
1896 it->pixel_width += thick;
1897 }
1898
1899 /* If face has an overline, add the height of the overline
1900 (1 pixel) and a 1 pixel margin to the character height. */
1901 if (face->overline_p)
1902 it->ascent += 2;
1903
1904 take_vertical_position_into_account (it);
1905
1906 /* If we have to actually produce glyphs, do it. */
1907 if (it->glyph_row)
1908 {
1909 if (stretched_p)
1910 {
1911 /* Translate a space with a `space-width' property
1912 into a stretch glyph. */
1913 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1914 x_append_stretch_glyph (it, it->object, it->pixel_width,
1915 it->ascent + it->descent, ascent);
1916 }
1917 else
1918 x_append_glyph (it);
1919
1920 /* If characters with lbearing or rbearing are displayed
1921 in this line, record that fact in a flag of the
1922 glyph row. This is used to optimize X output code. */
1c7e22fd 1923 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1924 it->glyph_row->contains_overlapping_glyphs_p = 1;
1925 }
1926 }
1927 else if (it->char_to_display == '\n')
1928 {
1929 /* A newline has no width but we need the height of the line. */
1930 it->pixel_width = 0;
1931 it->nglyphs = 0;
b4192550
KH
1932 it->ascent = it->phys_ascent = font->ascent + boff;
1933 it->descent = it->phys_descent = font->descent - boff;
06a2c219 1934
ea2ba0d4
KH
1935 if (face->box != FACE_NO_BOX
1936 && face->box_line_width > 0)
06a2c219 1937 {
ea2ba0d4
KH
1938 it->ascent += face->box_line_width;
1939 it->descent += face->box_line_width;
06a2c219
GM
1940 }
1941 }
1942 else if (it->char_to_display == '\t')
1943 {
1944 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1945 int x = it->current_x + it->continuation_lines_width;
06a2c219 1946 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
2a32b5ea
GM
1947
1948 /* If the distance from the current position to the next tab
1949 stop is less than a canonical character width, use the
1950 tab stop after that. */
1951 if (next_tab_x - x < CANON_X_UNIT (it->f))
1952 next_tab_x += tab_width;
06a2c219
GM
1953
1954 it->pixel_width = next_tab_x - x;
1955 it->nglyphs = 1;
b4192550
KH
1956 it->ascent = it->phys_ascent = font->ascent + boff;
1957 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1958
1959 if (it->glyph_row)
1960 {
1961 double ascent = (double) it->ascent / (it->ascent + it->descent);
1962 x_append_stretch_glyph (it, it->object, it->pixel_width,
1963 it->ascent + it->descent, ascent);
1964 }
1965 }
1966 else
1967 {
1968 /* A multi-byte character. Assume that the display width of the
1969 character is the width of the character multiplied by the
b4192550 1970 width of the font. */
06a2c219 1971
b4192550
KH
1972 /* If we found a font, this font should give us the right
1973 metrics. If we didn't find a font, use the frame's
1974 default font and calculate the width of the character
1975 from the charset width; this is what old redisplay code
1976 did. */
1977 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
1978 if (font_not_found_p || !pcm)
1979 {
1980 int charset = CHAR_CHARSET (it->char_to_display);
1981
1982 it->glyph_not_available_p = 1;
1983 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
1984 * CHARSET_WIDTH (charset));
1985 it->phys_ascent = font->ascent + boff;
1986 it->phys_descent = font->descent - boff;
1987 }
1988 else
1989 {
1990 it->pixel_width = pcm->width;
1991 it->phys_ascent = pcm->ascent + boff;
1992 it->phys_descent = pcm->descent - boff;
1993 if (it->glyph_row
1994 && (pcm->lbearing < 0
1995 || pcm->rbearing > pcm->width))
1996 it->glyph_row->contains_overlapping_glyphs_p = 1;
1997 }
b4192550
KH
1998 it->nglyphs = 1;
1999 it->ascent = font->ascent + boff;
2000 it->descent = font->descent - boff;
06a2c219
GM
2001 if (face->box != FACE_NO_BOX)
2002 {
2003 int thick = face->box_line_width;
ea2ba0d4
KH
2004
2005 if (thick > 0)
2006 {
2007 it->ascent += thick;
2008 it->descent += thick;
2009 }
2010 else
2011 thick = - thick;
06a2c219
GM
2012
2013 if (it->start_of_box_run_p)
2014 it->pixel_width += thick;
2015 if (it->end_of_box_run_p)
2016 it->pixel_width += thick;
2017 }
2018
2019 /* If face has an overline, add the height of the overline
2020 (1 pixel) and a 1 pixel margin to the character height. */
2021 if (face->overline_p)
2022 it->ascent += 2;
2023
2024 take_vertical_position_into_account (it);
2025
2026 if (it->glyph_row)
2027 x_append_glyph (it);
2028 }
a4249304 2029 it->multibyte_p = saved_multibyte_p;
06a2c219 2030 }
b4192550
KH
2031 else if (it->what == IT_COMPOSITION)
2032 {
2033 /* Note: A composition is represented as one glyph in the
2034 glyph matrix. There are no padding glyphs. */
2035 XChar2b char2b;
2036 XFontStruct *font;
ee569018 2037 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2038 XCharStruct *pcm;
2039 int font_not_found_p;
2040 struct font_info *font_info;
2041 int boff; /* baseline offset */
2042 struct composition *cmp = composition_table[it->cmp_id];
2043
2044 /* Maybe translate single-byte characters to multibyte. */
2045 it->char_to_display = it->c;
2046 if (unibyte_display_via_language_environment
2047 && SINGLE_BYTE_CHAR_P (it->c)
2048 && (it->c >= 0240
2049 || (it->c >= 0200
2050 && !NILP (Vnonascii_translation_table))))
2051 {
2052 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2053 }
2054
2055 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2056 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2057 face = FACE_FROM_ID (it->f, it->face_id);
2058 x_get_char_face_and_encoding (it->f, it->char_to_display,
2059 it->face_id, &char2b, it->multibyte_p);
b4192550
KH
2060 font = face->font;
2061
2062 /* When no suitable font found, use the default font. */
2063 font_not_found_p = font == NULL;
2064 if (font_not_found_p)
2065 {
2066 font = FRAME_FONT (it->f);
2067 boff = it->f->output_data.x->baseline_offset;
2068 font_info = NULL;
2069 }
2070 else
2071 {
2072 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2073 boff = font_info->baseline_offset;
2074 if (font_info->vertical_centering)
2075 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2076 }
2077
2078 /* There are no padding glyphs, so there is only one glyph to
2079 produce for the composition. Important is that pixel_width,
2080 ascent and descent are the values of what is drawn by
2081 draw_glyphs (i.e. the values of the overall glyphs composed). */
2082 it->nglyphs = 1;
2083
2084 /* If we have not yet calculated pixel size data of glyphs of
2085 the composition for the current face font, calculate them
2086 now. Theoretically, we have to check all fonts for the
2087 glyphs, but that requires much time and memory space. So,
2088 here we check only the font of the first glyph. This leads
2089 to incorrect display very rarely, and C-l (recenter) can
2090 correct the display anyway. */
2091 if (cmp->font != (void *) font)
2092 {
2093 /* Ascent and descent of the font of the first character of
2094 this composition (adjusted by baseline offset). Ascent
2095 and descent of overall glyphs should not be less than
2096 them respectively. */
2097 int font_ascent = font->ascent + boff;
2098 int font_descent = font->descent - boff;
2099 /* Bounding box of the overall glyphs. */
2100 int leftmost, rightmost, lowest, highest;
329bed06 2101 int i, width, ascent, descent;
b4192550
KH
2102
2103 cmp->font = (void *) font;
2104
2105 /* Initialize the bounding box. */
1bdeec2e
KH
2106 if (font_info
2107 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2108 {
2109 width = pcm->width;
2110 ascent = pcm->ascent;
2111 descent = pcm->descent;
2112 }
2113 else
2114 {
2115 width = FONT_WIDTH (font);
2116 ascent = font->ascent;
2117 descent = font->descent;
2118 }
2119
2120 rightmost = width;
2121 lowest = - descent + boff;
2122 highest = ascent + boff;
b4192550 2123 leftmost = 0;
329bed06 2124
b4192550
KH
2125 if (font_info
2126 && font_info->default_ascent
2127 && CHAR_TABLE_P (Vuse_default_ascent)
2128 && !NILP (Faref (Vuse_default_ascent,
2129 make_number (it->char_to_display))))
2130 highest = font_info->default_ascent + boff;
2131
2132 /* Draw the first glyph at the normal position. It may be
2133 shifted to right later if some other glyphs are drawn at
2134 the left. */
2135 cmp->offsets[0] = 0;
2136 cmp->offsets[1] = boff;
2137
2138 /* Set cmp->offsets for the remaining glyphs. */
2139 for (i = 1; i < cmp->glyph_len; i++)
2140 {
2141 int left, right, btm, top;
2142 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2143 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2144
2145 face = FACE_FROM_ID (it->f, face_id);
2146 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2147 it->multibyte_p);
b4192550
KH
2148 font = face->font;
2149 if (font == NULL)
2150 {
2151 font = FRAME_FONT (it->f);
2152 boff = it->f->output_data.x->baseline_offset;
2153 font_info = NULL;
2154 }
2155 else
2156 {
2157 font_info
2158 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2159 boff = font_info->baseline_offset;
2160 if (font_info->vertical_centering)
2161 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2162 }
2163
1bdeec2e
KH
2164 if (font_info
2165 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2166 {
2167 width = pcm->width;
2168 ascent = pcm->ascent;
2169 descent = pcm->descent;
2170 }
2171 else
2172 {
2173 width = FONT_WIDTH (font);
1bdeec2e
KH
2174 ascent = 1;
2175 descent = 0;
329bed06 2176 }
b4192550
KH
2177
2178 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2179 {
2180 /* Relative composition with or without
2181 alternate chars. */
329bed06
GM
2182 left = (leftmost + rightmost - width) / 2;
2183 btm = - descent + boff;
b4192550
KH
2184 if (font_info && font_info->relative_compose
2185 && (! CHAR_TABLE_P (Vignore_relative_composition)
2186 || NILP (Faref (Vignore_relative_composition,
2187 make_number (ch)))))
2188 {
2189
329bed06 2190 if (- descent >= font_info->relative_compose)
b4192550
KH
2191 /* One extra pixel between two glyphs. */
2192 btm = highest + 1;
329bed06 2193 else if (ascent <= 0)
b4192550 2194 /* One extra pixel between two glyphs. */
329bed06 2195 btm = lowest - 1 - ascent - descent;
b4192550
KH
2196 }
2197 }
2198 else
2199 {
2200 /* A composition rule is specified by an integer
2201 value that encodes global and new reference
2202 points (GREF and NREF). GREF and NREF are
2203 specified by numbers as below:
2204
2205 0---1---2 -- ascent
2206 | |
2207 | |
2208 | |
2209 9--10--11 -- center
2210 | |
2211 ---3---4---5--- baseline
2212 | |
2213 6---7---8 -- descent
2214 */
2215 int rule = COMPOSITION_RULE (cmp, i);
2216 int gref, nref, grefx, grefy, nrefx, nrefy;
2217
2218 COMPOSITION_DECODE_RULE (rule, gref, nref);
2219 grefx = gref % 3, nrefx = nref % 3;
2220 grefy = gref / 3, nrefy = nref / 3;
2221
2222 left = (leftmost
2223 + grefx * (rightmost - leftmost) / 2
329bed06 2224 - nrefx * width / 2);
b4192550
KH
2225 btm = ((grefy == 0 ? highest
2226 : grefy == 1 ? 0
2227 : grefy == 2 ? lowest
2228 : (highest + lowest) / 2)
329bed06
GM
2229 - (nrefy == 0 ? ascent + descent
2230 : nrefy == 1 ? descent - boff
b4192550 2231 : nrefy == 2 ? 0
329bed06 2232 : (ascent + descent) / 2));
b4192550
KH
2233 }
2234
2235 cmp->offsets[i * 2] = left;
329bed06 2236 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2237
2238 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2239 right = left + width;
2240 top = btm + descent + ascent;
b4192550
KH
2241 if (left < leftmost)
2242 leftmost = left;
2243 if (right > rightmost)
2244 rightmost = right;
2245 if (top > highest)
2246 highest = top;
2247 if (btm < lowest)
2248 lowest = btm;
2249 }
2250
2251 /* If there are glyphs whose x-offsets are negative,
2252 shift all glyphs to the right and make all x-offsets
2253 non-negative. */
2254 if (leftmost < 0)
2255 {
2256 for (i = 0; i < cmp->glyph_len; i++)
2257 cmp->offsets[i * 2] -= leftmost;
2258 rightmost -= leftmost;
2259 }
2260
2261 cmp->pixel_width = rightmost;
2262 cmp->ascent = highest;
2263 cmp->descent = - lowest;
2264 if (cmp->ascent < font_ascent)
2265 cmp->ascent = font_ascent;
2266 if (cmp->descent < font_descent)
2267 cmp->descent = font_descent;
2268 }
2269
2270 it->pixel_width = cmp->pixel_width;
2271 it->ascent = it->phys_ascent = cmp->ascent;
2272 it->descent = it->phys_descent = cmp->descent;
2273
2274 if (face->box != FACE_NO_BOX)
2275 {
2276 int thick = face->box_line_width;
ea2ba0d4
KH
2277
2278 if (thick > 0)
2279 {
2280 it->ascent += thick;
2281 it->descent += thick;
2282 }
2283 else
2284 thick = - thick;
b4192550
KH
2285
2286 if (it->start_of_box_run_p)
2287 it->pixel_width += thick;
2288 if (it->end_of_box_run_p)
2289 it->pixel_width += thick;
2290 }
2291
2292 /* If face has an overline, add the height of the overline
2293 (1 pixel) and a 1 pixel margin to the character height. */
2294 if (face->overline_p)
2295 it->ascent += 2;
2296
2297 take_vertical_position_into_account (it);
2298
2299 if (it->glyph_row)
2300 x_append_composite_glyph (it);
2301 }
06a2c219
GM
2302 else if (it->what == IT_IMAGE)
2303 x_produce_image_glyph (it);
2304 else if (it->what == IT_STRETCH)
2305 x_produce_stretch_glyph (it);
2306
3017fdd1
GM
2307 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2308 because this isn't true for images with `:ascent 100'. */
2309 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2310 if (it->area == TEXT_AREA)
2311 it->current_x += it->pixel_width;
66ac4b0e 2312
d365f5bb
GM
2313 it->descent += it->extra_line_spacing;
2314
06a2c219
GM
2315 it->max_ascent = max (it->max_ascent, it->ascent);
2316 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2317 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2318 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2319}
2320
2321
2322/* Estimate the pixel height of the mode or top line on frame F.
2323 FACE_ID specifies what line's height to estimate. */
2324
2325int
2326x_estimate_mode_line_height (f, face_id)
2327 struct frame *f;
2328 enum face_id face_id;
2329{
43281ee3 2330 int height = FONT_HEIGHT (FRAME_FONT (f));
06a2c219
GM
2331
2332 /* This function is called so early when Emacs starts that the face
2333 cache and mode line face are not yet initialized. */
2334 if (FRAME_FACE_CACHE (f))
2335 {
2336 struct face *face = FACE_FROM_ID (f, face_id);
2337 if (face)
43281ee3
GM
2338 {
2339 if (face->font)
2340 height = FONT_HEIGHT (face->font);
ea2ba0d4
KH
2341 if (face->box_line_width > 0)
2342 height += 2 * face->box_line_width;
43281ee3 2343 }
06a2c219
GM
2344 }
2345
2346 return height;
2347}
2348
2349\f
2350/***********************************************************************
2351 Glyph display
2352 ***********************************************************************/
2353
2354/* A sequence of glyphs to be drawn in the same face.
2355
2356 This data structure is not really completely X specific, so it
2357 could possibly, at least partially, be useful for other systems. It
2358 is currently not part of the external redisplay interface because
2359 it's not clear what other systems will need. */
2360
2361struct glyph_string
2362{
2363 /* X-origin of the string. */
2364 int x;
2365
2366 /* Y-origin and y-position of the base line of this string. */
2367 int y, ybase;
2368
2369 /* The width of the string, not including a face extension. */
2370 int width;
2371
2372 /* The width of the string, including a face extension. */
2373 int background_width;
2374
2375 /* The height of this string. This is the height of the line this
2376 string is drawn in, and can be different from the height of the
2377 font the string is drawn in. */
2378 int height;
2379
2380 /* Number of pixels this string overwrites in front of its x-origin.
2381 This number is zero if the string has an lbearing >= 0; it is
2382 -lbearing, if the string has an lbearing < 0. */
2383 int left_overhang;
2384
2385 /* Number of pixels this string overwrites past its right-most
2386 nominal x-position, i.e. x + width. Zero if the string's
2387 rbearing is <= its nominal width, rbearing - width otherwise. */
2388 int right_overhang;
2389
2390 /* The frame on which the glyph string is drawn. */
2391 struct frame *f;
2392
2393 /* The window on which the glyph string is drawn. */
2394 struct window *w;
2395
2396 /* X display and window for convenience. */
2397 Display *display;
2398 Window window;
2399
2400 /* The glyph row for which this string was built. It determines the
2401 y-origin and height of the string. */
2402 struct glyph_row *row;
2403
2404 /* The area within row. */
2405 enum glyph_row_area area;
2406
2407 /* Characters to be drawn, and number of characters. */
2408 XChar2b *char2b;
2409 int nchars;
2410
06a2c219
GM
2411 /* A face-override for drawing cursors, mouse face and similar. */
2412 enum draw_glyphs_face hl;
2413
2414 /* Face in which this string is to be drawn. */
2415 struct face *face;
2416
2417 /* Font in which this string is to be drawn. */
2418 XFontStruct *font;
2419
2420 /* Font info for this string. */
2421 struct font_info *font_info;
2422
b4192550
KH
2423 /* Non-null means this string describes (part of) a composition.
2424 All characters from char2b are drawn composed. */
2425 struct composition *cmp;
06a2c219
GM
2426
2427 /* Index of this glyph string's first character in the glyph
b4192550
KH
2428 definition of CMP. If this is zero, this glyph string describes
2429 the first character of a composition. */
06a2c219
GM
2430 int gidx;
2431
2432 /* 1 means this glyph strings face has to be drawn to the right end
2433 of the window's drawing area. */
2434 unsigned extends_to_end_of_line_p : 1;
2435
2436 /* 1 means the background of this string has been drawn. */
2437 unsigned background_filled_p : 1;
2438
2439 /* 1 means glyph string must be drawn with 16-bit functions. */
2440 unsigned two_byte_p : 1;
2441
2442 /* 1 means that the original font determined for drawing this glyph
2443 string could not be loaded. The member `font' has been set to
2444 the frame's default font in this case. */
2445 unsigned font_not_found_p : 1;
2446
2447 /* 1 means that the face in which this glyph string is drawn has a
2448 stipple pattern. */
2449 unsigned stippled_p : 1;
2450
66ac4b0e
GM
2451 /* 1 means only the foreground of this glyph string must be drawn,
2452 and we should use the physical height of the line this glyph
2453 string appears in as clip rect. */
2454 unsigned for_overlaps_p : 1;
2455
06a2c219
GM
2456 /* The GC to use for drawing this glyph string. */
2457 GC gc;
2458
2459 /* A pointer to the first glyph in the string. This glyph
2460 corresponds to char2b[0]. Needed to draw rectangles if
2461 font_not_found_p is 1. */
2462 struct glyph *first_glyph;
2463
2464 /* Image, if any. */
2465 struct image *img;
2466
2467 struct glyph_string *next, *prev;
2468};
2469
2470
61869b99 2471#if GLYPH_DEBUG
06a2c219
GM
2472
2473static void
2474x_dump_glyph_string (s)
2475 struct glyph_string *s;
2476{
2477 fprintf (stderr, "glyph string\n");
2478 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2479 s->x, s->y, s->width, s->height);
2480 fprintf (stderr, " ybase = %d\n", s->ybase);
2481 fprintf (stderr, " hl = %d\n", s->hl);
2482 fprintf (stderr, " left overhang = %d, right = %d\n",
2483 s->left_overhang, s->right_overhang);
2484 fprintf (stderr, " nchars = %d\n", s->nchars);
2485 fprintf (stderr, " extends to end of line = %d\n",
2486 s->extends_to_end_of_line_p);
2487 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2488 fprintf (stderr, " bg width = %d\n", s->background_width);
2489}
2490
2491#endif /* GLYPH_DEBUG */
2492
2493
2494
2495static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2496 struct glyph_string **,
2497 struct glyph_string *,
2498 struct glyph_string *));
2499static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2500 struct glyph_string **,
2501 struct glyph_string *,
2502 struct glyph_string *));
2503static void x_append_glyph_string P_ ((struct glyph_string **,
2504 struct glyph_string **,
2505 struct glyph_string *));
2506static int x_left_overwritten P_ ((struct glyph_string *));
2507static int x_left_overwriting P_ ((struct glyph_string *));
2508static int x_right_overwritten P_ ((struct glyph_string *));
2509static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2510static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2511 int));
06a2c219
GM
2512static void x_init_glyph_string P_ ((struct glyph_string *,
2513 XChar2b *, struct window *,
2514 struct glyph_row *,
2515 enum glyph_row_area, int,
2516 enum draw_glyphs_face));
2517static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2518 enum glyph_row_area, int, int,
f0a48a01 2519 enum draw_glyphs_face, int));
06a2c219
GM
2520static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2521static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2522static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2523 int));
2524static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2525static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2526static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2527static void x_draw_glyph_string P_ ((struct glyph_string *));
2528static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2529static void x_set_cursor_gc P_ ((struct glyph_string *));
2530static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2531static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2532static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2533 int *, int *));
2534static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2535static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2536 unsigned long *, double, int));
06a2c219 2537static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2538 double, int, unsigned long));
06a2c219
GM
2539static void x_setup_relief_colors P_ ((struct glyph_string *));
2540static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2541static void x_draw_image_relief P_ ((struct glyph_string *));
2542static void x_draw_image_foreground P_ ((struct glyph_string *));
2543static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2544static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2545static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2546 int, int, int));
2547static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2548 int, int, int, int, XRectangle *));
2549static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2550 int, int, int, XRectangle *));
66ac4b0e
GM
2551static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2552 enum glyph_row_area));
209f68d9
GM
2553static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2554 struct glyph_row *,
2555 enum glyph_row_area, int, int));
06a2c219 2556
163dcff3
GM
2557#if GLYPH_DEBUG
2558static void x_check_font P_ ((struct frame *, XFontStruct *));
2559#endif
2560
06a2c219 2561
06a2c219
GM
2562/* Append the list of glyph strings with head H and tail T to the list
2563 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2564
2565static INLINE void
2566x_append_glyph_string_lists (head, tail, h, t)
2567 struct glyph_string **head, **tail;
2568 struct glyph_string *h, *t;
2569{
2570 if (h)
2571 {
2572 if (*head)
2573 (*tail)->next = h;
2574 else
2575 *head = h;
2576 h->prev = *tail;
2577 *tail = t;
2578 }
2579}
2580
2581
2582/* Prepend the list of glyph strings with head H and tail T to the
2583 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2584 result. */
2585
2586static INLINE void
2587x_prepend_glyph_string_lists (head, tail, h, t)
2588 struct glyph_string **head, **tail;
2589 struct glyph_string *h, *t;
2590{
2591 if (h)
2592 {
2593 if (*head)
2594 (*head)->prev = t;
2595 else
2596 *tail = t;
2597 t->next = *head;
2598 *head = h;
2599 }
2600}
2601
2602
2603/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2604 Set *HEAD and *TAIL to the resulting list. */
2605
2606static INLINE void
2607x_append_glyph_string (head, tail, s)
2608 struct glyph_string **head, **tail;
2609 struct glyph_string *s;
2610{
2611 s->next = s->prev = NULL;
2612 x_append_glyph_string_lists (head, tail, s, s);
2613}
2614
2615
2616/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2617 face. */
2618
2619static void
2620x_set_cursor_gc (s)
2621 struct glyph_string *s;
2622{
2623 if (s->font == FRAME_FONT (s->f)
2624 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2625 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2626 && !s->cmp)
06a2c219
GM
2627 s->gc = s->f->output_data.x->cursor_gc;
2628 else
2629 {
2630 /* Cursor on non-default face: must merge. */
2631 XGCValues xgcv;
2632 unsigned long mask;
2633
2634 xgcv.background = s->f->output_data.x->cursor_pixel;
2635 xgcv.foreground = s->face->background;
2636
2637 /* If the glyph would be invisible, try a different foreground. */
2638 if (xgcv.foreground == xgcv.background)
2639 xgcv.foreground = s->face->foreground;
2640 if (xgcv.foreground == xgcv.background)
2641 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2642 if (xgcv.foreground == xgcv.background)
2643 xgcv.foreground = s->face->foreground;
2644
2645 /* Make sure the cursor is distinct from text in this face. */
2646 if (xgcv.background == s->face->background
2647 && xgcv.foreground == s->face->foreground)
2648 {
2649 xgcv.background = s->face->foreground;
2650 xgcv.foreground = s->face->background;
2651 }
2652
2653 IF_DEBUG (x_check_font (s->f, s->font));
2654 xgcv.font = s->font->fid;
2655 xgcv.graphics_exposures = False;
2656 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2657
2658 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2659 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2660 mask, &xgcv);
2661 else
2662 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2663 = XCreateGC (s->display, s->window, mask, &xgcv);
2664
2665 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2666 }
2667}
2668
2669
2670/* Set up S->gc of glyph string S for drawing text in mouse face. */
2671
2672static void
2673x_set_mouse_face_gc (s)
2674 struct glyph_string *s;
2675{
2676 int face_id;
ee569018 2677 struct face *face;
06a2c219 2678
e4ded23c 2679 /* What face has to be used last for the mouse face? */
06a2c219 2680 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2681 face = FACE_FROM_ID (s->f, face_id);
e4ded23c
GM
2682 if (face == NULL)
2683 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2684
033e3e18
GM
2685 if (s->first_glyph->type == CHAR_GLYPH)
2686 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2687 else
2688 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2689 s->face = FACE_FROM_ID (s->f, face_id);
2690 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2691
2692 /* If font in this face is same as S->font, use it. */
2693 if (s->font == s->face->font)
2694 s->gc = s->face->gc;
2695 else
2696 {
2697 /* Otherwise construct scratch_cursor_gc with values from FACE
2698 but font FONT. */
2699 XGCValues xgcv;
2700 unsigned long mask;
2701
2702 xgcv.background = s->face->background;
2703 xgcv.foreground = s->face->foreground;
2704 IF_DEBUG (x_check_font (s->f, s->font));
2705 xgcv.font = s->font->fid;
2706 xgcv.graphics_exposures = False;
2707 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2708
2709 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2710 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2711 mask, &xgcv);
2712 else
2713 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2714 = XCreateGC (s->display, s->window, mask, &xgcv);
2715
2716 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2717 }
2718
2719 xassert (s->gc != 0);
2720}
2721
2722
2723/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2724 Faces to use in the mode line have already been computed when the
2725 matrix was built, so there isn't much to do, here. */
2726
2727static INLINE void
2728x_set_mode_line_face_gc (s)
2729 struct glyph_string *s;
2730{
2731 s->gc = s->face->gc;
06a2c219
GM
2732}
2733
2734
2735/* Set S->gc of glyph string S for drawing that glyph string. Set
2736 S->stippled_p to a non-zero value if the face of S has a stipple
2737 pattern. */
2738
2739static INLINE void
2740x_set_glyph_string_gc (s)
2741 struct glyph_string *s;
2742{
209f68d9
GM
2743 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2744
06a2c219
GM
2745 if (s->hl == DRAW_NORMAL_TEXT)
2746 {
2747 s->gc = s->face->gc;
2748 s->stippled_p = s->face->stipple != 0;
2749 }
2750 else if (s->hl == DRAW_INVERSE_VIDEO)
2751 {
2752 x_set_mode_line_face_gc (s);
2753 s->stippled_p = s->face->stipple != 0;
2754 }
2755 else if (s->hl == DRAW_CURSOR)
2756 {
2757 x_set_cursor_gc (s);
2758 s->stippled_p = 0;
2759 }
2760 else if (s->hl == DRAW_MOUSE_FACE)
2761 {
2762 x_set_mouse_face_gc (s);
2763 s->stippled_p = s->face->stipple != 0;
2764 }
2765 else if (s->hl == DRAW_IMAGE_RAISED
2766 || s->hl == DRAW_IMAGE_SUNKEN)
2767 {
2768 s->gc = s->face->gc;
2769 s->stippled_p = s->face->stipple != 0;
2770 }
2771 else
2772 {
2773 s->gc = s->face->gc;
2774 s->stippled_p = s->face->stipple != 0;
2775 }
2776
2777 /* GC must have been set. */
2778 xassert (s->gc != 0);
2779}
2780
2781
2782/* Return in *R the clipping rectangle for glyph string S. */
2783
2784static void
2785x_get_glyph_string_clip_rect (s, r)
2786 struct glyph_string *s;
2787 XRectangle *r;
2788{
2789 if (s->row->full_width_p)
2790 {
2791 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2792 int canon_x = CANON_X_UNIT (s->f);
2793
2794 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2795 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2796
2797 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2798 {
1da3fd71 2799 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2800 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2801 r->x -= width;
2802 }
2803
b9432a85 2804 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2805
06a2c219
GM
2806 /* Unless displaying a mode or menu bar line, which are always
2807 fully visible, clip to the visible part of the row. */
2808 if (s->w->pseudo_window_p)
2809 r->height = s->row->visible_height;
2810 else
2811 r->height = s->height;
2812 }
2813 else
2814 {
2815 /* This is a text line that may be partially visible. */
2816 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2817 r->width = window_box_width (s->w, s->area);
2818 r->height = s->row->visible_height;
2819 }
2820
66ac4b0e
GM
2821 /* If S draws overlapping rows, it's sufficient to use the top and
2822 bottom of the window for clipping because this glyph string
2823 intentionally draws over other lines. */
2824 if (s->for_overlaps_p)
2825 {
045dee35 2826 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2827 r->height = window_text_bottom_y (s->w) - r->y;
2828 }
98b8a90f
GM
2829 else
2830 {
2831 /* Don't use S->y for clipping because it doesn't take partially
2832 visible lines into account. For example, it can be negative for
2833 partially visible lines at the top of a window. */
2834 if (!s->row->full_width_p
2835 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
2836 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
2837 else
2838 r->y = max (0, s->row->y);
2839
2840 /* If drawing a tool-bar window, draw it over the internal border
2841 at the top of the window. */
2842 if (s->w == XWINDOW (s->f->tool_bar_window))
2843 r->y -= s->f->output_data.x->internal_border_width;
2844 }
2845
66ac4b0e 2846 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2847}
2848
2849
2850/* Set clipping for output of glyph string S. S may be part of a mode
2851 line or menu if we don't have X toolkit support. */
2852
2853static INLINE void
2854x_set_glyph_string_clipping (s)
2855 struct glyph_string *s;
2856{
2857 XRectangle r;
2858 x_get_glyph_string_clip_rect (s, &r);
2859 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2860}
2861
2862
2863/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2864 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2865
2866static INLINE void
2867x_compute_glyph_string_overhangs (s)
2868 struct glyph_string *s;
2869{
b4192550 2870 if (s->cmp == NULL
06a2c219
GM
2871 && s->first_glyph->type == CHAR_GLYPH)
2872 {
2873 XCharStruct cs;
2874 int direction, font_ascent, font_descent;
2875 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2876 &font_ascent, &font_descent, &cs);
2877 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2878 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2879 }
2880}
2881
2882
2883/* Compute overhangs and x-positions for glyph string S and its
2884 predecessors, or successors. X is the starting x-position for S.
2885 BACKWARD_P non-zero means process predecessors. */
2886
2887static void
2888x_compute_overhangs_and_x (s, x, backward_p)
2889 struct glyph_string *s;
2890 int x;
2891 int backward_p;
2892{
2893 if (backward_p)
2894 {
2895 while (s)
2896 {
2897 x_compute_glyph_string_overhangs (s);
2898 x -= s->width;
2899 s->x = x;
2900 s = s->prev;
2901 }
2902 }
2903 else
2904 {
2905 while (s)
2906 {
2907 x_compute_glyph_string_overhangs (s);
2908 s->x = x;
2909 x += s->width;
2910 s = s->next;
2911 }
2912 }
2913}
2914
2915
2916/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2917 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2918 assumed to be zero. */
06a2c219
GM
2919
2920static void
2921x_get_glyph_overhangs (glyph, f, left, right)
2922 struct glyph *glyph;
2923 struct frame *f;
2924 int *left, *right;
2925{
06a2c219
GM
2926 *left = *right = 0;
2927
b4192550 2928 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2929 {
2930 XFontStruct *font;
2931 struct face *face;
2932 struct font_info *font_info;
2933 XChar2b char2b;
ee569018
KH
2934 XCharStruct *pcm;
2935
2936 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2937 font = face->font;
2938 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2939 if (font
2940 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2941 {
06a2c219
GM
2942 if (pcm->rbearing > pcm->width)
2943 *right = pcm->rbearing - pcm->width;
2944 if (pcm->lbearing < 0)
2945 *left = -pcm->lbearing;
2946 }
2947 }
2948}
2949
2950
2951/* Return the index of the first glyph preceding glyph string S that
2952 is overwritten by S because of S's left overhang. Value is -1
2953 if no glyphs are overwritten. */
2954
2955static int
2956x_left_overwritten (s)
2957 struct glyph_string *s;
2958{
2959 int k;
2960
2961 if (s->left_overhang)
2962 {
2963 int x = 0, i;
2964 struct glyph *glyphs = s->row->glyphs[s->area];
2965 int first = s->first_glyph - glyphs;
2966
2967 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2968 x -= glyphs[i].pixel_width;
2969
2970 k = i + 1;
2971 }
2972 else
2973 k = -1;
2974
2975 return k;
2976}
2977
2978
2979/* Return the index of the first glyph preceding glyph string S that
2980 is overwriting S because of its right overhang. Value is -1 if no
2981 glyph in front of S overwrites S. */
2982
2983static int
2984x_left_overwriting (s)
2985 struct glyph_string *s;
2986{
2987 int i, k, x;
2988 struct glyph *glyphs = s->row->glyphs[s->area];
2989 int first = s->first_glyph - glyphs;
2990
2991 k = -1;
2992 x = 0;
2993 for (i = first - 1; i >= 0; --i)
2994 {
2995 int left, right;
2996 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
2997 if (x + right > 0)
2998 k = i;
2999 x -= glyphs[i].pixel_width;
3000 }
3001
3002 return k;
3003}
3004
3005
3006/* Return the index of the last glyph following glyph string S that is
3007 not overwritten by S because of S's right overhang. Value is -1 if
3008 no such glyph is found. */
3009
3010static int
3011x_right_overwritten (s)
3012 struct glyph_string *s;
3013{
3014 int k = -1;
3015
3016 if (s->right_overhang)
3017 {
3018 int x = 0, i;
3019 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3020 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3021 int end = s->row->used[s->area];
3022
3023 for (i = first; i < end && s->right_overhang > x; ++i)
3024 x += glyphs[i].pixel_width;
3025
3026 k = i;
3027 }
3028
3029 return k;
3030}
3031
3032
3033/* Return the index of the last glyph following glyph string S that
3034 overwrites S because of its left overhang. Value is negative
3035 if no such glyph is found. */
3036
3037static int
3038x_right_overwriting (s)
3039 struct glyph_string *s;
3040{
3041 int i, k, x;
3042 int end = s->row->used[s->area];
3043 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3044 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3045
3046 k = -1;
3047 x = 0;
3048 for (i = first; i < end; ++i)
3049 {
3050 int left, right;
3051 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3052 if (x - left < 0)
3053 k = i;
3054 x += glyphs[i].pixel_width;
3055 }
3056
3057 return k;
3058}
3059
3060
3061/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3062
3063static INLINE void
3064x_clear_glyph_string_rect (s, x, y, w, h)
3065 struct glyph_string *s;
3066 int x, y, w, h;
3067{
3068 XGCValues xgcv;
3069 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3070 XSetForeground (s->display, s->gc, xgcv.background);
3071 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3072 XSetForeground (s->display, s->gc, xgcv.foreground);
3073}
3074
3075
3076/* Draw the background of glyph_string S. If S->background_filled_p
3077 is non-zero don't draw it. FORCE_P non-zero means draw the
3078 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3079 when a string preceding S draws into the background of S, or S
3080 contains the first component of a composition. */
06a2c219
GM
3081
3082static void
3083x_draw_glyph_string_background (s, force_p)
3084 struct glyph_string *s;
3085 int force_p;
3086{
3087 /* Nothing to do if background has already been drawn or if it
3088 shouldn't be drawn in the first place. */
3089 if (!s->background_filled_p)
3090 {
ea2ba0d4
KH
3091 int box_line_width = max (s->face->box_line_width, 0);
3092
b4192550 3093 if (s->stippled_p)
06a2c219
GM
3094 {
3095 /* Fill background with a stipple pattern. */
3096 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3097 XFillRectangle (s->display, s->window, s->gc, s->x,
ea2ba0d4 3098 s->y + box_line_width,
06a2c219 3099 s->background_width,
ea2ba0d4 3100 s->height - 2 * box_line_width);
06a2c219
GM
3101 XSetFillStyle (s->display, s->gc, FillSolid);
3102 s->background_filled_p = 1;
3103 }
ea2ba0d4 3104 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
06a2c219
GM
3105 || s->font_not_found_p
3106 || s->extends_to_end_of_line_p
06a2c219
GM
3107 || force_p)
3108 {
ea2ba0d4 3109 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
06a2c219 3110 s->background_width,
ea2ba0d4 3111 s->height - 2 * box_line_width);
06a2c219
GM
3112 s->background_filled_p = 1;
3113 }
3114 }
3115}
3116
3117
3118/* Draw the foreground of glyph string S. */
3119
3120static void
3121x_draw_glyph_string_foreground (s)
3122 struct glyph_string *s;
3123{
3124 int i, x;
3125
3126 /* If first glyph of S has a left box line, start drawing the text
3127 of S to the right of that box line. */
3128 if (s->face->box != FACE_NO_BOX
3129 && s->first_glyph->left_box_line_p)
ea2ba0d4 3130 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
3131 else
3132 x = s->x;
3133
b4192550
KH
3134 /* Draw characters of S as rectangles if S's font could not be
3135 loaded. */
3136 if (s->font_not_found_p)
06a2c219 3137 {
b4192550 3138 for (i = 0; i < s->nchars; ++i)
06a2c219 3139 {
b4192550
KH
3140 struct glyph *g = s->first_glyph + i;
3141 XDrawRectangle (s->display, s->window,
3142 s->gc, x, s->y, g->pixel_width - 1,
3143 s->height - 1);
3144 x += g->pixel_width;
06a2c219
GM
3145 }
3146 }
3147 else
3148 {
b4192550
KH
3149 char *char1b = (char *) s->char2b;
3150 int boff = s->font_info->baseline_offset;
06a2c219 3151
b4192550
KH
3152 if (s->font_info->vertical_centering)
3153 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3154
3155 /* If we can use 8-bit functions, condense S->char2b. */
3156 if (!s->two_byte_p)
3157 for (i = 0; i < s->nchars; ++i)
3158 char1b[i] = s->char2b[i].byte2;
3159
3160 /* Draw text with XDrawString if background has already been
3161 filled. Otherwise, use XDrawImageString. (Note that
3162 XDrawImageString is usually faster than XDrawString.) Always
3163 use XDrawImageString when drawing the cursor so that there is
3164 no chance that characters under a box cursor are invisible. */
3165 if (s->for_overlaps_p
3166 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3167 {
3168 /* Draw characters with 16-bit or 8-bit functions. */
3169 if (s->two_byte_p)
3170 XDrawString16 (s->display, s->window, s->gc, x,
3171 s->ybase - boff, s->char2b, s->nchars);
3172 else
3173 XDrawString (s->display, s->window, s->gc, x,
3174 s->ybase - boff, char1b, s->nchars);
3175 }
06a2c219
GM
3176 else
3177 {
b4192550
KH
3178 if (s->two_byte_p)
3179 XDrawImageString16 (s->display, s->window, s->gc, x,
3180 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3181 else
b4192550
KH
3182 XDrawImageString (s->display, s->window, s->gc, x,
3183 s->ybase - boff, char1b, s->nchars);
3184 }
3185 }
3186}
06a2c219 3187
b4192550 3188/* Draw the foreground of composite glyph string S. */
06a2c219 3189
b4192550
KH
3190static void
3191x_draw_composite_glyph_string_foreground (s)
3192 struct glyph_string *s;
3193{
3194 int i, x;
06a2c219 3195
b4192550
KH
3196 /* If first glyph of S has a left box line, start drawing the text
3197 of S to the right of that box line. */
3198 if (s->face->box != FACE_NO_BOX
3199 && s->first_glyph->left_box_line_p)
ea2ba0d4 3200 x = s->x + abs (s->face->box_line_width);
b4192550
KH
3201 else
3202 x = s->x;
06a2c219 3203
b4192550
KH
3204 /* S is a glyph string for a composition. S->gidx is the index of
3205 the first character drawn for glyphs of this composition.
3206 S->gidx == 0 means we are drawing the very first character of
3207 this composition. */
06a2c219 3208
b4192550
KH
3209 /* Draw a rectangle for the composition if the font for the very
3210 first character of the composition could not be loaded. */
3211 if (s->font_not_found_p)
3212 {
3213 if (s->gidx == 0)
3214 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3215 s->width - 1, s->height - 1);
3216 }
3217 else
3218 {
3219 for (i = 0; i < s->nchars; i++, ++s->gidx)
3220 XDrawString16 (s->display, s->window, s->gc,
3221 x + s->cmp->offsets[s->gidx * 2],
3222 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3223 s->char2b + i, 1);
06a2c219
GM
3224 }
3225}
3226
3227
80c32bcc
GM
3228#ifdef USE_X_TOOLKIT
3229
3e71d8f2 3230static struct frame *x_frame_of_widget P_ ((Widget));
651f03b6
GM
3231static Boolean cvt_string_to_pixel P_ ((Display *, XrmValue *, Cardinal *,
3232 XrmValue *, XrmValue *, XtPointer *));
3233static void cvt_pixel_dtor P_ ((XtAppContext, XrmValue *, XtPointer,
3234 XrmValue *, Cardinal *));
80c32bcc 3235
3e71d8f2
GM
3236
3237/* Return the frame on which widget WIDGET is used.. Abort if frame
3238 cannot be determined. */
3239
e851c833 3240static struct frame *
3e71d8f2 3241x_frame_of_widget (widget)
80c32bcc 3242 Widget widget;
80c32bcc 3243{
80c32bcc 3244 struct x_display_info *dpyinfo;
5c187dee 3245 Lisp_Object tail;
3e71d8f2
GM
3246 struct frame *f;
3247
80c32bcc
GM
3248 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3249
3250 /* Find the top-level shell of the widget. Note that this function
3251 can be called when the widget is not yet realized, so XtWindow
3252 (widget) == 0. That's the reason we can't simply use
3253 x_any_window_to_frame. */
3254 while (!XtIsTopLevelShell (widget))
3255 widget = XtParent (widget);
3256
3257 /* Look for a frame with that top-level widget. Allocate the color
3258 on that frame to get the right gamma correction value. */
3259 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3260 if (GC_FRAMEP (XCAR (tail))
3261 && (f = XFRAME (XCAR (tail)),
3262 (f->output_data.nothing != 1
3263 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3264 && f->output_data.x->widget == widget)
3e71d8f2 3265 return f;
80c32bcc
GM
3266
3267 abort ();
3268}
3269
3e71d8f2
GM
3270
3271/* Allocate the color COLOR->pixel on the screen and display of
3272 widget WIDGET in colormap CMAP. If an exact match cannot be
3273 allocated, try the nearest color available. Value is non-zero
3274 if successful. This is called from lwlib. */
3275
3276int
3277x_alloc_nearest_color_for_widget (widget, cmap, color)
3278 Widget widget;
3279 Colormap cmap;
3280 XColor *color;
3281{
3282 struct frame *f = x_frame_of_widget (widget);
3283 return x_alloc_nearest_color (f, cmap, color);
3284}
3285
3286
46d516e5
MB
3287/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3288 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3289 If this produces the same color as PIXEL, try a color where all RGB
3290 values have DELTA added. Return the allocated color in *PIXEL.
3291 DISPLAY is the X display, CMAP is the colormap to operate on.
3292 Value is non-zero if successful. */
3293
3294int
3295x_alloc_lighter_color_for_widget (widget, display, cmap, pixel, factor, delta)
3296 Widget widget;
3297 Display *display;
3298 Colormap cmap;
3299 unsigned long *pixel;
3300 double factor;
3301 int delta;
3302{
3303 struct frame *f = x_frame_of_widget (widget);
3304 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
3305}
3306
3307
651f03b6
GM
3308/* Structure specifying which arguments should be passed by Xt to
3309 cvt_string_to_pixel. We want the widget's screen and colormap. */
3310
3311static XtConvertArgRec cvt_string_to_pixel_args[] =
3312 {
3313 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.screen),
3314 sizeof (Screen *)},
3315 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.colormap),
3316 sizeof (Colormap)}
3317 };
3318
3319
3320/* The address of this variable is returned by
3321 cvt_string_to_pixel. */
3322
3323static Pixel cvt_string_to_pixel_value;
3324
3325
3326/* Convert a color name to a pixel color.
3327
3328 DPY is the display we are working on.
3329
3330 ARGS is an array of *NARGS XrmValue structures holding additional
3331 information about the widget for which the conversion takes place.
3332 The contents of this array are determined by the specification
3333 in cvt_string_to_pixel_args.
3334
3335 FROM is a pointer to an XrmValue which points to the color name to
3336 convert. TO is an XrmValue in which to return the pixel color.
3337
3338 CLOSURE_RET is a pointer to user-data, in which we record if
3339 we allocated the color or not.
3340
3341 Value is True if successful, False otherwise. */
3342
3343static Boolean
3344cvt_string_to_pixel (dpy, args, nargs, from, to, closure_ret)
3345 Display *dpy;
3346 XrmValue *args;
3347 Cardinal *nargs;
3348 XrmValue *from, *to;
3349 XtPointer *closure_ret;
3350{
3351 Screen *screen;
3352 Colormap cmap;
3353 Pixel pixel;
3354 String color_name;
3355 XColor color;
3356
3357 if (*nargs != 2)
3358 {
3359 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3360 "wrongParameters", "cvt_string_to_pixel",
3361 "XtToolkitError",
3362 "Screen and colormap args required", NULL, NULL);
3363 return False;
3364 }
3365
3366 screen = *(Screen **) args[0].addr;
3367 cmap = *(Colormap *) args[1].addr;
3368 color_name = (String) from->addr;
3369
3370 if (strcmp (color_name, XtDefaultBackground) == 0)
3371 {
3372 *closure_ret = (XtPointer) False;
3373 pixel = WhitePixelOfScreen (screen);
3374 }
3375 else if (strcmp (color_name, XtDefaultForeground) == 0)
3376 {
3377 *closure_ret = (XtPointer) False;
3378 pixel = BlackPixelOfScreen (screen);
3379 }
3380 else if (XParseColor (dpy, cmap, color_name, &color)
3381 && x_alloc_nearest_color_1 (dpy, cmap, &color))
3382 {
3383 pixel = color.pixel;
3384 *closure_ret = (XtPointer) True;
3385 }
3386 else
3387 {
3388 String params[1];
3389 Cardinal nparams = 1;
3390
3391 params[0] = color_name;
3392 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3393 "badValue", "cvt_string_to_pixel",
3394 "XtToolkitError", "Invalid color `%s'",
3395 params, &nparams);
3396 return False;
3397 }
3398
3399 if (to->addr != NULL)
3400 {
3401 if (to->size < sizeof (Pixel))
3402 {
3403 to->size = sizeof (Pixel);
3404 return False;
3405 }
3406
3407 *(Pixel *) to->addr = pixel;
3408 }
3409 else
3410 {
3411 cvt_string_to_pixel_value = pixel;
3412 to->addr = (XtPointer) &cvt_string_to_pixel_value;
3413 }
3414
3415 to->size = sizeof (Pixel);
3416 return True;
3417}
3418
3419
3420/* Free a pixel color which was previously allocated via
3421 cvt_string_to_pixel. This is registered as the destructor
3422 for this type of resource via XtSetTypeConverter.
3423
3424 APP is the application context in which we work.
3425
3426 TO is a pointer to an XrmValue holding the color to free.
3427 CLOSURE is the value we stored in CLOSURE_RET for this color
3428 in cvt_string_to_pixel.
3429
3430 ARGS and NARGS are like for cvt_string_to_pixel. */
3431
3432static void
3433cvt_pixel_dtor (app, to, closure, args, nargs)
3434 XtAppContext app;
3435 XrmValuePtr to;
3436 XtPointer closure;
3437 XrmValuePtr args;
3438 Cardinal *nargs;
3439{
3440 if (*nargs != 2)
3441 {
3442 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
3443 "XtToolkitError",
3444 "Screen and colormap arguments required",
3445 NULL, NULL);
3446 }
3447 else if (closure != NULL)
3448 {
3449 /* We did allocate the pixel, so free it. */
3450 Screen *screen = *(Screen **) args[0].addr;
3451 Colormap cmap = *(Colormap *) args[1].addr;
3452 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
97762eb7 3453 (Pixel *) to->addr, 1);
651f03b6
GM
3454 }
3455}
3456
3457
80c32bcc
GM
3458#endif /* USE_X_TOOLKIT */
3459
3460
f04e1297 3461/* Value is an array of XColor structures for the contents of the
651f03b6 3462 color map of display DPY. Set *NCELLS to the size of the array.
f04e1297
GM
3463 Note that this probably shouldn't be called for large color maps,
3464 say a 24-bit TrueColor map. */
3465
3466static const XColor *
651f03b6
GM
3467x_color_cells (dpy, ncells)
3468 Display *dpy;
f04e1297
GM
3469 int *ncells;
3470{
651f03b6 3471 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
f04e1297
GM
3472
3473 if (dpyinfo->color_cells == NULL)
3474 {
651f03b6 3475 Screen *screen = dpyinfo->screen;
f04e1297
GM
3476 int i;
3477
3478 dpyinfo->ncolor_cells
651f03b6 3479 = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
f04e1297
GM
3480 dpyinfo->color_cells
3481 = (XColor *) xmalloc (dpyinfo->ncolor_cells
3482 * sizeof *dpyinfo->color_cells);
3483
3484 for (i = 0; i < dpyinfo->ncolor_cells; ++i)
3485 dpyinfo->color_cells[i].pixel = i;
3486
651f03b6 3487 XQueryColors (dpy, dpyinfo->cmap,
f04e1297
GM
3488 dpyinfo->color_cells, dpyinfo->ncolor_cells);
3489 }
3490
3491 *ncells = dpyinfo->ncolor_cells;
3492 return dpyinfo->color_cells;
3493}
3494
3495
3496/* On frame F, translate pixel colors to RGB values for the NCOLORS
3497 colors in COLORS. Use cached information, if available. */
3498
3499void
3500x_query_colors (f, colors, ncolors)
3501 struct frame *f;
3502 XColor *colors;
3503 int ncolors;
3504{
3505 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3506
3507 if (dpyinfo->color_cells)
3508 {
3509 int i;
3510 for (i = 0; i < ncolors; ++i)
3511 {
3512 unsigned long pixel = colors[i].pixel;
3513 xassert (pixel < dpyinfo->ncolor_cells);
3514 xassert (dpyinfo->color_cells[pixel].pixel == pixel);
3515 colors[i] = dpyinfo->color_cells[pixel];
3516 }
3517 }
3518 else
3519 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
3520}
3521
3522
3523/* On frame F, translate pixel color to RGB values for the color in
3524 COLOR. Use cached information, if available. */
3525
3526void
3527x_query_color (f, color)
3528 struct frame *f;
3529 XColor *color;
3530{
3531 x_query_colors (f, color, 1);
3532}
3533
3534
651f03b6
GM
3535/* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
3536 exact match can't be allocated, try the nearest color available.
3537 Value is non-zero if successful. Set *COLOR to the color
3538 allocated. */
06a2c219 3539
651f03b6
GM
3540static int
3541x_alloc_nearest_color_1 (dpy, cmap, color)
3542 Display *dpy;
06a2c219
GM
3543 Colormap cmap;
3544 XColor *color;
3545{
80c32bcc
GM
3546 int rc;
3547
651f03b6 3548 rc = XAllocColor (dpy, cmap, color);
06a2c219
GM
3549 if (rc == 0)
3550 {
3551 /* If we got to this point, the colormap is full, so we're going
3552 to try to get the next closest color. The algorithm used is
3553 a least-squares matching, which is what X uses for closest
3554 color matching with StaticColor visuals. */
3555 int nearest, i;
3556 unsigned long nearest_delta = ~0;
f04e1297 3557 int ncells;
651f03b6 3558 const XColor *cells = x_color_cells (dpy, &ncells);
06a2c219
GM
3559
3560 for (nearest = i = 0; i < ncells; ++i)
3561 {
3562 long dred = (color->red >> 8) - (cells[i].red >> 8);
3563 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3564 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3565 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3566
3567 if (delta < nearest_delta)
3568 {
3569 nearest = i;
3570 nearest_delta = delta;
3571 }
3572 }
3573
3574 color->red = cells[nearest].red;
3575 color->green = cells[nearest].green;
3576 color->blue = cells[nearest].blue;
651f03b6 3577 rc = XAllocColor (dpy, cmap, color);
06a2c219 3578 }
35efe0a1
GM
3579 else
3580 {
3581 /* If allocation succeeded, and the allocated pixel color is not
3582 equal to a cached pixel color recorded earlier, there was a
3583 change in the colormap, so clear the color cache. */
651f03b6 3584 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
35efe0a1
GM
3585 XColor *cached_color;
3586
3587 if (dpyinfo->color_cells
3588 && (cached_color = &dpyinfo->color_cells[color->pixel],
cae71efe
GM
3589 (cached_color->red != color->red
3590 || cached_color->blue != color->blue
3591 || cached_color->green != color->green)))
35efe0a1
GM
3592 {
3593 xfree (dpyinfo->color_cells);
3594 dpyinfo->color_cells = NULL;
3595 dpyinfo->ncolor_cells = 0;
3596 }
3597 }
06a2c219 3598
d9c545da
GM
3599#ifdef DEBUG_X_COLORS
3600 if (rc)
3601 register_color (color->pixel);
3602#endif /* DEBUG_X_COLORS */
3603
06a2c219
GM
3604 return rc;
3605}
3606
3607
651f03b6
GM
3608/* Allocate the color COLOR->pixel on frame F, colormap CMAP. If an
3609 exact match can't be allocated, try the nearest color available.
3610 Value is non-zero if successful. Set *COLOR to the color
3611 allocated. */
3612
3613int
3614x_alloc_nearest_color (f, cmap, color)
3615 struct frame *f;
3616 Colormap cmap;
3617 XColor *color;
3618{
3619 gamma_correct (f, color);
3620 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
3621}
3622
3623
d9c545da
GM
3624/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3625 It's necessary to do this instead of just using PIXEL directly to
3626 get color reference counts right. */
3627
3628unsigned long
3629x_copy_color (f, pixel)
3630 struct frame *f;
3631 unsigned long pixel;
3632{
3633 XColor color;
3634
3635 color.pixel = pixel;
3636 BLOCK_INPUT;
f04e1297 3637 x_query_color (f, &color);
d9c545da
GM
3638 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3639 UNBLOCK_INPUT;
3640#ifdef DEBUG_X_COLORS
3641 register_color (pixel);
3642#endif
3643 return color.pixel;
3644}
3645
3646
3e71d8f2
GM
3647/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3648 It's necessary to do this instead of just using PIXEL directly to
3649 get color reference counts right. */
3650
3651unsigned long
3652x_copy_dpy_color (dpy, cmap, pixel)
3653 Display *dpy;
3654 Colormap cmap;
3655 unsigned long pixel;
3656{
3657 XColor color;
3658
3659 color.pixel = pixel;
3660 BLOCK_INPUT;
3661 XQueryColor (dpy, cmap, &color);
3662 XAllocColor (dpy, cmap, &color);
3663 UNBLOCK_INPUT;
3664#ifdef DEBUG_X_COLORS
3665 register_color (pixel);
3666#endif
3667 return color.pixel;
3668}
3669
3670
6d8b0acd 3671/* Brightness beyond which a color won't have its highlight brightness
d7361edf 3672 boosted.
6d8b0acd 3673
d7361edf
MB
3674 Nominally, highlight colors for `3d' faces are calculated by
3675 brightening an object's color by a constant scale factor, but this
3676 doesn't yield good results for dark colors, so for colors who's
3677 brightness is less than this value (on a scale of 0-65535) have an
3678 use an additional additive factor.
6d8b0acd
MB
3679
3680 The value here is set so that the default menu-bar/mode-line color
3681 (grey75) will not have its highlights changed at all. */
3682#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
3683
3684
06a2c219
GM
3685/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3686 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3687 If this produces the same color as PIXEL, try a color where all RGB
3688 values have DELTA added. Return the allocated color in *PIXEL.
3689 DISPLAY is the X display, CMAP is the colormap to operate on.
3690 Value is non-zero if successful. */
3691
3692static int
3693x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3694 struct frame *f;
3695 Display *display;
3696 Colormap cmap;
3697 unsigned long *pixel;
68c45bf0 3698 double factor;
06a2c219
GM
3699 int delta;
3700{
3701 XColor color, new;
6d8b0acd 3702 long bright;
06a2c219
GM
3703 int success_p;
3704
3705 /* Get RGB color values. */
3706 color.pixel = *pixel;
f04e1297 3707 x_query_color (f, &color);
06a2c219
GM
3708
3709 /* Change RGB values by specified FACTOR. Avoid overflow! */
3710 xassert (factor >= 0);
3711 new.red = min (0xffff, factor * color.red);
3712 new.green = min (0xffff, factor * color.green);
3713 new.blue = min (0xffff, factor * color.blue);
3714
d7361edf
MB
3715 /* Calculate brightness of COLOR. */
3716 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
6d8b0acd
MB
3717
3718 /* We only boost colors that are darker than
3719 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3720 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3721 /* Make an additive adjustment to NEW, because it's dark enough so
3722 that scaling by FACTOR alone isn't enough. */
3723 {
3724 /* How far below the limit this color is (0 - 1, 1 being darker). */
3725 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3726 /* The additive adjustment. */
d7361edf 3727 int min_delta = delta * dimness * factor / 2;
6d8b0acd
MB
3728
3729 if (factor < 1)
3730 {
6d8b0acd
MB
3731 new.red = max (0, new.red - min_delta);
3732 new.green = max (0, new.green - min_delta);
3733 new.blue = max (0, new.blue - min_delta);
3734 }
3735 else
3736 {
3737 new.red = min (0xffff, min_delta + new.red);
3738 new.green = min (0xffff, min_delta + new.green);
3739 new.blue = min (0xffff, min_delta + new.blue);
3740 }
3741 }
3742
06a2c219 3743 /* Try to allocate the color. */
80c32bcc 3744 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3745 if (success_p)
3746 {
3747 if (new.pixel == *pixel)
3748 {
3749 /* If we end up with the same color as before, try adding
3750 delta to the RGB values. */
0d605c67 3751 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3752
3753 new.red = min (0xffff, delta + color.red);
3754 new.green = min (0xffff, delta + color.green);
3755 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3756 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3757 }
3758 else
3759 success_p = 1;
3760 *pixel = new.pixel;
3761 }
3762
3763 return success_p;
3764}
3765
3766
3767/* Set up the foreground color for drawing relief lines of glyph
3768 string S. RELIEF is a pointer to a struct relief containing the GC
3769 with which lines will be drawn. Use a color that is FACTOR or
3770 DELTA lighter or darker than the relief's background which is found
3771 in S->f->output_data.x->relief_background. If such a color cannot
3772 be allocated, use DEFAULT_PIXEL, instead. */
3773
3774static void
3775x_setup_relief_color (f, relief, factor, delta, default_pixel)
3776 struct frame *f;
3777 struct relief *relief;
68c45bf0 3778 double factor;
06a2c219
GM
3779 int delta;
3780 unsigned long default_pixel;
3781{
3782 XGCValues xgcv;
3783 struct x_output *di = f->output_data.x;
3784 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3785 unsigned long pixel;
3786 unsigned long background = di->relief_background;
43bd1b2b 3787 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3788 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3789 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3790
3791 xgcv.graphics_exposures = False;
3792 xgcv.line_width = 1;
3793
3794 /* Free previously allocated color. The color cell will be reused
3795 when it has been freed as many times as it was allocated, so this
3796 doesn't affect faces using the same colors. */
3797 if (relief->gc
3798 && relief->allocated_p)
3799 {
0d605c67 3800 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3801 relief->allocated_p = 0;
3802 }
3803
3804 /* Allocate new color. */
3805 xgcv.foreground = default_pixel;
3806 pixel = background;
dcd08bfb
GM
3807 if (dpyinfo->n_planes != 1
3808 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3809 {
3810 relief->allocated_p = 1;
3811 xgcv.foreground = relief->pixel = pixel;
3812 }
3813
3814 if (relief->gc == 0)
3815 {
dcd08bfb 3816 xgcv.stipple = dpyinfo->gray;
06a2c219 3817 mask |= GCStipple;
dcd08bfb 3818 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3819 }
3820 else
dcd08bfb 3821 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3822}
3823
3824
3825/* Set up colors for the relief lines around glyph string S. */
3826
3827static void
3828x_setup_relief_colors (s)
3829 struct glyph_string *s;
3830{
3831 struct x_output *di = s->f->output_data.x;
3832 unsigned long color;
3833
3834 if (s->face->use_box_color_for_shadows_p)
3835 color = s->face->box_color;
e2a57b34
MB
3836 else if (s->first_glyph->type == IMAGE_GLYPH
3837 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3838 color = IMAGE_BACKGROUND (s->img, s->f, 0);
06a2c219
GM
3839 else
3840 {
3841 XGCValues xgcv;
3842
3843 /* Get the background color of the face. */
3844 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3845 color = xgcv.background;
3846 }
3847
3848 if (di->white_relief.gc == 0
3849 || color != di->relief_background)
3850 {
3851 di->relief_background = color;
3852 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3853 WHITE_PIX_DEFAULT (s->f));
3854 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3855 BLACK_PIX_DEFAULT (s->f));
3856 }
3857}
3858
3859
3860/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3861 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3862 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3863 relief. LEFT_P non-zero means draw a relief on the left side of
3864 the rectangle. RIGHT_P non-zero means draw a relief on the right
3865 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3866 when drawing. */
3867
3868static void
3869x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3870 raised_p, left_p, right_p, clip_rect)
3871 struct frame *f;
3872 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3873 XRectangle *clip_rect;
3874{
de507556
GM
3875 Display *dpy = FRAME_X_DISPLAY (f);
3876 Window window = FRAME_X_WINDOW (f);
06a2c219
GM
3877 int i;
3878 GC gc;
3879
3880 if (raised_p)
3881 gc = f->output_data.x->white_relief.gc;
3882 else
3883 gc = f->output_data.x->black_relief.gc;
de507556 3884 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3885
3886 /* Top. */
3887 for (i = 0; i < width; ++i)
de507556 3888 XDrawLine (dpy, window, gc,
06a2c219
GM
3889 left_x + i * left_p, top_y + i,
3890 right_x + 1 - i * right_p, top_y + i);
3891
3892 /* Left. */
3893 if (left_p)
3894 for (i = 0; i < width; ++i)
de507556 3895 XDrawLine (dpy, window, gc,
44655e77 3896 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
06a2c219 3897
de507556 3898 XSetClipMask (dpy, gc, None);
06a2c219
GM
3899 if (raised_p)
3900 gc = f->output_data.x->black_relief.gc;
3901 else
3902 gc = f->output_data.x->white_relief.gc;
de507556 3903 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3904
3905 /* Bottom. */
3906 for (i = 0; i < width; ++i)
de507556
GM
3907 XDrawLine (dpy, window, gc,
3908 left_x + i * left_p, bottom_y - i,
327f42ee 3909 right_x + 1 - i * right_p, bottom_y - i);
06a2c219
GM
3910
3911 /* Right. */
3912 if (right_p)
3913 for (i = 0; i < width; ++i)
de507556 3914 XDrawLine (dpy, window, gc,
06a2c219
GM
3915 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3916
de507556 3917 XSetClipMask (dpy, gc, None);
06a2c219
GM
3918}
3919
3920
3921/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3922 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3923 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3924 left side of the rectangle. RIGHT_P non-zero means draw a line
3925 on the right side of the rectangle. CLIP_RECT is the clipping
3926 rectangle to use when drawing. */
3927
3928static void
3929x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3930 left_p, right_p, clip_rect)
3931 struct glyph_string *s;
3932 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3933 XRectangle *clip_rect;
3934{
3935 XGCValues xgcv;
3936
3937 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3938 XSetForeground (s->display, s->gc, s->face->box_color);
3939 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3940
3941 /* Top. */
3942 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3943 left_x, top_y, right_x - left_x + 1, width);
06a2c219
GM
3944
3945 /* Left. */
3946 if (left_p)
3947 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3948 left_x, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3949
3950 /* Bottom. */
3951 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3952 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
06a2c219
GM
3953
3954 /* Right. */
3955 if (right_p)
3956 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3957 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3958
3959 XSetForeground (s->display, s->gc, xgcv.foreground);
3960 XSetClipMask (s->display, s->gc, None);
3961}
3962
3963
3964/* Draw a box around glyph string S. */
3965
3966static void
3967x_draw_glyph_string_box (s)
3968 struct glyph_string *s;
3969{
3970 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3971 int left_p, right_p;
3972 struct glyph *last_glyph;
3973 XRectangle clip_rect;
3974
3975 last_x = window_box_right (s->w, s->area);
3976 if (s->row->full_width_p
3977 && !s->w->pseudo_window_p)
3978 {
3f332ef3 3979 last_x += FRAME_X_RIGHT_FRINGE_WIDTH (s->f);
06a2c219
GM
3980 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3981 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3982 }
3983
3984 /* The glyph that may have a right box line. */
b4192550 3985 last_glyph = (s->cmp || s->img
06a2c219
GM
3986 ? s->first_glyph
3987 : s->first_glyph + s->nchars - 1);
3988
ea2ba0d4 3989 width = abs (s->face->box_line_width);
06a2c219
GM
3990 raised_p = s->face->box == FACE_RAISED_BOX;
3991 left_x = s->x;
57ac7c81
GM
3992 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
3993 ? last_x - 1
3994 : min (last_x, s->x + s->background_width) - 1);
06a2c219
GM
3995 top_y = s->y;
3996 bottom_y = top_y + s->height - 1;
3997
3998 left_p = (s->first_glyph->left_box_line_p
3999 || (s->hl == DRAW_MOUSE_FACE
4000 && (s->prev == NULL
4001 || s->prev->hl != s->hl)));
4002 right_p = (last_glyph->right_box_line_p
4003 || (s->hl == DRAW_MOUSE_FACE
4004 && (s->next == NULL
4005 || s->next->hl != s->hl)));
327f42ee 4006
06a2c219
GM
4007 x_get_glyph_string_clip_rect (s, &clip_rect);
4008
4009 if (s->face->box == FACE_SIMPLE_BOX)
4010 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4011 left_p, right_p, &clip_rect);
4012 else
4013 {
4014 x_setup_relief_colors (s);
4015 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
4016 width, raised_p, left_p, right_p, &clip_rect);
4017 }
4018}
4019
4020
4021/* Draw foreground of image glyph string S. */
4022
4023static void
4024x_draw_image_foreground (s)
4025 struct glyph_string *s;
4026{
4027 int x;
95af8492 4028 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4029
4030 /* If first glyph of S has a left box line, start drawing it to the
4031 right of that line. */
4032 if (s->face->box != FACE_NO_BOX
4033 && s->first_glyph->left_box_line_p)
ea2ba0d4 4034 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4035 else
4036 x = s->x;
4037
4038 /* If there is a margin around the image, adjust x- and y-position
4039 by that margin. */
22d650b8
GM
4040 x += s->img->hmargin;
4041 y += s->img->vmargin;
06a2c219
GM
4042
4043 if (s->img->pixmap)
4044 {
4045 if (s->img->mask)
4046 {
4047 /* We can't set both a clip mask and use XSetClipRectangles
4048 because the latter also sets a clip mask. We also can't
4049 trust on the shape extension to be available
4050 (XShapeCombineRegion). So, compute the rectangle to draw
4051 manually. */
4052 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4053 | GCFunction);
4054 XGCValues xgcv;
4055 XRectangle clip_rect, image_rect, r;
4056
4057 xgcv.clip_mask = s->img->mask;
4058 xgcv.clip_x_origin = x;
4059 xgcv.clip_y_origin = y;
4060 xgcv.function = GXcopy;
4061 XChangeGC (s->display, s->gc, mask, &xgcv);
4062
4063 x_get_glyph_string_clip_rect (s, &clip_rect);
4064 image_rect.x = x;
4065 image_rect.y = y;
4066 image_rect.width = s->img->width;
4067 image_rect.height = s->img->height;
4068 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4069 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4070 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
4071 }
4072 else
4073 {
49ad1d99
GM
4074 XRectangle clip_rect, image_rect, r;
4075
4076 x_get_glyph_string_clip_rect (s, &clip_rect);
4077 image_rect.x = x;
4078 image_rect.y = y;
4079 image_rect.width = s->img->width;
4080 image_rect.height = s->img->height;
4081 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4082 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4083 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
06a2c219
GM
4084
4085 /* When the image has a mask, we can expect that at
4086 least part of a mouse highlight or a block cursor will
4087 be visible. If the image doesn't have a mask, make
4088 a block cursor visible by drawing a rectangle around
4089 the image. I believe it's looking better if we do
4090 nothing here for mouse-face. */
4091 if (s->hl == DRAW_CURSOR)
4092 XDrawRectangle (s->display, s->window, s->gc, x, y,
4093 s->img->width - 1, s->img->height - 1);
4094 }
4095 }
4096 else
4097 /* Draw a rectangle if image could not be loaded. */
4098 XDrawRectangle (s->display, s->window, s->gc, x, y,
4099 s->img->width - 1, s->img->height - 1);
4100}
4101
4102
4103/* Draw a relief around the image glyph string S. */
4104
4105static void
4106x_draw_image_relief (s)
4107 struct glyph_string *s;
4108{
4109 int x0, y0, x1, y1, thick, raised_p;
4110 XRectangle r;
4111 int x;
95af8492 4112 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4113
4114 /* If first glyph of S has a left box line, start drawing it to the
4115 right of that line. */
4116 if (s->face->box != FACE_NO_BOX
4117 && s->first_glyph->left_box_line_p)
ea2ba0d4 4118 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4119 else
4120 x = s->x;
4121
4122 /* If there is a margin around the image, adjust x- and y-position
4123 by that margin. */
22d650b8
GM
4124 x += s->img->hmargin;
4125 y += s->img->vmargin;
06a2c219
GM
4126
4127 if (s->hl == DRAW_IMAGE_SUNKEN
4128 || s->hl == DRAW_IMAGE_RAISED)
4129 {
a10b6ff1 4130 thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : 3;
06a2c219
GM
4131 raised_p = s->hl == DRAW_IMAGE_RAISED;
4132 }
4133 else
4134 {
4135 thick = abs (s->img->relief);
4136 raised_p = s->img->relief > 0;
4137 }
4138
4139 x0 = x - thick;
4140 y0 = y - thick;
4141 x1 = x + s->img->width + thick - 1;
4142 y1 = y + s->img->height + thick - 1;
4143
4144 x_setup_relief_colors (s);
4145 x_get_glyph_string_clip_rect (s, &r);
4146 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
4147}
4148
4149
4150/* Draw the foreground of image glyph string S to PIXMAP. */
4151
4152static void
4153x_draw_image_foreground_1 (s, pixmap)
4154 struct glyph_string *s;
4155 Pixmap pixmap;
4156{
4157 int x;
95af8492 4158 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
4159
4160 /* If first glyph of S has a left box line, start drawing it to the
4161 right of that line. */
4162 if (s->face->box != FACE_NO_BOX
4163 && s->first_glyph->left_box_line_p)
ea2ba0d4 4164 x = abs (s->face->box_line_width);
06a2c219
GM
4165 else
4166 x = 0;
4167
4168 /* If there is a margin around the image, adjust x- and y-position
4169 by that margin. */
22d650b8
GM
4170 x += s->img->hmargin;
4171 y += s->img->vmargin;
dc43ef94 4172
06a2c219
GM
4173 if (s->img->pixmap)
4174 {
4175 if (s->img->mask)
4176 {
4177 /* We can't set both a clip mask and use XSetClipRectangles
4178 because the latter also sets a clip mask. We also can't
4179 trust on the shape extension to be available
4180 (XShapeCombineRegion). So, compute the rectangle to draw
4181 manually. */
4182 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4183 | GCFunction);
4184 XGCValues xgcv;
4185
4186 xgcv.clip_mask = s->img->mask;
4187 xgcv.clip_x_origin = x;
4188 xgcv.clip_y_origin = y;
4189 xgcv.function = GXcopy;
4190 XChangeGC (s->display, s->gc, mask, &xgcv);
4191
4192 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4193 0, 0, s->img->width, s->img->height, x, y);
4194 XSetClipMask (s->display, s->gc, None);
4195 }
4196 else
4197 {
4198 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4199 0, 0, s->img->width, s->img->height, x, y);
4200
4201 /* When the image has a mask, we can expect that at
4202 least part of a mouse highlight or a block cursor will
4203 be visible. If the image doesn't have a mask, make
4204 a block cursor visible by drawing a rectangle around
4205 the image. I believe it's looking better if we do
4206 nothing here for mouse-face. */
4207 if (s->hl == DRAW_CURSOR)
4208 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4209 s->img->width - 1, s->img->height - 1);
4210 }
4211 }
4212 else
4213 /* Draw a rectangle if image could not be loaded. */
4214 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4215 s->img->width - 1, s->img->height - 1);
4216}
dc43ef94 4217
990ba854 4218
06a2c219
GM
4219/* Draw part of the background of glyph string S. X, Y, W, and H
4220 give the rectangle to draw. */
a9a5b0a5 4221
06a2c219
GM
4222static void
4223x_draw_glyph_string_bg_rect (s, x, y, w, h)
4224 struct glyph_string *s;
4225 int x, y, w, h;
4226{
4227 if (s->stippled_p)
4228 {
4229 /* Fill background with a stipple pattern. */
4230 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4231 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4232 XSetFillStyle (s->display, s->gc, FillSolid);
4233 }
4234 else
4235 x_clear_glyph_string_rect (s, x, y, w, h);
4236}
07e34cb0 4237
b5210ea7 4238
06a2c219 4239/* Draw image glyph string S.
dc43ef94 4240
06a2c219
GM
4241 s->y
4242 s->x +-------------------------
4243 | s->face->box
4244 |
4245 | +-------------------------
4246 | | s->img->margin
4247 | |
4248 | | +-------------------
4249 | | | the image
dc43ef94 4250
06a2c219 4251 */
dc43ef94 4252
06a2c219
GM
4253static void
4254x_draw_image_glyph_string (s)
4255 struct glyph_string *s;
4256{
4257 int x, y;
ea2ba0d4
KH
4258 int box_line_hwidth = abs (s->face->box_line_width);
4259 int box_line_vwidth = max (s->face->box_line_width, 0);
06a2c219
GM
4260 int height;
4261 Pixmap pixmap = None;
4262
ea2ba0d4 4263 height = s->height - 2 * box_line_vwidth;
06a2c219
GM
4264
4265 /* Fill background with face under the image. Do it only if row is
4266 taller than image or if image has a clip mask to reduce
4267 flickering. */
4268 s->stippled_p = s->face->stipple != 0;
4269 if (height > s->img->height
22d650b8
GM
4270 || s->img->hmargin
4271 || s->img->vmargin
06a2c219
GM
4272 || s->img->mask
4273 || s->img->pixmap == 0
4274 || s->width != s->background_width)
4275 {
ea2ba0d4
KH
4276 if (box_line_hwidth && s->first_glyph->left_box_line_p)
4277 x = s->x + box_line_hwidth;
06a2c219
GM
4278 else
4279 x = s->x;
4280
ea2ba0d4 4281 y = s->y + box_line_vwidth;
06a2c219
GM
4282
4283 if (s->img->mask)
4284 {
f9b5db02
GM
4285 /* Create a pixmap as large as the glyph string. Fill it
4286 with the background color. Copy the image to it, using
4287 its mask. Copy the temporary pixmap to the display. */
06a2c219
GM
4288 Screen *screen = FRAME_X_SCREEN (s->f);
4289 int depth = DefaultDepthOfScreen (screen);
4290
4291 /* Create a pixmap as large as the glyph string. */
4292 pixmap = XCreatePixmap (s->display, s->window,
4293 s->background_width,
4294 s->height, depth);
4295
4296 /* Don't clip in the following because we're working on the
4297 pixmap. */
4298 XSetClipMask (s->display, s->gc, None);
4299
4300 /* Fill the pixmap with the background color/stipple. */
4301 if (s->stippled_p)
4302 {
4303 /* Fill background with a stipple pattern. */
4304 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4305 XFillRectangle (s->display, pixmap, s->gc,
4306 0, 0, s->background_width, s->height);
4307 XSetFillStyle (s->display, s->gc, FillSolid);
4308 }
4309 else
4310 {
4311 XGCValues xgcv;
4312 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4313 &xgcv);
4314 XSetForeground (s->display, s->gc, xgcv.background);
4315 XFillRectangle (s->display, pixmap, s->gc,
4316 0, 0, s->background_width, s->height);
4317 XSetForeground (s->display, s->gc, xgcv.foreground);
4318 }
4319 }
4320 else
06a2c219
GM
4321 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
4322
4323 s->background_filled_p = 1;
4324 }
dc43ef94 4325
06a2c219
GM
4326 /* Draw the foreground. */
4327 if (pixmap != None)
4328 {
4329 x_draw_image_foreground_1 (s, pixmap);
4330 x_set_glyph_string_clipping (s);
4331 XCopyArea (s->display, pixmap, s->window, s->gc,
4332 0, 0, s->background_width, s->height, s->x, s->y);
4333 XFreePixmap (s->display, pixmap);
4334 }
4335 else
4336 x_draw_image_foreground (s);
b5210ea7 4337
06a2c219
GM
4338 /* If we must draw a relief around the image, do it. */
4339 if (s->img->relief
4340 || s->hl == DRAW_IMAGE_RAISED
4341 || s->hl == DRAW_IMAGE_SUNKEN)
4342 x_draw_image_relief (s);
4343}
8c1a6a84 4344
990ba854 4345
06a2c219 4346/* Draw stretch glyph string S. */
dc43ef94 4347
06a2c219
GM
4348static void
4349x_draw_stretch_glyph_string (s)
4350 struct glyph_string *s;
4351{
4352 xassert (s->first_glyph->type == STRETCH_GLYPH);
4353 s->stippled_p = s->face->stipple != 0;
990ba854 4354
06a2c219
GM
4355 if (s->hl == DRAW_CURSOR
4356 && !x_stretch_cursor_p)
4357 {
4358 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4359 as wide as the stretch glyph. */
4360 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4361
06a2c219
GM
4362 /* Draw cursor. */
4363 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4364
06a2c219
GM
4365 /* Clear rest using the GC of the original non-cursor face. */
4366 if (width < s->background_width)
4367 {
06a2c219
GM
4368 int x = s->x + width, y = s->y;
4369 int w = s->background_width - width, h = s->height;
4370 XRectangle r;
b7f83f9e 4371 GC gc;
dc43ef94 4372
b7f83f9e
GM
4373 if (s->row->mouse_face_p
4374 && cursor_in_mouse_face_p (s->w))
4375 {
4376 x_set_mouse_face_gc (s);
4377 gc = s->gc;
4378 }
4379 else
4380 gc = s->face->gc;
4381
06a2c219
GM
4382 x_get_glyph_string_clip_rect (s, &r);
4383 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
b7f83f9e 4384
06a2c219
GM
4385 if (s->face->stipple)
4386 {
4387 /* Fill background with a stipple pattern. */
4388 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4389 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4390 XSetFillStyle (s->display, gc, FillSolid);
4391 }
4392 else
4393 {
4394 XGCValues xgcv;
4395 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4396 XSetForeground (s->display, gc, xgcv.background);
4397 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4398 XSetForeground (s->display, gc, xgcv.foreground);
4399 }
4400 }
4401 }
61e9f9f3 4402 else if (!s->background_filled_p)
06a2c219
GM
4403 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4404 s->height);
4405
4406 s->background_filled_p = 1;
4407}
4408
4409
4410/* Draw glyph string S. */
4411
4412static void
4413x_draw_glyph_string (s)
4414 struct glyph_string *s;
4415{
4458cf11
KH
4416 int relief_drawn_p = 0;
4417
06a2c219
GM
4418 /* If S draws into the background of its successor, draw the
4419 background of the successor first so that S can draw into it.
4420 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4421 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4422 {
4423 xassert (s->next->img == NULL);
4424 x_set_glyph_string_gc (s->next);
4425 x_set_glyph_string_clipping (s->next);
4426 x_draw_glyph_string_background (s->next, 1);
4427 }
97210f4e 4428
06a2c219
GM
4429 /* Set up S->gc, set clipping and draw S. */
4430 x_set_glyph_string_gc (s);
06a2c219 4431
4458cf11
KH
4432 /* Draw relief (if any) in advance for char/composition so that the
4433 glyph string can be drawn over it. */
4434 if (!s->for_overlaps_p
4435 && s->face->box != FACE_NO_BOX
4436 && (s->first_glyph->type == CHAR_GLYPH
4437 || s->first_glyph->type == COMPOSITE_GLYPH))
4438
4439 {
e6269cbb 4440 x_set_glyph_string_clipping (s);
4458cf11
KH
4441 x_draw_glyph_string_background (s, 1);
4442 x_draw_glyph_string_box (s);
e6269cbb 4443 x_set_glyph_string_clipping (s);
4458cf11
KH
4444 relief_drawn_p = 1;
4445 }
e6269cbb
GM
4446 else
4447 x_set_glyph_string_clipping (s);
4458cf11 4448
06a2c219
GM
4449 switch (s->first_glyph->type)
4450 {
4451 case IMAGE_GLYPH:
4452 x_draw_image_glyph_string (s);
4453 break;
4454
4455 case STRETCH_GLYPH:
4456 x_draw_stretch_glyph_string (s);
4457 break;
4458
4459 case CHAR_GLYPH:
66ac4b0e
GM
4460 if (s->for_overlaps_p)
4461 s->background_filled_p = 1;
4462 else
4463 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4464 x_draw_glyph_string_foreground (s);
4465 break;
4466
b4192550
KH
4467 case COMPOSITE_GLYPH:
4468 if (s->for_overlaps_p || s->gidx > 0)
4469 s->background_filled_p = 1;
4470 else
4471 x_draw_glyph_string_background (s, 1);
4472 x_draw_composite_glyph_string_foreground (s);
4473 break;
4474
06a2c219
GM
4475 default:
4476 abort ();
4477 }
4478
66ac4b0e 4479 if (!s->for_overlaps_p)
06a2c219 4480 {
66ac4b0e
GM
4481 /* Draw underline. */
4482 if (s->face->underline_p)
4483 {
e24e84cc
GM
4484 unsigned long tem, h;
4485 int y;
06a2c219 4486
e24e84cc 4487 /* Get the underline thickness. Default is 1 pixel. */
66ac4b0e
GM
4488 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4489 h = 1;
e24e84cc
GM
4490
4491 /* Get the underline position. This is the recommended
4492 vertical offset in pixels from the baseline to the top of
4493 the underline. This is a signed value according to the
4494 specs, and its default is
4495
4496 ROUND ((maximum descent) / 2), with
4497 ROUND(x) = floor (x + 0.5) */
4498
a72d5ce5
GM
4499 if (x_use_underline_position_properties
4500 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
e24e84cc
GM
4501 y = s->ybase + (long) tem;
4502 else if (s->face->font)
4503 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4504 else
a02f1be0 4505 y = s->y + s->height - h;
06a2c219 4506
66ac4b0e 4507 if (s->face->underline_defaulted_p)
e24e84cc
GM
4508 XFillRectangle (s->display, s->window, s->gc,
4509 s->x, y, s->width, h);
66ac4b0e
GM
4510 else
4511 {
4512 XGCValues xgcv;
4513 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4514 XSetForeground (s->display, s->gc, s->face->underline_color);
e24e84cc
GM
4515 XFillRectangle (s->display, s->window, s->gc,
4516 s->x, y, s->width, h);
66ac4b0e
GM
4517 XSetForeground (s->display, s->gc, xgcv.foreground);
4518 }
dc6f92b8 4519 }
07e34cb0 4520
66ac4b0e
GM
4521 /* Draw overline. */
4522 if (s->face->overline_p)
06a2c219 4523 {
66ac4b0e
GM
4524 unsigned long dy = 0, h = 1;
4525
4526 if (s->face->overline_color_defaulted_p)
4527 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4528 s->width, h);
4529 else
4530 {
4531 XGCValues xgcv;
4532 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4533 XSetForeground (s->display, s->gc, s->face->overline_color);
4534 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4535 s->width, h);
4536 XSetForeground (s->display, s->gc, xgcv.foreground);
4537 }
06a2c219 4538 }
06a2c219 4539
66ac4b0e
GM
4540 /* Draw strike-through. */
4541 if (s->face->strike_through_p)
06a2c219 4542 {
66ac4b0e
GM
4543 unsigned long h = 1;
4544 unsigned long dy = (s->height - h) / 2;
4545
4546 if (s->face->strike_through_color_defaulted_p)
4547 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4548 s->width, h);
4549 else
4550 {
4551 XGCValues xgcv;
4552 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4553 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4554 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4555 s->width, h);
4556 XSetForeground (s->display, s->gc, xgcv.foreground);
4557 }
06a2c219 4558 }
06a2c219 4559
4458cf11
KH
4560 /* Draw relief if not yet drawn. */
4561 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
66ac4b0e
GM
4562 x_draw_glyph_string_box (s);
4563 }
06a2c219
GM
4564
4565 /* Reset clipping. */
4566 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4567}
07e34cb0 4568
06a2c219 4569
b4192550
KH
4570static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4571 struct face **, int));
06a2c219 4572
06a2c219 4573
209f68d9
GM
4574/* Fill glyph string S with composition components specified by S->cmp.
4575
b4192550
KH
4576 FACES is an array of faces for all components of this composition.
4577 S->gidx is the index of the first component for S.
4578 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4579 use its physical height for clipping.
06a2c219 4580
b4192550 4581 Value is the index of a component not in S. */
07e34cb0 4582
b4192550
KH
4583static int
4584x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4585 struct glyph_string *s;
b4192550 4586 struct face **faces;
66ac4b0e 4587 int overlaps_p;
07e34cb0 4588{
b4192550 4589 int i;
06a2c219 4590
b4192550 4591 xassert (s);
06a2c219 4592
b4192550 4593 s->for_overlaps_p = overlaps_p;
06a2c219 4594
b4192550
KH
4595 s->face = faces[s->gidx];
4596 s->font = s->face->font;
4597 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4598
b4192550
KH
4599 /* For all glyphs of this composition, starting at the offset
4600 S->gidx, until we reach the end of the definition or encounter a
4601 glyph that requires the different face, add it to S. */
4602 ++s->nchars;
4603 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4604 ++s->nchars;
06a2c219 4605
b4192550
KH
4606 /* All glyph strings for the same composition has the same width,
4607 i.e. the width set for the first component of the composition. */
06a2c219 4608
06a2c219
GM
4609 s->width = s->first_glyph->pixel_width;
4610
4611 /* If the specified font could not be loaded, use the frame's
4612 default font, but record the fact that we couldn't load it in
4613 the glyph string so that we can draw rectangles for the
4614 characters of the glyph string. */
4615 if (s->font == NULL)
4616 {
4617 s->font_not_found_p = 1;
4618 s->font = FRAME_FONT (s->f);
4619 }
4620
4621 /* Adjust base line for subscript/superscript text. */
4622 s->ybase += s->first_glyph->voffset;
4623
4624 xassert (s->face && s->face->gc);
4625
4626 /* This glyph string must always be drawn with 16-bit functions. */
4627 s->two_byte_p = 1;
b4192550
KH
4628
4629 return s->gidx + s->nchars;
06a2c219
GM
4630}
4631
4632
209f68d9
GM
4633/* Fill glyph string S from a sequence of character glyphs.
4634
06a2c219 4635 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4636 first glyph to consider, END is the index of the last + 1.
4637 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4638 use its physical height for clipping.
66ac4b0e
GM
4639
4640 Value is the index of the first glyph not in S. */
06a2c219
GM
4641
4642static int
66ac4b0e 4643x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4644 struct glyph_string *s;
4645 int face_id;
66ac4b0e 4646 int start, end, overlaps_p;
06a2c219
GM
4647{
4648 struct glyph *glyph, *last;
4649 int voffset;
ee569018 4650 int glyph_not_available_p;
06a2c219 4651
06a2c219
GM
4652 xassert (s->f == XFRAME (s->w->frame));
4653 xassert (s->nchars == 0);
4654 xassert (start >= 0 && end > start);
4655
66ac4b0e 4656 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4657 glyph = s->row->glyphs[s->area] + start;
4658 last = s->row->glyphs[s->area] + end;
4659 voffset = glyph->voffset;
4660
ee569018
KH
4661 glyph_not_available_p = glyph->glyph_not_available_p;
4662
06a2c219
GM
4663 while (glyph < last
4664 && glyph->type == CHAR_GLYPH
4665 && glyph->voffset == voffset
ee569018
KH
4666 /* Same face id implies same font, nowadays. */
4667 && glyph->face_id == face_id
4668 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4669 {
ee569018
KH
4670 int two_byte_p;
4671
06a2c219 4672 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4673 s->char2b + s->nchars,
4674 &two_byte_p);
4675 s->two_byte_p = two_byte_p;
06a2c219
GM
4676 ++s->nchars;
4677 xassert (s->nchars <= end - start);
4678 s->width += glyph->pixel_width;
4679 ++glyph;
4680 }
4681
4682 s->font = s->face->font;
4683 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4684
4685 /* If the specified font could not be loaded, use the frame's font,
4686 but record the fact that we couldn't load it in
4687 S->font_not_found_p so that we can draw rectangles for the
4688 characters of the glyph string. */
ee569018 4689 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4690 {
4691 s->font_not_found_p = 1;
4692 s->font = FRAME_FONT (s->f);
4693 }
4694
4695 /* Adjust base line for subscript/superscript text. */
4696 s->ybase += voffset;
66ac4b0e 4697
06a2c219
GM
4698 xassert (s->face && s->face->gc);
4699 return glyph - s->row->glyphs[s->area];
07e34cb0 4700}
dc6f92b8 4701
06a2c219
GM
4702
4703/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4704
dfcf069d 4705static void
06a2c219
GM
4706x_fill_image_glyph_string (s)
4707 struct glyph_string *s;
4708{
4709 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4710 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4711 xassert (s->img);
43d120d8 4712 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4713 s->font = s->face->font;
4714 s->width = s->first_glyph->pixel_width;
4715
4716 /* Adjust base line for subscript/superscript text. */
4717 s->ybase += s->first_glyph->voffset;
4718}
4719
4720
209f68d9 4721/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4722
209f68d9
GM
4723 ROW is the glyph row in which the glyphs are found, AREA is the
4724 area within the row. START is the index of the first glyph to
4725 consider, END is the index of the last + 1.
4726
4727 Value is the index of the first glyph not in S. */
4728
4729static int
4730x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4731 struct glyph_string *s;
209f68d9
GM
4732 struct glyph_row *row;
4733 enum glyph_row_area area;
4734 int start, end;
06a2c219 4735{
209f68d9
GM
4736 struct glyph *glyph, *last;
4737 int voffset, face_id;
4738
06a2c219 4739 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4740
4741 glyph = s->row->glyphs[s->area] + start;
4742 last = s->row->glyphs[s->area] + end;
4743 face_id = glyph->face_id;
4744 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4745 s->font = s->face->font;
209f68d9
GM
4746 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4747 s->width = glyph->pixel_width;
4748 voffset = glyph->voffset;
4749
4750 for (++glyph;
4751 (glyph < last
4752 && glyph->type == STRETCH_GLYPH
4753 && glyph->voffset == voffset
4754 && glyph->face_id == face_id);
4755 ++glyph)
4756 s->width += glyph->pixel_width;
06a2c219
GM
4757
4758 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4759 s->ybase += voffset;
4760
c296fc01
GM
4761 /* The case that face->gc == 0 is handled when drawing the glyph
4762 string by calling PREPARE_FACE_FOR_DISPLAY. */
4763 xassert (s->face);
209f68d9 4764 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4765}
4766
4767
4768/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4769 of XChar2b structures for S; it can't be allocated in
4770 x_init_glyph_string because it must be allocated via `alloca'. W
4771 is the window on which S is drawn. ROW and AREA are the glyph row
4772 and area within the row from which S is constructed. START is the
4773 index of the first glyph structure covered by S. HL is a
4774 face-override for drawing S. */
4775
4776static void
4777x_init_glyph_string (s, char2b, w, row, area, start, hl)
4778 struct glyph_string *s;
4779 XChar2b *char2b;
4780 struct window *w;
4781 struct glyph_row *row;
4782 enum glyph_row_area area;
4783 int start;
4784 enum draw_glyphs_face hl;
4785{
4786 bzero (s, sizeof *s);
4787 s->w = w;
4788 s->f = XFRAME (w->frame);
4789 s->display = FRAME_X_DISPLAY (s->f);
4790 s->window = FRAME_X_WINDOW (s->f);
4791 s->char2b = char2b;
4792 s->hl = hl;
4793 s->row = row;
4794 s->area = area;
4795 s->first_glyph = row->glyphs[area] + start;
4796 s->height = row->height;
4797 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4798
9ea173e8
GM
4799 /* Display the internal border below the tool-bar window. */
4800 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4801 s->y -= s->f->output_data.x->internal_border_width;
4802
4803 s->ybase = s->y + row->ascent;
4804}
4805
4806
4807/* Set background width of glyph string S. START is the index of the
4808 first glyph following S. LAST_X is the right-most x-position + 1
4809 in the drawing area. */
4810
4811static INLINE void
4812x_set_glyph_string_background_width (s, start, last_x)
4813 struct glyph_string *s;
4814 int start;
4815 int last_x;
4816{
4817 /* If the face of this glyph string has to be drawn to the end of
4818 the drawing area, set S->extends_to_end_of_line_p. */
4819 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4820
4821 if (start == s->row->used[s->area]
eb79f5cc 4822 && s->area == TEXT_AREA
7b0870b2
GM
4823 && ((s->hl == DRAW_NORMAL_TEXT
4824 && (s->row->fill_line_p
4825 || s->face->background != default_face->background
4826 || s->face->stipple != default_face->stipple
4827 || s->row->mouse_face_p))
327f42ee
GM
4828 || s->hl == DRAW_MOUSE_FACE
4829 || ((s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN)
4830 && s->row->fill_line_p)))
7b0870b2 4831 s->extends_to_end_of_line_p = 1;
06a2c219
GM
4832
4833 /* If S extends its face to the end of the line, set its
4834 background_width to the distance to the right edge of the drawing
4835 area. */
4836 if (s->extends_to_end_of_line_p)
1da3fd71 4837 s->background_width = last_x - s->x + 1;
06a2c219
GM
4838 else
4839 s->background_width = s->width;
4840}
4841
4842
4843/* Add a glyph string for a stretch glyph to the list of strings
4844 between HEAD and TAIL. START is the index of the stretch glyph in
4845 row area AREA of glyph row ROW. END is the index of the last glyph
4846 in that glyph row area. X is the current output position assigned
4847 to the new glyph string constructed. HL overrides that face of the
4848 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4849 is the right-most x-position of the drawing area. */
4850
8abee2e1
DL
4851/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4852 and below -- keep them on one line. */
4853#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4854 do \
4855 { \
4856 s = (struct glyph_string *) alloca (sizeof *s); \
4857 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4858 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4859 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4860 s->x = (X); \
4861 } \
4862 while (0)
4863
4864
4865/* Add a glyph string for an image glyph to the list of strings
4866 between HEAD and TAIL. START is the index of the image glyph in
4867 row area AREA of glyph row ROW. END is the index of the last glyph
4868 in that glyph row area. X is the current output position assigned
4869 to the new glyph string constructed. HL overrides that face of the
4870 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4871 is the right-most x-position of the drawing area. */
4872
8abee2e1 4873#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4874 do \
4875 { \
4876 s = (struct glyph_string *) alloca (sizeof *s); \
4877 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4878 x_fill_image_glyph_string (s); \
4879 x_append_glyph_string (&HEAD, &TAIL, s); \
4880 ++START; \
4881 s->x = (X); \
4882 } \
4883 while (0)
4884
4885
4886/* Add a glyph string for a sequence of character glyphs to the list
4887 of strings between HEAD and TAIL. START is the index of the first
4888 glyph in row area AREA of glyph row ROW that is part of the new
4889 glyph string. END is the index of the last glyph in that glyph row
4890 area. X is the current output position assigned to the new glyph
4891 string constructed. HL overrides that face of the glyph; e.g. it
4892 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4893 right-most x-position of the drawing area. */
4894
8abee2e1 4895#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4896 do \
4897 { \
3e71d8f2 4898 int c, face_id; \
06a2c219
GM
4899 XChar2b *char2b; \
4900 \
43d120d8 4901 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4902 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4903 \
b4192550
KH
4904 s = (struct glyph_string *) alloca (sizeof *s); \
4905 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4906 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4907 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4908 s->x = (X); \
4909 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4910 OVERLAPS_P); \
06a2c219
GM
4911 } \
4912 while (0)
4913
4914
b4192550
KH
4915/* Add a glyph string for a composite sequence to the list of strings
4916 between HEAD and TAIL. START is the index of the first glyph in
4917 row area AREA of glyph row ROW that is part of the new glyph
4918 string. END is the index of the last glyph in that glyph row area.
4919 X is the current output position assigned to the new glyph string
4920 constructed. HL overrides that face of the glyph; e.g. it is
4921 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4922 x-position of the drawing area. */
4923
6c27ec25 4924#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4925 do { \
43d120d8
KH
4926 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4927 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4928 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4929 struct composition *cmp = composition_table[cmp_id]; \
4930 int glyph_len = cmp->glyph_len; \
4931 XChar2b *char2b; \
4932 struct face **faces; \
4933 struct glyph_string *first_s = NULL; \
4934 int n; \
4935 \
ee569018 4936 base_face = base_face->ascii_face; \
b4192550
KH
4937 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4938 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4939 /* At first, fill in `char2b' and `faces'. */ \
4940 for (n = 0; n < glyph_len; n++) \
4941 { \
43d120d8 4942 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4943 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4944 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4945 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4946 this_face_id, char2b + n, 1); \
b4192550
KH
4947 } \
4948 \
4949 /* Make glyph_strings for each glyph sequence that is drawable by \
4950 the same face, and append them to HEAD/TAIL. */ \
4951 for (n = 0; n < cmp->glyph_len;) \
4952 { \
4953 s = (struct glyph_string *) alloca (sizeof *s); \
4954 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4955 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4956 s->cmp = cmp; \
4957 s->gidx = n; \
b4192550
KH
4958 s->x = (X); \
4959 \
4960 if (n == 0) \
4961 first_s = s; \
4962 \
4963 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4964 } \
4965 \
4966 ++START; \
4967 s = first_s; \
4968 } while (0)
4969
4970
06a2c219
GM
4971/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4972 of AREA of glyph row ROW on window W between indices START and END.
4973 HL overrides the face for drawing glyph strings, e.g. it is
4974 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4975 x-positions of the drawing area.
4976
4977 This is an ugly monster macro construct because we must use alloca
4978 to allocate glyph strings (because x_draw_glyphs can be called
4979 asynchronously). */
4980
8abee2e1 4981#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4982 do \
4983 { \
4984 HEAD = TAIL = NULL; \
4985 while (START < END) \
4986 { \
4987 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4988 switch (first_glyph->type) \
4989 { \
4990 case CHAR_GLYPH: \
4991 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
4992 TAIL, HL, X, LAST_X, \
4993 OVERLAPS_P); \
06a2c219
GM
4994 break; \
4995 \
b4192550
KH
4996 case COMPOSITE_GLYPH: \
4997 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
4998 HEAD, TAIL, HL, X, LAST_X,\
4999 OVERLAPS_P); \
5000 break; \
5001 \
06a2c219
GM
5002 case STRETCH_GLYPH: \
5003 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
5004 HEAD, TAIL, HL, X, LAST_X); \
5005 break; \
5006 \
5007 case IMAGE_GLYPH: \
5008 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
5009 TAIL, HL, X, LAST_X); \
5010 break; \
5011 \
5012 default: \
5013 abort (); \
5014 } \
5015 \
5016 x_set_glyph_string_background_width (s, START, LAST_X); \
5017 (X) += s->width; \
5018 } \
5019 } \
5020 while (0)
5021
5022
5023/* Draw glyphs between START and END in AREA of ROW on window W,
5024 starting at x-position X. X is relative to AREA in W. HL is a
5025 face-override with the following meaning:
5026
5027 DRAW_NORMAL_TEXT draw normally
5028 DRAW_CURSOR draw in cursor face
5029 DRAW_MOUSE_FACE draw in mouse face.
5030 DRAW_INVERSE_VIDEO draw in mode line face
5031 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
5032 DRAW_IMAGE_RAISED draw an image with a raised relief around it
5033
66ac4b0e
GM
5034 If OVERLAPS_P is non-zero, draw only the foreground of characters
5035 and clip to the physical height of ROW.
5036
06a2c219
GM
5037 Value is the x-position reached, relative to AREA of W. */
5038
5039static int
f0a48a01 5040x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
06a2c219
GM
5041 struct window *w;
5042 int x;
5043 struct glyph_row *row;
5044 enum glyph_row_area area;
5045 int start, end;
5046 enum draw_glyphs_face hl;
66ac4b0e 5047 int overlaps_p;
dc6f92b8 5048{
06a2c219
GM
5049 struct glyph_string *head, *tail;
5050 struct glyph_string *s;
5051 int last_x, area_width;
5052 int x_reached;
5053 int i, j;
5054
5055 /* Let's rather be paranoid than getting a SEGV. */
06a2c219 5056 end = min (end, row->used[area]);
a8710abf
GM
5057 start = max (0, start);
5058 start = min (end, start);
06a2c219
GM
5059
5060 /* Translate X to frame coordinates. Set last_x to the right
5061 end of the drawing area. */
5062 if (row->full_width_p)
5063 {
5064 /* X is relative to the left edge of W, without scroll bars
3f332ef3 5065 or fringes. */
06a2c219 5066 struct frame *f = XFRAME (w->frame);
3f332ef3 5067 /* int width = FRAME_FRINGE_WIDTH (f); */
06a2c219 5068 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 5069
06a2c219
GM
5070 x += window_left_x;
5071 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
5072 last_x = window_left_x + area_width;
5073
5074 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5075 {
110859fc 5076 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
5077 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
5078 last_x += width;
5079 else
5080 x -= width;
5081 }
dc6f92b8 5082
b9432a85 5083 x += FRAME_INTERNAL_BORDER_WIDTH (f);
98fedd97 5084 last_x += FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
5085 }
5086 else
dc6f92b8 5087 {
06a2c219
GM
5088 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
5089 area_width = window_box_width (w, area);
5090 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
5091 }
5092
06a2c219
GM
5093 /* Build a doubly-linked list of glyph_string structures between
5094 head and tail from what we have to draw. Note that the macro
5095 BUILD_GLYPH_STRINGS will modify its start parameter. That's
5096 the reason we use a separate variable `i'. */
5097 i = start;
66ac4b0e
GM
5098 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
5099 overlaps_p);
06a2c219
GM
5100 if (tail)
5101 x_reached = tail->x + tail->background_width;
5102 else
5103 x_reached = x;
90e65f07 5104
06a2c219
GM
5105 /* If there are any glyphs with lbearing < 0 or rbearing > width in
5106 the row, redraw some glyphs in front or following the glyph
5107 strings built above. */
a8710abf 5108 if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
5109 {
5110 int dummy_x = 0;
5111 struct glyph_string *h, *t;
5112
5113 /* Compute overhangs for all glyph strings. */
5114 for (s = head; s; s = s->next)
5115 x_compute_glyph_string_overhangs (s);
5116
5117 /* Prepend glyph strings for glyphs in front of the first glyph
5118 string that are overwritten because of the first glyph
5119 string's left overhang. The background of all strings
5120 prepended must be drawn because the first glyph string
5121 draws over it. */
5122 i = x_left_overwritten (head);
5123 if (i >= 0)
5124 {
5125 j = i;
5126 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
5127 DRAW_NORMAL_TEXT, dummy_x, last_x,
5128 overlaps_p);
06a2c219 5129 start = i;
06a2c219
GM
5130 x_compute_overhangs_and_x (t, head->x, 1);
5131 x_prepend_glyph_string_lists (&head, &tail, h, t);
5132 }
58769bee 5133
06a2c219
GM
5134 /* Prepend glyph strings for glyphs in front of the first glyph
5135 string that overwrite that glyph string because of their
5136 right overhang. For these strings, only the foreground must
5137 be drawn, because it draws over the glyph string at `head'.
5138 The background must not be drawn because this would overwrite
5139 right overhangs of preceding glyphs for which no glyph
5140 strings exist. */
5141 i = x_left_overwriting (head);
5142 if (i >= 0)
5143 {
5144 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
5145 DRAW_NORMAL_TEXT, dummy_x, last_x,
5146 overlaps_p);
06a2c219
GM
5147 for (s = h; s; s = s->next)
5148 s->background_filled_p = 1;
06a2c219
GM
5149 x_compute_overhangs_and_x (t, head->x, 1);
5150 x_prepend_glyph_string_lists (&head, &tail, h, t);
5151 }
dbcb258a 5152
06a2c219
GM
5153 /* Append glyphs strings for glyphs following the last glyph
5154 string tail that are overwritten by tail. The background of
5155 these strings has to be drawn because tail's foreground draws
5156 over it. */
5157 i = x_right_overwritten (tail);
5158 if (i >= 0)
5159 {
5160 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5161 DRAW_NORMAL_TEXT, x, last_x,
5162 overlaps_p);
06a2c219
GM
5163 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5164 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219 5165 }
dc6f92b8 5166
06a2c219
GM
5167 /* Append glyph strings for glyphs following the last glyph
5168 string tail that overwrite tail. The foreground of such
5169 glyphs has to be drawn because it writes into the background
5170 of tail. The background must not be drawn because it could
5171 paint over the foreground of following glyphs. */
5172 i = x_right_overwriting (tail);
5173 if (i >= 0)
5174 {
5175 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5176 DRAW_NORMAL_TEXT, x, last_x,
5177 overlaps_p);
06a2c219
GM
5178 for (s = h; s; s = s->next)
5179 s->background_filled_p = 1;
5180 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5181 x_append_glyph_string_lists (&head, &tail, h, t);
06a2c219
GM
5182 }
5183 }
58769bee 5184
06a2c219
GM
5185 /* Draw all strings. */
5186 for (s = head; s; s = s->next)
5187 x_draw_glyph_string (s);
dc6f92b8 5188
bb313871
GM
5189 if (area == TEXT_AREA
5190 && !row->full_width_p
5191 /* When drawing overlapping rows, only the glyph strings'
5192 foreground is drawn, which doesn't erase a cursor
5193 completely. */
5194 && !overlaps_p)
f0a48a01
GM
5195 {
5196 int x0 = head ? head->x : x;
5197 int x1 = tail ? tail->x + tail->background_width : x;
5198
5199 x0 = FRAME_TO_WINDOW_PIXEL_X (w, x0);
5200 x1 = FRAME_TO_WINDOW_PIXEL_X (w, x1);
5201
bb313871 5202 if (XFASTINT (w->left_margin_width) != 0)
f0a48a01
GM
5203 {
5204 int left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
5205 x0 -= left_area_width;
5206 x1 -= left_area_width;
5207 }
5208
5209 notice_overwritten_cursor (w, x0, x1);
5210 }
5211
06a2c219
GM
5212 /* Value is the x-position up to which drawn, relative to AREA of W.
5213 This doesn't include parts drawn because of overhangs. */
5214 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
5215 if (!row->full_width_p)
5216 {
f0a48a01 5217 if (area > LEFT_MARGIN_AREA && XFASTINT (w->left_margin_width) != 0)
06a2c219
GM
5218 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
5219 if (area > TEXT_AREA)
5220 x_reached -= window_box_width (w, TEXT_AREA);
5221 }
a8710abf 5222
06a2c219
GM
5223 return x_reached;
5224}
dc6f92b8 5225
dc6f92b8 5226
66ac4b0e
GM
5227/* Fix the display of area AREA of overlapping row ROW in window W. */
5228
5229static void
5230x_fix_overlapping_area (w, row, area)
5231 struct window *w;
5232 struct glyph_row *row;
5233 enum glyph_row_area area;
5234{
5235 int i, x;
5236
5237 BLOCK_INPUT;
5238
5239 if (area == LEFT_MARGIN_AREA)
5240 x = 0;
5241 else if (area == TEXT_AREA)
5242 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5243 else
5244 x = (window_box_width (w, LEFT_MARGIN_AREA)
5245 + window_box_width (w, TEXT_AREA));
5246
5247 for (i = 0; i < row->used[area];)
5248 {
5249 if (row->glyphs[area][i].overlaps_vertically_p)
5250 {
5251 int start = i, start_x = x;
5252
5253 do
5254 {
5255 x += row->glyphs[area][i].pixel_width;
5256 ++i;
5257 }
5258 while (i < row->used[area]
5259 && row->glyphs[area][i].overlaps_vertically_p);
5260
5261 x_draw_glyphs (w, start_x, row, area, start, i,
f0a48a01 5262 DRAW_NORMAL_TEXT, 1);
66ac4b0e
GM
5263 }
5264 else
5265 {
5266 x += row->glyphs[area][i].pixel_width;
5267 ++i;
5268 }
5269 }
5270
5271 UNBLOCK_INPUT;
5272}
5273
5274
06a2c219
GM
5275/* Output LEN glyphs starting at START at the nominal cursor position.
5276 Advance the nominal cursor over the text. The global variable
5277 updated_window contains the window being updated, updated_row is
5278 the glyph row being updated, and updated_area is the area of that
5279 row being updated. */
dc6f92b8 5280
06a2c219
GM
5281static void
5282x_write_glyphs (start, len)
5283 struct glyph *start;
5284 int len;
5285{
f0a48a01 5286 int x, hpos;
d9cdbb3d 5287
06a2c219 5288 xassert (updated_window && updated_row);
dc6f92b8 5289 BLOCK_INPUT;
06a2c219
GM
5290
5291 /* Write glyphs. */
dc6f92b8 5292
06a2c219
GM
5293 hpos = start - updated_row->glyphs[updated_area];
5294 x = x_draw_glyphs (updated_window, output_cursor.x,
5295 updated_row, updated_area,
5296 hpos, hpos + len,
f0a48a01 5297 DRAW_NORMAL_TEXT, 0);
dc6f92b8
JB
5298
5299 UNBLOCK_INPUT;
06a2c219
GM
5300
5301 /* Advance the output cursor. */
5302 output_cursor.hpos += len;
5303 output_cursor.x = x;
dc6f92b8
JB
5304}
5305
0cdd0c9f 5306
06a2c219 5307/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 5308
06a2c219
GM
5309static void
5310x_insert_glyphs (start, len)
5311 struct glyph *start;
5312 register int len;
5313{
5314 struct frame *f;
5315 struct window *w;
5316 int line_height, shift_by_width, shifted_region_width;
5317 struct glyph_row *row;
5318 struct glyph *glyph;
2beb36f9 5319 int frame_x, frame_y, hpos;
58769bee 5320
06a2c219 5321 xassert (updated_window && updated_row);
0cdd0c9f 5322 BLOCK_INPUT;
06a2c219
GM
5323 w = updated_window;
5324 f = XFRAME (WINDOW_FRAME (w));
5325
5326 /* Get the height of the line we are in. */
5327 row = updated_row;
5328 line_height = row->height;
5329
5330 /* Get the width of the glyphs to insert. */
5331 shift_by_width = 0;
5332 for (glyph = start; glyph < start + len; ++glyph)
5333 shift_by_width += glyph->pixel_width;
5334
5335 /* Get the width of the region to shift right. */
5336 shifted_region_width = (window_box_width (w, updated_area)
5337 - output_cursor.x
5338 - shift_by_width);
5339
5340 /* Shift right. */
bf0ab8a2 5341 frame_x = window_box_left (w, updated_area) + output_cursor.x;
06a2c219
GM
5342 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
5343 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5344 f->output_data.x->normal_gc,
5345 frame_x, frame_y,
5346 shifted_region_width, line_height,
5347 frame_x + shift_by_width, frame_y);
5348
5349 /* Write the glyphs. */
5350 hpos = start - row->glyphs[updated_area];
5351 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
f0a48a01 5352 DRAW_NORMAL_TEXT, 0);
06a2c219
GM
5353
5354 /* Advance the output cursor. */
5355 output_cursor.hpos += len;
5356 output_cursor.x += shift_by_width;
0cdd0c9f
RS
5357 UNBLOCK_INPUT;
5358}
0cdd0c9f 5359
0cdd0c9f 5360
06a2c219
GM
5361/* Delete N glyphs at the nominal cursor position. Not implemented
5362 for X frames. */
c83febd7
RS
5363
5364static void
06a2c219
GM
5365x_delete_glyphs (n)
5366 register int n;
c83febd7 5367{
06a2c219 5368 abort ();
c83febd7
RS
5369}
5370
0cdd0c9f 5371
c5e6e06b
GM
5372/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
5373 If they are <= 0, this is probably an error. */
5374
5375void
5376x_clear_area (dpy, window, x, y, width, height, exposures)
5377 Display *dpy;
5378 Window window;
5379 int x, y;
5380 int width, height;
5381 int exposures;
5382{
5383 xassert (width > 0 && height > 0);
5384 XClearArea (dpy, window, x, y, width, height, exposures);
5385}
5386
5387
06a2c219
GM
5388/* Erase the current text line from the nominal cursor position
5389 (inclusive) to pixel column TO_X (exclusive). The idea is that
5390 everything from TO_X onward is already erased.
5391
5392 TO_X is a pixel position relative to updated_area of
5393 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 5394
06a2c219
GM
5395static void
5396x_clear_end_of_line (to_x)
5397 int to_x;
5398{
5399 struct frame *f;
5400 struct window *w = updated_window;
5401 int max_x, min_y, max_y;
5402 int from_x, from_y, to_y;
5403
5404 xassert (updated_window && updated_row);
5405 f = XFRAME (w->frame);
5406
5407 if (updated_row->full_width_p)
5408 {
5409 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
5410 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5411 && !w->pseudo_window_p)
5412 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 5413 }
06a2c219
GM
5414 else
5415 max_x = window_box_width (w, updated_area);
5416 max_y = window_text_bottom_y (w);
dc6f92b8 5417
06a2c219
GM
5418 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5419 of window. For TO_X > 0, truncate to end of drawing area. */
5420 if (to_x == 0)
5421 return;
5422 else if (to_x < 0)
5423 to_x = max_x;
5424 else
5425 to_x = min (to_x, max_x);
dbc4e1c1 5426
06a2c219
GM
5427 to_y = min (max_y, output_cursor.y + updated_row->height);
5428
5429 /* Notice if the cursor will be cleared by this operation. */
5430 if (!updated_row->full_width_p)
f0a48a01 5431 notice_overwritten_cursor (w, output_cursor.x, -1);
dbc4e1c1 5432
06a2c219
GM
5433 from_x = output_cursor.x;
5434
5435 /* Translate to frame coordinates. */
5436 if (updated_row->full_width_p)
5437 {
5438 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5439 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5440 }
0cdd0c9f
RS
5441 else
5442 {
06a2c219
GM
5443 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5444 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5445 }
5446
045dee35 5447 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5448 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5449 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5450
5451 /* Prevent inadvertently clearing to end of the X window. */
5452 if (to_x > from_x && to_y > from_y)
5453 {
5454 BLOCK_INPUT;
c5e6e06b
GM
5455 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5456 from_x, from_y, to_x - from_x, to_y - from_y,
5457 False);
06a2c219 5458 UNBLOCK_INPUT;
0cdd0c9f 5459 }
0cdd0c9f 5460}
dbc4e1c1 5461
0cdd0c9f 5462
06a2c219 5463/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5464 frame. Otherwise clear the selected frame. */
06a2c219
GM
5465
5466static void
5467x_clear_frame ()
0cdd0c9f 5468{
06a2c219 5469 struct frame *f;
0cdd0c9f 5470
06a2c219
GM
5471 if (updating_frame)
5472 f = updating_frame;
0cdd0c9f 5473 else
b86bd3dd 5474 f = SELECTED_FRAME ();
58769bee 5475
06a2c219
GM
5476 /* Clearing the frame will erase any cursor, so mark them all as no
5477 longer visible. */
5478 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5479 output_cursor.hpos = output_cursor.vpos = 0;
5480 output_cursor.x = -1;
5481
5482 /* We don't set the output cursor here because there will always
5483 follow an explicit cursor_to. */
5484 BLOCK_INPUT;
5485 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5486
5487 /* We have to clear the scroll bars, too. If we have changed
5488 colors or something like that, then they should be notified. */
5489 x_scroll_bar_clear (f);
0cdd0c9f 5490
06a2c219
GM
5491 XFlush (FRAME_X_DISPLAY (f));
5492 UNBLOCK_INPUT;
dc6f92b8 5493}
06a2c219
GM
5494
5495
dc6f92b8 5496\f
dbc4e1c1
JB
5497/* Invert the middle quarter of the frame for .15 sec. */
5498
06a2c219
GM
5499/* We use the select system call to do the waiting, so we have to make
5500 sure it's available. If it isn't, we just won't do visual bells. */
5501
dbc4e1c1
JB
5502#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5503
06a2c219
GM
5504
5505/* Subtract the `struct timeval' values X and Y, storing the result in
5506 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5507
5508static int
5509timeval_subtract (result, x, y)
5510 struct timeval *result, x, y;
5511{
06a2c219
GM
5512 /* Perform the carry for the later subtraction by updating y. This
5513 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5514 if (x.tv_usec < y.tv_usec)
5515 {
5516 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5517 y.tv_usec -= 1000000 * nsec;
5518 y.tv_sec += nsec;
5519 }
06a2c219 5520
dbc4e1c1
JB
5521 if (x.tv_usec - y.tv_usec > 1000000)
5522 {
5523 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5524 y.tv_usec += 1000000 * nsec;
5525 y.tv_sec -= nsec;
5526 }
5527
06a2c219
GM
5528 /* Compute the time remaining to wait. tv_usec is certainly
5529 positive. */
dbc4e1c1
JB
5530 result->tv_sec = x.tv_sec - y.tv_sec;
5531 result->tv_usec = x.tv_usec - y.tv_usec;
5532
06a2c219
GM
5533 /* Return indication of whether the result should be considered
5534 negative. */
dbc4e1c1
JB
5535 return x.tv_sec < y.tv_sec;
5536}
dc6f92b8 5537
dfcf069d 5538void
f676886a
JB
5539XTflash (f)
5540 struct frame *f;
dc6f92b8 5541{
dbc4e1c1 5542 BLOCK_INPUT;
dc6f92b8 5543
dbc4e1c1
JB
5544 {
5545 GC gc;
dc6f92b8 5546
06a2c219
GM
5547 /* Create a GC that will use the GXxor function to flip foreground
5548 pixels into background pixels. */
dbc4e1c1
JB
5549 {
5550 XGCValues values;
dc6f92b8 5551
dbc4e1c1 5552 values.function = GXxor;
7556890b
RS
5553 values.foreground = (f->output_data.x->foreground_pixel
5554 ^ f->output_data.x->background_pixel);
58769bee 5555
334208b7 5556 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5557 GCFunction | GCForeground, &values);
5558 }
dc6f92b8 5559
dbc4e1c1 5560 {
e84e14c3
RS
5561 /* Get the height not including a menu bar widget. */
5562 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5563 /* Height of each line to flash. */
5564 int flash_height = FRAME_LINE_HEIGHT (f);
5565 /* These will be the left and right margins of the rectangles. */
5566 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5567 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5568
5569 int width;
5570
5571 /* Don't flash the area between a scroll bar and the frame
5572 edge it is next to. */
5573 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5574 {
5575 case vertical_scroll_bar_left:
5576 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5577 break;
5578
5579 case vertical_scroll_bar_right:
5580 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5581 break;
06a2c219
GM
5582
5583 default:
5584 break;
e84e14c3
RS
5585 }
5586
5587 width = flash_right - flash_left;
5588
5589 /* If window is tall, flash top and bottom line. */
5590 if (height > 3 * FRAME_LINE_HEIGHT (f))
5591 {
5592 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5593 flash_left,
5594 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5595 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5596 width, flash_height);
5597 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5598 flash_left,
5599 (height - flash_height
5600 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5601 width, flash_height);
5602 }
5603 else
5604 /* If it is short, flash it all. */
5605 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5606 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5607 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5608
06a2c219 5609 x_flush (f);
dc6f92b8 5610
dbc4e1c1 5611 {
06a2c219 5612 struct timeval wakeup;
dc6f92b8 5613
66c30ea1 5614 EMACS_GET_TIME (wakeup);
dc6f92b8 5615
dbc4e1c1
JB
5616 /* Compute time to wait until, propagating carry from usecs. */
5617 wakeup.tv_usec += 150000;
5618 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5619 wakeup.tv_usec %= 1000000;
5620
101922c3
GM
5621 /* Keep waiting until past the time wakeup or any input gets
5622 available. */
5623 while (! detect_input_pending ())
dbc4e1c1 5624 {
101922c3 5625 struct timeval current;
dbc4e1c1
JB
5626 struct timeval timeout;
5627
101922c3 5628 EMACS_GET_TIME (current);
dbc4e1c1 5629
101922c3
GM
5630 /* Break if result would be negative. */
5631 if (timeval_subtract (&current, wakeup, current))
dbc4e1c1
JB
5632 break;
5633
101922c3
GM
5634 /* How long `select' should wait. */
5635 timeout.tv_sec = 0;
5636 timeout.tv_usec = 10000;
5637
dbc4e1c1 5638 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5639 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5640 }
5641 }
58769bee 5642
e84e14c3
RS
5643 /* If window is tall, flash top and bottom line. */
5644 if (height > 3 * FRAME_LINE_HEIGHT (f))
5645 {
5646 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5647 flash_left,
5648 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5649 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5650 width, flash_height);
5651 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5652 flash_left,
5653 (height - flash_height
5654 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5655 width, flash_height);
5656 }
5657 else
5658 /* If it is short, flash it all. */
5659 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5660 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5661 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5662
334208b7 5663 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5664 x_flush (f);
dc6f92b8 5665 }
dbc4e1c1
JB
5666 }
5667
5668 UNBLOCK_INPUT;
dc6f92b8
JB
5669}
5670
06a2c219 5671#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5672
5673
dc6f92b8
JB
5674/* Make audible bell. */
5675
dfcf069d 5676void
dc6f92b8
JB
5677XTring_bell ()
5678{
b86bd3dd
GM
5679 struct frame *f = SELECTED_FRAME ();
5680
5681 if (FRAME_X_DISPLAY (f))
5682 {
dbc4e1c1 5683#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5684 if (visible_bell)
5685 XTflash (f);
5686 else
dbc4e1c1 5687#endif
b86bd3dd
GM
5688 {
5689 BLOCK_INPUT;
5690 XBell (FRAME_X_DISPLAY (f), 0);
5691 XFlush (FRAME_X_DISPLAY (f));
5692 UNBLOCK_INPUT;
5693 }
dc6f92b8
JB
5694 }
5695}
06a2c219 5696
dc6f92b8 5697\f
06a2c219
GM
5698/* Specify how many text lines, from the top of the window,
5699 should be affected by insert-lines and delete-lines operations.
5700 This, and those operations, are used only within an update
5701 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5702
dfcf069d 5703static void
06a2c219
GM
5704XTset_terminal_window (n)
5705 register int n;
dc6f92b8 5706{
06a2c219 5707 /* This function intentionally left blank. */
dc6f92b8
JB
5708}
5709
06a2c219
GM
5710
5711\f
5712/***********************************************************************
5713 Line Dance
5714 ***********************************************************************/
5715
5716/* Perform an insert-lines or delete-lines operation, inserting N
5717 lines or deleting -N lines at vertical position VPOS. */
5718
dfcf069d 5719static void
06a2c219
GM
5720x_ins_del_lines (vpos, n)
5721 int vpos, n;
dc6f92b8
JB
5722{
5723 abort ();
5724}
06a2c219
GM
5725
5726
5727/* Scroll part of the display as described by RUN. */
dc6f92b8 5728
dfcf069d 5729static void
06a2c219
GM
5730x_scroll_run (w, run)
5731 struct window *w;
5732 struct run *run;
dc6f92b8 5733{
06a2c219
GM
5734 struct frame *f = XFRAME (w->frame);
5735 int x, y, width, height, from_y, to_y, bottom_y;
5736
5737 /* Get frame-relative bounding box of the text display area of W,
3f332ef3
KS
5738 without mode lines. Include in this box the left and right
5739 fringe of W. */
06a2c219 5740 window_box (w, -1, &x, &y, &width, &height);
3f332ef3
KS
5741 width += FRAME_X_FRINGE_WIDTH (f);
5742 x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
06a2c219
GM
5743
5744 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5745 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5746 bottom_y = y + height;
dc6f92b8 5747
06a2c219
GM
5748 if (to_y < from_y)
5749 {
5750 /* Scrolling up. Make sure we don't copy part of the mode
5751 line at the bottom. */
5752 if (from_y + run->height > bottom_y)
5753 height = bottom_y - from_y;
5754 else
5755 height = run->height;
5756 }
dc6f92b8 5757 else
06a2c219
GM
5758 {
5759 /* Scolling down. Make sure we don't copy over the mode line.
5760 at the bottom. */
5761 if (to_y + run->height > bottom_y)
5762 height = bottom_y - to_y;
5763 else
5764 height = run->height;
5765 }
7a13e894 5766
06a2c219
GM
5767 BLOCK_INPUT;
5768
5769 /* Cursor off. Will be switched on again in x_update_window_end. */
5770 updated_window = w;
5771 x_clear_cursor (w);
5772
5773 XCopyArea (FRAME_X_DISPLAY (f),
5774 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5775 f->output_data.x->normal_gc,
5776 x, from_y,
5777 width, height,
5778 x, to_y);
5779
5780 UNBLOCK_INPUT;
5781}
dc6f92b8 5782
dc6f92b8 5783
06a2c219
GM
5784\f
5785/***********************************************************************
5786 Exposure Events
5787 ***********************************************************************/
5788
5789/* Redisplay an exposed area of frame F. X and Y are the upper-left
5790 corner of the exposed rectangle. W and H are width and height of
5791 the exposed area. All are pixel values. W or H zero means redraw
5792 the entire frame. */
dc6f92b8 5793
06a2c219
GM
5794static void
5795expose_frame (f, x, y, w, h)
5796 struct frame *f;
5797 int x, y, w, h;
dc6f92b8 5798{
06a2c219 5799 XRectangle r;
82f053ab 5800 int mouse_face_overwritten_p = 0;
dc6f92b8 5801
06a2c219 5802 TRACE ((stderr, "expose_frame "));
dc6f92b8 5803
06a2c219
GM
5804 /* No need to redraw if frame will be redrawn soon. */
5805 if (FRAME_GARBAGED_P (f))
dc6f92b8 5806 {
06a2c219
GM
5807 TRACE ((stderr, " garbaged\n"));
5808 return;
5809 }
5810
5811 /* If basic faces haven't been realized yet, there is no point in
5812 trying to redraw anything. This can happen when we get an expose
5813 event while Emacs is starting, e.g. by moving another window. */
5814 if (FRAME_FACE_CACHE (f) == NULL
5815 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5816 {
5817 TRACE ((stderr, " no faces\n"));
5818 return;
58769bee 5819 }
06a2c219
GM
5820
5821 if (w == 0 || h == 0)
58769bee 5822 {
06a2c219
GM
5823 r.x = r.y = 0;
5824 r.width = CANON_X_UNIT (f) * f->width;
5825 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5826 }
5827 else
5828 {
06a2c219
GM
5829 r.x = x;
5830 r.y = y;
5831 r.width = w;
5832 r.height = h;
5833 }
5834
5835 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
82f053ab 5836 mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
06a2c219 5837
9ea173e8 5838 if (WINDOWP (f->tool_bar_window))
82f053ab
GM
5839 mouse_face_overwritten_p
5840 |= expose_window (XWINDOW (f->tool_bar_window), &r);
06a2c219
GM
5841
5842#ifndef USE_X_TOOLKIT
5843 if (WINDOWP (f->menu_bar_window))
82f053ab
GM
5844 mouse_face_overwritten_p
5845 |= expose_window (XWINDOW (f->menu_bar_window), &r);
06a2c219 5846#endif /* not USE_X_TOOLKIT */
82f053ab
GM
5847
5848 /* Some window managers support a focus-follows-mouse style with
5849 delayed raising of frames. Imagine a partially obscured frame,
5850 and moving the mouse into partially obscured mouse-face on that
5851 frame. The visible part of the mouse-face will be highlighted,
5852 then the WM raises the obscured frame. With at least one WM, KDE
5853 2.1, Emacs is not getting any event for the raising of the frame
5854 (even tried with SubstructureRedirectMask), only Expose events.
5855 These expose events will draw text normally, i.e. not
5856 highlighted. Which means we must redo the highlight here.
5857 Subsume it under ``we love X''. --gerd 2001-08-15 */
5858 if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
5859 {
5860 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5861 if (f == dpyinfo->mouse_face_mouse_frame)
5862 {
5863 int x = dpyinfo->mouse_face_mouse_x;
5864 int y = dpyinfo->mouse_face_mouse_y;
5865 clear_mouse_face (dpyinfo);
5866 note_mouse_highlight (f, x, y);
5867 }
5868 }
dc6f92b8
JB
5869}
5870
06a2c219
GM
5871
5872/* Redraw (parts) of all windows in the window tree rooted at W that
82f053ab
GM
5873 intersect R. R contains frame pixel coordinates. Value is
5874 non-zero if the exposure overwrites mouse-face. */
06a2c219 5875
82f053ab 5876static int
06a2c219
GM
5877expose_window_tree (w, r)
5878 struct window *w;
5879 XRectangle *r;
dc6f92b8 5880{
82f053ab
GM
5881 struct frame *f = XFRAME (w->frame);
5882 int mouse_face_overwritten_p = 0;
5883
5884 while (w && !FRAME_GARBAGED_P (f))
06a2c219
GM
5885 {
5886 if (!NILP (w->hchild))
82f053ab
GM
5887 mouse_face_overwritten_p
5888 |= expose_window_tree (XWINDOW (w->hchild), r);
06a2c219 5889 else if (!NILP (w->vchild))
82f053ab
GM
5890 mouse_face_overwritten_p
5891 |= expose_window_tree (XWINDOW (w->vchild), r);
5892 else
5893 mouse_face_overwritten_p |= expose_window (w, r);
5894
a02f1be0 5895 w = NILP (w->next) ? NULL : XWINDOW (w->next);
06a2c219 5896 }
82f053ab
GM
5897
5898 return mouse_face_overwritten_p;
06a2c219 5899}
58769bee 5900
dc6f92b8 5901
06a2c219
GM
5902/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5903 which intersects rectangle R. R is in window-relative coordinates. */
5904
5905static void
5906expose_area (w, row, r, area)
5907 struct window *w;
5908 struct glyph_row *row;
5909 XRectangle *r;
5910 enum glyph_row_area area;
5911{
06a2c219
GM
5912 struct glyph *first = row->glyphs[area];
5913 struct glyph *end = row->glyphs[area] + row->used[area];
5914 struct glyph *last;
4bc6dcc7 5915 int first_x, start_x, x;
06a2c219 5916
6fb13182
GM
5917 if (area == TEXT_AREA && row->fill_line_p)
5918 /* If row extends face to end of line write the whole line. */
153f5ed7 5919 x_draw_glyphs (w, 0, row, area, 0, row->used[area],
f0a48a01 5920 DRAW_NORMAL_TEXT, 0);
6fb13182
GM
5921 else
5922 {
4bc6dcc7
GM
5923 /* Set START_X to the window-relative start position for drawing glyphs of
5924 AREA. The first glyph of the text area can be partially visible.
5925 The first glyphs of other areas cannot. */
5926 if (area == LEFT_MARGIN_AREA)
5927 start_x = 0;
5928 else if (area == TEXT_AREA)
5929 start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5930 else
5931 start_x = (window_box_width (w, LEFT_MARGIN_AREA)
5932 + window_box_width (w, TEXT_AREA));
5933 x = start_x;
5934
6fb13182
GM
5935 /* Find the first glyph that must be redrawn. */
5936 while (first < end
5937 && x + first->pixel_width < r->x)
5938 {
5939 x += first->pixel_width;
5940 ++first;
5941 }
5942
5943 /* Find the last one. */
5944 last = first;
5945 first_x = x;
5946 while (last < end
5947 && x < r->x + r->width)
5948 {
5949 x += last->pixel_width;
5950 ++last;
5951 }
5952
5953 /* Repaint. */
5954 if (last > first)
4bc6dcc7 5955 x_draw_glyphs (w, first_x - start_x, row, area,
6fb13182
GM
5956 first - row->glyphs[area],
5957 last - row->glyphs[area],
f0a48a01 5958 DRAW_NORMAL_TEXT, 0);
6fb13182 5959 }
06a2c219
GM
5960}
5961
58769bee 5962
06a2c219 5963/* Redraw the parts of the glyph row ROW on window W intersecting
82f053ab
GM
5964 rectangle R. R is in window-relative coordinates. Value is
5965 non-zero if mouse-face was overwritten. */
dc6f92b8 5966
82f053ab 5967static int
06a2c219
GM
5968expose_line (w, row, r)
5969 struct window *w;
5970 struct glyph_row *row;
5971 XRectangle *r;
5972{
5973 xassert (row->enabled_p);
5974
5975 if (row->mode_line_p || w->pseudo_window_p)
5976 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
f0a48a01 5977 DRAW_NORMAL_TEXT, 0);
06a2c219
GM
5978 else
5979 {
5980 if (row->used[LEFT_MARGIN_AREA])
5981 expose_area (w, row, r, LEFT_MARGIN_AREA);
5982 if (row->used[TEXT_AREA])
5983 expose_area (w, row, r, TEXT_AREA);
5984 if (row->used[RIGHT_MARGIN_AREA])
5985 expose_area (w, row, r, RIGHT_MARGIN_AREA);
3f332ef3 5986 x_draw_row_fringe_bitmaps (w, row);
06a2c219 5987 }
82f053ab
GM
5988
5989 return row->mouse_face_p;
06a2c219 5990}
dc6f92b8 5991
58769bee 5992
06a2c219
GM
5993/* Return non-zero if W's cursor intersects rectangle R. */
5994
5995static int
5996x_phys_cursor_in_rect_p (w, r)
5997 struct window *w;
5998 XRectangle *r;
5999{
6000 XRectangle cr, result;
6001 struct glyph *cursor_glyph;
6002
6003 cursor_glyph = get_phys_cursor_glyph (w);
6004 if (cursor_glyph)
6005 {
6006 cr.x = w->phys_cursor.x;
6007 cr.y = w->phys_cursor.y;
6008 cr.width = cursor_glyph->pixel_width;
6009 cr.height = w->phys_cursor_height;
6010 return x_intersect_rectangles (&cr, r, &result);
6011 }
6012 else
6013 return 0;
dc6f92b8 6014}
dc6f92b8 6015
06a2c219 6016
a02f1be0
GM
6017/* Redraw the part of window W intersection rectangle FR. Pixel
6018 coordinates in FR are frame-relative. Call this function with
82f053ab
GM
6019 input blocked. Value is non-zero if the exposure overwrites
6020 mouse-face. */
dc6f92b8 6021
a39202f6 6022static int
a02f1be0 6023expose_window (w, fr)
06a2c219 6024 struct window *w;
a02f1be0 6025 XRectangle *fr;
dc6f92b8 6026{
a02f1be0 6027 struct frame *f = XFRAME (w->frame);
a02f1be0 6028 XRectangle wr, r;
82f053ab 6029 int mouse_face_overwritten_p = 0;
dc6f92b8 6030
80c32bcc
GM
6031 /* If window is not yet fully initialized, do nothing. This can
6032 happen when toolkit scroll bars are used and a window is split.
6033 Reconfiguring the scroll bar will generate an expose for a newly
6034 created window. */
a39202f6 6035 if (w->current_matrix == NULL)
82f053ab 6036 return 0;
a39202f6
GM
6037
6038 /* When we're currently updating the window, display and current
6039 matrix usually don't agree. Arrange for a thorough display
6040 later. */
6041 if (w == updated_window)
6042 {
6043 SET_FRAME_GARBAGED (f);
6044 return 0;
6045 }
80c32bcc 6046
a39202f6 6047 /* Frame-relative pixel rectangle of W. */
a02f1be0
GM
6048 wr.x = XFASTINT (w->left) * CANON_X_UNIT (f);
6049 wr.y = XFASTINT (w->top) * CANON_Y_UNIT (f);
6050 wr.width = XFASTINT (w->width) * CANON_X_UNIT (f);
6051 wr.height = XFASTINT (w->height) * CANON_Y_UNIT (f);
6052
a39202f6
GM
6053 if (x_intersect_rectangles (fr, &wr, &r))
6054 {
6055 int yb = window_text_bottom_y (w);
6056 struct glyph_row *row;
6057 int cursor_cleared_p;
a02f1be0 6058
a39202f6
GM
6059 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
6060 r.x, r.y, r.width, r.height));
dc6f92b8 6061
a39202f6
GM
6062 /* Convert to window coordinates. */
6063 r.x = FRAME_TO_WINDOW_PIXEL_X (w, r.x);
6064 r.y = FRAME_TO_WINDOW_PIXEL_Y (w, r.y);
dc6f92b8 6065
a39202f6
GM
6066 /* Turn off the cursor. */
6067 if (!w->pseudo_window_p
6068 && x_phys_cursor_in_rect_p (w, &r))
6069 {
6070 x_clear_cursor (w);
6071 cursor_cleared_p = 1;
6072 }
6073 else
6074 cursor_cleared_p = 0;
06a2c219 6075
a39202f6
GM
6076 /* Find the first row intersecting the rectangle R. */
6077 for (row = w->current_matrix->rows;
6078 row->enabled_p;
6079 ++row)
6080 {
6081 int y0 = row->y;
6082 int y1 = MATRIX_ROW_BOTTOM_Y (row);
6083
6084 if ((y0 >= r.y && y0 < r.y + r.height)
6085 || (y1 > r.y && y1 < r.y + r.height)
6086 || (r.y >= y0 && r.y < y1)
6087 || (r.y + r.height > y0 && r.y + r.height < y1))
82f053ab
GM
6088 {
6089 if (expose_line (w, row, &r))
6090 mouse_face_overwritten_p = 1;
6091 }
6092
a39202f6
GM
6093 if (y1 >= yb)
6094 break;
6095 }
dc6f92b8 6096
a39202f6
GM
6097 /* Display the mode line if there is one. */
6098 if (WINDOW_WANTS_MODELINE_P (w)
6099 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
6100 row->enabled_p)
6101 && row->y < r.y + r.height)
82f053ab
GM
6102 {
6103 if (expose_line (w, row, &r))
6104 mouse_face_overwritten_p = 1;
6105 }
a39202f6
GM
6106
6107 if (!w->pseudo_window_p)
6108 {
6109 /* Draw border between windows. */
6110 x_draw_vertical_border (w);
06a2c219 6111
a39202f6
GM
6112 /* Turn the cursor on again. */
6113 if (cursor_cleared_p)
6114 x_update_window_cursor (w, 1);
6115 }
06a2c219 6116 }
82f053ab
GM
6117
6118 return mouse_face_overwritten_p;
06a2c219 6119}
dc6f92b8 6120
dc6f92b8 6121
06a2c219
GM
6122/* Determine the intersection of two rectangles R1 and R2. Return
6123 the intersection in *RESULT. Value is non-zero if RESULT is not
6124 empty. */
6125
6126static int
6127x_intersect_rectangles (r1, r2, result)
6128 XRectangle *r1, *r2, *result;
6129{
6130 XRectangle *left, *right;
6131 XRectangle *upper, *lower;
6132 int intersection_p = 0;
6133
6134 /* Rearrange so that R1 is the left-most rectangle. */
6135 if (r1->x < r2->x)
6136 left = r1, right = r2;
6137 else
6138 left = r2, right = r1;
6139
6140 /* X0 of the intersection is right.x0, if this is inside R1,
6141 otherwise there is no intersection. */
6142 if (right->x <= left->x + left->width)
6143 {
6144 result->x = right->x;
6145
6146 /* The right end of the intersection is the minimum of the
6147 the right ends of left and right. */
6148 result->width = (min (left->x + left->width, right->x + right->width)
6149 - result->x);
6150
6151 /* Same game for Y. */
6152 if (r1->y < r2->y)
6153 upper = r1, lower = r2;
6154 else
6155 upper = r2, lower = r1;
6156
6157 /* The upper end of the intersection is lower.y0, if this is inside
6158 of upper. Otherwise, there is no intersection. */
6159 if (lower->y <= upper->y + upper->height)
dc43ef94 6160 {
06a2c219
GM
6161 result->y = lower->y;
6162
6163 /* The lower end of the intersection is the minimum of the lower
6164 ends of upper and lower. */
6165 result->height = (min (lower->y + lower->height,
6166 upper->y + upper->height)
6167 - result->y);
6168 intersection_p = 1;
dc43ef94 6169 }
dc6f92b8
JB
6170 }
6171
06a2c219 6172 return intersection_p;
dc6f92b8 6173}
06a2c219
GM
6174
6175
6176
6177
dc6f92b8 6178\f
dc6f92b8 6179static void
334208b7
RS
6180frame_highlight (f)
6181 struct frame *f;
dc6f92b8 6182{
b3e1e05c
JB
6183 /* We used to only do this if Vx_no_window_manager was non-nil, but
6184 the ICCCM (section 4.1.6) says that the window's border pixmap
6185 and border pixel are window attributes which are "private to the
6186 client", so we can always change it to whatever we want. */
6187 BLOCK_INPUT;
334208b7 6188 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6189 f->output_data.x->border_pixel);
b3e1e05c 6190 UNBLOCK_INPUT;
5d46f928 6191 x_update_cursor (f, 1);
dc6f92b8
JB
6192}
6193
6194static void
334208b7
RS
6195frame_unhighlight (f)
6196 struct frame *f;
dc6f92b8 6197{
b3e1e05c
JB
6198 /* We used to only do this if Vx_no_window_manager was non-nil, but
6199 the ICCCM (section 4.1.6) says that the window's border pixmap
6200 and border pixel are window attributes which are "private to the
6201 client", so we can always change it to whatever we want. */
6202 BLOCK_INPUT;
334208b7 6203 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6204 f->output_data.x->border_tile);
b3e1e05c 6205 UNBLOCK_INPUT;
5d46f928 6206 x_update_cursor (f, 1);
dc6f92b8 6207}
dc6f92b8 6208
f676886a
JB
6209/* The focus has changed. Update the frames as necessary to reflect
6210 the new situation. Note that we can't change the selected frame
c5acd733 6211 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 6212 Each event gets marked with the frame in which it occurred, so the
c5acd733 6213 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 6214
6d4238f3 6215static void
0f941935
KH
6216x_new_focus_frame (dpyinfo, frame)
6217 struct x_display_info *dpyinfo;
f676886a 6218 struct frame *frame;
dc6f92b8 6219{
0f941935 6220 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 6221
0f941935 6222 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 6223 {
58769bee 6224 /* Set this before calling other routines, so that they see
f676886a 6225 the correct value of x_focus_frame. */
0f941935 6226 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
6227
6228 if (old_focus && old_focus->auto_lower)
f676886a 6229 x_lower_frame (old_focus);
dc6f92b8
JB
6230
6231#if 0
f676886a 6232 selected_frame = frame;
e0c1aef2
KH
6233 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6234 selected_frame);
f676886a
JB
6235 Fselect_window (selected_frame->selected_window);
6236 choose_minibuf_frame ();
c118dd06 6237#endif /* ! 0 */
dc6f92b8 6238
0f941935
KH
6239 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6240 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
6241 else
6242 pending_autoraise_frame = 0;
6d4238f3 6243 }
dc6f92b8 6244
0f941935 6245 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
6246}
6247
37c2c98b
RS
6248/* Handle an event saying the mouse has moved out of an Emacs frame. */
6249
6250void
0f941935
KH
6251x_mouse_leave (dpyinfo)
6252 struct x_display_info *dpyinfo;
37c2c98b 6253{
0f941935 6254 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 6255}
6d4238f3 6256
f451eb13
JB
6257/* The focus has changed, or we have redirected a frame's focus to
6258 another frame (this happens when a frame uses a surrogate
06a2c219 6259 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
6260
6261 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 6262 frame is being highlighted or un-highlighted; we only use it to find
0f941935 6263 the appropriate X display info. */
06a2c219 6264
6d4238f3 6265static void
0f941935
KH
6266XTframe_rehighlight (frame)
6267 struct frame *frame;
6d4238f3 6268{
0f941935
KH
6269 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6270}
6d4238f3 6271
0f941935
KH
6272static void
6273x_frame_rehighlight (dpyinfo)
6274 struct x_display_info *dpyinfo;
6275{
6276 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6277
6278 if (dpyinfo->x_focus_frame)
6d4238f3 6279 {
0f941935
KH
6280 dpyinfo->x_highlight_frame
6281 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6282 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6283 : dpyinfo->x_focus_frame);
6284 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 6285 {
0f941935
KH
6286 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6287 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 6288 }
dc6f92b8 6289 }
6d4238f3 6290 else
0f941935 6291 dpyinfo->x_highlight_frame = 0;
dc6f92b8 6292
0f941935 6293 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
6294 {
6295 if (old_highlight)
f676886a 6296 frame_unhighlight (old_highlight);
0f941935
KH
6297 if (dpyinfo->x_highlight_frame)
6298 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 6299 }
dc6f92b8 6300}
06a2c219
GM
6301
6302
dc6f92b8 6303\f
06a2c219 6304/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 6305
28430d3c
JB
6306/* Initialize mode_switch_bit and modifier_meaning. */
6307static void
334208b7
RS
6308x_find_modifier_meanings (dpyinfo)
6309 struct x_display_info *dpyinfo;
28430d3c 6310{
f689eb05 6311 int min_code, max_code;
28430d3c
JB
6312 KeySym *syms;
6313 int syms_per_code;
6314 XModifierKeymap *mods;
6315
334208b7
RS
6316 dpyinfo->meta_mod_mask = 0;
6317 dpyinfo->shift_lock_mask = 0;
6318 dpyinfo->alt_mod_mask = 0;
6319 dpyinfo->super_mod_mask = 0;
6320 dpyinfo->hyper_mod_mask = 0;
58769bee 6321
9658a521 6322#ifdef HAVE_X11R4
334208b7 6323 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 6324#else
4a60f8c5
RS
6325 min_code = dpyinfo->display->min_keycode;
6326 max_code = dpyinfo->display->max_keycode;
9658a521
JB
6327#endif
6328
334208b7 6329 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
6330 min_code, max_code - min_code + 1,
6331 &syms_per_code);
334208b7 6332 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 6333
58769bee 6334 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 6335 Alt keysyms are on. */
28430d3c 6336 {
06a2c219 6337 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
6338
6339 for (row = 3; row < 8; row++)
6340 for (col = 0; col < mods->max_keypermod; col++)
6341 {
0299d313
RS
6342 KeyCode code
6343 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 6344
af92970c
KH
6345 /* Zeroes are used for filler. Skip them. */
6346 if (code == 0)
6347 continue;
6348
28430d3c
JB
6349 /* Are any of this keycode's keysyms a meta key? */
6350 {
6351 int code_col;
6352
6353 for (code_col = 0; code_col < syms_per_code; code_col++)
6354 {
f689eb05 6355 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 6356
f689eb05 6357 switch (sym)
28430d3c 6358 {
f689eb05
JB
6359 case XK_Meta_L:
6360 case XK_Meta_R:
334208b7 6361 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 6362 break;
f689eb05
JB
6363
6364 case XK_Alt_L:
6365 case XK_Alt_R:
334208b7 6366 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
6367 break;
6368
6369 case XK_Hyper_L:
6370 case XK_Hyper_R:
334208b7 6371 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
6372 break;
6373
6374 case XK_Super_L:
6375 case XK_Super_R:
334208b7 6376 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 6377 break;
11edeb03
JB
6378
6379 case XK_Shift_Lock:
6380 /* Ignore this if it's not on the lock modifier. */
6381 if ((1 << row) == LockMask)
334208b7 6382 dpyinfo->shift_lock_mask = LockMask;
11edeb03 6383 break;
28430d3c
JB
6384 }
6385 }
6386 }
6387 }
6388 }
6389
f689eb05 6390 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 6391 if (! dpyinfo->meta_mod_mask)
a3c44b14 6392 {
334208b7
RS
6393 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6394 dpyinfo->alt_mod_mask = 0;
a3c44b14 6395 }
f689eb05 6396
148c4b70
RS
6397 /* If some keys are both alt and meta,
6398 make them just meta, not alt. */
334208b7 6399 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 6400 {
334208b7 6401 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 6402 }
58769bee 6403
28430d3c 6404 XFree ((char *) syms);
f689eb05 6405 XFreeModifiermap (mods);
28430d3c
JB
6406}
6407
dfeccd2d
JB
6408/* Convert between the modifier bits X uses and the modifier bits
6409 Emacs uses. */
06a2c219 6410
7c5283e4 6411static unsigned int
334208b7
RS
6412x_x_to_emacs_modifiers (dpyinfo, state)
6413 struct x_display_info *dpyinfo;
dc6f92b8
JB
6414 unsigned int state;
6415{
334208b7
RS
6416 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
6417 | ((state & ControlMask) ? ctrl_modifier : 0)
6418 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
6419 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
6420 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
6421 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
6422}
6423
dfeccd2d 6424static unsigned int
334208b7
RS
6425x_emacs_to_x_modifiers (dpyinfo, state)
6426 struct x_display_info *dpyinfo;
dfeccd2d
JB
6427 unsigned int state;
6428{
334208b7
RS
6429 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
6430 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6431 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6432 | ((state & shift_modifier) ? ShiftMask : 0)
6433 | ((state & ctrl_modifier) ? ControlMask : 0)
6434 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6435}
d047c4eb
KH
6436
6437/* Convert a keysym to its name. */
6438
6439char *
6440x_get_keysym_name (keysym)
6441 KeySym keysym;
6442{
6443 char *value;
6444
6445 BLOCK_INPUT;
6446 value = XKeysymToString (keysym);
6447 UNBLOCK_INPUT;
6448
6449 return value;
6450}
06a2c219
GM
6451
6452
e4571a43
JB
6453\f
6454/* Mouse clicks and mouse movement. Rah. */
e4571a43 6455
06a2c219
GM
6456/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6457 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6458 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6459 not force the value into range. */
69388238 6460
c8dba240 6461void
69388238 6462pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6463 FRAME_PTR f;
69388238 6464 register int pix_x, pix_y;
e4571a43
JB
6465 register int *x, *y;
6466 XRectangle *bounds;
69388238 6467 int noclip;
e4571a43 6468{
06a2c219 6469 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6470 even for negative values. */
6471 if (pix_x < 0)
7556890b 6472 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6473 if (pix_y < 0)
7556890b 6474 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6475
e4571a43
JB
6476 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6477 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6478
6479 if (bounds)
6480 {
7556890b
RS
6481 bounds->width = FONT_WIDTH (f->output_data.x->font);
6482 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6483 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6484 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6485 }
6486
69388238
RS
6487 if (!noclip)
6488 {
6489 if (pix_x < 0)
6490 pix_x = 0;
3cbd2e0b
RS
6491 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6492 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6493
6494 if (pix_y < 0)
6495 pix_y = 0;
6496 else if (pix_y > f->height)
6497 pix_y = f->height;
6498 }
e4571a43
JB
6499
6500 *x = pix_x;
6501 *y = pix_y;
6502}
6503
06a2c219
GM
6504
6505/* Given HPOS/VPOS in the current matrix of W, return corresponding
6506 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6507 can't tell the positions because W's display is not up to date,
6508 return 0. */
6509
6510int
6511glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6512 struct window *w;
6513 int hpos, vpos;
6514 int *frame_x, *frame_y;
2b5c9e71 6515{
06a2c219
GM
6516 int success_p;
6517
6518 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6519 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6520
6521 if (display_completed)
6522 {
6523 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6524 struct glyph *glyph = row->glyphs[TEXT_AREA];
6525 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6526
6527 *frame_y = row->y;
6528 *frame_x = row->x;
6529 while (glyph < end)
6530 {
6531 *frame_x += glyph->pixel_width;
6532 ++glyph;
6533 }
6534
6535 success_p = 1;
6536 }
6537 else
6538 {
6539 *frame_y = *frame_x = 0;
6540 success_p = 0;
6541 }
6542
6543 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6544 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6545 return success_p;
2b5c9e71
RS
6546}
6547
06a2c219 6548
dc6f92b8
JB
6549/* Prepare a mouse-event in *RESULT for placement in the input queue.
6550
6551 If the event is a button press, then note that we have grabbed
f451eb13 6552 the mouse. */
dc6f92b8
JB
6553
6554static Lisp_Object
f451eb13 6555construct_mouse_click (result, event, f)
dc6f92b8
JB
6556 struct input_event *result;
6557 XButtonEvent *event;
f676886a 6558 struct frame *f;
dc6f92b8 6559{
f451eb13 6560 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6561 otherwise. */
f451eb13 6562 result->kind = mouse_click;
69388238 6563 result->code = event->button - Button1;
1113d9db 6564 result->timestamp = event->time;
334208b7
RS
6565 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6566 event->state)
f689eb05 6567 | (event->type == ButtonRelease
58769bee 6568 ? up_modifier
f689eb05 6569 : down_modifier));
dc6f92b8 6570
06a2c219
GM
6571 XSETINT (result->x, event->x);
6572 XSETINT (result->y, event->y);
6573 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6574 result->arg = Qnil;
06a2c219 6575 return Qnil;
dc6f92b8 6576}
b849c413 6577
69388238 6578\f
90e65f07
JB
6579/* Function to report a mouse movement to the mainstream Emacs code.
6580 The input handler calls this.
6581
6582 We have received a mouse movement event, which is given in *event.
6583 If the mouse is over a different glyph than it was last time, tell
6584 the mainstream emacs code by setting mouse_moved. If not, ask for
6585 another motion event, so we can check again the next time it moves. */
b8009dd1 6586
06a2c219
GM
6587static XMotionEvent last_mouse_motion_event;
6588static Lisp_Object last_mouse_motion_frame;
6589
90e65f07 6590static void
12ba150f 6591note_mouse_movement (frame, event)
f676886a 6592 FRAME_PTR frame;
90e65f07 6593 XMotionEvent *event;
90e65f07 6594{
e5d77022 6595 last_mouse_movement_time = event->time;
06a2c219
GM
6596 last_mouse_motion_event = *event;
6597 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6598
27f338af
RS
6599 if (event->window != FRAME_X_WINDOW (frame))
6600 {
39d8bb4d 6601 frame->mouse_moved = 1;
27f338af 6602 last_mouse_scroll_bar = Qnil;
27f338af 6603 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6604 }
6605
90e65f07 6606 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6607 else if (event->x < last_mouse_glyph.x
6608 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6609 || event->y < last_mouse_glyph.y
6610 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6611 {
39d8bb4d 6612 frame->mouse_moved = 1;
ab648270 6613 last_mouse_scroll_bar = Qnil;
b8009dd1 6614 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6615 }
6616}
6617
bf1c0ba1 6618/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6619
06a2c219
GM
6620 int disable_mouse_highlight;
6621
6622
6623\f
6624/************************************************************************
6625 Mouse Face
6626 ************************************************************************/
6627
6628/* Find the glyph under window-relative coordinates X/Y in window W.
6629 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6630 strings. Return in *HPOS and *VPOS the row and column number of
6631 the glyph found. Return in *AREA the glyph area containing X.
6632 Value is a pointer to the glyph found or null if X/Y is not on
6633 text, or we can't tell because W's current matrix is not up to
6634 date. */
6635
6636static struct glyph *
f9db2310 6637x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
06a2c219
GM
6638 struct window *w;
6639 int x, y;
6640 int *hpos, *vpos, *area;
f9db2310 6641 int buffer_only_p;
06a2c219
GM
6642{
6643 struct glyph *glyph, *end;
3e71d8f2 6644 struct glyph_row *row = NULL;
06a2c219
GM
6645 int x0, i, left_area_width;
6646
6647 /* Find row containing Y. Give up if some row is not enabled. */
6648 for (i = 0; i < w->current_matrix->nrows; ++i)
6649 {
6650 row = MATRIX_ROW (w->current_matrix, i);
6651 if (!row->enabled_p)
6652 return NULL;
6653 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6654 break;
6655 }
6656
6657 *vpos = i;
6658 *hpos = 0;
6659
6660 /* Give up if Y is not in the window. */
6661 if (i == w->current_matrix->nrows)
6662 return NULL;
6663
6664 /* Get the glyph area containing X. */
6665 if (w->pseudo_window_p)
6666 {
6667 *area = TEXT_AREA;
6668 x0 = 0;
6669 }
6670 else
6671 {
6672 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6673 if (x < left_area_width)
6674 {
6675 *area = LEFT_MARGIN_AREA;
6676 x0 = 0;
6677 }
6678 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6679 {
6680 *area = TEXT_AREA;
6681 x0 = row->x + left_area_width;
6682 }
6683 else
6684 {
6685 *area = RIGHT_MARGIN_AREA;
6686 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6687 }
6688 }
6689
6690 /* Find glyph containing X. */
6691 glyph = row->glyphs[*area];
6692 end = glyph + row->used[*area];
6693 while (glyph < end)
6694 {
6695 if (x < x0 + glyph->pixel_width)
6696 {
6697 if (w->pseudo_window_p)
6698 break;
f9db2310 6699 else if (!buffer_only_p || BUFFERP (glyph->object))
06a2c219
GM
6700 break;
6701 }
6702
6703 x0 += glyph->pixel_width;
6704 ++glyph;
6705 }
6706
6707 if (glyph == end)
6708 return NULL;
6709
6710 *hpos = glyph - row->glyphs[*area];
6711 return glyph;
6712}
6713
6714
6715/* Convert frame-relative x/y to coordinates relative to window W.
6716 Takes pseudo-windows into account. */
6717
6718static void
6719frame_to_window_pixel_xy (w, x, y)
6720 struct window *w;
6721 int *x, *y;
6722{
6723 if (w->pseudo_window_p)
6724 {
6725 /* A pseudo-window is always full-width, and starts at the
6726 left edge of the frame, plus a frame border. */
6727 struct frame *f = XFRAME (w->frame);
6728 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6729 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6730 }
6731 else
6732 {
6733 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6734 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6735 }
6736}
6737
6738
e371a781 6739/* Take proper action when mouse has moved to the mode or header line of
06a2c219
GM
6740 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6741 mode line. X is relative to the start of the text display area of
3f332ef3 6742 W, so the width of fringes and scroll bars must be subtracted
06a2c219
GM
6743 to get a position relative to the start of the mode line. */
6744
6745static void
6746note_mode_line_highlight (w, x, mode_line_p)
6747 struct window *w;
6748 int x, mode_line_p;
6749{
6750 struct frame *f = XFRAME (w->frame);
6751 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6752 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6753 struct glyph_row *row;
6754
6755 if (mode_line_p)
6756 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6757 else
045dee35 6758 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
e371a781 6759
06a2c219
GM
6760 if (row->enabled_p)
6761 {
6762 struct glyph *glyph, *end;
6763 Lisp_Object help, map;
6764 int x0;
6765
6766 /* Find the glyph under X. */
6767 glyph = row->glyphs[TEXT_AREA];
6768 end = glyph + row->used[TEXT_AREA];
6769 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
3f332ef3 6770 + FRAME_X_LEFT_FRINGE_WIDTH (f));
e371a781 6771
06a2c219
GM
6772 while (glyph < end
6773 && x >= x0 + glyph->pixel_width)
6774 {
6775 x0 += glyph->pixel_width;
6776 ++glyph;
6777 }
6778
6779 if (glyph < end
6780 && STRINGP (glyph->object)
6781 && XSTRING (glyph->object)->intervals
6782 && glyph->charpos >= 0
6783 && glyph->charpos < XSTRING (glyph->object)->size)
6784 {
6785 /* If we're on a string with `help-echo' text property,
6786 arrange for the help to be displayed. This is done by
6787 setting the global variable help_echo to the help string. */
6788 help = Fget_text_property (make_number (glyph->charpos),
6789 Qhelp_echo, glyph->object);
b7e80413 6790 if (!NILP (help))
be010514
GM
6791 {
6792 help_echo = help;
7cea38bc 6793 XSETWINDOW (help_echo_window, w);
be010514
GM
6794 help_echo_object = glyph->object;
6795 help_echo_pos = glyph->charpos;
6796 }
06a2c219
GM
6797
6798 /* Change the mouse pointer according to what is under X/Y. */
6799 map = Fget_text_property (make_number (glyph->charpos),
6800 Qlocal_map, glyph->object);
02067692 6801 if (KEYMAPP (map))
06a2c219 6802 cursor = f->output_data.x->nontext_cursor;
be010514
GM
6803 else
6804 {
6805 map = Fget_text_property (make_number (glyph->charpos),
6806 Qkeymap, glyph->object);
02067692 6807 if (KEYMAPP (map))
be010514
GM
6808 cursor = f->output_data.x->nontext_cursor;
6809 }
06a2c219
GM
6810 }
6811 }
6812
6813 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6814}
6815
6816
6817/* Take proper action when the mouse has moved to position X, Y on
6818 frame F as regards highlighting characters that have mouse-face
6819 properties. Also de-highlighting chars where the mouse was before.
27f338af 6820 X and Y can be negative or out of range. */
b8009dd1
RS
6821
6822static void
6823note_mouse_highlight (f, x, y)
06a2c219 6824 struct frame *f;
c32cdd9a 6825 int x, y;
b8009dd1 6826{
06a2c219
GM
6827 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6828 int portion;
b8009dd1
RS
6829 Lisp_Object window;
6830 struct window *w;
0d487c52
GM
6831 Cursor cursor = None;
6832 struct buffer *b;
b8009dd1 6833
06a2c219
GM
6834 /* When a menu is active, don't highlight because this looks odd. */
6835#ifdef USE_X_TOOLKIT
6836 if (popup_activated ())
6837 return;
6838#endif
6839
04fff9c0
GM
6840 if (disable_mouse_highlight
6841 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6842 return;
6843
06a2c219
GM
6844 dpyinfo->mouse_face_mouse_x = x;
6845 dpyinfo->mouse_face_mouse_y = y;
6846 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6847
06a2c219 6848 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6849 return;
6850
514e4681
RS
6851 if (gc_in_progress)
6852 {
06a2c219 6853 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6854 return;
6855 }
6856
b8009dd1 6857 /* Which window is that in? */
06a2c219 6858 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6859
6860 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6861 if (! EQ (window, dpyinfo->mouse_face_window))
6862 clear_mouse_face (dpyinfo);
6863
6864 /* Not on a window -> return. */
6865 if (!WINDOWP (window))
6866 return;
6867
6868 /* Convert to window-relative pixel coordinates. */
6869 w = XWINDOW (window);
6870 frame_to_window_pixel_xy (w, &x, &y);
6871
9ea173e8 6872 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6873 buffer. */
9ea173e8 6874 if (EQ (window, f->tool_bar_window))
06a2c219 6875 {
9ea173e8 6876 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6877 return;
6878 }
6879
0d487c52 6880 /* Mouse is on the mode or header line? */
06a2c219
GM
6881 if (portion == 1 || portion == 3)
6882 {
06a2c219
GM
6883 note_mode_line_highlight (w, x, portion == 1);
6884 return;
6885 }
0d487c52
GM
6886
6887 if (portion == 2)
6888 cursor = f->output_data.x->horizontal_drag_cursor;
06a2c219 6889 else
0d487c52 6890 cursor = f->output_data.x->text_cursor;
b8009dd1 6891
0cdd0c9f
RS
6892 /* Are we in a window whose display is up to date?
6893 And verify the buffer's text has not changed. */
0d487c52 6894 b = XBUFFER (w->buffer);
06a2c219
GM
6895 if (/* Within text portion of the window. */
6896 portion == 0
0cdd0c9f 6897 && EQ (w->window_end_valid, w->buffer)
0d487c52
GM
6898 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
6899 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
b8009dd1 6900 {
06a2c219
GM
6901 int hpos, vpos, pos, i, area;
6902 struct glyph *glyph;
f9db2310 6903 Lisp_Object object;
0d487c52
GM
6904 Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
6905 Lisp_Object *overlay_vec = NULL;
6906 int len, noverlays;
6907 struct buffer *obuf;
6908 int obegv, ozv, same_region;
b8009dd1 6909
06a2c219 6910 /* Find the glyph under X/Y. */
f9db2310 6911 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
06a2c219
GM
6912
6913 /* Clear mouse face if X/Y not over text. */
6914 if (glyph == NULL
6915 || area != TEXT_AREA
6916 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6917 {
fa262c07
GM
6918 if (clear_mouse_face (dpyinfo))
6919 cursor = None;
6920 goto set_cursor;
06a2c219
GM
6921 }
6922
6923 pos = glyph->charpos;
f9db2310
GM
6924 object = glyph->object;
6925 if (!STRINGP (object) && !BUFFERP (object))
fa262c07 6926 goto set_cursor;
06a2c219 6927
0d487c52
GM
6928 /* If we get an out-of-range value, return now; avoid an error. */
6929 if (BUFFERP (object) && pos > BUF_Z (b))
fa262c07 6930 goto set_cursor;
06a2c219 6931
0d487c52
GM
6932 /* Make the window's buffer temporarily current for
6933 overlays_at and compute_char_face. */
6934 obuf = current_buffer;
6935 current_buffer = b;
6936 obegv = BEGV;
6937 ozv = ZV;
6938 BEGV = BEG;
6939 ZV = Z;
06a2c219 6940
0d487c52
GM
6941 /* Is this char mouse-active or does it have help-echo? */
6942 position = make_number (pos);
f9db2310 6943
0d487c52
GM
6944 if (BUFFERP (object))
6945 {
6946 /* Put all the overlays we want in a vector in overlay_vec.
6947 Store the length in len. If there are more than 10, make
6948 enough space for all, and try again. */
6949 len = 10;
6950 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6951 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
6952 if (noverlays > len)
6953 {
6954 len = noverlays;
6955 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6956 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
6957 }
f8349001 6958
0d487c52
GM
6959 /* Sort overlays into increasing priority order. */
6960 noverlays = sort_overlays (overlay_vec, noverlays, w);
6961 }
6962 else
6963 noverlays = 0;
6964
6965 same_region = (EQ (window, dpyinfo->mouse_face_window)
6966 && vpos >= dpyinfo->mouse_face_beg_row
6967 && vpos <= dpyinfo->mouse_face_end_row
6968 && (vpos > dpyinfo->mouse_face_beg_row
6969 || hpos >= dpyinfo->mouse_face_beg_col)
6970 && (vpos < dpyinfo->mouse_face_end_row
6971 || hpos < dpyinfo->mouse_face_end_col
6972 || dpyinfo->mouse_face_past_end));
6973
6974 if (same_region)
6975 cursor = None;
6976
6977 /* Check mouse-face highlighting. */
6978 if (! same_region
6979 /* If there exists an overlay with mouse-face overlapping
6980 the one we are currently highlighting, we have to
6981 check if we enter the overlapping overlay, and then
6982 highlight only that. */
6983 || (OVERLAYP (dpyinfo->mouse_face_overlay)
6984 && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
6985 {
0d487c52
GM
6986 /* Find the highest priority overlay that has a mouse-face
6987 property. */
6988 overlay = Qnil;
6989 for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
6990 {
6991 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6992 if (!NILP (mouse_face))
6993 overlay = overlay_vec[i];
6994 }
8bd189fb
GM
6995
6996 /* If we're actually highlighting the same overlay as
6997 before, there's no need to do that again. */
6998 if (!NILP (overlay)
6999 && EQ (overlay, dpyinfo->mouse_face_overlay))
7000 goto check_help_echo;
f9db2310 7001
8bd189fb
GM
7002 dpyinfo->mouse_face_overlay = overlay;
7003
7004 /* Clear the display of the old active region, if any. */
7005 if (clear_mouse_face (dpyinfo))
7006 cursor = None;
7007
0d487c52
GM
7008 /* If no overlay applies, get a text property. */
7009 if (NILP (overlay))
7010 mouse_face = Fget_text_property (position, Qmouse_face, object);
06a2c219 7011
0d487c52
GM
7012 /* Handle the overlay case. */
7013 if (!NILP (overlay))
7014 {
7015 /* Find the range of text around this char that
7016 should be active. */
7017 Lisp_Object before, after;
7018 int ignore;
7019
7020 before = Foverlay_start (overlay);
7021 after = Foverlay_end (overlay);
7022 /* Record this as the current active region. */
7023 fast_find_position (w, XFASTINT (before),
7024 &dpyinfo->mouse_face_beg_col,
7025 &dpyinfo->mouse_face_beg_row,
7026 &dpyinfo->mouse_face_beg_x,
7e376260
GM
7027 &dpyinfo->mouse_face_beg_y, Qnil);
7028
0d487c52
GM
7029 dpyinfo->mouse_face_past_end
7030 = !fast_find_position (w, XFASTINT (after),
7031 &dpyinfo->mouse_face_end_col,
7032 &dpyinfo->mouse_face_end_row,
7033 &dpyinfo->mouse_face_end_x,
7e376260 7034 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7035 dpyinfo->mouse_face_window = window;
7036 dpyinfo->mouse_face_face_id
7037 = face_at_buffer_position (w, pos, 0, 0,
7038 &ignore, pos + 1, 1);
7039
7040 /* Display it as active. */
7041 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7042 cursor = None;
0d487c52
GM
7043 }
7044 /* Handle the text property case. */
7045 else if (!NILP (mouse_face) && BUFFERP (object))
7046 {
7047 /* Find the range of text around this char that
7048 should be active. */
7049 Lisp_Object before, after, beginning, end;
7050 int ignore;
7051
7052 beginning = Fmarker_position (w->start);
7053 end = make_number (BUF_Z (XBUFFER (object))
7054 - XFASTINT (w->window_end_pos));
7055 before
7056 = Fprevious_single_property_change (make_number (pos + 1),
7057 Qmouse_face,
7058 object, beginning);
7059 after
7060 = Fnext_single_property_change (position, Qmouse_face,
7061 object, end);
7062
7063 /* Record this as the current active region. */
7064 fast_find_position (w, XFASTINT (before),
7065 &dpyinfo->mouse_face_beg_col,
7066 &dpyinfo->mouse_face_beg_row,
7067 &dpyinfo->mouse_face_beg_x,
7e376260 7068 &dpyinfo->mouse_face_beg_y, Qnil);
0d487c52
GM
7069 dpyinfo->mouse_face_past_end
7070 = !fast_find_position (w, XFASTINT (after),
7071 &dpyinfo->mouse_face_end_col,
7072 &dpyinfo->mouse_face_end_row,
7073 &dpyinfo->mouse_face_end_x,
7e376260 7074 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7075 dpyinfo->mouse_face_window = window;
7076
7077 if (BUFFERP (object))
06a2c219
GM
7078 dpyinfo->mouse_face_face_id
7079 = face_at_buffer_position (w, pos, 0, 0,
7080 &ignore, pos + 1, 1);
7081
0d487c52
GM
7082 /* Display it as active. */
7083 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7084 cursor = None;
0d487c52
GM
7085 }
7086 else if (!NILP (mouse_face) && STRINGP (object))
7087 {
7088 Lisp_Object b, e;
7089 int ignore;
f9db2310 7090
0d487c52
GM
7091 b = Fprevious_single_property_change (make_number (pos + 1),
7092 Qmouse_face,
7093 object, Qnil);
7094 e = Fnext_single_property_change (position, Qmouse_face,
7095 object, Qnil);
7096 if (NILP (b))
7097 b = make_number (0);
7098 if (NILP (e))
7099 e = make_number (XSTRING (object)->size - 1);
7100 fast_find_string_pos (w, XINT (b), object,
06a2c219
GM
7101 &dpyinfo->mouse_face_beg_col,
7102 &dpyinfo->mouse_face_beg_row,
7103 &dpyinfo->mouse_face_beg_x,
0d487c52
GM
7104 &dpyinfo->mouse_face_beg_y, 0);
7105 fast_find_string_pos (w, XINT (e), object,
7106 &dpyinfo->mouse_face_end_col,
7107 &dpyinfo->mouse_face_end_row,
7108 &dpyinfo->mouse_face_end_x,
7109 &dpyinfo->mouse_face_end_y, 1);
7110 dpyinfo->mouse_face_past_end = 0;
7111 dpyinfo->mouse_face_window = window;
7112 dpyinfo->mouse_face_face_id
7113 = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
7114 glyph->face_id, 1);
7115 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7116 cursor = None;
0d487c52 7117 }
7e376260
GM
7118 else if (STRINGP (object) && NILP (mouse_face))
7119 {
7120 /* A string which doesn't have mouse-face, but
7121 the text ``under'' it might have. */
7122 struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
7123 int start = MATRIX_ROW_START_CHARPOS (r);
7124
7125 pos = string_buffer_position (w, object, start);
7126 if (pos > 0)
7127 mouse_face = get_char_property_and_overlay (make_number (pos),
7128 Qmouse_face,
7129 w->buffer,
7130 &overlay);
7131 if (!NILP (mouse_face) && !NILP (overlay))
7132 {
7133 Lisp_Object before = Foverlay_start (overlay);
7134 Lisp_Object after = Foverlay_end (overlay);
91c153e2 7135 int ignore;
7e376260
GM
7136
7137 /* Note that we might not be able to find position
7138 BEFORE in the glyph matrix if the overlay is
7139 entirely covered by a `display' property. In
7140 this case, we overshoot. So let's stop in
7141 the glyph matrix before glyphs for OBJECT. */
7142 fast_find_position (w, XFASTINT (before),
7143 &dpyinfo->mouse_face_beg_col,
7144 &dpyinfo->mouse_face_beg_row,
7145 &dpyinfo->mouse_face_beg_x,
7146 &dpyinfo->mouse_face_beg_y,
7147 object);
7148
7149 dpyinfo->mouse_face_past_end
7150 = !fast_find_position (w, XFASTINT (after),
7151 &dpyinfo->mouse_face_end_col,
7152 &dpyinfo->mouse_face_end_row,
7153 &dpyinfo->mouse_face_end_x,
7154 &dpyinfo->mouse_face_end_y,
7155 Qnil);
7156 dpyinfo->mouse_face_window = window;
7157 dpyinfo->mouse_face_face_id
7158 = face_at_buffer_position (w, pos, 0, 0,
7159 &ignore, pos + 1, 1);
7160
7161 /* Display it as active. */
7162 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
7163 cursor = None;
7164 }
7165 }
0d487c52 7166 }
06a2c219 7167
8bd189fb
GM
7168 check_help_echo:
7169
0d487c52
GM
7170 /* Look for a `help-echo' property. */
7171 {
7172 Lisp_Object help, overlay;
06a2c219 7173
0d487c52
GM
7174 /* Check overlays first. */
7175 help = overlay = Qnil;
7176 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
7177 {
7178 overlay = overlay_vec[i];
7179 help = Foverlay_get (overlay, Qhelp_echo);
7180 }
be010514 7181
0d487c52
GM
7182 if (!NILP (help))
7183 {
7184 help_echo = help;
7185 help_echo_window = window;
7186 help_echo_object = overlay;
7187 help_echo_pos = pos;
7188 }
7189 else
7190 {
7191 Lisp_Object object = glyph->object;
7192 int charpos = glyph->charpos;
7177d86b 7193
0d487c52
GM
7194 /* Try text properties. */
7195 if (STRINGP (object)
7196 && charpos >= 0
7197 && charpos < XSTRING (object)->size)
7198 {
7199 help = Fget_text_property (make_number (charpos),
7200 Qhelp_echo, object);
7201 if (NILP (help))
7202 {
7203 /* If the string itself doesn't specify a help-echo,
7204 see if the buffer text ``under'' it does. */
7205 struct glyph_row *r
7206 = MATRIX_ROW (w->current_matrix, vpos);
7207 int start = MATRIX_ROW_START_CHARPOS (r);
7208 int pos = string_buffer_position (w, object, start);
7209 if (pos > 0)
7210 {
7e376260 7211 help = Fget_char_property (make_number (pos),
0d487c52
GM
7212 Qhelp_echo, w->buffer);
7213 if (!NILP (help))
7214 {
7215 charpos = pos;
7216 object = w->buffer;
7217 }
7218 }
7219 }
7220 }
7221 else if (BUFFERP (object)
7222 && charpos >= BEGV
7223 && charpos < ZV)
7224 help = Fget_text_property (make_number (charpos), Qhelp_echo,
7225 object);
06a2c219 7226
0d487c52
GM
7227 if (!NILP (help))
7228 {
7229 help_echo = help;
7230 help_echo_window = window;
7231 help_echo_object = object;
7232 help_echo_pos = charpos;
7233 }
7234 }
06a2c219 7235 }
0d487c52
GM
7236
7237 BEGV = obegv;
7238 ZV = ozv;
7239 current_buffer = obuf;
06a2c219 7240 }
0d487c52 7241
fa262c07
GM
7242 set_cursor:
7243
0d487c52
GM
7244 if (cursor != None)
7245 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
06a2c219
GM
7246}
7247
7248static void
7249redo_mouse_highlight ()
7250{
7251 if (!NILP (last_mouse_motion_frame)
7252 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
7253 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
7254 last_mouse_motion_event.x,
7255 last_mouse_motion_event.y);
7256}
7257
7258
7259\f
7260/***********************************************************************
9ea173e8 7261 Tool-bars
06a2c219
GM
7262 ***********************************************************************/
7263
9ea173e8
GM
7264static int x_tool_bar_item P_ ((struct frame *, int, int,
7265 struct glyph **, int *, int *, int *));
06a2c219 7266
9ea173e8 7267/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
7268 or -1. */
7269
9ea173e8 7270static int last_tool_bar_item;
06a2c219
GM
7271
7272
9ea173e8
GM
7273/* Get information about the tool-bar item at position X/Y on frame F.
7274 Return in *GLYPH a pointer to the glyph of the tool-bar item in
7275 the current matrix of the tool-bar window of F, or NULL if not
7276 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
8daf1204 7277 item in F->tool_bar_items. Value is
06a2c219 7278
9ea173e8 7279 -1 if X/Y is not on a tool-bar item
06a2c219
GM
7280 0 if X/Y is on the same item that was highlighted before.
7281 1 otherwise. */
7282
7283static int
9ea173e8 7284x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
7285 struct frame *f;
7286 int x, y;
7287 struct glyph **glyph;
7288 int *hpos, *vpos, *prop_idx;
7289{
7290 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7291 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7292 int area;
7293
7294 /* Find the glyph under X/Y. */
f9db2310 7295 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
06a2c219
GM
7296 if (*glyph == NULL)
7297 return -1;
7298
9ea173e8 7299 /* Get the start of this tool-bar item's properties in
8daf1204 7300 f->tool_bar_items. */
9ea173e8 7301 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
7302 return -1;
7303
7304 /* Is mouse on the highlighted item? */
9ea173e8 7305 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
7306 && *vpos >= dpyinfo->mouse_face_beg_row
7307 && *vpos <= dpyinfo->mouse_face_end_row
7308 && (*vpos > dpyinfo->mouse_face_beg_row
7309 || *hpos >= dpyinfo->mouse_face_beg_col)
7310 && (*vpos < dpyinfo->mouse_face_end_row
7311 || *hpos < dpyinfo->mouse_face_end_col
7312 || dpyinfo->mouse_face_past_end))
7313 return 0;
7314
7315 return 1;
7316}
7317
7318
9ea173e8 7319/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
7320 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
7321 or ButtonRelase. */
7322
7323static void
9ea173e8 7324x_handle_tool_bar_click (f, button_event)
06a2c219
GM
7325 struct frame *f;
7326 XButtonEvent *button_event;
7327{
7328 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7329 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7330 int hpos, vpos, prop_idx;
7331 struct glyph *glyph;
7332 Lisp_Object enabled_p;
7333 int x = button_event->x;
7334 int y = button_event->y;
7335
9ea173e8 7336 /* If not on the highlighted tool-bar item, return. */
06a2c219 7337 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 7338 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
7339 return;
7340
7341 /* If item is disabled, do nothing. */
8daf1204 7342 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7343 if (NILP (enabled_p))
7344 return;
7345
7346 if (button_event->type == ButtonPress)
7347 {
7348 /* Show item in pressed state. */
7349 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
7350 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 7351 last_tool_bar_item = prop_idx;
06a2c219
GM
7352 }
7353 else
7354 {
7355 Lisp_Object key, frame;
7356 struct input_event event;
7357
7358 /* Show item in released state. */
7359 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
7360 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
7361
8daf1204 7362 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
06a2c219
GM
7363
7364 XSETFRAME (frame, f);
9ea173e8 7365 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7366 event.frame_or_window = frame;
7367 event.arg = frame;
06a2c219
GM
7368 kbd_buffer_store_event (&event);
7369
9ea173e8 7370 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7371 event.frame_or_window = frame;
7372 event.arg = key;
06a2c219
GM
7373 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7374 button_event->state);
7375 kbd_buffer_store_event (&event);
9ea173e8 7376 last_tool_bar_item = -1;
06a2c219
GM
7377 }
7378}
7379
7380
9ea173e8
GM
7381/* Possibly highlight a tool-bar item on frame F when mouse moves to
7382 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
7383 note_mouse_highlight. */
7384
7385static void
9ea173e8 7386note_tool_bar_highlight (f, x, y)
06a2c219
GM
7387 struct frame *f;
7388 int x, y;
7389{
9ea173e8 7390 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
7391 struct window *w = XWINDOW (window);
7392 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7393 int hpos, vpos;
7394 struct glyph *glyph;
7395 struct glyph_row *row;
5c187dee 7396 int i;
06a2c219
GM
7397 Lisp_Object enabled_p;
7398 int prop_idx;
140330de 7399 enum draw_glyphs_face draw;
5c187dee 7400 int mouse_down_p, rc;
06a2c219
GM
7401
7402 /* Function note_mouse_highlight is called with negative x(y
7403 values when mouse moves outside of the frame. */
7404 if (x <= 0 || y <= 0)
7405 {
7406 clear_mouse_face (dpyinfo);
7407 return;
7408 }
7409
9ea173e8 7410 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
7411 if (rc < 0)
7412 {
9ea173e8 7413 /* Not on tool-bar item. */
06a2c219
GM
7414 clear_mouse_face (dpyinfo);
7415 return;
7416 }
7417 else if (rc == 0)
06a2c219 7418 goto set_help_echo;
b8009dd1 7419
06a2c219
GM
7420 clear_mouse_face (dpyinfo);
7421
9ea173e8 7422 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
7423 mouse_down_p = (dpyinfo->grabbed
7424 && f == last_mouse_frame
7425 && FRAME_LIVE_P (f));
7426 if (mouse_down_p
9ea173e8 7427 && last_tool_bar_item != prop_idx)
06a2c219
GM
7428 return;
7429
7430 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7431 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7432
9ea173e8 7433 /* If tool-bar item is not enabled, don't highlight it. */
8daf1204 7434 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7435 if (!NILP (enabled_p))
7436 {
7437 /* Compute the x-position of the glyph. In front and past the
7438 image is a space. We include this is the highlighted area. */
7439 row = MATRIX_ROW (w->current_matrix, vpos);
7440 for (i = x = 0; i < hpos; ++i)
7441 x += row->glyphs[TEXT_AREA][i].pixel_width;
7442
7443 /* Record this as the current active region. */
7444 dpyinfo->mouse_face_beg_col = hpos;
7445 dpyinfo->mouse_face_beg_row = vpos;
7446 dpyinfo->mouse_face_beg_x = x;
7447 dpyinfo->mouse_face_beg_y = row->y;
7448 dpyinfo->mouse_face_past_end = 0;
7449
7450 dpyinfo->mouse_face_end_col = hpos + 1;
7451 dpyinfo->mouse_face_end_row = vpos;
7452 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7453 dpyinfo->mouse_face_end_y = row->y;
7454 dpyinfo->mouse_face_window = window;
9ea173e8 7455 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
7456
7457 /* Display it as active. */
7458 show_mouse_face (dpyinfo, draw);
7459 dpyinfo->mouse_face_image_state = draw;
b8009dd1 7460 }
06a2c219
GM
7461
7462 set_help_echo:
7463
9ea173e8 7464 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 7465 XTread_socket does the rest. */
7cea38bc 7466 help_echo_object = help_echo_window = Qnil;
be010514 7467 help_echo_pos = -1;
8daf1204 7468 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
b7e80413 7469 if (NILP (help_echo))
8daf1204 7470 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
b8009dd1 7471}
4d73d038 7472
06a2c219
GM
7473
7474\f
9f8531e5
GM
7475/* Find the glyph matrix position of buffer position CHARPOS in window
7476 *W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7477 current glyphs must be up to date. If CHARPOS is above window
7478 start return (0, 0, 0, 0). If CHARPOS is after end of W, return end
7479 of last line in W. In the row containing CHARPOS, stop before glyphs
7e376260 7480 having STOP as object. */
b8009dd1 7481
9f8531e5
GM
7482#if 0 /* This is a version of fast_find_position that's more correct
7483 in the presence of hscrolling, for example. I didn't install
7484 it right away because the problem fixed is minor, it failed
7485 in 20.x as well, and I think it's too risky to install
7486 so near the release of 21.1. 2001-09-25 gerd. */
7487
7488static int
7489fast_find_position (w, charpos, hpos, vpos, x, y, stop)
7490 struct window *w;
7491 int charpos;
7492 int *hpos, *vpos, *x, *y;
7493 Lisp_Object stop;
7494{
7495 struct glyph_row *row, *first;
7496 struct glyph *glyph, *end;
7497 int i, past_end = 0;
7498
7499 first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
62e33982 7500 row = row_containing_pos (w, charpos, first, NULL, 0);
9f8531e5
GM
7501 if (row == NULL)
7502 {
7503 if (charpos < MATRIX_ROW_START_CHARPOS (first))
7504 {
7505 *x = *y = *hpos = *vpos = 0;
7506 return 0;
7507 }
7508 else
7509 {
7510 row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
7511 past_end = 1;
7512 }
7513 }
7514
7515 *x = row->x;
7516 *y = row->y;
7517 *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7518
7519 glyph = row->glyphs[TEXT_AREA];
7520 end = glyph + row->used[TEXT_AREA];
7521
7522 /* Skip over glyphs not having an object at the start of the row.
7523 These are special glyphs like truncation marks on terminal
7524 frames. */
7525 if (row->displays_text_p)
7526 while (glyph < end
7527 && INTEGERP (glyph->object)
7528 && !EQ (stop, glyph->object)
7529 && glyph->charpos < 0)
7530 {
7531 *x += glyph->pixel_width;
7532 ++glyph;
7533 }
7534
7535 while (glyph < end
7536 && !INTEGERP (glyph->object)
7537 && !EQ (stop, glyph->object)
7538 && (!BUFFERP (glyph->object)
7539 || glyph->charpos < charpos))
7540 {
7541 *x += glyph->pixel_width;
7542 ++glyph;
7543 }
7544
7545 *hpos = glyph - row->glyphs[TEXT_AREA];
7546 return past_end;
7547}
7548
7549#else /* not 0 */
7550
b8009dd1 7551static int
7e376260 7552fast_find_position (w, pos, hpos, vpos, x, y, stop)
06a2c219 7553 struct window *w;
b8009dd1 7554 int pos;
06a2c219 7555 int *hpos, *vpos, *x, *y;
7e376260 7556 Lisp_Object stop;
b8009dd1 7557{
b8009dd1 7558 int i;
bf1c0ba1 7559 int lastcol;
06a2c219
GM
7560 int maybe_next_line_p = 0;
7561 int line_start_position;
7562 int yb = window_text_bottom_y (w);
03d1a189
GM
7563 struct glyph_row *row, *best_row;
7564 int row_vpos, best_row_vpos;
06a2c219
GM
7565 int current_x;
7566
03d1a189
GM
7567 row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7568 row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7569
06a2c219 7570 while (row->y < yb)
b8009dd1 7571 {
06a2c219
GM
7572 if (row->used[TEXT_AREA])
7573 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7574 else
7575 line_start_position = 0;
7576
7577 if (line_start_position > pos)
b8009dd1 7578 break;
77b68646
RS
7579 /* If the position sought is the end of the buffer,
7580 don't include the blank lines at the bottom of the window. */
06a2c219
GM
7581 else if (line_start_position == pos
7582 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 7583 {
06a2c219 7584 maybe_next_line_p = 1;
77b68646
RS
7585 break;
7586 }
06a2c219
GM
7587 else if (line_start_position > 0)
7588 {
7589 best_row = row;
7590 best_row_vpos = row_vpos;
7591 }
4b0bb6f3
GM
7592
7593 if (row->y + row->height >= yb)
7594 break;
06a2c219
GM
7595
7596 ++row;
7597 ++row_vpos;
b8009dd1 7598 }
06a2c219
GM
7599
7600 /* Find the right column within BEST_ROW. */
7601 lastcol = 0;
7602 current_x = best_row->x;
7603 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 7604 {
06a2c219 7605 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7e376260 7606 int charpos = glyph->charpos;
06a2c219 7607
7e376260 7608 if (BUFFERP (glyph->object))
bf1c0ba1 7609 {
7e376260
GM
7610 if (charpos == pos)
7611 {
7612 *hpos = i;
7613 *vpos = best_row_vpos;
7614 *x = current_x;
7615 *y = best_row->y;
7616 return 1;
7617 }
7618 else if (charpos > pos)
7619 break;
bf1c0ba1 7620 }
7e376260 7621 else if (EQ (glyph->object, stop))
4d73d038 7622 break;
06a2c219 7623
7e376260
GM
7624 if (charpos > 0)
7625 lastcol = i;
06a2c219 7626 current_x += glyph->pixel_width;
bf1c0ba1 7627 }
b8009dd1 7628
77b68646
RS
7629 /* If we're looking for the end of the buffer,
7630 and we didn't find it in the line we scanned,
7631 use the start of the following line. */
06a2c219 7632 if (maybe_next_line_p)
77b68646 7633 {
06a2c219
GM
7634 ++best_row;
7635 ++best_row_vpos;
7636 lastcol = 0;
7637 current_x = best_row->x;
77b68646
RS
7638 }
7639
06a2c219
GM
7640 *vpos = best_row_vpos;
7641 *hpos = lastcol + 1;
7642 *x = current_x;
7643 *y = best_row->y;
b8009dd1
RS
7644 return 0;
7645}
7646
9f8531e5
GM
7647#endif /* not 0 */
7648
06a2c219 7649
f9db2310
GM
7650/* Find the position of the the glyph for position POS in OBJECT in
7651 window W's current matrix, and return in *X/*Y the pixel
7652 coordinates, and return in *HPOS/*VPOS the column/row of the glyph.
7653
7654 RIGHT_P non-zero means return the position of the right edge of the
7655 glyph, RIGHT_P zero means return the left edge position.
7656
7657 If no glyph for POS exists in the matrix, return the position of
7658 the glyph with the next smaller position that is in the matrix, if
7659 RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS
7660 exists in the matrix, return the position of the glyph with the
7661 next larger position in OBJECT.
7662
7663 Value is non-zero if a glyph was found. */
7664
7665static int
7666fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
7667 struct window *w;
7668 int pos;
7669 Lisp_Object object;
7670 int *hpos, *vpos, *x, *y;
7671 int right_p;
7672{
7673 int yb = window_text_bottom_y (w);
7674 struct glyph_row *r;
7675 struct glyph *best_glyph = NULL;
7676 struct glyph_row *best_row = NULL;
7677 int best_x = 0;
7678
7679 for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7680 r->enabled_p && r->y < yb;
7681 ++r)
7682 {
7683 struct glyph *g = r->glyphs[TEXT_AREA];
7684 struct glyph *e = g + r->used[TEXT_AREA];
7685 int gx;
7686
7687 for (gx = r->x; g < e; gx += g->pixel_width, ++g)
7688 if (EQ (g->object, object))
7689 {
7690 if (g->charpos == pos)
7691 {
7692 best_glyph = g;
7693 best_x = gx;
7694 best_row = r;
7695 goto found;
7696 }
7697 else if (best_glyph == NULL
7698 || ((abs (g->charpos - pos)
7699 < abs (best_glyph->charpos - pos))
7700 && (right_p
7701 ? g->charpos < pos
7702 : g->charpos > pos)))
7703 {
7704 best_glyph = g;
7705 best_x = gx;
7706 best_row = r;
7707 }
7708 }
7709 }
7710
7711 found:
7712
7713 if (best_glyph)
7714 {
7715 *x = best_x;
7716 *hpos = best_glyph - best_row->glyphs[TEXT_AREA];
7717
7718 if (right_p)
7719 {
7720 *x += best_glyph->pixel_width;
7721 ++*hpos;
7722 }
7723
7724 *y = best_row->y;
7725 *vpos = best_row - w->current_matrix->rows;
7726 }
7727
7728 return best_glyph != NULL;
7729}
7730
7731
b8009dd1
RS
7732/* Display the active region described by mouse_face_*
7733 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7734
7735static void
06a2c219 7736show_mouse_face (dpyinfo, draw)
7a13e894 7737 struct x_display_info *dpyinfo;
06a2c219 7738 enum draw_glyphs_face draw;
b8009dd1 7739{
7a13e894 7740 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7741 struct frame *f = XFRAME (WINDOW_FRAME (w));
06a2c219 7742
b2bbd509
GM
7743 if (/* If window is in the process of being destroyed, don't bother
7744 to do anything. */
7745 w->current_matrix != NULL
7746 /* Recognize when we are called to operate on rows that don't exist
7747 anymore. This can happen when a window is split. */
7748 && dpyinfo->mouse_face_end_row < w->current_matrix->nrows)
06a2c219 7749 {
b2bbd509
GM
7750 int phys_cursor_on_p = w->phys_cursor_on_p;
7751 struct glyph_row *row, *first, *last;
06a2c219 7752
b2bbd509
GM
7753 first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row);
7754 last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row);
7755
7756 for (row = first; row <= last && row->enabled_p; ++row)
06a2c219 7757 {
b2bbd509 7758 int start_hpos, end_hpos, start_x;
06a2c219 7759
b2bbd509
GM
7760 /* For all but the first row, the highlight starts at column 0. */
7761 if (row == first)
7762 {
7763 start_hpos = dpyinfo->mouse_face_beg_col;
7764 start_x = dpyinfo->mouse_face_beg_x;
7765 }
7766 else
7767 {
7768 start_hpos = 0;
7769 start_x = 0;
7770 }
06a2c219 7771
b2bbd509
GM
7772 if (row == last)
7773 end_hpos = dpyinfo->mouse_face_end_col;
7774 else
7775 end_hpos = row->used[TEXT_AREA];
b8009dd1 7776
b2bbd509
GM
7777 if (end_hpos > start_hpos)
7778 {
7779 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7780 start_hpos, end_hpos, draw, 0);
b8009dd1 7781
b2bbd509
GM
7782 row->mouse_face_p = draw == DRAW_MOUSE_FACE || DRAW_IMAGE_RAISED;
7783 }
7784 }
2729a2b5 7785
b2bbd509
GM
7786 /* When we've written over the cursor, arrange for it to
7787 be displayed again. */
7788 if (phys_cursor_on_p && !w->phys_cursor_on_p)
7789 x_display_cursor (w, 1,
7790 w->phys_cursor.hpos, w->phys_cursor.vpos,
7791 w->phys_cursor.x, w->phys_cursor.y);
7792 }
fb3b7de5 7793
06a2c219
GM
7794 /* Change the mouse cursor. */
7795 if (draw == DRAW_NORMAL_TEXT)
7796 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7797 f->output_data.x->text_cursor);
7798 else if (draw == DRAW_MOUSE_FACE)
334208b7 7799 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7800 f->output_data.x->cross_cursor);
27ead1d5 7801 else
334208b7 7802 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7803 f->output_data.x->nontext_cursor);
b8009dd1
RS
7804}
7805
7806/* Clear out the mouse-highlighted active region.
fa262c07
GM
7807 Redraw it un-highlighted first. Value is non-zero if mouse
7808 face was actually drawn unhighlighted. */
b8009dd1 7809
fa262c07 7810static int
7a13e894
RS
7811clear_mouse_face (dpyinfo)
7812 struct x_display_info *dpyinfo;
b8009dd1 7813{
fa262c07 7814 int cleared = 0;
06a2c219 7815
fa262c07
GM
7816 if (!NILP (dpyinfo->mouse_face_window))
7817 {
7818 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
7819 cleared = 1;
7820 }
b8009dd1 7821
7a13e894
RS
7822 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7823 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7824 dpyinfo->mouse_face_window = Qnil;
1b85dc1c 7825 dpyinfo->mouse_face_overlay = Qnil;
fa262c07 7826 return cleared;
b8009dd1 7827}
e687d06e 7828
71b8321e
GM
7829
7830/* Clear any mouse-face on window W. This function is part of the
7831 redisplay interface, and is called from try_window_id and similar
7832 functions to ensure the mouse-highlight is off. */
7833
7834static void
7835x_clear_mouse_face (w)
7836 struct window *w;
7837{
7838 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7839 Lisp_Object window;
7840
2e636f9d 7841 BLOCK_INPUT;
71b8321e
GM
7842 XSETWINDOW (window, w);
7843 if (EQ (window, dpyinfo->mouse_face_window))
7844 clear_mouse_face (dpyinfo);
2e636f9d 7845 UNBLOCK_INPUT;
71b8321e
GM
7846}
7847
7848
e687d06e
RS
7849/* Just discard the mouse face information for frame F, if any.
7850 This is used when the size of F is changed. */
7851
dfcf069d 7852void
e687d06e
RS
7853cancel_mouse_face (f)
7854 FRAME_PTR f;
7855{
7856 Lisp_Object window;
7857 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7858
7859 window = dpyinfo->mouse_face_window;
7860 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7861 {
7862 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7863 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7864 dpyinfo->mouse_face_window = Qnil;
7865 }
7866}
b52b65bd 7867
b8009dd1 7868\f
b52b65bd
GM
7869static int glyph_rect P_ ((struct frame *f, int, int, XRectangle *));
7870
7871
7872/* Try to determine frame pixel position and size of the glyph under
7873 frame pixel coordinates X/Y on frame F . Return the position and
7874 size in *RECT. Value is non-zero if we could compute these
7875 values. */
7876
7877static int
7878glyph_rect (f, x, y, rect)
7879 struct frame *f;
7880 int x, y;
7881 XRectangle *rect;
7882{
7883 Lisp_Object window;
7884 int part, found = 0;
7885
7886 window = window_from_coordinates (f, x, y, &part, 0);
7887 if (!NILP (window))
7888 {
7889 struct window *w = XWINDOW (window);
7890 struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7891 struct glyph_row *end = r + w->current_matrix->nrows - 1;
b52b65bd
GM
7892
7893 frame_to_window_pixel_xy (w, &x, &y);
7894
7895 for (; !found && r < end && r->enabled_p; ++r)
7896 if (r->y >= y)
7897 {
7898 struct glyph *g = r->glyphs[TEXT_AREA];
7899 struct glyph *end = g + r->used[TEXT_AREA];
7900 int gx;
7901
7902 for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
7903 if (gx >= x)
7904 {
7905 rect->width = g->pixel_width;
7906 rect->height = r->height;
7907 rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
7908 rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
7909 found = 1;
7910 }
7911 }
7912 }
7913
7914 return found;
7915}
7916
12ba150f 7917
90e65f07 7918/* Return the current position of the mouse.
b52b65bd 7919 *FP should be a frame which indicates which display to ask about.
90e65f07 7920
b52b65bd
GM
7921 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
7922 and *PART to the frame, window, and scroll bar part that the mouse
7923 is over. Set *X and *Y to the portion and whole of the mouse's
ab648270 7924 position on the scroll bar.
12ba150f 7925
b52b65bd
GM
7926 If the mouse movement started elsewhere, set *FP to the frame the
7927 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
12ba150f
JB
7928 the mouse is over.
7929
b52b65bd 7930 Set *TIME to the server time-stamp for the time at which the mouse
12ba150f
JB
7931 was at this position.
7932
a135645a
RS
7933 Don't store anything if we don't have a valid set of values to report.
7934
90e65f07 7935 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7936 movement. */
90e65f07
JB
7937
7938static void
1cf412ec 7939XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7940 FRAME_PTR *fp;
1cf412ec 7941 int insist;
12ba150f 7942 Lisp_Object *bar_window;
ab648270 7943 enum scroll_bar_part *part;
90e65f07 7944 Lisp_Object *x, *y;
e5d77022 7945 unsigned long *time;
90e65f07 7946{
a135645a
RS
7947 FRAME_PTR f1;
7948
90e65f07
JB
7949 BLOCK_INPUT;
7950
8bcee03e 7951 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7952 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7953 else
7954 {
12ba150f
JB
7955 Window root;
7956 int root_x, root_y;
90e65f07 7957
12ba150f
JB
7958 Window dummy_window;
7959 int dummy;
7960
39d8bb4d
KH
7961 Lisp_Object frame, tail;
7962
7963 /* Clear the mouse-moved flag for every frame on this display. */
7964 FOR_EACH_FRAME (tail, frame)
7965 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7966 XFRAME (frame)->mouse_moved = 0;
7967
ab648270 7968 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7969
7970 /* Figure out which root window we're on. */
334208b7
RS
7971 XQueryPointer (FRAME_X_DISPLAY (*fp),
7972 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7973
7974 /* The root window which contains the pointer. */
7975 &root,
7976
7977 /* Trash which we can't trust if the pointer is on
7978 a different screen. */
7979 &dummy_window,
7980
7981 /* The position on that root window. */
58769bee 7982 &root_x, &root_y,
12ba150f
JB
7983
7984 /* More trash we can't trust. */
7985 &dummy, &dummy,
7986
7987 /* Modifier keys and pointer buttons, about which
7988 we don't care. */
7989 (unsigned int *) &dummy);
7990
7991 /* Now we have a position on the root; find the innermost window
7992 containing the pointer. */
7993 {
7994 Window win, child;
7995 int win_x, win_y;
06a2c219 7996 int parent_x = 0, parent_y = 0;
e99db5a1 7997 int count;
12ba150f
JB
7998
7999 win = root;
69388238 8000
2d7fc7e8
RS
8001 /* XTranslateCoordinates can get errors if the window
8002 structure is changing at the same time this function
8003 is running. So at least we must not crash from them. */
8004
e99db5a1 8005 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 8006
334208b7 8007 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 8008 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 8009 {
69388238
RS
8010 /* If mouse was grabbed on a frame, give coords for that frame
8011 even if the mouse is now outside it. */
334208b7 8012 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 8013
12ba150f 8014 /* From-window, to-window. */
69388238 8015 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
8016
8017 /* From-position, to-position. */
8018 root_x, root_y, &win_x, &win_y,
8019
8020 /* Child of win. */
8021 &child);
69388238
RS
8022 f1 = last_mouse_frame;
8023 }
8024 else
8025 {
8026 while (1)
8027 {
334208b7 8028 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 8029
69388238
RS
8030 /* From-window, to-window. */
8031 root, win,
12ba150f 8032
69388238
RS
8033 /* From-position, to-position. */
8034 root_x, root_y, &win_x, &win_y,
8035
8036 /* Child of win. */
8037 &child);
8038
9af3143a 8039 if (child == None || child == win)
69388238
RS
8040 break;
8041
8042 win = child;
8043 parent_x = win_x;
8044 parent_y = win_y;
8045 }
12ba150f 8046
69388238
RS
8047 /* Now we know that:
8048 win is the innermost window containing the pointer
8049 (XTC says it has no child containing the pointer),
8050 win_x and win_y are the pointer's position in it
8051 (XTC did this the last time through), and
8052 parent_x and parent_y are the pointer's position in win's parent.
8053 (They are what win_x and win_y were when win was child.
8054 If win is the root window, it has no parent, and
8055 parent_{x,y} are invalid, but that's okay, because we'll
8056 never use them in that case.) */
8057
8058 /* Is win one of our frames? */
19126e11 8059 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
aad0f6ab
GM
8060
8061#ifdef USE_X_TOOLKIT
8062 /* If we end up with the menu bar window, say it's not
8063 on the frame. */
8064 if (f1 != NULL
8065 && f1->output_data.x->menubar_widget
8066 && win == XtWindow (f1->output_data.x->menubar_widget))
8067 f1 = NULL;
8068#endif /* USE_X_TOOLKIT */
69388238 8069 }
58769bee 8070
2d7fc7e8
RS
8071 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
8072 f1 = 0;
8073
e99db5a1 8074 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 8075
ab648270 8076 /* If not, is it one of our scroll bars? */
a135645a 8077 if (! f1)
12ba150f 8078 {
ab648270 8079 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
8080
8081 if (bar)
8082 {
a135645a 8083 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
8084 win_x = parent_x;
8085 win_y = parent_y;
8086 }
8087 }
90e65f07 8088
8bcee03e 8089 if (f1 == 0 && insist > 0)
b86bd3dd 8090 f1 = SELECTED_FRAME ();
1cf412ec 8091
a135645a 8092 if (f1)
12ba150f 8093 {
06a2c219
GM
8094 /* Ok, we found a frame. Store all the values.
8095 last_mouse_glyph is a rectangle used to reduce the
8096 generation of mouse events. To not miss any motion
8097 events, we must divide the frame into rectangles of the
8098 size of the smallest character that could be displayed
8099 on it, i.e. into the same rectangles that matrices on
8100 the frame are divided into. */
8101
b52b65bd
GM
8102 int width, height, gx, gy;
8103 XRectangle rect;
8104
8105 if (glyph_rect (f1, win_x, win_y, &rect))
8106 last_mouse_glyph = rect;
8107 else
8108 {
8109 width = FRAME_SMALLEST_CHAR_WIDTH (f1);
8110 height = FRAME_SMALLEST_FONT_HEIGHT (f1);
8111 gx = win_x;
8112 gy = win_y;
06a2c219 8113
b52b65bd
GM
8114 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
8115 round down even for negative values. */
8116 if (gx < 0)
8117 gx -= width - 1;
4f00e84d 8118 if (gy < 0)
b52b65bd
GM
8119 gy -= height - 1;
8120 gx = (gx + width - 1) / width * width;
8121 gy = (gy + height - 1) / height * height;
8122
8123 last_mouse_glyph.width = width;
8124 last_mouse_glyph.height = height;
8125 last_mouse_glyph.x = gx;
8126 last_mouse_glyph.y = gy;
8127 }
12ba150f
JB
8128
8129 *bar_window = Qnil;
8130 *part = 0;
334208b7 8131 *fp = f1;
e0c1aef2
KH
8132 XSETINT (*x, win_x);
8133 XSETINT (*y, win_y);
12ba150f
JB
8134 *time = last_mouse_movement_time;
8135 }
8136 }
8137 }
90e65f07
JB
8138
8139 UNBLOCK_INPUT;
8140}
f451eb13 8141
06a2c219 8142
06a2c219 8143#ifdef USE_X_TOOLKIT
bffcfca9
GM
8144
8145/* Atimer callback function for TIMER. Called every 0.1s to process
8146 Xt timeouts, if needed. We must avoid calling XtAppPending as
8147 much as possible because that function does an implicit XFlush
8148 that slows us down. */
8149
8150static void
8151x_process_timeouts (timer)
8152 struct atimer *timer;
8153{
8154 if (toolkit_scroll_bar_interaction || popup_activated_flag)
8155 {
8156 BLOCK_INPUT;
8157 while (XtAppPending (Xt_app_con) & XtIMTimer)
8158 XtAppProcessEvent (Xt_app_con, XtIMTimer);
8159 UNBLOCK_INPUT;
8160 }
06a2c219
GM
8161}
8162
bffcfca9 8163#endif /* USE_X_TOOLKIT */
06a2c219
GM
8164
8165\f
8166/* Scroll bar support. */
8167
8168/* Given an X window ID, find the struct scroll_bar which manages it.
8169 This can be called in GC, so we have to make sure to strip off mark
8170 bits. */
bffcfca9 8171
06a2c219
GM
8172static struct scroll_bar *
8173x_window_to_scroll_bar (window_id)
8174 Window window_id;
8175{
8176 Lisp_Object tail;
8177
8178 for (tail = Vframe_list;
8179 XGCTYPE (tail) == Lisp_Cons;
8e713be6 8180 tail = XCDR (tail))
06a2c219
GM
8181 {
8182 Lisp_Object frame, bar, condemned;
8183
8e713be6 8184 frame = XCAR (tail);
06a2c219
GM
8185 /* All elements of Vframe_list should be frames. */
8186 if (! GC_FRAMEP (frame))
8187 abort ();
8188
8189 /* Scan this frame's scroll bar list for a scroll bar with the
8190 right window ID. */
8191 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
8192 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
8193 /* This trick allows us to search both the ordinary and
8194 condemned scroll bar lists with one loop. */
8195 ! GC_NILP (bar) || (bar = condemned,
8196 condemned = Qnil,
8197 ! GC_NILP (bar));
8198 bar = XSCROLL_BAR (bar)->next)
8199 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
8200 return XSCROLL_BAR (bar);
8201 }
8202
8203 return 0;
8204}
8205
8206
01f67d2c 8207#if defined USE_LUCID
c95fc5f1
GM
8208
8209/* Return the Lucid menu bar WINDOW is part of. Return null
8210 if WINDOW is not part of a menu bar. */
8211
8212static Widget
8213x_window_to_menu_bar (window)
8214 Window window;
8215{
8216 Lisp_Object tail;
8217
8218 for (tail = Vframe_list;
8219 XGCTYPE (tail) == Lisp_Cons;
8220 tail = XCDR (tail))
8221 {
8222 Lisp_Object frame = XCAR (tail);
8223 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
8224
8225 if (menu_bar && xlwmenu_window_p (menu_bar, window))
8226 return menu_bar;
8227 }
8228
8229 return NULL;
8230}
8231
01f67d2c 8232#endif /* USE_LUCID */
c95fc5f1 8233
06a2c219
GM
8234\f
8235/************************************************************************
8236 Toolkit scroll bars
8237 ************************************************************************/
8238
eccc05db 8239#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8240
8241static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
8242static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
8243static void x_create_toolkit_scroll_bar P_ ((struct frame *,
8244 struct scroll_bar *));
8245static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
8246 int, int, int));
8247
8248
8249/* Id of action hook installed for scroll bars. */
8250
8251static XtActionHookId action_hook_id;
8252
8253/* Lisp window being scrolled. Set when starting to interact with
8254 a toolkit scroll bar, reset to nil when ending the interaction. */
8255
8256static Lisp_Object window_being_scrolled;
8257
8258/* Last scroll bar part sent in xm_scroll_callback. */
8259
8260static int last_scroll_bar_part;
8261
ec18280f
SM
8262/* Whether this is an Xaw with arrow-scrollbars. This should imply
8263 that movements of 1/20 of the screen size are mapped to up/down. */
8264
8265static Boolean xaw3d_arrow_scroll;
8266
8267/* Whether the drag scrolling maintains the mouse at the top of the
8268 thumb. If not, resizing the thumb needs to be done more carefully
8269 to avoid jerkyness. */
8270
8271static Boolean xaw3d_pick_top;
8272
06a2c219
GM
8273
8274/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 8275 bars are used.. The hook is responsible for detecting when
06a2c219
GM
8276 the user ends an interaction with the scroll bar, and generates
8277 a `end-scroll' scroll_bar_click' event if so. */
8278
8279static void
8280xt_action_hook (widget, client_data, action_name, event, params,
8281 num_params)
8282 Widget widget;
8283 XtPointer client_data;
8284 String action_name;
8285 XEvent *event;
8286 String *params;
8287 Cardinal *num_params;
8288{
8289 int scroll_bar_p;
8290 char *end_action;
8291
8292#ifdef USE_MOTIF
8293 scroll_bar_p = XmIsScrollBar (widget);
8294 end_action = "Release";
ec18280f 8295#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8296 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
8297 end_action = "EndScroll";
ec18280f 8298#endif /* USE_MOTIF */
06a2c219 8299
06a2c219
GM
8300 if (scroll_bar_p
8301 && strcmp (action_name, end_action) == 0
8302 && WINDOWP (window_being_scrolled))
8303 {
8304 struct window *w;
8305
8306 x_send_scroll_bar_event (window_being_scrolled,
8307 scroll_bar_end_scroll, 0, 0);
8308 w = XWINDOW (window_being_scrolled);
8309 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
8310 window_being_scrolled = Qnil;
8311 last_scroll_bar_part = -1;
bffcfca9
GM
8312
8313 /* Xt timeouts no longer needed. */
8314 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
8315 }
8316}
8317
07b3d16e
GM
8318/* A vector of windows used for communication between
8319 x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
8320
8321static struct window **scroll_bar_windows;
8322static int scroll_bar_windows_size;
8323
06a2c219
GM
8324
8325/* Send a client message with message type Xatom_Scrollbar for a
8326 scroll action to the frame of WINDOW. PART is a value identifying
8327 the part of the scroll bar that was clicked on. PORTION is the
8328 amount to scroll of a whole of WHOLE. */
8329
8330static void
8331x_send_scroll_bar_event (window, part, portion, whole)
8332 Lisp_Object window;
8333 int part, portion, whole;
8334{
8335 XEvent event;
8336 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
07b3d16e
GM
8337 struct window *w = XWINDOW (window);
8338 struct frame *f = XFRAME (w->frame);
8339 int i;
06a2c219 8340
07b3d16e
GM
8341 BLOCK_INPUT;
8342
06a2c219
GM
8343 /* Construct a ClientMessage event to send to the frame. */
8344 ev->type = ClientMessage;
8345 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
8346 ev->display = FRAME_X_DISPLAY (f);
8347 ev->window = FRAME_X_WINDOW (f);
8348 ev->format = 32;
07b3d16e
GM
8349
8350 /* We can only transfer 32 bits in the XClientMessageEvent, which is
8351 not enough to store a pointer or Lisp_Object on a 64 bit system.
8352 So, store the window in scroll_bar_windows and pass the index
8353 into that array in the event. */
8354 for (i = 0; i < scroll_bar_windows_size; ++i)
8355 if (scroll_bar_windows[i] == NULL)
8356 break;
8357
8358 if (i == scroll_bar_windows_size)
8359 {
8360 int new_size = max (10, 2 * scroll_bar_windows_size);
8361 size_t nbytes = new_size * sizeof *scroll_bar_windows;
8362 size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows;
8363
8364 scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
8365 nbytes);
8366 bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
8367 scroll_bar_windows_size = new_size;
8368 }
8369
8370 scroll_bar_windows[i] = w;
8371 ev->data.l[0] = (long) i;
06a2c219
GM
8372 ev->data.l[1] = (long) part;
8373 ev->data.l[2] = (long) 0;
8374 ev->data.l[3] = (long) portion;
8375 ev->data.l[4] = (long) whole;
8376
bffcfca9
GM
8377 /* Make Xt timeouts work while the scroll bar is active. */
8378 toolkit_scroll_bar_interaction = 1;
8379
06a2c219
GM
8380 /* Setting the event mask to zero means that the message will
8381 be sent to the client that created the window, and if that
8382 window no longer exists, no event will be sent. */
06a2c219
GM
8383 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
8384 UNBLOCK_INPUT;
8385}
8386
8387
8388/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
8389 in *IEVENT. */
8390
8391static void
8392x_scroll_bar_to_input_event (event, ievent)
8393 XEvent *event;
8394 struct input_event *ievent;
8395{
8396 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
8397 Lisp_Object window;
8398 struct frame *f;
07b3d16e
GM
8399 struct window *w;
8400
8401 w = scroll_bar_windows[ev->data.l[0]];
8402 scroll_bar_windows[ev->data.l[0]] = NULL;
52e386c2 8403
07b3d16e
GM
8404 XSETWINDOW (window, w);
8405 f = XFRAME (w->frame);
06a2c219
GM
8406
8407 ievent->kind = scroll_bar_click;
8408 ievent->frame_or_window = window;
0f8aabe9 8409 ievent->arg = Qnil;
06a2c219
GM
8410 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
8411 ievent->part = ev->data.l[1];
8412 ievent->code = ev->data.l[2];
8413 ievent->x = make_number ((int) ev->data.l[3]);
8414 ievent->y = make_number ((int) ev->data.l[4]);
8415 ievent->modifiers = 0;
8416}
8417
8418
8419#ifdef USE_MOTIF
8420
8421/* Minimum and maximum values used for Motif scroll bars. */
8422
8423#define XM_SB_MIN 1
8424#define XM_SB_MAX 10000000
8425#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
8426
8427
8428/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
8429 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
8430 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
8431
8432static void
8433xm_scroll_callback (widget, client_data, call_data)
8434 Widget widget;
8435 XtPointer client_data, call_data;
8436{
8437 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8438 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
06a2c219
GM
8439 int part = -1, whole = 0, portion = 0;
8440
8441 switch (cs->reason)
8442 {
8443 case XmCR_DECREMENT:
8444 bar->dragging = Qnil;
8445 part = scroll_bar_up_arrow;
8446 break;
8447
8448 case XmCR_INCREMENT:
8449 bar->dragging = Qnil;
8450 part = scroll_bar_down_arrow;
8451 break;
8452
8453 case XmCR_PAGE_DECREMENT:
8454 bar->dragging = Qnil;
8455 part = scroll_bar_above_handle;
8456 break;
8457
8458 case XmCR_PAGE_INCREMENT:
8459 bar->dragging = Qnil;
8460 part = scroll_bar_below_handle;
8461 break;
8462
8463 case XmCR_TO_TOP:
8464 bar->dragging = Qnil;
8465 part = scroll_bar_to_top;
8466 break;
8467
8468 case XmCR_TO_BOTTOM:
8469 bar->dragging = Qnil;
8470 part = scroll_bar_to_bottom;
8471 break;
8472
8473 case XmCR_DRAG:
8474 {
8475 int slider_size;
8476 int dragging_down_p = (INTEGERP (bar->dragging)
8477 && XINT (bar->dragging) <= cs->value);
8478
8479 /* Get the slider size. */
8480 BLOCK_INPUT;
8481 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
8482 UNBLOCK_INPUT;
8483
8484 /* At the max position of the scroll bar, do a line-wise
23442ae4
GM
8485 movement. Without doing anything, we would be called with
8486 the same cs->value again and again. If we want to make
8487 sure that we can reach the end of the buffer, we have to do
8488 something.
06a2c219
GM
8489
8490 Implementation note: setting bar->dragging always to
8491 cs->value gives a smoother movement at the max position.
8492 Setting it to nil when doing line-wise movement gives
8493 a better slider behavior. */
8494
8495 if (cs->value + slider_size == XM_SB_MAX
8496 || (dragging_down_p
8497 && last_scroll_bar_part == scroll_bar_down_arrow))
8498 {
8499 part = scroll_bar_down_arrow;
8500 bar->dragging = Qnil;
8501 }
8502 else
8503 {
8504 whole = XM_SB_RANGE;
8505 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
8506 part = scroll_bar_handle;
8507 bar->dragging = make_number (cs->value);
8508 }
8509 }
8510 break;
8511
8512 case XmCR_VALUE_CHANGED:
8513 break;
8514 };
8515
8516 if (part >= 0)
8517 {
8518 window_being_scrolled = bar->window;
8519 last_scroll_bar_part = part;
8520 x_send_scroll_bar_event (bar->window, part, portion, whole);
8521 }
8522}
8523
8524
ec18280f 8525#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
8526
8527
ec18280f 8528/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
8529 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
8530 scroll bar struct. CALL_DATA is a pointer to a float saying where
8531 the thumb is. */
8532
8533static void
ec18280f 8534xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
8535 Widget widget;
8536 XtPointer client_data, call_data;
8537{
8538 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8539 float top = *(float *) call_data;
8540 float shown;
ec18280f
SM
8541 int whole, portion, height;
8542 int part;
06a2c219
GM
8543
8544 /* Get the size of the thumb, a value between 0 and 1. */
8545 BLOCK_INPUT;
ec18280f 8546 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
8547 UNBLOCK_INPUT;
8548
8549 whole = 10000000;
8550 portion = shown < 1 ? top * whole : 0;
06a2c219 8551
ec18280f
SM
8552 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
8553 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
8554 the bottom, so we force the scrolling whenever we see that we're
8555 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
8556 we try to ensure that we always stay two pixels away from the
8557 bottom). */
06a2c219
GM
8558 part = scroll_bar_down_arrow;
8559 else
8560 part = scroll_bar_handle;
8561
8562 window_being_scrolled = bar->window;
8563 bar->dragging = make_number (portion);
8564 last_scroll_bar_part = part;
8565 x_send_scroll_bar_event (bar->window, part, portion, whole);
8566}
8567
8568
ec18280f
SM
8569/* Xaw scroll bar callback. Invoked for incremental scrolling.,
8570 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
8571 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
8572 the scroll bar. CALL_DATA is an integer specifying the action that
8573 has taken place. It's magnitude is in the range 0..height of the
8574 scroll bar. Negative values mean scroll towards buffer start.
8575 Values < height of scroll bar mean line-wise movement. */
8576
8577static void
ec18280f 8578xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
8579 Widget widget;
8580 XtPointer client_data, call_data;
8581{
8582 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8583 int position = (int) call_data;
8584 Dimension height;
8585 int part;
8586
8587 /* Get the height of the scroll bar. */
8588 BLOCK_INPUT;
8589 XtVaGetValues (widget, XtNheight, &height, NULL);
8590 UNBLOCK_INPUT;
8591
ec18280f
SM
8592 if (abs (position) >= height)
8593 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
8594
8595 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
8596 it maps line-movement to call_data = max(5, height/20). */
8597 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
8598 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 8599 else
ec18280f 8600 part = scroll_bar_move_ratio;
06a2c219
GM
8601
8602 window_being_scrolled = bar->window;
8603 bar->dragging = Qnil;
8604 last_scroll_bar_part = part;
ec18280f 8605 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
8606}
8607
8608
8609#endif /* not USE_MOTIF */
8610
8611
8612/* Create the widget for scroll bar BAR on frame F. Record the widget
8613 and X window of the scroll bar in BAR. */
8614
8615static void
8616x_create_toolkit_scroll_bar (f, bar)
8617 struct frame *f;
8618 struct scroll_bar *bar;
8619{
8620 Window xwindow;
8621 Widget widget;
8622 Arg av[20];
8623 int ac = 0;
8624 char *scroll_bar_name = "verticalScrollBar";
8625 unsigned long pixel;
8626
8627 BLOCK_INPUT;
8628
8629#ifdef USE_MOTIF
06a2c219
GM
8630 /* Set resources. Create the widget. */
8631 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8632 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
8633 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
8634 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
8635 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
8636 XtSetArg (av[ac], XmNincrement, 1); ++ac;
8637 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
8638
8639 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8640 if (pixel != -1)
8641 {
8642 XtSetArg (av[ac], XmNforeground, pixel);
8643 ++ac;
8644 }
8645
8646 pixel = f->output_data.x->scroll_bar_background_pixel;
8647 if (pixel != -1)
8648 {
8649 XtSetArg (av[ac], XmNbackground, pixel);
8650 ++ac;
8651 }
8652
8653 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
8654 scroll_bar_name, av, ac);
8655
8656 /* Add one callback for everything that can happen. */
8657 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
8658 (XtPointer) bar);
8659 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
8660 (XtPointer) bar);
8661 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
8662 (XtPointer) bar);
8663 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
8664 (XtPointer) bar);
8665 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
8666 (XtPointer) bar);
8667 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
8668 (XtPointer) bar);
8669 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
8670 (XtPointer) bar);
8671
8672 /* Realize the widget. Only after that is the X window created. */
8673 XtRealizeWidget (widget);
8674
8675 /* Set the cursor to an arrow. I didn't find a resource to do that.
8676 And I'm wondering why it hasn't an arrow cursor by default. */
8677 XDefineCursor (XtDisplay (widget), XtWindow (widget),
8678 f->output_data.x->nontext_cursor);
8679
ec18280f 8680#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8681
8682 /* Set resources. Create the widget. The background of the
8683 Xaw3d scroll bar widget is a little bit light for my taste.
8684 We don't alter it here to let users change it according
8685 to their taste with `emacs*verticalScrollBar.background: xxx'. */
8686 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8687 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
8688 /* For smoother scrolling with Xaw3d -sm */
8689 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
06a2c219
GM
8690
8691 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8692 if (pixel != -1)
8693 {
8694 XtSetArg (av[ac], XtNforeground, pixel);
8695 ++ac;
8696 }
8697
8698 pixel = f->output_data.x->scroll_bar_background_pixel;
8699 if (pixel != -1)
8700 {
8701 XtSetArg (av[ac], XtNbackground, pixel);
8702 ++ac;
8703 }
7c1bef7a
MB
8704
8705 /* Top/bottom shadow colors. */
8706
8707 /* Allocate them, if necessary. */
8708 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
8709 {
8710 pixel = f->output_data.x->scroll_bar_background_pixel;
8711 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8712 &pixel, 1.2, 0x8000))
8713 pixel = -1;
8714 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
8715 }
8716 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8717 {
8718 pixel = f->output_data.x->scroll_bar_background_pixel;
8719 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8720 &pixel, 0.6, 0x4000))
8721 pixel = -1;
8722 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
8723 }
8724
8725 /* Tell the toolkit about them. */
8726 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
8727 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8728 /* We tried to allocate a color for the top/bottom shadow, and
8729 failed, so tell Xaw3d to use dithering instead. */
8730 {
8731 XtSetArg (av[ac], XtNbeNiceToColormap, True);
8732 ++ac;
8733 }
8734 else
8735 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
8736 be more consistent with other emacs 3d colors, and since Xaw3d is
8737 not good at dealing with allocation failure. */
8738 {
8739 /* This tells Xaw3d to use real colors instead of dithering for
8740 the shadows. */
8741 XtSetArg (av[ac], XtNbeNiceToColormap, False);
8742 ++ac;
8743
8744 /* Specify the colors. */
8745 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
8746 if (pixel != -1)
8747 {
8748 XtSetArg (av[ac], "topShadowPixel", pixel);
8749 ++ac;
8750 }
8751 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
8752 if (pixel != -1)
8753 {
8754 XtSetArg (av[ac], "bottomShadowPixel", pixel);
8755 ++ac;
8756 }
8757 }
8758
06a2c219
GM
8759 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
8760 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
8761
8762 {
8763 char *initial = "";
8764 char *val = initial;
8765 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
8766 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
8767 if (val == initial)
8768 { /* ARROW_SCROLL */
8769 xaw3d_arrow_scroll = True;
8770 /* Isn't that just a personal preference ? -sm */
8771 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
8772 }
8773 }
06a2c219
GM
8774
8775 /* Define callbacks. */
ec18280f
SM
8776 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
8777 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
8778 (XtPointer) bar);
8779
8780 /* Realize the widget. Only after that is the X window created. */
8781 XtRealizeWidget (widget);
8782
ec18280f 8783#endif /* !USE_MOTIF */
06a2c219
GM
8784
8785 /* Install an action hook that let's us detect when the user
8786 finishes interacting with a scroll bar. */
8787 if (action_hook_id == 0)
8788 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
8789
8790 /* Remember X window and widget in the scroll bar vector. */
8791 SET_SCROLL_BAR_X_WIDGET (bar, widget);
8792 xwindow = XtWindow (widget);
8793 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
8794
8795 UNBLOCK_INPUT;
8796}
8797
8798
8799/* Set the thumb size and position of scroll bar BAR. We are currently
8800 displaying PORTION out of a whole WHOLE, and our position POSITION. */
8801
8802static void
8803x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
8804 struct scroll_bar *bar;
8805 int portion, position, whole;
f451eb13 8806{
e83dc917
GM
8807 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8808 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
06a2c219 8809 float top, shown;
f451eb13 8810
06a2c219
GM
8811 if (whole == 0)
8812 top = 0, shown = 1;
8813 else
f451eb13 8814 {
06a2c219
GM
8815 top = (float) position / whole;
8816 shown = (float) portion / whole;
8817 }
f451eb13 8818
06a2c219 8819 BLOCK_INPUT;
f451eb13 8820
06a2c219
GM
8821#ifdef USE_MOTIF
8822 {
8823 int size, value;
06a2c219 8824
ec18280f 8825 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
8826 is the scroll bar's maximum and MIN is the scroll bar's minimum
8827 value. */
8828 size = shown * XM_SB_RANGE;
8829 size = min (size, XM_SB_RANGE);
8830 size = max (size, 1);
8831
8832 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
8833 value = top * XM_SB_RANGE;
8834 value = min (value, XM_SB_MAX - size);
8835 value = max (value, XM_SB_MIN);
8836
06a2c219
GM
8837 if (NILP (bar->dragging))
8838 XmScrollBarSetValues (widget, value, size, 0, 0, False);
8839 else if (last_scroll_bar_part == scroll_bar_down_arrow)
8840 /* This has the negative side effect that the slider value is
ec18280f 8841 not what it would be if we scrolled here using line-wise or
06a2c219
GM
8842 page-wise movement. */
8843 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
8844 else
8845 {
8846 /* If currently dragging, only update the slider size.
8847 This reduces flicker effects. */
8848 int old_value, old_size, increment, page_increment;
8849
8850 XmScrollBarGetValues (widget, &old_value, &old_size,
8851 &increment, &page_increment);
8852 XmScrollBarSetValues (widget, old_value,
8853 min (size, XM_SB_RANGE - old_value),
8854 0, 0, False);
8855 }
06a2c219 8856 }
ec18280f 8857#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 8858 {
ec18280f
SM
8859 float old_top, old_shown;
8860 Dimension height;
8861 XtVaGetValues (widget,
8862 XtNtopOfThumb, &old_top,
8863 XtNshown, &old_shown,
8864 XtNheight, &height,
8865 NULL);
8866
8867 /* Massage the top+shown values. */
8868 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8869 top = max (0, min (1, top));
8870 else
8871 top = old_top;
8872 /* Keep two pixels available for moving the thumb down. */
8873 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8874
8875 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8876 check that your system's configuration file contains a define
8877 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8878 if (top != old_top || shown != old_shown)
eb393530 8879 {
ec18280f 8880 if (NILP (bar->dragging))
eb393530 8881 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8882 else
8883 {
ec18280f
SM
8884#ifdef HAVE_XAW3D
8885 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8886 int scroll_mode = 0;
ec18280f
SM
8887
8888 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8889 if (xaw3d_arrow_scroll)
8890 {
8891 /* Xaw3d stupidly ignores resize requests while dragging
8892 so we have to make it believe it's not in dragging mode. */
8893 scroll_mode = sb->scrollbar.scroll_mode;
8894 if (scroll_mode == 2)
8895 sb->scrollbar.scroll_mode = 0;
8896 }
8897#endif
8898 /* Try to make the scrolling a tad smoother. */
8899 if (!xaw3d_pick_top)
8900 shown = min (shown, old_shown);
8901
8902 XawScrollbarSetThumb (widget, top, shown);
8903
8904#ifdef HAVE_XAW3D
8905 if (xaw3d_arrow_scroll && scroll_mode == 2)
8906 sb->scrollbar.scroll_mode = scroll_mode;
8907#endif
06a2c219 8908 }
06a2c219
GM
8909 }
8910 }
ec18280f 8911#endif /* !USE_MOTIF */
06a2c219
GM
8912
8913 UNBLOCK_INPUT;
f451eb13
JB
8914}
8915
06a2c219
GM
8916#endif /* USE_TOOLKIT_SCROLL_BARS */
8917
8918
8919\f
8920/************************************************************************
8921 Scroll bars, general
8922 ************************************************************************/
8923
8924/* Create a scroll bar and return the scroll bar vector for it. W is
8925 the Emacs window on which to create the scroll bar. TOP, LEFT,
8926 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8927 scroll bar. */
8928
ab648270 8929static struct scroll_bar *
06a2c219
GM
8930x_scroll_bar_create (w, top, left, width, height)
8931 struct window *w;
f451eb13
JB
8932 int top, left, width, height;
8933{
06a2c219 8934 struct frame *f = XFRAME (w->frame);
334208b7
RS
8935 struct scroll_bar *bar
8936 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8937
8938 BLOCK_INPUT;
8939
eccc05db 8940#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8941 x_create_toolkit_scroll_bar (f, bar);
8942#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8943 {
8944 XSetWindowAttributes a;
8945 unsigned long mask;
5c187dee 8946 Window window;
06a2c219
GM
8947
8948 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8949 if (a.background_pixel == -1)
8950 a.background_pixel = f->output_data.x->background_pixel;
8951
12ba150f 8952 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 8953 | ButtonMotionMask | PointerMotionHintMask
12ba150f 8954 | ExposureMask);
7a13e894 8955 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 8956
dbc4e1c1 8957 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8958
06a2c219
GM
8959 /* Clear the area of W that will serve as a scroll bar. This is
8960 for the case that a window has been split horizontally. In
8961 this case, no clear_frame is generated to reduce flickering. */
7b49b9d2
GM
8962 if (width > 0 && height > 0)
8963 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8964 left, top, width,
8965 window_box_height (w), False);
06a2c219
GM
8966
8967 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8968 /* Position and size of scroll bar. */
8969 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8970 top,
8971 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8972 height,
8973 /* Border width, depth, class, and visual. */
8974 0,
8975 CopyFromParent,
8976 CopyFromParent,
8977 CopyFromParent,
8978 /* Attributes. */
8979 mask, &a);
8980 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 8981 }
06a2c219 8982#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8983
06a2c219 8984 XSETWINDOW (bar->window, w);
e0c1aef2
KH
8985 XSETINT (bar->top, top);
8986 XSETINT (bar->left, left);
8987 XSETINT (bar->width, width);
8988 XSETINT (bar->height, height);
8989 XSETINT (bar->start, 0);
8990 XSETINT (bar->end, 0);
12ba150f 8991 bar->dragging = Qnil;
f451eb13
JB
8992
8993 /* Add bar to its frame's list of scroll bars. */
334208b7 8994 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8995 bar->prev = Qnil;
334208b7 8996 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 8997 if (!NILP (bar->next))
e0c1aef2 8998 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 8999
06a2c219 9000 /* Map the window/widget. */
eccc05db 9001#ifdef USE_TOOLKIT_SCROLL_BARS
f964b4d7
GM
9002 {
9003 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
9004 XtConfigureWidget (scroll_bar,
9005 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9006 top,
9007 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
9008 max (height, 1), 0);
9009 XtMapWidget (scroll_bar);
9010 }
06a2c219 9011#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 9012 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 9013#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9014
9015 UNBLOCK_INPUT;
12ba150f 9016 return bar;
f451eb13
JB
9017}
9018
06a2c219 9019
12ba150f 9020/* Draw BAR's handle in the proper position.
06a2c219 9021
12ba150f
JB
9022 If the handle is already drawn from START to END, don't bother
9023 redrawing it, unless REBUILD is non-zero; in that case, always
9024 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 9025 events.)
12ba150f
JB
9026
9027 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
9028 fit inside its rectangle, but if the user is dragging the scroll
9029 bar handle, we want to let them drag it down all the way, so that
9030 the bar's top is as far down as it goes; otherwise, there's no way
9031 to move to the very end of the buffer. */
9032
5c187dee
GM
9033#ifndef USE_TOOLKIT_SCROLL_BARS
9034
f451eb13 9035static void
ab648270
JB
9036x_scroll_bar_set_handle (bar, start, end, rebuild)
9037 struct scroll_bar *bar;
f451eb13 9038 int start, end;
12ba150f 9039 int rebuild;
f451eb13 9040{
12ba150f 9041 int dragging = ! NILP (bar->dragging);
ab648270 9042 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9043 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9044 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
9045
9046 /* If the display is already accurate, do nothing. */
9047 if (! rebuild
9048 && start == XINT (bar->start)
9049 && end == XINT (bar->end))
9050 return;
9051
f451eb13
JB
9052 BLOCK_INPUT;
9053
9054 {
d9cdbb3d
RS
9055 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
9056 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
9057 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
9058
9059 /* Make sure the values are reasonable, and try to preserve
9060 the distance between start and end. */
12ba150f
JB
9061 {
9062 int length = end - start;
9063
9064 if (start < 0)
9065 start = 0;
9066 else if (start > top_range)
9067 start = top_range;
9068 end = start + length;
9069
9070 if (end < start)
9071 end = start;
9072 else if (end > top_range && ! dragging)
9073 end = top_range;
9074 }
f451eb13 9075
ab648270 9076 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
9077 XSETINT (bar->start, start);
9078 XSETINT (bar->end, end);
f451eb13 9079
12ba150f
JB
9080 /* Clip the end position, just for display. */
9081 if (end > top_range)
9082 end = top_range;
f451eb13 9083
ab648270 9084 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
9085 below top positions, to make sure the handle is always at least
9086 that many pixels tall. */
ab648270 9087 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 9088
12ba150f
JB
9089 /* Draw the empty space above the handle. Note that we can't clear
9090 zero-height areas; that means "clear to end of window." */
9091 if (0 < start)
c5e6e06b
GM
9092 x_clear_area (FRAME_X_DISPLAY (f), w,
9093 /* x, y, width, height, and exposures. */
9094 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9095 VERTICAL_SCROLL_BAR_TOP_BORDER,
9096 inside_width, start,
9097 False);
f451eb13 9098
06a2c219
GM
9099 /* Change to proper foreground color if one is specified. */
9100 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9101 XSetForeground (FRAME_X_DISPLAY (f), gc,
9102 f->output_data.x->scroll_bar_foreground_pixel);
9103
12ba150f 9104 /* Draw the handle itself. */
334208b7 9105 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
12ba150f 9106 /* x, y, width, height */
ab648270
JB
9107 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9108 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 9109 inside_width, end - start);
f451eb13 9110
06a2c219
GM
9111 /* Restore the foreground color of the GC if we changed it above. */
9112 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9113 XSetForeground (FRAME_X_DISPLAY (f), gc,
9114 f->output_data.x->foreground_pixel);
f451eb13 9115
12ba150f
JB
9116 /* Draw the empty space below the handle. Note that we can't
9117 clear zero-height areas; that means "clear to end of window." */
9118 if (end < inside_height)
c5e6e06b
GM
9119 x_clear_area (FRAME_X_DISPLAY (f), w,
9120 /* x, y, width, height, and exposures. */
9121 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9122 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
9123 inside_width, inside_height - end,
9124 False);
f451eb13 9125
f451eb13
JB
9126 }
9127
f451eb13
JB
9128 UNBLOCK_INPUT;
9129}
9130
5c187dee 9131#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 9132
06a2c219
GM
9133/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
9134 nil. */
58769bee 9135
12ba150f 9136static void
ab648270
JB
9137x_scroll_bar_remove (bar)
9138 struct scroll_bar *bar;
12ba150f 9139{
e83dc917 9140 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
9141 BLOCK_INPUT;
9142
eccc05db 9143#ifdef USE_TOOLKIT_SCROLL_BARS
e83dc917
GM
9144 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
9145#else
9146 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
9147#endif
06a2c219 9148
ab648270
JB
9149 /* Disassociate this scroll bar from its window. */
9150 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
9151
9152 UNBLOCK_INPUT;
9153}
9154
06a2c219 9155
12ba150f
JB
9156/* Set the handle of the vertical scroll bar for WINDOW to indicate
9157 that we are displaying PORTION characters out of a total of WHOLE
ab648270 9158 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 9159 create one. */
06a2c219 9160
12ba150f 9161static void
06a2c219
GM
9162XTset_vertical_scroll_bar (w, portion, whole, position)
9163 struct window *w;
f451eb13
JB
9164 int portion, whole, position;
9165{
06a2c219 9166 struct frame *f = XFRAME (w->frame);
ab648270 9167 struct scroll_bar *bar;
3c6ede7b 9168 int top, height, left, sb_left, width, sb_width;
06a2c219 9169 int window_x, window_y, window_width, window_height;
06a2c219 9170
3c6ede7b 9171 /* Get window dimensions. */
06a2c219 9172 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
9173 top = window_y;
9174 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9175 height = window_height;
06a2c219 9176
3c6ede7b 9177 /* Compute the left edge of the scroll bar area. */
06a2c219 9178 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
9179 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
9180 else
9181 left = XFASTINT (w->left);
9182 left *= CANON_X_UNIT (f);
9183 left += FRAME_INTERNAL_BORDER_WIDTH (f);
9184
9185 /* Compute the width of the scroll bar which might be less than
9186 the width of the area reserved for the scroll bar. */
9187 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
9188 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 9189 else
3c6ede7b 9190 sb_width = width;
12ba150f 9191
3c6ede7b
GM
9192 /* Compute the left edge of the scroll bar. */
9193#ifdef USE_TOOLKIT_SCROLL_BARS
9194 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9195 sb_left = left + width - sb_width - (width - sb_width) / 2;
9196 else
9197 sb_left = left + (width - sb_width) / 2;
9198#else
9199 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9200 sb_left = left + width - sb_width;
9201 else
9202 sb_left = left;
9203#endif
9204
ab648270 9205 /* Does the scroll bar exist yet? */
06a2c219 9206 if (NILP (w->vertical_scroll_bar))
3c6ede7b 9207 {
7b49b9d2 9208 if (width > 0 && height > 0)
b547b6e8
GM
9209 {
9210 BLOCK_INPUT;
9211 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9212 left, top, width, height, False);
9213 UNBLOCK_INPUT;
9214 }
9215
3c6ede7b
GM
9216 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
9217 }
f451eb13 9218 else
12ba150f
JB
9219 {
9220 /* It may just need to be moved and resized. */
06a2c219
GM
9221 unsigned int mask = 0;
9222
9223 bar = XSCROLL_BAR (w->vertical_scroll_bar);
9224
9225 BLOCK_INPUT;
9226
3c6ede7b 9227 if (sb_left != XINT (bar->left))
06a2c219 9228 mask |= CWX;
3c6ede7b 9229 if (top != XINT (bar->top))
06a2c219 9230 mask |= CWY;
3c6ede7b 9231 if (sb_width != XINT (bar->width))
06a2c219 9232 mask |= CWWidth;
3c6ede7b 9233 if (height != XINT (bar->height))
06a2c219
GM
9234 mask |= CWHeight;
9235
9236#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
9237
9238 /* Since toolkit scroll bars are smaller than the space reserved
9239 for them on the frame, we have to clear "under" them. */
7b49b9d2 9240 if (width > 0 && height > 0)
f964b4d7
GM
9241 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9242 left, top, width, height, False);
06a2c219
GM
9243
9244 /* Move/size the scroll bar widget. */
9245 if (mask)
e83dc917 9246 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
3c6ede7b
GM
9247 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9248 top,
9249 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
f964b4d7 9250 max (height, 1), 0);
06a2c219
GM
9251
9252#else /* not USE_TOOLKIT_SCROLL_BARS */
9253
357e7376
GM
9254 /* Clear areas not covered by the scroll bar because of
9255 VERTICAL_SCROLL_BAR_WIDTH_TRIM. */
e1f6572f
RS
9256 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
9257 {
c5e6e06b
GM
9258 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9259 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9260 height, False);
9261 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9262 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9263 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9264 height, False);
e1f6572f 9265 }
357e7376
GM
9266
9267 /* Clear areas not covered by the scroll bar because it's not as
9268 wide as the area reserved for it . This makes sure a
9269 previous mode line display is cleared after C-x 2 C-x 1, for
9270 example. */
9271 {
9272 int area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9273 int rest = area_width - sb_width;
38d2af0c
GM
9274 if (rest > 0 && height > 0)
9275 {
9276 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
9277 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9278 left + area_width - rest, top,
9279 rest, height, False);
9280 else
9281 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9282 left, top, rest, height, False);
9283 }
357e7376 9284 }
06a2c219
GM
9285
9286 /* Move/size the scroll bar window. */
9287 if (mask)
9288 {
9289 XWindowChanges wc;
9290
3c6ede7b
GM
9291 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
9292 wc.y = top;
9293 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
9294 wc.height = height;
06a2c219
GM
9295 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
9296 mask, &wc);
9297 }
9298
9299#endif /* not USE_TOOLKIT_SCROLL_BARS */
9300
9301 /* Remember new settings. */
3c6ede7b
GM
9302 XSETINT (bar->left, sb_left);
9303 XSETINT (bar->top, top);
9304 XSETINT (bar->width, sb_width);
9305 XSETINT (bar->height, height);
06a2c219
GM
9306
9307 UNBLOCK_INPUT;
12ba150f 9308 }
f451eb13 9309
eccc05db 9310#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
9311 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
9312#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 9313 /* Set the scroll bar's current state, unless we're currently being
f451eb13 9314 dragged. */
12ba150f 9315 if (NILP (bar->dragging))
f451eb13 9316 {
92857db0 9317 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 9318
12ba150f 9319 if (whole == 0)
ab648270 9320 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
9321 else
9322 {
43f868f5
JB
9323 int start = ((double) position * top_range) / whole;
9324 int end = ((double) (position + portion) * top_range) / whole;
ab648270 9325 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 9326 }
f451eb13 9327 }
06a2c219 9328#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9329
06a2c219 9330 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
9331}
9332
12ba150f 9333
f451eb13 9334/* The following three hooks are used when we're doing a thorough
ab648270 9335 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 9336 are going to be deleted, because keeping track of when windows go
12ba150f
JB
9337 away is a real pain - "Can you say set-window-configuration, boys
9338 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 9339 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 9340 from the fiery pit when we actually redisplay its window. */
f451eb13 9341
ab648270
JB
9342/* Arrange for all scroll bars on FRAME to be removed at the next call
9343 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
9344 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
9345
58769bee 9346static void
ab648270 9347XTcondemn_scroll_bars (frame)
f451eb13
JB
9348 FRAME_PTR frame;
9349{
f9e24cb9
RS
9350 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
9351 while (! NILP (FRAME_SCROLL_BARS (frame)))
9352 {
9353 Lisp_Object bar;
9354 bar = FRAME_SCROLL_BARS (frame);
9355 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
9356 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
9357 XSCROLL_BAR (bar)->prev = Qnil;
9358 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
9359 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
9360 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
9361 }
f451eb13
JB
9362}
9363
fa2dfc30 9364
06a2c219 9365/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 9366 Note that WINDOW isn't necessarily condemned at all. */
fa2dfc30 9367
f451eb13 9368static void
ab648270 9369XTredeem_scroll_bar (window)
12ba150f 9370 struct window *window;
f451eb13 9371{
ab648270 9372 struct scroll_bar *bar;
fa2dfc30 9373 struct frame *f;
12ba150f 9374
ab648270
JB
9375 /* We can't redeem this window's scroll bar if it doesn't have one. */
9376 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
9377 abort ();
9378
ab648270 9379 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
9380
9381 /* Unlink it from the condemned list. */
fa2dfc30
GM
9382 f = XFRAME (WINDOW_FRAME (window));
9383 if (NILP (bar->prev))
9384 {
9385 /* If the prev pointer is nil, it must be the first in one of
9386 the lists. */
9387 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
9388 /* It's not condemned. Everything's fine. */
9389 return;
9390 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
9391 window->vertical_scroll_bar))
9392 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
9393 else
9394 /* If its prev pointer is nil, it must be at the front of
9395 one or the other! */
9396 abort ();
9397 }
9398 else
9399 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f 9400
fa2dfc30
GM
9401 if (! NILP (bar->next))
9402 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 9403
fa2dfc30
GM
9404 bar->next = FRAME_SCROLL_BARS (f);
9405 bar->prev = Qnil;
9406 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
9407 if (! NILP (bar->next))
9408 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13
JB
9409}
9410
ab648270
JB
9411/* Remove all scroll bars on FRAME that haven't been saved since the
9412 last call to `*condemn_scroll_bars_hook'. */
06a2c219 9413
f451eb13 9414static void
ab648270 9415XTjudge_scroll_bars (f)
12ba150f 9416 FRAME_PTR f;
f451eb13 9417{
12ba150f 9418 Lisp_Object bar, next;
f451eb13 9419
ab648270 9420 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
9421
9422 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
9423 more events on the hapless scroll bars. */
9424 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
9425
9426 for (; ! NILP (bar); bar = next)
f451eb13 9427 {
ab648270 9428 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 9429
ab648270 9430 x_scroll_bar_remove (b);
12ba150f
JB
9431
9432 next = b->next;
9433 b->next = b->prev = Qnil;
f451eb13 9434 }
12ba150f 9435
ab648270 9436 /* Now there should be no references to the condemned scroll bars,
12ba150f 9437 and they should get garbage-collected. */
f451eb13
JB
9438}
9439
9440
06a2c219
GM
9441/* Handle an Expose or GraphicsExpose event on a scroll bar. This
9442 is a no-op when using toolkit scroll bars.
ab648270
JB
9443
9444 This may be called from a signal handler, so we have to ignore GC
9445 mark bits. */
06a2c219 9446
f451eb13 9447static void
ab648270
JB
9448x_scroll_bar_expose (bar, event)
9449 struct scroll_bar *bar;
f451eb13
JB
9450 XEvent *event;
9451{
06a2c219
GM
9452#ifndef USE_TOOLKIT_SCROLL_BARS
9453
ab648270 9454 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9455 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9456 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 9457 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 9458
f451eb13
JB
9459 BLOCK_INPUT;
9460
ab648270 9461 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 9462
06a2c219 9463 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 9464 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
9465
9466 /* x, y, width, height */
d9cdbb3d 9467 0, 0,
3cbd2e0b 9468 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
9469 XINT (bar->height) - 1);
9470
f451eb13 9471 UNBLOCK_INPUT;
06a2c219
GM
9472
9473#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9474}
9475
ab648270
JB
9476/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
9477 is set to something other than no_event, it is enqueued.
9478
9479 This may be called from a signal handler, so we have to ignore GC
9480 mark bits. */
06a2c219 9481
5c187dee
GM
9482#ifndef USE_TOOLKIT_SCROLL_BARS
9483
f451eb13 9484static void
ab648270
JB
9485x_scroll_bar_handle_click (bar, event, emacs_event)
9486 struct scroll_bar *bar;
f451eb13
JB
9487 XEvent *event;
9488 struct input_event *emacs_event;
9489{
0299d313 9490 if (! GC_WINDOWP (bar->window))
12ba150f
JB
9491 abort ();
9492
ab648270 9493 emacs_event->kind = scroll_bar_click;
69388238 9494 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
9495 emacs_event->modifiers
9496 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
9497 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
9498 event->xbutton.state)
9499 | (event->type == ButtonRelease
9500 ? up_modifier
9501 : down_modifier));
12ba150f 9502 emacs_event->frame_or_window = bar->window;
0f8aabe9 9503 emacs_event->arg = Qnil;
f451eb13 9504 emacs_event->timestamp = event->xbutton.time;
12ba150f 9505 {
06a2c219 9506#if 0
d9cdbb3d 9507 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 9508 int internal_height
d9cdbb3d 9509 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9510#endif
0299d313 9511 int top_range
d9cdbb3d 9512 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 9513 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
9514
9515 if (y < 0) y = 0;
9516 if (y > top_range) y = top_range;
9517
9518 if (y < XINT (bar->start))
ab648270
JB
9519 emacs_event->part = scroll_bar_above_handle;
9520 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9521 emacs_event->part = scroll_bar_handle;
12ba150f 9522 else
ab648270 9523 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
9524
9525 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
9526 they want to drag it. Lisp code needs to be able to decide
9527 whether or not we're dragging. */
929787e1 9528#if 0
12ba150f
JB
9529 /* If the user has just clicked on the handle, record where they're
9530 holding it. */
9531 if (event->type == ButtonPress
ab648270 9532 && emacs_event->part == scroll_bar_handle)
e0c1aef2 9533 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 9534#endif
12ba150f
JB
9535
9536 /* If the user has released the handle, set it to its final position. */
9537 if (event->type == ButtonRelease
9538 && ! NILP (bar->dragging))
9539 {
9540 int new_start = y - XINT (bar->dragging);
9541 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 9542
ab648270 9543 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
9544 bar->dragging = Qnil;
9545 }
f451eb13 9546
5116f055
JB
9547 /* Same deal here as the other #if 0. */
9548#if 0
58769bee 9549 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 9550 the handle. */
ab648270 9551 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
9552 emacs_event->x = bar->start;
9553 else
e0c1aef2 9554 XSETINT (emacs_event->x, y);
5116f055 9555#else
e0c1aef2 9556 XSETINT (emacs_event->x, y);
5116f055 9557#endif
f451eb13 9558
e0c1aef2 9559 XSETINT (emacs_event->y, top_range);
12ba150f
JB
9560 }
9561}
f451eb13 9562
ab648270
JB
9563/* Handle some mouse motion while someone is dragging the scroll bar.
9564
9565 This may be called from a signal handler, so we have to ignore GC
9566 mark bits. */
06a2c219 9567
f451eb13 9568static void
ab648270
JB
9569x_scroll_bar_note_movement (bar, event)
9570 struct scroll_bar *bar;
f451eb13
JB
9571 XEvent *event;
9572{
39d8bb4d
KH
9573 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
9574
f451eb13
JB
9575 last_mouse_movement_time = event->xmotion.time;
9576
39d8bb4d 9577 f->mouse_moved = 1;
e0c1aef2 9578 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
9579
9580 /* If we're dragging the bar, display it. */
ab648270 9581 if (! GC_NILP (bar->dragging))
f451eb13
JB
9582 {
9583 /* Where should the handle be now? */
12ba150f 9584 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 9585
12ba150f 9586 if (new_start != XINT (bar->start))
f451eb13 9587 {
12ba150f 9588 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 9589
ab648270 9590 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
9591 }
9592 }
f451eb13
JB
9593}
9594
5c187dee
GM
9595#endif /* !USE_TOOLKIT_SCROLL_BARS */
9596
12ba150f 9597/* Return information to the user about the current position of the mouse
ab648270 9598 on the scroll bar. */
06a2c219 9599
12ba150f 9600static void
334208b7
RS
9601x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
9602 FRAME_PTR *fp;
12ba150f 9603 Lisp_Object *bar_window;
ab648270 9604 enum scroll_bar_part *part;
12ba150f
JB
9605 Lisp_Object *x, *y;
9606 unsigned long *time;
9607{
ab648270 9608 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
9609 Window w = SCROLL_BAR_X_WINDOW (bar);
9610 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 9611 int win_x, win_y;
559cb2fb
JB
9612 Window dummy_window;
9613 int dummy_coord;
9614 unsigned int dummy_mask;
12ba150f 9615
cf7cb199
JB
9616 BLOCK_INPUT;
9617
ab648270 9618 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 9619 report that. */
334208b7 9620 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 9621
559cb2fb
JB
9622 /* Root, child, root x and root y. */
9623 &dummy_window, &dummy_window,
9624 &dummy_coord, &dummy_coord,
12ba150f 9625
559cb2fb
JB
9626 /* Position relative to scroll bar. */
9627 &win_x, &win_y,
12ba150f 9628
559cb2fb
JB
9629 /* Mouse buttons and modifier keys. */
9630 &dummy_mask))
7a13e894 9631 ;
559cb2fb
JB
9632 else
9633 {
06a2c219 9634#if 0
559cb2fb 9635 int inside_height
d9cdbb3d 9636 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9637#endif
559cb2fb 9638 int top_range
d9cdbb3d 9639 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
9640
9641 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
9642
9643 if (! NILP (bar->dragging))
9644 win_y -= XINT (bar->dragging);
9645
9646 if (win_y < 0)
9647 win_y = 0;
9648 if (win_y > top_range)
9649 win_y = top_range;
9650
334208b7 9651 *fp = f;
7a13e894 9652 *bar_window = bar->window;
559cb2fb
JB
9653
9654 if (! NILP (bar->dragging))
9655 *part = scroll_bar_handle;
9656 else if (win_y < XINT (bar->start))
9657 *part = scroll_bar_above_handle;
9658 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9659 *part = scroll_bar_handle;
9660 else
9661 *part = scroll_bar_below_handle;
12ba150f 9662
e0c1aef2
KH
9663 XSETINT (*x, win_y);
9664 XSETINT (*y, top_range);
12ba150f 9665
39d8bb4d 9666 f->mouse_moved = 0;
559cb2fb
JB
9667 last_mouse_scroll_bar = Qnil;
9668 }
12ba150f 9669
559cb2fb 9670 *time = last_mouse_movement_time;
cf7cb199 9671
cf7cb199 9672 UNBLOCK_INPUT;
12ba150f
JB
9673}
9674
f451eb13 9675
dbc4e1c1 9676/* The screen has been cleared so we may have changed foreground or
ab648270
JB
9677 background colors, and the scroll bars may need to be redrawn.
9678 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
9679 redraw them. */
9680
dfcf069d 9681void
ab648270 9682x_scroll_bar_clear (f)
dbc4e1c1
JB
9683 FRAME_PTR f;
9684{
06a2c219 9685#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
9686 Lisp_Object bar;
9687
b80c363e
RS
9688 /* We can have scroll bars even if this is 0,
9689 if we just turned off scroll bar mode.
9690 But in that case we should not clear them. */
9691 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
9692 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
9693 bar = XSCROLL_BAR (bar)->next)
c5e6e06b
GM
9694 XClearArea (FRAME_X_DISPLAY (f),
9695 SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
b80c363e 9696 0, 0, 0, 0, True);
06a2c219 9697#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
9698}
9699
06a2c219 9700/* This processes Expose events from the menu-bar specific X event
19126e11 9701 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 9702 when handling menu-bar or pop-up items. */
3afe33e7 9703
06a2c219 9704int
3afe33e7
RS
9705process_expose_from_menu (event)
9706 XEvent event;
9707{
9708 FRAME_PTR f;
19126e11 9709 struct x_display_info *dpyinfo;
06a2c219 9710 int frame_exposed_p = 0;
3afe33e7 9711
f94397b5
KH
9712 BLOCK_INPUT;
9713
19126e11
KH
9714 dpyinfo = x_display_info_for_display (event.xexpose.display);
9715 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
9716 if (f)
9717 {
9718 if (f->async_visible == 0)
9719 {
9720 f->async_visible = 1;
9721 f->async_iconified = 0;
06c488fd 9722 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
9723 SET_FRAME_GARBAGED (f);
9724 }
9725 else
9726 {
06a2c219
GM
9727 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
9728 event.xexpose.x, event.xexpose.y,
9729 event.xexpose.width, event.xexpose.height);
9730 frame_exposed_p = 1;
3afe33e7
RS
9731 }
9732 }
9733 else
9734 {
9735 struct scroll_bar *bar
9736 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9737
3afe33e7
RS
9738 if (bar)
9739 x_scroll_bar_expose (bar, &event);
9740 }
f94397b5
KH
9741
9742 UNBLOCK_INPUT;
06a2c219 9743 return frame_exposed_p;
3afe33e7 9744}
09756a85
RS
9745\f
9746/* Define a queue to save up SelectionRequest events for later handling. */
9747
9748struct selection_event_queue
9749 {
9750 XEvent event;
9751 struct selection_event_queue *next;
9752 };
9753
9754static struct selection_event_queue *queue;
9755
9756/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 9757
09756a85
RS
9758static int x_queue_selection_requests;
9759
9760/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 9761
09756a85 9762static void
334208b7
RS
9763x_queue_event (f, event)
9764 FRAME_PTR f;
09756a85
RS
9765 XEvent *event;
9766{
9767 struct selection_event_queue *queue_tmp
06a2c219 9768 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 9769
58769bee 9770 if (queue_tmp != NULL)
09756a85
RS
9771 {
9772 queue_tmp->event = *event;
9773 queue_tmp->next = queue;
9774 queue = queue_tmp;
9775 }
9776}
9777
9778/* Take all the queued events and put them back
9779 so that they get processed afresh. */
9780
9781static void
db3906fd
RS
9782x_unqueue_events (display)
9783 Display *display;
09756a85 9784{
58769bee 9785 while (queue != NULL)
09756a85
RS
9786 {
9787 struct selection_event_queue *queue_tmp = queue;
db3906fd 9788 XPutBackEvent (display, &queue_tmp->event);
09756a85 9789 queue = queue_tmp->next;
06a2c219 9790 xfree ((char *)queue_tmp);
09756a85
RS
9791 }
9792}
9793
9794/* Start queuing SelectionRequest events. */
9795
9796void
db3906fd
RS
9797x_start_queuing_selection_requests (display)
9798 Display *display;
09756a85
RS
9799{
9800 x_queue_selection_requests++;
9801}
9802
9803/* Stop queuing SelectionRequest events. */
9804
9805void
db3906fd
RS
9806x_stop_queuing_selection_requests (display)
9807 Display *display;
09756a85
RS
9808{
9809 x_queue_selection_requests--;
db3906fd 9810 x_unqueue_events (display);
09756a85 9811}
f451eb13
JB
9812\f
9813/* The main X event-reading loop - XTread_socket. */
dc6f92b8 9814
06a2c219 9815/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
9816 but we have to put it out here, since static variables within functions
9817 sometimes don't work. */
06a2c219 9818
dc6f92b8
JB
9819static Time enter_timestamp;
9820
11edeb03 9821/* This holds the state XLookupString needs to implement dead keys
58769bee 9822 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
9823 says that a portable program can't use this, but Stephen Gildea assures
9824 me that letting the compiler initialize it to zeros will work okay.
9825
9826 This must be defined outside of XTread_socket, for the same reasons
f7d40b3b 9827 given for enter_timestamp, above. */
06a2c219 9828
11edeb03
JB
9829static XComposeStatus compose_status;
9830
10e6549c
RS
9831/* Record the last 100 characters stored
9832 to help debug the loss-of-chars-during-GC problem. */
06a2c219 9833
2224b905
RS
9834static int temp_index;
9835static short temp_buffer[100];
10e6549c 9836
7a13e894
RS
9837/* Set this to nonzero to fake an "X I/O error"
9838 on a particular display. */
06a2c219 9839
7a13e894
RS
9840struct x_display_info *XTread_socket_fake_io_error;
9841
2224b905
RS
9842/* When we find no input here, we occasionally do a no-op command
9843 to verify that the X server is still running and we can still talk with it.
9844 We try all the open displays, one by one.
9845 This variable is used for cycling thru the displays. */
06a2c219 9846
2224b905
RS
9847static struct x_display_info *next_noop_dpyinfo;
9848
06a2c219
GM
9849#define SET_SAVED_MENU_EVENT(size) \
9850 do \
9851 { \
9852 if (f->output_data.x->saved_menu_event == 0) \
9853 f->output_data.x->saved_menu_event \
9854 = (XEvent *) xmalloc (sizeof (XEvent)); \
9855 bcopy (&event, f->output_data.x->saved_menu_event, size); \
9856 if (numchars >= 1) \
9857 { \
9858 bufp->kind = menu_bar_activate_event; \
9859 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 9860 bufp->arg = Qnil; \
06a2c219
GM
9861 bufp++; \
9862 count++; \
9863 numchars--; \
9864 } \
9865 } \
9866 while (0)
9867
8805890a 9868#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 9869#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 9870
dc6f92b8
JB
9871/* Read events coming from the X server.
9872 This routine is called by the SIGIO handler.
9873 We return as soon as there are no more events to be read.
9874
9875 Events representing keys are stored in buffer BUFP,
9876 which can hold up to NUMCHARS characters.
9877 We return the number of characters stored into the buffer,
9878 thus pretending to be `read'.
9879
dc6f92b8
JB
9880 EXPECTED is nonzero if the caller knows input is available. */
9881
7c5283e4 9882int
f66868ba 9883XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 9884 register int sd;
8805890a
KH
9885 /* register */ struct input_event *bufp;
9886 /* register */ int numchars;
dc6f92b8
JB
9887 int expected;
9888{
9889 int count = 0;
9890 int nbytes = 0;
dc6f92b8 9891 XEvent event;
f676886a 9892 struct frame *f;
66f55a9d 9893 int event_found = 0;
334208b7 9894 struct x_display_info *dpyinfo;
379b5ac0 9895 struct coding_system coding;
dc6f92b8 9896
9ac0d9e0 9897 if (interrupt_input_blocked)
dc6f92b8 9898 {
9ac0d9e0 9899 interrupt_input_pending = 1;
dc6f92b8
JB
9900 return -1;
9901 }
9902
9ac0d9e0 9903 interrupt_input_pending = 0;
dc6f92b8 9904 BLOCK_INPUT;
c0a04927
RS
9905
9906 /* So people can tell when we have read the available input. */
9907 input_signal_count++;
9908
dc6f92b8 9909 if (numchars <= 0)
06a2c219 9910 abort (); /* Don't think this happens. */
dc6f92b8 9911
bde5503b
GM
9912 ++handling_signal;
9913
379b5ac0
KH
9914 /* The input should be decoded if it is from XIM. Currently the
9915 locale of XIM is the same as that of the system. So, we can use
9916 Vlocale_coding_system which is initialized properly at Emacs
9917 startup time. */
9918 setup_coding_system (Vlocale_coding_system, &coding);
9919 coding.src_multibyte = 0;
9920 coding.dst_multibyte = 1;
9921 /* The input is converted to events, thus we can't handle
9922 composition. Anyway, there's no XIM that gives us composition
9923 information. */
9924 coding.composing = COMPOSITION_DISABLED;
9925
7a13e894
RS
9926 /* Find the display we are supposed to read input for.
9927 It's the one communicating on descriptor SD. */
9928 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9929 {
9930#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9931#ifdef FIOSNBIO
7a13e894
RS
9932 /* If available, Xlib uses FIOSNBIO to make the socket
9933 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9934 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9935 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9936 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9937#endif /* ! defined (FIOSNBIO) */
7a13e894 9938#endif
dc6f92b8 9939
7a13e894
RS
9940#if 0 /* This code can't be made to work, with multiple displays,
9941 and appears not to be used on any system any more.
9942 Also keyboard.c doesn't turn O_NDELAY on and off
9943 for X connections. */
dc6f92b8
JB
9944#ifndef SIGIO
9945#ifndef HAVE_SELECT
7a13e894
RS
9946 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9947 {
9948 extern int read_alarm_should_throw;
9949 read_alarm_should_throw = 1;
9950 XPeekEvent (dpyinfo->display, &event);
9951 read_alarm_should_throw = 0;
9952 }
c118dd06
JB
9953#endif /* HAVE_SELECT */
9954#endif /* SIGIO */
7a13e894 9955#endif
dc6f92b8 9956
7a13e894
RS
9957 /* For debugging, this gives a way to fake an I/O error. */
9958 if (dpyinfo == XTread_socket_fake_io_error)
9959 {
9960 XTread_socket_fake_io_error = 0;
9961 x_io_error_quitter (dpyinfo->display);
9962 }
dc6f92b8 9963
06a2c219 9964 while (XPending (dpyinfo->display))
dc6f92b8 9965 {
7a13e894 9966 XNextEvent (dpyinfo->display, &event);
06a2c219 9967
531483fb 9968#ifdef HAVE_X_I18N
d1bc4182 9969 {
f2be1146
GM
9970 /* Filter events for the current X input method.
9971 XFilterEvent returns non-zero if the input method has
9972 consumed the event. We pass the frame's X window to
9973 XFilterEvent because that's the one for which the IC
9974 was created. */
f5d11644
GM
9975 struct frame *f1 = x_any_window_to_frame (dpyinfo,
9976 event.xclient.window);
9977 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
9978 break;
9979 }
0cd6403b 9980#endif
7a13e894
RS
9981 event_found = 1;
9982
9983 switch (event.type)
9984 {
9985 case ClientMessage:
c047688c 9986 {
7a13e894
RS
9987 if (event.xclient.message_type
9988 == dpyinfo->Xatom_wm_protocols
9989 && event.xclient.format == 32)
c047688c 9990 {
7a13e894
RS
9991 if (event.xclient.data.l[0]
9992 == dpyinfo->Xatom_wm_take_focus)
c047688c 9993 {
8c1a6a84
RS
9994 /* Use x_any_window_to_frame because this
9995 could be the shell widget window
9996 if the frame has no title bar. */
9997 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
9998#ifdef HAVE_X_I18N
9999 /* Not quite sure this is needed -pd */
8c1a6a84 10000 if (f && FRAME_XIC (f))
6c183ba5
RS
10001 XSetICFocus (FRAME_XIC (f));
10002#endif
f1da8f06
GM
10003#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
10004 instructs the WM to set the input focus automatically for
10005 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
10006 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
10007 it has set the focus. So, XSetInputFocus below is not
10008 needed.
10009
10010 The call to XSetInputFocus below has also caused trouble. In
10011 cases where the XSetInputFocus done by the WM and the one
10012 below are temporally close (on a fast machine), the call
10013 below can generate additional FocusIn events which confuse
10014 Emacs. */
10015
bf7253f4
RS
10016 /* Since we set WM_TAKE_FOCUS, we must call
10017 XSetInputFocus explicitly. But not if f is null,
10018 since that might be an event for a deleted frame. */
7a13e894 10019 if (f)
bf7253f4
RS
10020 {
10021 Display *d = event.xclient.display;
10022 /* Catch and ignore errors, in case window has been
10023 iconified by a window manager such as GWM. */
10024 int count = x_catch_errors (d);
10025 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
10026 /* The ICCCM says this is
10027 the only valid choice. */
10028 RevertToParent,
bf7253f4
RS
10029 event.xclient.data.l[1]);
10030 /* This is needed to detect the error
10031 if there is an error. */
10032 XSync (d, False);
10033 x_uncatch_errors (d, count);
10034 }
7a13e894 10035 /* Not certain about handling scroll bars here */
f1da8f06 10036#endif /* 0 */
c047688c 10037 }
7a13e894
RS
10038 else if (event.xclient.data.l[0]
10039 == dpyinfo->Xatom_wm_save_yourself)
10040 {
10041 /* Save state modify the WM_COMMAND property to
06a2c219 10042 something which can reinstate us. This notifies
7a13e894
RS
10043 the session manager, who's looking for such a
10044 PropertyNotify. Can restart processing when
06a2c219 10045 a keyboard or mouse event arrives. */
7a13e894
RS
10046 if (numchars > 0)
10047 {
19126e11
KH
10048 f = x_top_window_to_frame (dpyinfo,
10049 event.xclient.window);
7a13e894
RS
10050
10051 /* This is just so we only give real data once
10052 for a single Emacs process. */
b86bd3dd 10053 if (f == SELECTED_FRAME ())
7a13e894
RS
10054 XSetCommand (FRAME_X_DISPLAY (f),
10055 event.xclient.window,
10056 initial_argv, initial_argc);
f000f5c5 10057 else if (f)
7a13e894
RS
10058 XSetCommand (FRAME_X_DISPLAY (f),
10059 event.xclient.window,
10060 0, 0);
10061 }
10062 }
10063 else if (event.xclient.data.l[0]
10064 == dpyinfo->Xatom_wm_delete_window)
1fb20991 10065 {
19126e11
KH
10066 struct frame *f
10067 = x_any_window_to_frame (dpyinfo,
10068 event.xclient.window);
1fb20991 10069
7a13e894
RS
10070 if (f)
10071 {
10072 if (numchars == 0)
10073 abort ();
1fb20991 10074
7a13e894
RS
10075 bufp->kind = delete_window_event;
10076 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10077 bufp->arg = Qnil;
7a13e894
RS
10078 bufp++;
10079
10080 count += 1;
10081 numchars -= 1;
10082 }
1fb20991 10083 }
c047688c 10084 }
7a13e894
RS
10085 else if (event.xclient.message_type
10086 == dpyinfo->Xatom_wm_configure_denied)
10087 {
10088 }
10089 else if (event.xclient.message_type
10090 == dpyinfo->Xatom_wm_window_moved)
10091 {
10092 int new_x, new_y;
19126e11
KH
10093 struct frame *f
10094 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 10095
7a13e894
RS
10096 new_x = event.xclient.data.s[0];
10097 new_y = event.xclient.data.s[1];
1fb20991 10098
7a13e894
RS
10099 if (f)
10100 {
7556890b
RS
10101 f->output_data.x->left_pos = new_x;
10102 f->output_data.x->top_pos = new_y;
7a13e894 10103 }
1fb20991 10104 }
0fdff6bb 10105#ifdef HACK_EDITRES
7a13e894
RS
10106 else if (event.xclient.message_type
10107 == dpyinfo->Xatom_editres)
10108 {
19126e11
KH
10109 struct frame *f
10110 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 10111 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 10112 &event, NULL);
7a13e894 10113 }
0fdff6bb 10114#endif /* HACK_EDITRES */
06a2c219
GM
10115 else if ((event.xclient.message_type
10116 == dpyinfo->Xatom_DONE)
10117 || (event.xclient.message_type
10118 == dpyinfo->Xatom_PAGE))
10119 {
10120 /* Ghostview job completed. Kill it. We could
10121 reply with "Next" if we received "Page", but we
10122 currently never do because we are interested in
10123 images, only, which should have 1 page. */
06a2c219
GM
10124 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
10125 struct frame *f
10126 = x_window_to_frame (dpyinfo, event.xclient.window);
10127 x_kill_gs_process (pixmap, f);
10128 expose_frame (f, 0, 0, 0, 0);
10129 }
10130#ifdef USE_TOOLKIT_SCROLL_BARS
10131 /* Scroll bar callbacks send a ClientMessage from which
10132 we construct an input_event. */
10133 else if (event.xclient.message_type
10134 == dpyinfo->Xatom_Scrollbar)
10135 {
10136 x_scroll_bar_to_input_event (&event, bufp);
10137 ++bufp, ++count, --numchars;
10138 goto out;
10139 }
10140#endif /* USE_TOOLKIT_SCROLL_BARS */
10141 else
10142 goto OTHER;
7a13e894
RS
10143 }
10144 break;
dc6f92b8 10145
7a13e894 10146 case SelectionNotify:
3afe33e7 10147#ifdef USE_X_TOOLKIT
19126e11 10148 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 10149 goto OTHER;
3afe33e7 10150#endif /* not USE_X_TOOLKIT */
dfcf069d 10151 x_handle_selection_notify (&event.xselection);
7a13e894 10152 break;
d56a553a 10153
06a2c219 10154 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 10155#ifdef USE_X_TOOLKIT
19126e11 10156 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 10157 goto OTHER;
3afe33e7 10158#endif /* USE_X_TOOLKIT */
7a13e894
RS
10159 {
10160 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 10161
7a13e894
RS
10162 if (numchars == 0)
10163 abort ();
d56a553a 10164
7a13e894
RS
10165 bufp->kind = selection_clear_event;
10166 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10167 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10168 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10169 bufp->frame_or_window = Qnil;
0f8aabe9 10170 bufp->arg = Qnil;
7a13e894 10171 bufp++;
d56a553a 10172
7a13e894
RS
10173 count += 1;
10174 numchars -= 1;
10175 }
10176 break;
dc6f92b8 10177
06a2c219 10178 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 10179#ifdef USE_X_TOOLKIT
19126e11 10180 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 10181 goto OTHER;
3afe33e7 10182#endif /* USE_X_TOOLKIT */
7a13e894 10183 if (x_queue_selection_requests)
19126e11 10184 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
10185 &event);
10186 else
10187 {
1d2b2268
GM
10188 XSelectionRequestEvent *eventp
10189 = (XSelectionRequestEvent *) &event;
dc6f92b8 10190
7a13e894
RS
10191 if (numchars == 0)
10192 abort ();
10193
10194 bufp->kind = selection_request_event;
10195 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10196 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
10197 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10198 SELECTION_EVENT_TARGET (bufp) = eventp->target;
10199 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
10200 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10201 bufp->frame_or_window = Qnil;
0f8aabe9 10202 bufp->arg = Qnil;
7a13e894
RS
10203 bufp++;
10204
10205 count += 1;
10206 numchars -= 1;
10207 }
10208 break;
10209
10210 case PropertyNotify:
1d2b2268
GM
10211#if 0 /* This is plain wrong. In the case that we are waiting for a
10212 PropertyNotify used as an ACK in incremental selection
10213 transfer, the property will be on the receiver's window. */
10214#if defined USE_X_TOOLKIT
19126e11 10215 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 10216 goto OTHER;
1d2b2268
GM
10217#endif
10218#endif
dfcf069d 10219 x_handle_property_notify (&event.xproperty);
1d2b2268 10220 goto OTHER;
dc6f92b8 10221
7a13e894 10222 case ReparentNotify:
19126e11 10223 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
10224 if (f)
10225 {
10226 int x, y;
7556890b 10227 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 10228 x_real_positions (f, &x, &y);
7556890b
RS
10229 f->output_data.x->left_pos = x;
10230 f->output_data.x->top_pos = y;
7a13e894
RS
10231 }
10232 break;
3bd330d4 10233
7a13e894 10234 case Expose:
19126e11 10235 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 10236 if (f)
dc6f92b8 10237 {
7a13e894
RS
10238 if (f->async_visible == 0)
10239 {
10240 f->async_visible = 1;
10241 f->async_iconified = 0;
06c488fd 10242 f->output_data.x->has_been_visible = 1;
7a13e894
RS
10243 SET_FRAME_GARBAGED (f);
10244 }
10245 else
06a2c219
GM
10246 expose_frame (x_window_to_frame (dpyinfo,
10247 event.xexpose.window),
10248 event.xexpose.x, event.xexpose.y,
10249 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
10250 }
10251 else
7a13e894 10252 {
12949a7f
EZ
10253#ifndef USE_TOOLKIT_SCROLL_BARS
10254 struct scroll_bar *bar;
10255#endif
01f67d2c 10256#if defined USE_LUCID
c95fc5f1
GM
10257 /* Submenus of the Lucid menu bar aren't widgets
10258 themselves, so there's no way to dispatch events
10259 to them. Recognize this case separately. */
10260 {
10261 Widget widget
10262 = x_window_to_menu_bar (event.xexpose.window);
10263 if (widget)
10264 xlwmenu_redisplay (widget);
10265 }
01f67d2c
PJ
10266#endif /* USE_LUCID */
10267
06a2c219
GM
10268#ifdef USE_TOOLKIT_SCROLL_BARS
10269 /* Dispatch event to the widget. */
10270 goto OTHER;
10271#else /* not USE_TOOLKIT_SCROLL_BARS */
12949a7f 10272 bar = x_window_to_scroll_bar (event.xexpose.window);
58769bee 10273
7a13e894
RS
10274 if (bar)
10275 x_scroll_bar_expose (bar, &event);
3afe33e7 10276#ifdef USE_X_TOOLKIT
7a13e894
RS
10277 else
10278 goto OTHER;
3afe33e7 10279#endif /* USE_X_TOOLKIT */
06a2c219 10280#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10281 }
10282 break;
dc6f92b8 10283
7a13e894 10284 case GraphicsExpose: /* This occurs when an XCopyArea's
d624284c
PJ
10285 source area was obscured or not
10286 available. */
19126e11 10287 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
10288 if (f)
10289 {
06a2c219
GM
10290 expose_frame (f,
10291 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
10292 event.xgraphicsexpose.width,
10293 event.xgraphicsexpose.height);
7a13e894 10294 }
3afe33e7 10295#ifdef USE_X_TOOLKIT
7a13e894
RS
10296 else
10297 goto OTHER;
3afe33e7 10298#endif /* USE_X_TOOLKIT */
7a13e894 10299 break;
dc6f92b8 10300
7a13e894 10301 case NoExpose: /* This occurs when an XCopyArea's
06a2c219 10302 source area was completely
d624284c 10303 available. */
7a13e894 10304 break;
dc6f92b8 10305
7a13e894 10306 case UnmapNotify:
06a2c219
GM
10307 /* Redo the mouse-highlight after the tooltip has gone. */
10308 if (event.xmap.window == tip_window)
10309 {
10310 tip_window = 0;
10311 redo_mouse_highlight ();
10312 }
10313
91ea2a7a 10314 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894 10315 if (f) /* F may no longer exist if
d624284c 10316 the frame was deleted. */
7a13e894
RS
10317 {
10318 /* While a frame is unmapped, display generation is
10319 disabled; you don't want to spend time updating a
10320 display that won't ever be seen. */
10321 f->async_visible = 0;
10322 /* We can't distinguish, from the event, whether the window
10323 has become iconified or invisible. So assume, if it
10324 was previously visible, than now it is iconified.
1aa6072f
RS
10325 But x_make_frame_invisible clears both
10326 the visible flag and the iconified flag;
10327 and that way, we know the window is not iconified now. */
7a13e894 10328 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
10329 {
10330 f->async_iconified = 1;
bddd097c 10331
1aa6072f
RS
10332 bufp->kind = iconify_event;
10333 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10334 bufp->arg = Qnil;
1aa6072f
RS
10335 bufp++;
10336 count++;
10337 numchars--;
10338 }
7a13e894 10339 }
7a13e894 10340 goto OTHER;
dc6f92b8 10341
7a13e894 10342 case MapNotify:
06a2c219
GM
10343 if (event.xmap.window == tip_window)
10344 /* The tooltip has been drawn already. Avoid
10345 the SET_FRAME_GARBAGED below. */
10346 goto OTHER;
10347
10348 /* We use x_top_window_to_frame because map events can
10349 come for sub-windows and they don't mean that the
10350 frame is visible. */
19126e11 10351 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
10352 if (f)
10353 {
10354 f->async_visible = 1;
10355 f->async_iconified = 0;
06c488fd 10356 f->output_data.x->has_been_visible = 1;
dc6f92b8 10357
7a13e894
RS
10358 /* wait_reading_process_input will notice this and update
10359 the frame's display structures. */
10360 SET_FRAME_GARBAGED (f);
bddd097c 10361
d806e720
RS
10362 if (f->iconified)
10363 {
10364 bufp->kind = deiconify_event;
10365 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10366 bufp->arg = Qnil;
d806e720
RS
10367 bufp++;
10368 count++;
10369 numchars--;
10370 }
e73ec6fa 10371 else if (! NILP (Vframe_list)
8e713be6 10372 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
10373 /* Force a redisplay sooner or later
10374 to update the frame titles
10375 in case this is the second frame. */
10376 record_asynch_buffer_change ();
7a13e894 10377 }
7a13e894 10378 goto OTHER;
dc6f92b8 10379
7a13e894 10380 case KeyPress:
19126e11 10381 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 10382
eccc05db 10383#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
10384 if (f == 0)
10385 {
2564ea1b
GM
10386 /* Scroll bars consume key events, but we want
10387 the keys to go to the scroll bar's frame. */
06a2c219
GM
10388 Widget widget = XtWindowToWidget (dpyinfo->display,
10389 event.xkey.window);
10390 if (widget && XmIsScrollBar (widget))
10391 {
10392 widget = XtParent (widget);
10393 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
10394 }
10395 }
eccc05db 10396#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
06a2c219 10397
7a13e894
RS
10398 if (f != 0)
10399 {
10400 KeySym keysym, orig_keysym;
379b5ac0
KH
10401 /* al%imercury@uunet.uu.net says that making this 81
10402 instead of 80 fixed a bug whereby meta chars made
10403 his Emacs hang.
10404
10405 It seems that some version of XmbLookupString has
10406 a bug of not returning XBufferOverflow in
10407 status_return even if the input is too long to
10408 fit in 81 bytes. So, we must prepare sufficient
10409 bytes for copy_buffer. 513 bytes (256 chars for
10410 two-byte character set) seems to be a faily good
10411 approximation. -- 2000.8.10 handa@etl.go.jp */
10412 unsigned char copy_buffer[513];
10413 unsigned char *copy_bufptr = copy_buffer;
10414 int copy_bufsiz = sizeof (copy_buffer);
7a13e894 10415 int modifiers;
64bb1782 10416
7a13e894
RS
10417 event.xkey.state
10418 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
10419 extra_keyboard_modifiers);
10420 modifiers = event.xkey.state;
3a2712f9 10421
7a13e894 10422 /* This will have to go some day... */
752a043f 10423
7a13e894
RS
10424 /* make_lispy_event turns chars into control chars.
10425 Don't do it here because XLookupString is too eager. */
10426 event.xkey.state &= ~ControlMask;
5d46f928
RS
10427 event.xkey.state &= ~(dpyinfo->meta_mod_mask
10428 | dpyinfo->super_mod_mask
10429 | dpyinfo->hyper_mod_mask
10430 | dpyinfo->alt_mod_mask);
10431
1cf4a0d1
RS
10432 /* In case Meta is ComposeCharacter,
10433 clear its status. According to Markus Ehrnsperger
10434 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
10435 this enables ComposeCharacter to work whether or
10436 not it is combined with Meta. */
10437 if (modifiers & dpyinfo->meta_mod_mask)
10438 bzero (&compose_status, sizeof (compose_status));
10439
6c183ba5
RS
10440#ifdef HAVE_X_I18N
10441 if (FRAME_XIC (f))
10442 {
f5d11644
GM
10443 Status status_return;
10444
6c183ba5 10445 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
10446 &event.xkey, copy_bufptr,
10447 copy_bufsiz, &keysym,
6c183ba5 10448 &status_return);
f5d11644
GM
10449 if (status_return == XBufferOverflow)
10450 {
10451 copy_bufsiz = nbytes + 1;
10452 copy_bufptr = (char *) alloca (copy_bufsiz);
10453 nbytes = XmbLookupString (FRAME_XIC (f),
10454 &event.xkey, copy_bufptr,
10455 copy_bufsiz, &keysym,
10456 &status_return);
10457 }
10458
1decb680
PE
10459 if (status_return == XLookupNone)
10460 break;
10461 else if (status_return == XLookupChars)
fdd9d55e
GM
10462 {
10463 keysym = NoSymbol;
10464 modifiers = 0;
10465 }
1decb680
PE
10466 else if (status_return != XLookupKeySym
10467 && status_return != XLookupBoth)
10468 abort ();
6c183ba5
RS
10469 }
10470 else
379b5ac0
KH
10471 nbytes = XLookupString (&event.xkey, copy_bufptr,
10472 copy_bufsiz, &keysym,
10473 &compose_status);
6c183ba5 10474#else
379b5ac0
KH
10475 nbytes = XLookupString (&event.xkey, copy_bufptr,
10476 copy_bufsiz, &keysym,
10477 &compose_status);
6c183ba5 10478#endif
dc6f92b8 10479
7a13e894 10480 orig_keysym = keysym;
55123275 10481
7a13e894
RS
10482 if (numchars > 1)
10483 {
10484 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
10485 || keysym == XK_Delete
1097aea0 10486#ifdef XK_ISO_Left_Tab
441affdb 10487 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 10488#endif
852bff8f 10489 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
10490 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
10491 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 10492#ifdef HPUX
7a13e894
RS
10493 /* This recognizes the "extended function keys".
10494 It seems there's no cleaner way.
10495 Test IsModifierKey to avoid handling mode_switch
10496 incorrectly. */
10497 || ((unsigned) (keysym) >= XK_Select
10498 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
10499#endif
10500#ifdef XK_dead_circumflex
7a13e894 10501 || orig_keysym == XK_dead_circumflex
69388238
RS
10502#endif
10503#ifdef XK_dead_grave
7a13e894 10504 || orig_keysym == XK_dead_grave
69388238
RS
10505#endif
10506#ifdef XK_dead_tilde
7a13e894 10507 || orig_keysym == XK_dead_tilde
69388238
RS
10508#endif
10509#ifdef XK_dead_diaeresis
7a13e894 10510 || orig_keysym == XK_dead_diaeresis
69388238
RS
10511#endif
10512#ifdef XK_dead_macron
7a13e894 10513 || orig_keysym == XK_dead_macron
69388238
RS
10514#endif
10515#ifdef XK_dead_degree
7a13e894 10516 || orig_keysym == XK_dead_degree
69388238
RS
10517#endif
10518#ifdef XK_dead_acute
7a13e894 10519 || orig_keysym == XK_dead_acute
69388238
RS
10520#endif
10521#ifdef XK_dead_cedilla
7a13e894 10522 || orig_keysym == XK_dead_cedilla
69388238
RS
10523#endif
10524#ifdef XK_dead_breve
7a13e894 10525 || orig_keysym == XK_dead_breve
69388238
RS
10526#endif
10527#ifdef XK_dead_ogonek
7a13e894 10528 || orig_keysym == XK_dead_ogonek
69388238
RS
10529#endif
10530#ifdef XK_dead_caron
7a13e894 10531 || orig_keysym == XK_dead_caron
69388238
RS
10532#endif
10533#ifdef XK_dead_doubleacute
7a13e894 10534 || orig_keysym == XK_dead_doubleacute
69388238
RS
10535#endif
10536#ifdef XK_dead_abovedot
7a13e894 10537 || orig_keysym == XK_dead_abovedot
c34790e0 10538#endif
7a13e894
RS
10539 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
10540 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
10541 /* Any "vendor-specific" key is ok. */
f0e299de
GM
10542 || (orig_keysym & (1 << 28))
10543 || (keysym != NoSymbol && nbytes == 0))
7a13e894 10544 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
10545#ifndef HAVE_X11R5
10546#ifdef XK_Mode_switch
7a13e894 10547 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
10548#endif
10549#ifdef XK_Num_Lock
7a13e894 10550 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
10551#endif
10552#endif /* not HAVE_X11R5 */
7a13e894 10553 ))
dc6f92b8 10554 {
10e6549c
RS
10555 if (temp_index == sizeof temp_buffer / sizeof (short))
10556 temp_index = 0;
7a13e894
RS
10557 temp_buffer[temp_index++] = keysym;
10558 bufp->kind = non_ascii_keystroke;
10559 bufp->code = keysym;
e0c1aef2 10560 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10561 bufp->arg = Qnil;
334208b7
RS
10562 bufp->modifiers
10563 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10564 modifiers);
1113d9db 10565 bufp->timestamp = event.xkey.time;
dc6f92b8 10566 bufp++;
7a13e894
RS
10567 count++;
10568 numchars--;
dc6f92b8 10569 }
7a13e894
RS
10570 else if (numchars > nbytes)
10571 {
10572 register int i;
379b5ac0 10573 register int c;
379b5ac0 10574 int nchars, len;
7a13e894
RS
10575
10576 for (i = 0; i < nbytes; i++)
10577 {
379b5ac0
KH
10578 if (temp_index == (sizeof temp_buffer
10579 / sizeof (short)))
7a13e894 10580 temp_index = 0;
379b5ac0
KH
10581 temp_buffer[temp_index++] = copy_bufptr[i];
10582 }
10583
10584 if (/* If the event is not from XIM, */
10585 event.xkey.keycode != 0
10586 /* or the current locale doesn't request
10587 decoding of the intup data, ... */
10588 || coding.type == coding_type_raw_text
10589 || coding.type == coding_type_no_conversion)
10590 {
10591 /* ... we can use the input data as is. */
10592 nchars = nbytes;
10593 }
10594 else
10595 {
10596 /* We have to decode the input data. */
10597 int require;
10598 unsigned char *p;
10599
10600 require = decoding_buffer_size (&coding, nbytes);
10601 p = (unsigned char *) alloca (require);
10602 coding.mode |= CODING_MODE_LAST_BLOCK;
10603 decode_coding (&coding, copy_bufptr, p,
10604 nbytes, require);
10605 nbytes = coding.produced;
10606 nchars = coding.produced_char;
10607 copy_bufptr = p;
10608 }
10609
10610 /* Convert the input data to a sequence of
10611 character events. */
10612 for (i = 0; i < nbytes; i += len)
10613 {
fee2aedc
GM
10614 if (nchars == nbytes)
10615 c = copy_bufptr[i], len = 1;
10616 else
10617 c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
10618 nbytes - i, len);
10619
379b5ac0
KH
10620 bufp->kind = (SINGLE_BYTE_CHAR_P (c)
10621 ? ascii_keystroke
10622 : multibyte_char_keystroke);
10623 bufp->code = c;
7a13e894 10624 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10625 bufp->arg = Qnil;
7a13e894
RS
10626 bufp->modifiers
10627 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10628 modifiers);
10629 bufp->timestamp = event.xkey.time;
10630 bufp++;
10631 }
10632
379b5ac0
KH
10633 count += nchars;
10634 numchars -= nchars;
1decb680
PE
10635
10636 if (keysym == NoSymbol)
10637 break;
7a13e894
RS
10638 }
10639 else
10640 abort ();
dc6f92b8 10641 }
10e6549c
RS
10642 else
10643 abort ();
dc6f92b8 10644 }
59ddecde
GM
10645#ifdef HAVE_X_I18N
10646 /* Don't dispatch this event since XtDispatchEvent calls
10647 XFilterEvent, and two calls in a row may freeze the
10648 client. */
10649 break;
10650#else
717ca130 10651 goto OTHER;
59ddecde 10652#endif
f451eb13 10653
f5d11644 10654 case KeyRelease:
59ddecde
GM
10655#ifdef HAVE_X_I18N
10656 /* Don't dispatch this event since XtDispatchEvent calls
10657 XFilterEvent, and two calls in a row may freeze the
10658 client. */
10659 break;
10660#else
f5d11644 10661 goto OTHER;
59ddecde 10662#endif
f5d11644 10663
7a13e894 10664 /* Here's a possible interpretation of the whole
06a2c219
GM
10665 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
10666 you get a FocusIn event, you have to get a FocusOut
10667 event before you relinquish the focus. If you
10668 haven't received a FocusIn event, then a mere
10669 LeaveNotify is enough to free you. */
f451eb13 10670
7a13e894 10671 case EnterNotify:
06a2c219 10672 {
06a2c219
GM
10673 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
10674
2c850e26 10675#if 0
582c60f8 10676 if (event.xcrossing.focus)
06a2c219
GM
10677 {
10678 /* Avoid nasty pop/raise loops. */
10679 if (f && (!(f->auto_raise)
10680 || !(f->auto_lower)
10681 || (event.xcrossing.time - enter_timestamp) > 500))
10682 {
10683 x_new_focus_frame (dpyinfo, f);
10684 enter_timestamp = event.xcrossing.time;
10685 }
10686 }
10687 else if (f == dpyinfo->x_focus_frame)
10688 x_new_focus_frame (dpyinfo, 0);
2c850e26
RS
10689#endif
10690
06a2c219
GM
10691 /* EnterNotify counts as mouse movement,
10692 so update things that depend on mouse position. */
2533c408 10693 if (f && !f->output_data.x->hourglass_p)
06a2c219
GM
10694 note_mouse_movement (f, &event.xmotion);
10695 goto OTHER;
10696 }
dc6f92b8 10697
7a13e894 10698 case FocusIn:
19126e11 10699 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10700 if (event.xfocus.detail != NotifyPointer)
0f941935 10701 dpyinfo->x_focus_event_frame = f;
7a13e894 10702 if (f)
eb72635f
GM
10703 {
10704 x_new_focus_frame (dpyinfo, f);
10705
10706 /* Don't stop displaying the initial startup message
10707 for a switch-frame event we don't need. */
10708 if (GC_NILP (Vterminal_frame)
10709 && GC_CONSP (Vframe_list)
10710 && !GC_NILP (XCDR (Vframe_list)))
10711 {
10712 bufp->kind = FOCUS_IN_EVENT;
10713 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10714 bufp->arg = Qnil;
eb72635f
GM
10715 ++bufp, ++count, --numchars;
10716 }
10717 }
f9e24cb9 10718
6c183ba5
RS
10719#ifdef HAVE_X_I18N
10720 if (f && FRAME_XIC (f))
10721 XSetICFocus (FRAME_XIC (f));
10722#endif
10723
7a13e894 10724 goto OTHER;
10c5e63d 10725
7a13e894 10726 case LeaveNotify:
19126e11 10727 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 10728 if (f)
10c5e63d 10729 {
7a13e894 10730 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
10731 {
10732 /* If we move outside the frame, then we're
10733 certainly no longer on any text in the frame. */
10734 clear_mouse_face (dpyinfo);
10735 dpyinfo->mouse_face_mouse_frame = 0;
10736 }
10737
10738 /* Generate a nil HELP_EVENT to cancel a help-echo.
10739 Do it only if there's something to cancel.
10740 Otherwise, the startup message is cleared when
10741 the mouse leaves the frame. */
10742 if (any_help_event_p)
10743 {
be010514
GM
10744 Lisp_Object frame;
10745 int n;
10746
06a2c219 10747 XSETFRAME (frame, f);
82c5d67a 10748 help_echo = Qnil;
5ab2570d
GM
10749 n = gen_help_event (bufp, numchars,
10750 Qnil, frame, Qnil, Qnil, 0);
be010514 10751 bufp += n, count += n, numchars -= n;
06a2c219 10752 }
7a13e894 10753
2c850e26 10754#if 0
582c60f8 10755 if (event.xcrossing.focus)
0f941935 10756 x_mouse_leave (dpyinfo);
10c5e63d 10757 else
7a13e894 10758 {
0f941935
KH
10759 if (f == dpyinfo->x_focus_event_frame)
10760 dpyinfo->x_focus_event_frame = 0;
140d6643 10761 if (f == dpyinfo->x_focus_frame)
0f941935 10762 x_new_focus_frame (dpyinfo, 0);
7a13e894 10763 }
2c850e26 10764#endif
10c5e63d 10765 }
7a13e894 10766 goto OTHER;
dc6f92b8 10767
7a13e894 10768 case FocusOut:
19126e11 10769 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10770 if (event.xfocus.detail != NotifyPointer
0f941935
KH
10771 && f == dpyinfo->x_focus_event_frame)
10772 dpyinfo->x_focus_event_frame = 0;
10773 if (f && f == dpyinfo->x_focus_frame)
10774 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 10775
6c183ba5
RS
10776#ifdef HAVE_X_I18N
10777 if (f && FRAME_XIC (f))
10778 XUnsetICFocus (FRAME_XIC (f));
10779#endif
10780
7a13e894 10781 goto OTHER;
dc6f92b8 10782
7a13e894 10783 case MotionNotify:
dc6f92b8 10784 {
06a2c219 10785 previous_help_echo = help_echo;
7cea38bc 10786 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 10787 help_echo_pos = -1;
06a2c219 10788
7a13e894
RS
10789 if (dpyinfo->grabbed && last_mouse_frame
10790 && FRAME_LIVE_P (last_mouse_frame))
10791 f = last_mouse_frame;
10792 else
19126e11 10793 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 10794
7a13e894
RS
10795 if (f)
10796 note_mouse_movement (f, &event.xmotion);
10797 else
10798 {
e88b3c50 10799#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10800 struct scroll_bar *bar
10801 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 10802
7a13e894
RS
10803 if (bar)
10804 x_scroll_bar_note_movement (bar, &event);
e88b3c50 10805#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 10806
06a2c219
GM
10807 /* If we move outside the frame, then we're
10808 certainly no longer on any text in the frame. */
7a13e894
RS
10809 clear_mouse_face (dpyinfo);
10810 }
06a2c219
GM
10811
10812 /* If the contents of the global variable help_echo
10813 has changed, generate a HELP_EVENT. */
b7e80413
SM
10814 if (!NILP (help_echo)
10815 || !NILP (previous_help_echo))
06a2c219
GM
10816 {
10817 Lisp_Object frame;
be010514 10818 int n;
06a2c219
GM
10819
10820 if (f)
10821 XSETFRAME (frame, f);
10822 else
10823 frame = Qnil;
10824
10825 any_help_event_p = 1;
5ab2570d 10826 n = gen_help_event (bufp, numchars, help_echo, frame,
7cea38bc
GM
10827 help_echo_window, help_echo_object,
10828 help_echo_pos);
be010514 10829 bufp += n, count += n, numchars -= n;
06a2c219
GM
10830 }
10831
10832 goto OTHER;
dc6f92b8 10833 }
dc6f92b8 10834
7a13e894 10835 case ConfigureNotify:
9829ddba
RS
10836 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
10837 if (f)
af395ec1 10838 {
5c187dee 10839#ifndef USE_X_TOOLKIT
bf1b7b30
KH
10840 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
10841 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 10842
2d7fc7e8
RS
10843 /* In the toolkit version, change_frame_size
10844 is called by the code that handles resizing
10845 of the EmacsFrame widget. */
7a13e894 10846
7a13e894
RS
10847 /* Even if the number of character rows and columns has
10848 not changed, the font size may have changed, so we need
10849 to check the pixel dimensions as well. */
10850 if (columns != f->width
10851 || rows != f->height
7556890b
RS
10852 || event.xconfigure.width != f->output_data.x->pixel_width
10853 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 10854 {
7d1e984f 10855 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 10856 SET_FRAME_GARBAGED (f);
e687d06e 10857 cancel_mouse_face (f);
7a13e894 10858 }
2d7fc7e8 10859#endif
af395ec1 10860
7556890b
RS
10861 f->output_data.x->pixel_width = event.xconfigure.width;
10862 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
10863
10864 /* What we have now is the position of Emacs's own window.
10865 Convert that to the position of the window manager window. */
dcb07ae9
RS
10866 x_real_positions (f, &f->output_data.x->left_pos,
10867 &f->output_data.x->top_pos);
10868
f5d11644
GM
10869#ifdef HAVE_X_I18N
10870 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
10871 xic_set_statusarea (f);
10872#endif
10873
dcb07ae9
RS
10874 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
10875 {
10876 /* Since the WM decorations come below top_pos now,
10877 we must put them below top_pos in the future. */
10878 f->output_data.x->win_gravity = NorthWestGravity;
10879 x_wm_set_size_hint (f, (long) 0, 0);
10880 }
8f08dc93
KH
10881#ifdef USE_MOTIF
10882 /* Some window managers pass (0,0) as the location of
10883 the window, and the Motif event handler stores it
10884 in the emacs widget, which messes up Motif menus. */
10885 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
10886 {
10887 event.xconfigure.x = f->output_data.x->widget->core.x;
10888 event.xconfigure.y = f->output_data.x->widget->core.y;
10889 }
06a2c219 10890#endif /* USE_MOTIF */
7a13e894 10891 }
2d7fc7e8 10892 goto OTHER;
dc6f92b8 10893
7a13e894
RS
10894 case ButtonPress:
10895 case ButtonRelease:
10896 {
10897 /* If we decide we want to generate an event to be seen
10898 by the rest of Emacs, we put it here. */
10899 struct input_event emacs_event;
9ea173e8 10900 int tool_bar_p = 0;
06a2c219 10901
7a13e894 10902 emacs_event.kind = no_event;
7a13e894 10903 bzero (&compose_status, sizeof (compose_status));
9b07615b 10904
06a2c219
GM
10905 if (dpyinfo->grabbed
10906 && last_mouse_frame
9f67f20b
RS
10907 && FRAME_LIVE_P (last_mouse_frame))
10908 f = last_mouse_frame;
10909 else
2224b905 10910 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 10911
06a2c219
GM
10912 if (f)
10913 {
9ea173e8
GM
10914 /* Is this in the tool-bar? */
10915 if (WINDOWP (f->tool_bar_window)
10916 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
10917 {
10918 Lisp_Object window;
10919 int p, x, y;
10920
10921 x = event.xbutton.x;
10922 y = event.xbutton.y;
10923
10924 /* Set x and y. */
10925 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 10926 if (EQ (window, f->tool_bar_window))
06a2c219 10927 {
9ea173e8
GM
10928 x_handle_tool_bar_click (f, &event.xbutton);
10929 tool_bar_p = 1;
06a2c219
GM
10930 }
10931 }
10932
9ea173e8 10933 if (!tool_bar_p)
06a2c219
GM
10934 if (!dpyinfo->x_focus_frame
10935 || f == dpyinfo->x_focus_frame)
10936 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
10937 }
10938 else
10939 {
06a2c219 10940#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10941 struct scroll_bar *bar
10942 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 10943
7a13e894
RS
10944 if (bar)
10945 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 10946#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10947 }
10948
10949 if (event.type == ButtonPress)
10950 {
10951 dpyinfo->grabbed |= (1 << event.xbutton.button);
10952 last_mouse_frame = f;
edad46f6
KH
10953 /* Ignore any mouse motion that happened
10954 before this event; any subsequent mouse-movement
10955 Emacs events should reflect only motion after
10956 the ButtonPress. */
a00e91cd
KH
10957 if (f != 0)
10958 f->mouse_moved = 0;
06a2c219 10959
9ea173e8
GM
10960 if (!tool_bar_p)
10961 last_tool_bar_item = -1;
7a13e894 10962 }
3afe33e7
RS
10963 else
10964 {
7a13e894 10965 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10966 }
23faf38f 10967
7a13e894
RS
10968 if (numchars >= 1 && emacs_event.kind != no_event)
10969 {
10970 bcopy (&emacs_event, bufp, sizeof (struct input_event));
10971 bufp++;
10972 count++;
10973 numchars--;
10974 }
3afe33e7
RS
10975
10976#ifdef USE_X_TOOLKIT
2224b905
RS
10977 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
10978 /* For a down-event in the menu bar,
10979 don't pass it to Xt right now.
10980 Instead, save it away
10981 and we will pass it to Xt from kbd_buffer_get_event.
10982 That way, we can run some Lisp code first. */
91375f8f
RS
10983 if (f && event.type == ButtonPress
10984 /* Verify the event is really within the menu bar
10985 and not just sent to it due to grabbing. */
10986 && event.xbutton.x >= 0
10987 && event.xbutton.x < f->output_data.x->pixel_width
10988 && event.xbutton.y >= 0
10989 && event.xbutton.y < f->output_data.x->menubar_height
10990 && event.xbutton.same_screen)
2224b905 10991 {
8805890a 10992 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
10993 XSETFRAME (last_mouse_press_frame, f);
10994 }
10995 else if (event.type == ButtonPress)
10996 {
10997 last_mouse_press_frame = Qnil;
30e671c3 10998 goto OTHER;
ce89ef46 10999 }
06a2c219 11000
2237cac9
RS
11001#ifdef USE_MOTIF /* This should do not harm for Lucid,
11002 but I am trying to be cautious. */
ce89ef46
RS
11003 else if (event.type == ButtonRelease)
11004 {
2237cac9 11005 if (!NILP (last_mouse_press_frame))
f10ded1c 11006 {
2237cac9
RS
11007 f = XFRAME (last_mouse_press_frame);
11008 if (f->output_data.x)
06a2c219 11009 SET_SAVED_BUTTON_EVENT;
f10ded1c 11010 }
06a2c219 11011 else
30e671c3 11012 goto OTHER;
2224b905 11013 }
2237cac9 11014#endif /* USE_MOTIF */
2224b905
RS
11015 else
11016 goto OTHER;
3afe33e7 11017#endif /* USE_X_TOOLKIT */
7a13e894
RS
11018 }
11019 break;
dc6f92b8 11020
7a13e894 11021 case CirculateNotify:
06a2c219
GM
11022 goto OTHER;
11023
7a13e894 11024 case CirculateRequest:
06a2c219
GM
11025 goto OTHER;
11026
11027 case VisibilityNotify:
11028 goto OTHER;
dc6f92b8 11029
7a13e894
RS
11030 case MappingNotify:
11031 /* Someone has changed the keyboard mapping - update the
11032 local cache. */
11033 switch (event.xmapping.request)
11034 {
11035 case MappingModifier:
11036 x_find_modifier_meanings (dpyinfo);
11037 /* This is meant to fall through. */
11038 case MappingKeyboard:
11039 XRefreshKeyboardMapping (&event.xmapping);
11040 }
7a13e894 11041 goto OTHER;
dc6f92b8 11042
7a13e894 11043 default:
7a13e894 11044 OTHER:
717ca130 11045#ifdef USE_X_TOOLKIT
7a13e894
RS
11046 BLOCK_INPUT;
11047 XtDispatchEvent (&event);
11048 UNBLOCK_INPUT;
3afe33e7 11049#endif /* USE_X_TOOLKIT */
7a13e894
RS
11050 break;
11051 }
dc6f92b8
JB
11052 }
11053 }
11054
06a2c219
GM
11055 out:;
11056
9a5196d0
RS
11057 /* On some systems, an X bug causes Emacs to get no more events
11058 when the window is destroyed. Detect that. (1994.) */
58769bee 11059 if (! event_found)
ef2a22d0 11060 {
ef2a22d0
RS
11061 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
11062 One XNOOP in 100 loops will make Emacs terminate.
11063 B. Bretthauer, 1994 */
11064 x_noop_count++;
58769bee 11065 if (x_noop_count >= 100)
ef2a22d0
RS
11066 {
11067 x_noop_count=0;
2224b905
RS
11068
11069 if (next_noop_dpyinfo == 0)
11070 next_noop_dpyinfo = x_display_list;
11071
11072 XNoOp (next_noop_dpyinfo->display);
11073
11074 /* Each time we get here, cycle through the displays now open. */
11075 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
11076 }
11077 }
502add23 11078
06a2c219 11079 /* If the focus was just given to an auto-raising frame,
0134a210 11080 raise it now. */
7a13e894 11081 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
11082 if (pending_autoraise_frame)
11083 {
11084 x_raise_frame (pending_autoraise_frame);
11085 pending_autoraise_frame = 0;
11086 }
0134a210 11087
dc6f92b8 11088 UNBLOCK_INPUT;
bde5503b 11089 --handling_signal;
dc6f92b8
JB
11090 return count;
11091}
06a2c219
GM
11092
11093
11094
dc6f92b8 11095\f
06a2c219
GM
11096/***********************************************************************
11097 Text Cursor
11098 ***********************************************************************/
11099
78a9a4c5 11100/* Notice if the text cursor of window W has been overwritten by a
f0a48a01
GM
11101 drawing operation that outputs N glyphs starting at START_X and
11102 ending at END_X in the line given by output_cursor.vpos.
bb4600a4 11103 Coordinates are area-relative. END_X < 0 means all the rest
f0a48a01 11104 of the line after START_X has been written. */
06a2c219
GM
11105
11106static void
f0a48a01 11107notice_overwritten_cursor (w, start_x, end_x)
06a2c219 11108 struct window *w;
f0a48a01 11109 int start_x, end_x;
06a2c219
GM
11110{
11111 if (updated_area == TEXT_AREA
f0a48a01 11112 && w->phys_cursor_on_p
06a2c219 11113 && output_cursor.vpos == w->phys_cursor.vpos
f0a48a01 11114 && start_x <= w->phys_cursor.x
9f0de4e3 11115 && (end_x < 0 || end_x > w->phys_cursor.x))
f0a48a01 11116 w->phys_cursor_on_p = 0;
06a2c219 11117}
f451eb13
JB
11118
11119
06a2c219
GM
11120/* Set clipping for output in glyph row ROW. W is the window in which
11121 we operate. GC is the graphics context to set clipping in.
11122 WHOLE_LINE_P non-zero means include the areas used for truncation
11123 mark display and alike in the clipping rectangle.
11124
11125 ROW may be a text row or, e.g., a mode line. Text rows must be
11126 clipped to the interior of the window dedicated to text display,
11127 mode lines must be clipped to the whole window. */
dc6f92b8
JB
11128
11129static void
06a2c219
GM
11130x_clip_to_row (w, row, gc, whole_line_p)
11131 struct window *w;
11132 struct glyph_row *row;
11133 GC gc;
11134 int whole_line_p;
dc6f92b8 11135{
06a2c219
GM
11136 struct frame *f = XFRAME (WINDOW_FRAME (w));
11137 XRectangle clip_rect;
11138 int window_x, window_y, window_width, window_height;
dc6f92b8 11139
06a2c219 11140 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 11141
06a2c219
GM
11142 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
11143 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
11144 clip_rect.y = max (clip_rect.y, window_y);
11145 clip_rect.width = window_width;
11146 clip_rect.height = row->visible_height;
5c1aae96 11147
06a2c219
GM
11148 /* If clipping to the whole line, including trunc marks, extend
11149 the rectangle to the left and increase its width. */
11150 if (whole_line_p)
11151 {
3f332ef3
KS
11152 clip_rect.x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
11153 clip_rect.width += FRAME_X_FRINGE_WIDTH (f);
06a2c219 11154 }
5c1aae96 11155
06a2c219 11156 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
11157}
11158
06a2c219
GM
11159
11160/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
11161
11162static void
06a2c219
GM
11163x_draw_hollow_cursor (w, row)
11164 struct window *w;
11165 struct glyph_row *row;
dc6f92b8 11166{
06a2c219
GM
11167 struct frame *f = XFRAME (WINDOW_FRAME (w));
11168 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11169 Display *dpy = FRAME_X_DISPLAY (f);
11170 int x, y, wd, h;
11171 XGCValues xgcv;
11172 struct glyph *cursor_glyph;
11173 GC gc;
11174
11175 /* Compute frame-relative coordinates from window-relative
11176 coordinates. */
11177 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11178 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
11179 + row->ascent - w->phys_cursor_ascent);
11180 h = row->height - 1;
11181
11182 /* Get the glyph the cursor is on. If we can't tell because
11183 the current matrix is invalid or such, give up. */
11184 cursor_glyph = get_phys_cursor_glyph (w);
11185 if (cursor_glyph == NULL)
dc6f92b8
JB
11186 return;
11187
06a2c219
GM
11188 /* Compute the width of the rectangle to draw. If on a stretch
11189 glyph, and `x-stretch-block-cursor' is nil, don't draw a
11190 rectangle as wide as the glyph, but use a canonical character
11191 width instead. */
11192 wd = cursor_glyph->pixel_width - 1;
11193 if (cursor_glyph->type == STRETCH_GLYPH
11194 && !x_stretch_cursor_p)
11195 wd = min (CANON_X_UNIT (f), wd);
11196
11197 /* The foreground of cursor_gc is typically the same as the normal
11198 background color, which can cause the cursor box to be invisible. */
11199 xgcv.foreground = f->output_data.x->cursor_pixel;
11200 if (dpyinfo->scratch_cursor_gc)
11201 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
11202 else
11203 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
11204 GCForeground, &xgcv);
11205 gc = dpyinfo->scratch_cursor_gc;
11206
11207 /* Set clipping, draw the rectangle, and reset clipping again. */
11208 x_clip_to_row (w, row, gc, 0);
11209 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
11210 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
11211}
11212
06a2c219
GM
11213
11214/* Draw a bar cursor on window W in glyph row ROW.
11215
11216 Implementation note: One would like to draw a bar cursor with an
11217 angle equal to the one given by the font property XA_ITALIC_ANGLE.
11218 Unfortunately, I didn't find a font yet that has this property set.
11219 --gerd. */
dc6f92b8
JB
11220
11221static void
f02d8aa0 11222x_draw_bar_cursor (w, row, width)
06a2c219
GM
11223 struct window *w;
11224 struct glyph_row *row;
f02d8aa0 11225 int width;
dc6f92b8 11226{
92f424df
GM
11227 struct frame *f = XFRAME (w->frame);
11228 struct glyph *cursor_glyph;
06a2c219 11229
92f424df
GM
11230 /* If cursor is out of bounds, don't draw garbage. This can happen
11231 in mini-buffer windows when switching between echo area glyphs
11232 and mini-buffer. */
11233 cursor_glyph = get_phys_cursor_glyph (w);
11234 if (cursor_glyph == NULL)
11235 return;
06a2c219 11236
92f424df
GM
11237 /* If on an image, draw like a normal cursor. That's usually better
11238 visible than drawing a bar, esp. if the image is large so that
11239 the bar might not be in the window. */
11240 if (cursor_glyph->type == IMAGE_GLYPH)
11241 {
11242 struct glyph_row *row;
11243 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
11244 x_draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
11245 }
11246 else
11247 {
34e5d0af
GM
11248 Display *dpy = FRAME_X_DISPLAY (f);
11249 Window window = FRAME_X_WINDOW (f);
11250 GC gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
11251 unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures;
11252 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
11253 XGCValues xgcv;
11254
11255 /* If the glyph's background equals the color we normally draw
11256 the bar cursor in, the bar cursor in its normal color is
11257 invisible. Use the glyph's foreground color instead in this
11258 case, on the assumption that the glyph's colors are chosen so
11259 that the glyph is legible. */
11260 if (face->background == f->output_data.x->cursor_pixel)
11261 xgcv.background = xgcv.foreground = face->foreground;
11262 else
11263 xgcv.background = xgcv.foreground = f->output_data.x->cursor_pixel;
06a2c219 11264 xgcv.graphics_exposures = 0;
92f424df 11265
06a2c219
GM
11266 if (gc)
11267 XChangeGC (dpy, gc, mask, &xgcv);
11268 else
11269 {
11270 gc = XCreateGC (dpy, window, mask, &xgcv);
11271 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
11272 }
92f424df 11273
f02d8aa0
GM
11274 if (width < 0)
11275 width = f->output_data.x->cursor_width;
34e5d0af 11276 width = min (cursor_glyph->pixel_width, width);
92f424df 11277
06a2c219
GM
11278 x_clip_to_row (w, row, gc, 0);
11279 XFillRectangle (dpy, window, gc,
34e5d0af 11280 WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
06a2c219 11281 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
34e5d0af 11282 width, row->height);
06a2c219
GM
11283 XSetClipMask (dpy, gc, None);
11284 }
dc6f92b8
JB
11285}
11286
06a2c219
GM
11287
11288/* Clear the cursor of window W to background color, and mark the
11289 cursor as not shown. This is used when the text where the cursor
11290 is is about to be rewritten. */
11291
dc6f92b8 11292static void
06a2c219
GM
11293x_clear_cursor (w)
11294 struct window *w;
dc6f92b8 11295{
06a2c219
GM
11296 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
11297 x_update_window_cursor (w, 0);
11298}
90e65f07 11299
dbc4e1c1 11300
06a2c219
GM
11301/* Draw the cursor glyph of window W in glyph row ROW. See the
11302 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 11303
06a2c219
GM
11304static void
11305x_draw_phys_cursor_glyph (w, row, hl)
11306 struct window *w;
11307 struct glyph_row *row;
11308 enum draw_glyphs_face hl;
11309{
11310 /* If cursor hpos is out of bounds, don't draw garbage. This can
11311 happen in mini-buffer windows when switching between echo area
11312 glyphs and mini-buffer. */
11313 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e 11314 {
f0a48a01
GM
11315 int on_p = w->phys_cursor_on_p;
11316
66ac4b0e
GM
11317 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
11318 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
f0a48a01
GM
11319 hl, 0);
11320 w->phys_cursor_on_p = on_p;
66ac4b0e
GM
11321
11322 /* When we erase the cursor, and ROW is overlapped by other
11323 rows, make sure that these overlapping parts of other rows
11324 are redrawn. */
11325 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
11326 {
11327 if (row > w->current_matrix->rows
11328 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
11329 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
11330
11331 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
11332 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
11333 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
11334 }
11335 }
06a2c219 11336}
dbc4e1c1 11337
eea6af04 11338
06a2c219 11339/* Erase the image of a cursor of window W from the screen. */
eea6af04 11340
06a2c219
GM
11341static void
11342x_erase_phys_cursor (w)
11343 struct window *w;
11344{
11345 struct frame *f = XFRAME (w->frame);
11346 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11347 int hpos = w->phys_cursor.hpos;
11348 int vpos = w->phys_cursor.vpos;
11349 int mouse_face_here_p = 0;
11350 struct glyph_matrix *active_glyphs = w->current_matrix;
11351 struct glyph_row *cursor_row;
11352 struct glyph *cursor_glyph;
11353 enum draw_glyphs_face hl;
11354
11355 /* No cursor displayed or row invalidated => nothing to do on the
11356 screen. */
11357 if (w->phys_cursor_type == NO_CURSOR)
11358 goto mark_cursor_off;
11359
11360 /* VPOS >= active_glyphs->nrows means that window has been resized.
11361 Don't bother to erase the cursor. */
11362 if (vpos >= active_glyphs->nrows)
11363 goto mark_cursor_off;
11364
11365 /* If row containing cursor is marked invalid, there is nothing we
11366 can do. */
11367 cursor_row = MATRIX_ROW (active_glyphs, vpos);
11368 if (!cursor_row->enabled_p)
11369 goto mark_cursor_off;
11370
11371 /* This can happen when the new row is shorter than the old one.
11372 In this case, either x_draw_glyphs or clear_end_of_line
11373 should have cleared the cursor. Note that we wouldn't be
11374 able to erase the cursor in this case because we don't have a
11375 cursor glyph at hand. */
11376 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
11377 goto mark_cursor_off;
11378
11379 /* If the cursor is in the mouse face area, redisplay that when
11380 we clear the cursor. */
8801a864
KR
11381 if (! NILP (dpyinfo->mouse_face_window)
11382 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
11383 && (vpos > dpyinfo->mouse_face_beg_row
11384 || (vpos == dpyinfo->mouse_face_beg_row
11385 && hpos >= dpyinfo->mouse_face_beg_col))
11386 && (vpos < dpyinfo->mouse_face_end_row
11387 || (vpos == dpyinfo->mouse_face_end_row
11388 && hpos < dpyinfo->mouse_face_end_col))
11389 /* Don't redraw the cursor's spot in mouse face if it is at the
11390 end of a line (on a newline). The cursor appears there, but
11391 mouse highlighting does not. */
11392 && cursor_row->used[TEXT_AREA] > hpos)
11393 mouse_face_here_p = 1;
11394
11395 /* Maybe clear the display under the cursor. */
11396 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
11397 {
11398 int x;
045dee35 11399 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 11400
06a2c219
GM
11401 cursor_glyph = get_phys_cursor_glyph (w);
11402 if (cursor_glyph == NULL)
11403 goto mark_cursor_off;
dbc4e1c1 11404
e0300d33 11405 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
06a2c219 11406
c5e6e06b
GM
11407 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11408 x,
11409 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
11410 cursor_row->y)),
11411 cursor_glyph->pixel_width,
11412 cursor_row->visible_height,
11413 False);
dbc4e1c1 11414 }
06a2c219
GM
11415
11416 /* Erase the cursor by redrawing the character underneath it. */
11417 if (mouse_face_here_p)
11418 hl = DRAW_MOUSE_FACE;
06a2c219
GM
11419 else
11420 hl = DRAW_NORMAL_TEXT;
11421 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 11422
06a2c219
GM
11423 mark_cursor_off:
11424 w->phys_cursor_on_p = 0;
11425 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
11426}
11427
11428
b7f83f9e
GM
11429/* Non-zero if physical cursor of window W is within mouse face. */
11430
11431static int
11432cursor_in_mouse_face_p (w)
11433 struct window *w;
11434{
11435 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
11436 int in_mouse_face = 0;
11437
11438 if (WINDOWP (dpyinfo->mouse_face_window)
11439 && XWINDOW (dpyinfo->mouse_face_window) == w)
11440 {
11441 int hpos = w->phys_cursor.hpos;
11442 int vpos = w->phys_cursor.vpos;
11443
11444 if (vpos >= dpyinfo->mouse_face_beg_row
11445 && vpos <= dpyinfo->mouse_face_end_row
11446 && (vpos > dpyinfo->mouse_face_beg_row
11447 || hpos >= dpyinfo->mouse_face_beg_col)
11448 && (vpos < dpyinfo->mouse_face_end_row
11449 || hpos < dpyinfo->mouse_face_end_col
11450 || dpyinfo->mouse_face_past_end))
11451 in_mouse_face = 1;
11452 }
11453
11454 return in_mouse_face;
11455}
11456
11457
06a2c219
GM
11458/* Display or clear cursor of window W. If ON is zero, clear the
11459 cursor. If it is non-zero, display the cursor. If ON is nonzero,
11460 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 11461
06a2c219
GM
11462void
11463x_display_and_set_cursor (w, on, hpos, vpos, x, y)
11464 struct window *w;
11465 int on, hpos, vpos, x, y;
dbc4e1c1 11466{
06a2c219
GM
11467 struct frame *f = XFRAME (w->frame);
11468 int new_cursor_type;
f02d8aa0 11469 int new_cursor_width;
06a2c219
GM
11470 struct glyph_matrix *current_glyphs;
11471 struct glyph_row *glyph_row;
11472 struct glyph *glyph;
34368a22 11473 int cursor_non_selected;
dbc4e1c1 11474
49d838ea 11475 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
11476 windows and frames; in the latter case, the frame or window may
11477 be in the midst of changing its size, and x and y may be off the
11478 window. */
11479 if (! FRAME_VISIBLE_P (f)
11480 || FRAME_GARBAGED_P (f)
11481 || vpos >= w->current_matrix->nrows
11482 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
11483 return;
11484
11485 /* If cursor is off and we want it off, return quickly. */
06a2c219 11486 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
11487 return;
11488
06a2c219
GM
11489 current_glyphs = w->current_matrix;
11490 glyph_row = MATRIX_ROW (current_glyphs, vpos);
11491 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
11492
11493 /* If cursor row is not enabled, we don't really know where to
11494 display the cursor. */
11495 if (!glyph_row->enabled_p)
11496 {
11497 w->phys_cursor_on_p = 0;
11498 return;
11499 }
11500
11501 xassert (interrupt_input_blocked);
11502
11503 /* Set new_cursor_type to the cursor we want to be displayed. In a
11504 mini-buffer window, we want the cursor only to appear if we are
11505 reading input from this window. For the selected window, we want
11506 the cursor type given by the frame parameter. If explicitly
11507 marked off, draw no cursor. In all other cases, we want a hollow
11508 box cursor. */
34368a22
RS
11509 cursor_non_selected
11510 = !NILP (Fbuffer_local_value (Qcursor_in_non_selected_windows,
11511 w->buffer));
f02d8aa0 11512 new_cursor_width = -1;
9b4a7047
GM
11513 if (cursor_in_echo_area
11514 && FRAME_HAS_MINIBUF_P (f)
11515 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 11516 {
9b4a7047
GM
11517 if (w == XWINDOW (echo_area_window))
11518 new_cursor_type = FRAME_DESIRED_CURSOR (f);
34368a22 11519 else if (cursor_non_selected)
06a2c219 11520 new_cursor_type = HOLLOW_BOX_CURSOR;
9a7bdceb
GM
11521 else
11522 new_cursor_type = NO_CURSOR;
06a2c219 11523 }
06a2c219 11524 else
9b4a7047 11525 {
7a58ab59
GM
11526 if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
11527 || w != XWINDOW (f->selected_window))
9b4a7047 11528 {
2c850e26 11529 if ((MINI_WINDOW_P (w) && minibuf_level == 0)
34368a22 11530 || !cursor_non_selected
5cefa566 11531 || NILP (XBUFFER (w->buffer)->cursor_type))
9b4a7047
GM
11532 new_cursor_type = NO_CURSOR;
11533 else
11534 new_cursor_type = HOLLOW_BOX_CURSOR;
11535 }
11536 else if (w->cursor_off_p)
11537 new_cursor_type = NO_CURSOR;
11538 else
f02d8aa0
GM
11539 {
11540 struct buffer *b = XBUFFER (w->buffer);
11541
11542 if (EQ (b->cursor_type, Qt))
11543 new_cursor_type = FRAME_DESIRED_CURSOR (f);
11544 else
11545 new_cursor_type = x_specified_cursor_type (b->cursor_type,
11546 &new_cursor_width);
11547 }
9b4a7047 11548 }
06a2c219
GM
11549
11550 /* If cursor is currently being shown and we don't want it to be or
11551 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 11552 erase it. */
06a2c219 11553 if (w->phys_cursor_on_p
dc6f92b8 11554 && (!on
06a2c219
GM
11555 || w->phys_cursor.x != x
11556 || w->phys_cursor.y != y
11557 || new_cursor_type != w->phys_cursor_type))
11558 x_erase_phys_cursor (w);
11559
11560 /* If the cursor is now invisible and we want it to be visible,
11561 display it. */
11562 if (on && !w->phys_cursor_on_p)
11563 {
11564 w->phys_cursor_ascent = glyph_row->ascent;
11565 w->phys_cursor_height = glyph_row->height;
11566
11567 /* Set phys_cursor_.* before x_draw_.* is called because some
11568 of them may need the information. */
11569 w->phys_cursor.x = x;
11570 w->phys_cursor.y = glyph_row->y;
11571 w->phys_cursor.hpos = hpos;
11572 w->phys_cursor.vpos = vpos;
11573 w->phys_cursor_type = new_cursor_type;
11574 w->phys_cursor_on_p = 1;
11575
11576 switch (new_cursor_type)
dc6f92b8 11577 {
06a2c219
GM
11578 case HOLLOW_BOX_CURSOR:
11579 x_draw_hollow_cursor (w, glyph_row);
11580 break;
11581
11582 case FILLED_BOX_CURSOR:
11583 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
11584 break;
11585
11586 case BAR_CURSOR:
f02d8aa0 11587 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
11588 break;
11589
11590 case NO_CURSOR:
11591 break;
dc6f92b8 11592
06a2c219
GM
11593 default:
11594 abort ();
11595 }
59ddecde
GM
11596
11597#ifdef HAVE_X_I18N
11598 if (w == XWINDOW (f->selected_window))
11599 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
11600 xic_set_preeditarea (w, x, y);
11601#endif
dc6f92b8
JB
11602 }
11603
06a2c219 11604#ifndef XFlush
f676886a 11605 if (updating_frame != f)
334208b7 11606 XFlush (FRAME_X_DISPLAY (f));
06a2c219 11607#endif
dc6f92b8
JB
11608}
11609
06a2c219
GM
11610
11611/* Display the cursor on window W, or clear it. X and Y are window
11612 relative pixel coordinates. HPOS and VPOS are glyph matrix
11613 positions. If W is not the selected window, display a hollow
11614 cursor. ON non-zero means display the cursor at X, Y which
11615 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 11616
dfcf069d 11617void
06a2c219
GM
11618x_display_cursor (w, on, hpos, vpos, x, y)
11619 struct window *w;
11620 int on, hpos, vpos, x, y;
dc6f92b8 11621{
f94397b5 11622 BLOCK_INPUT;
06a2c219 11623 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
11624 UNBLOCK_INPUT;
11625}
11626
06a2c219
GM
11627
11628/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
11629 Don't change the cursor's position. */
11630
dfcf069d 11631void
06a2c219 11632x_update_cursor (f, on_p)
5d46f928 11633 struct frame *f;
5d46f928 11634{
06a2c219
GM
11635 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
11636}
11637
11638
11639/* Call x_update_window_cursor with parameter ON_P on all leaf windows
11640 in the window tree rooted at W. */
11641
11642static void
11643x_update_cursor_in_window_tree (w, on_p)
11644 struct window *w;
11645 int on_p;
11646{
11647 while (w)
11648 {
11649 if (!NILP (w->hchild))
11650 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
11651 else if (!NILP (w->vchild))
11652 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
11653 else
11654 x_update_window_cursor (w, on_p);
11655
11656 w = NILP (w->next) ? 0 : XWINDOW (w->next);
11657 }
11658}
5d46f928 11659
f94397b5 11660
06a2c219
GM
11661/* Switch the display of W's cursor on or off, according to the value
11662 of ON. */
11663
11664static void
11665x_update_window_cursor (w, on)
11666 struct window *w;
11667 int on;
11668{
16b5d424
GM
11669 /* Don't update cursor in windows whose frame is in the process
11670 of being deleted. */
11671 if (w->current_matrix)
11672 {
11673 BLOCK_INPUT;
11674 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
11675 w->phys_cursor.x, w->phys_cursor.y);
11676 UNBLOCK_INPUT;
11677 }
dc6f92b8 11678}
06a2c219
GM
11679
11680
11681
dc6f92b8
JB
11682\f
11683/* Icons. */
11684
dbc4e1c1 11685/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
11686
11687int
990ba854 11688x_bitmap_icon (f, file)
f676886a 11689 struct frame *f;
990ba854 11690 Lisp_Object file;
dc6f92b8 11691{
06a2c219 11692 int bitmap_id;
dc6f92b8 11693
c118dd06 11694 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11695 return 1;
11696
990ba854 11697 /* Free up our existing icon bitmap if any. */
7556890b
RS
11698 if (f->output_data.x->icon_bitmap > 0)
11699 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11700 f->output_data.x->icon_bitmap = 0;
990ba854
RS
11701
11702 if (STRINGP (file))
7f2ae036
RS
11703 bitmap_id = x_create_bitmap_from_file (f, file);
11704 else
11705 {
990ba854 11706 /* Create the GNU bitmap if necessary. */
5bf01b68 11707 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
11708 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
11709 = x_create_bitmap_from_data (f, gnu_bits,
11710 gnu_width, gnu_height);
990ba854
RS
11711
11712 /* The first time we create the GNU bitmap,
06a2c219 11713 this increments the ref-count one extra time.
990ba854
RS
11714 As a result, the GNU bitmap is never freed.
11715 That way, we don't have to worry about allocating it again. */
334208b7 11716 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 11717
334208b7 11718 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
11719 }
11720
11721 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 11722 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
11723
11724 return 0;
11725}
11726
11727
1be2d067
KH
11728/* Make the x-window of frame F use a rectangle with text.
11729 Use ICON_NAME as the text. */
dc6f92b8
JB
11730
11731int
f676886a
JB
11732x_text_icon (f, icon_name)
11733 struct frame *f;
dc6f92b8
JB
11734 char *icon_name;
11735{
c118dd06 11736 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11737 return 1;
11738
1be2d067
KH
11739#ifdef HAVE_X11R4
11740 {
11741 XTextProperty text;
11742 text.value = (unsigned char *) icon_name;
11743 text.encoding = XA_STRING;
11744 text.format = 8;
11745 text.nitems = strlen (icon_name);
11746#ifdef USE_X_TOOLKIT
7556890b 11747 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
11748 &text);
11749#else /* not USE_X_TOOLKIT */
11750 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
11751#endif /* not USE_X_TOOLKIT */
11752 }
11753#else /* not HAVE_X11R4 */
11754 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
11755#endif /* not HAVE_X11R4 */
58769bee 11756
7556890b
RS
11757 if (f->output_data.x->icon_bitmap > 0)
11758 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11759 f->output_data.x->icon_bitmap = 0;
b1c884c3 11760 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
11761
11762 return 0;
11763}
11764\f
e99db5a1
RS
11765#define X_ERROR_MESSAGE_SIZE 200
11766
11767/* If non-nil, this should be a string.
11768 It means catch X errors and store the error message in this string. */
11769
11770static Lisp_Object x_error_message_string;
11771
11772/* An X error handler which stores the error message in
11773 x_error_message_string. This is called from x_error_handler if
11774 x_catch_errors is in effect. */
11775
06a2c219 11776static void
e99db5a1
RS
11777x_error_catcher (display, error)
11778 Display *display;
11779 XErrorEvent *error;
11780{
11781 XGetErrorText (display, error->error_code,
11782 XSTRING (x_error_message_string)->data,
11783 X_ERROR_MESSAGE_SIZE);
11784}
11785
11786/* Begin trapping X errors for display DPY. Actually we trap X errors
11787 for all displays, but DPY should be the display you are actually
11788 operating on.
11789
11790 After calling this function, X protocol errors no longer cause
11791 Emacs to exit; instead, they are recorded in the string
11792 stored in x_error_message_string.
11793
11794 Calling x_check_errors signals an Emacs error if an X error has
11795 occurred since the last call to x_catch_errors or x_check_errors.
11796
11797 Calling x_uncatch_errors resumes the normal error handling. */
11798
11799void x_check_errors ();
11800static Lisp_Object x_catch_errors_unwind ();
11801
11802int
11803x_catch_errors (dpy)
11804 Display *dpy;
11805{
11806 int count = specpdl_ptr - specpdl;
11807
11808 /* Make sure any errors from previous requests have been dealt with. */
11809 XSync (dpy, False);
11810
11811 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
11812
11813 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
11814 XSTRING (x_error_message_string)->data[0] = 0;
11815
11816 return count;
11817}
11818
11819/* Unbind the binding that we made to check for X errors. */
11820
11821static Lisp_Object
11822x_catch_errors_unwind (old_val)
11823 Lisp_Object old_val;
11824{
11825 x_error_message_string = old_val;
11826 return Qnil;
11827}
11828
11829/* If any X protocol errors have arrived since the last call to
11830 x_catch_errors or x_check_errors, signal an Emacs error using
11831 sprintf (a buffer, FORMAT, the x error message text) as the text. */
11832
11833void
11834x_check_errors (dpy, format)
11835 Display *dpy;
11836 char *format;
11837{
11838 /* Make sure to catch any errors incurred so far. */
11839 XSync (dpy, False);
11840
11841 if (XSTRING (x_error_message_string)->data[0])
11842 error (format, XSTRING (x_error_message_string)->data);
11843}
11844
9829ddba
RS
11845/* Nonzero if we had any X protocol errors
11846 since we did x_catch_errors on DPY. */
e99db5a1
RS
11847
11848int
11849x_had_errors_p (dpy)
11850 Display *dpy;
11851{
11852 /* Make sure to catch any errors incurred so far. */
11853 XSync (dpy, False);
11854
11855 return XSTRING (x_error_message_string)->data[0] != 0;
11856}
11857
9829ddba
RS
11858/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
11859
06a2c219 11860void
9829ddba
RS
11861x_clear_errors (dpy)
11862 Display *dpy;
11863{
11864 XSTRING (x_error_message_string)->data[0] = 0;
11865}
11866
e99db5a1
RS
11867/* Stop catching X protocol errors and let them make Emacs die.
11868 DPY should be the display that was passed to x_catch_errors.
11869 COUNT should be the value that was returned by
11870 the corresponding call to x_catch_errors. */
11871
11872void
11873x_uncatch_errors (dpy, count)
11874 Display *dpy;
11875 int count;
11876{
11877 unbind_to (count, Qnil);
11878}
11879
11880#if 0
11881static unsigned int x_wire_count;
11882x_trace_wire ()
11883{
11884 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
11885}
11886#endif /* ! 0 */
11887
11888\f
11889/* Handle SIGPIPE, which can happen when the connection to a server
11890 simply goes away. SIGPIPE is handled by x_connection_signal.
11891 Don't need to do anything, because the write which caused the
11892 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 11893 which will do the appropriate cleanup for us. */
e99db5a1
RS
11894
11895static SIGTYPE
11896x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 11897 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
11898{
11899#ifdef USG
11900 /* USG systems forget handlers when they are used;
11901 must reestablish each time */
11902 signal (signalnum, x_connection_signal);
11903#endif /* USG */
11904}
0da1ab50 11905
e99db5a1 11906\f
0da1ab50
GM
11907/************************************************************************
11908 Handling X errors
11909 ************************************************************************/
4746118a 11910
f0e299de
GM
11911/* Error message passed to x_connection_closed. */
11912
11913static char *error_msg;
11914
a7248e4f 11915/* Function installed as fatal_error_signal_hook in
f0e299de
GM
11916 x_connection_closed. Print the X error message, and exit normally,
11917 instead of dumping core when XtCloseDisplay fails. */
11918
11919static void
11920x_fatal_error_signal ()
11921{
11922 fprintf (stderr, "%s\n", error_msg);
11923 exit (70);
11924}
11925
0da1ab50
GM
11926/* Handle the loss of connection to display DPY. ERROR_MESSAGE is
11927 the text of an error message that lead to the connection loss. */
16bd92ea 11928
4746118a 11929static SIGTYPE
5978125e
GM
11930x_connection_closed (dpy, error_message)
11931 Display *dpy;
7a13e894 11932 char *error_message;
4746118a 11933{
5978125e 11934 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
7a13e894 11935 Lisp_Object frame, tail;
0da1ab50 11936 int count;
0da1ab50 11937
f0e299de
GM
11938 error_msg = (char *) alloca (strlen (error_message) + 1);
11939 strcpy (error_msg, error_message);
1a532e54
GM
11940 handling_signal = 0;
11941
0da1ab50
GM
11942 /* Prevent being called recursively because of an error condition
11943 below. Otherwise, we might end up with printing ``can't find per
11944 display information'' in the recursive call instead of printing
11945 the original message here. */
11946 count = x_catch_errors (dpy);
11947
8a4f36cc
GM
11948 /* We have to close the display to inform Xt that it doesn't
11949 exist anymore. If we don't, Xt will continue to wait for
11950 events from the display. As a consequence, a sequence of
11951
11952 M-x make-frame-on-display RET :1 RET
11953 ...kill the new frame, so that we get an IO error...
11954 M-x make-frame-on-display RET :1 RET
11955
11956 will indefinitely wait in Xt for events for display `:1', opened
11957 in the first class to make-frame-on-display.
6186a4a0 11958
8a4f36cc
GM
11959 Closing the display is reported to lead to a bus error on
11960 OpenWindows in certain situations. I suspect that is a bug
11961 in OpenWindows. I don't know how to cicumvent it here. */
11962
f613a4c8 11963#ifdef USE_X_TOOLKIT
ae24cb3b
GM
11964 /* If DPYINFO is null, this means we didn't open the display
11965 in the first place, so don't try to close it. */
11966 if (dpyinfo)
f0e299de
GM
11967 {
11968 extern void (*fatal_error_signal_hook) P_ ((void));
11969 fatal_error_signal_hook = x_fatal_error_signal;
11970 XtCloseDisplay (dpy);
11971 fatal_error_signal_hook = NULL;
11972 }
f613a4c8 11973#endif
adabc3a9 11974
8a4f36cc 11975 /* Indicate that this display is dead. */
9e80b57d
KR
11976 if (dpyinfo)
11977 dpyinfo->display = 0;
6186a4a0 11978
06a2c219 11979 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
11980 that are on the dead display. */
11981 FOR_EACH_FRAME (tail, frame)
11982 {
11983 Lisp_Object minibuf_frame;
11984 minibuf_frame
11985 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
11986 if (FRAME_X_P (XFRAME (frame))
11987 && FRAME_X_P (XFRAME (minibuf_frame))
11988 && ! EQ (frame, minibuf_frame)
11989 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
11990 Fdelete_frame (frame, Qt);
11991 }
11992
11993 /* Now delete all remaining frames on the dead display.
06a2c219 11994 We are now sure none of these is used as the mini-buffer
7a13e894
RS
11995 for another frame that we need to delete. */
11996 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
11997 if (FRAME_X_P (XFRAME (frame))
11998 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
11999 {
12000 /* Set this to t so that Fdelete_frame won't get confused
12001 trying to find a replacement. */
12002 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
12003 Fdelete_frame (frame, Qt);
12004 }
7a13e894 12005
482a1bd2
KH
12006 if (dpyinfo)
12007 x_delete_display (dpyinfo);
7a13e894 12008
0da1ab50
GM
12009 x_uncatch_errors (dpy, count);
12010
7a13e894
RS
12011 if (x_display_list == 0)
12012 {
f0e299de 12013 fprintf (stderr, "%s\n", error_msg);
7a13e894
RS
12014 shut_down_emacs (0, 0, Qnil);
12015 exit (70);
12016 }
12ba150f 12017
7a13e894
RS
12018 /* Ordinary stack unwind doesn't deal with these. */
12019#ifdef SIGIO
12020 sigunblock (sigmask (SIGIO));
12021#endif
12022 sigunblock (sigmask (SIGALRM));
12023 TOTALLY_UNBLOCK_INPUT;
12024
aa4d9a9e 12025 clear_waiting_for_input ();
f0e299de 12026 error ("%s", error_msg);
4746118a
JB
12027}
12028
0da1ab50 12029
7a13e894
RS
12030/* This is the usual handler for X protocol errors.
12031 It kills all frames on the display that we got the error for.
12032 If that was the only one, it prints an error message and kills Emacs. */
12033
06a2c219 12034static void
c118dd06
JB
12035x_error_quitter (display, error)
12036 Display *display;
12037 XErrorEvent *error;
12038{
7a13e894 12039 char buf[256], buf1[356];
dc6f92b8 12040
58769bee 12041 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 12042 original error handler. */
dc6f92b8 12043
c118dd06 12044 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 12045 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 12046 buf, error->request_code);
7a13e894 12047 x_connection_closed (display, buf1);
dc6f92b8
JB
12048}
12049
0da1ab50 12050
e99db5a1
RS
12051/* This is the first-level handler for X protocol errors.
12052 It calls x_error_quitter or x_error_catcher. */
7a13e894 12053
8922af5f 12054static int
e99db5a1 12055x_error_handler (display, error)
8922af5f 12056 Display *display;
e99db5a1 12057 XErrorEvent *error;
8922af5f 12058{
e99db5a1
RS
12059 if (! NILP (x_error_message_string))
12060 x_error_catcher (display, error);
12061 else
12062 x_error_quitter (display, error);
06a2c219 12063 return 0;
f9e24cb9 12064}
c118dd06 12065
e99db5a1
RS
12066/* This is the handler for X IO errors, always.
12067 It kills all frames on the display that we lost touch with.
12068 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 12069
c118dd06 12070static int
e99db5a1 12071x_io_error_quitter (display)
c118dd06 12072 Display *display;
c118dd06 12073{
e99db5a1 12074 char buf[256];
dc6f92b8 12075
e99db5a1
RS
12076 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
12077 x_connection_closed (display, buf);
06a2c219 12078 return 0;
dc6f92b8 12079}
dc6f92b8 12080\f
f451eb13
JB
12081/* Changing the font of the frame. */
12082
76bcdf39
RS
12083/* Give frame F the font named FONTNAME as its default font, and
12084 return the full name of that font. FONTNAME may be a wildcard
12085 pattern; in that case, we choose some font that fits the pattern.
12086 The return value shows which font we chose. */
12087
b5cf7a0e 12088Lisp_Object
f676886a
JB
12089x_new_font (f, fontname)
12090 struct frame *f;
dc6f92b8
JB
12091 register char *fontname;
12092{
dc43ef94 12093 struct font_info *fontp
ee569018 12094 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 12095
dc43ef94
KH
12096 if (!fontp)
12097 return Qnil;
2224a5fc 12098
dc43ef94 12099 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 12100 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
12101 f->output_data.x->fontset = -1;
12102
b2cad826
KH
12103 /* Compute the scroll bar width in character columns. */
12104 if (f->scroll_bar_pixel_width > 0)
12105 {
7556890b 12106 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
12107 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
12108 }
12109 else
4e61bddf
RS
12110 {
12111 int wid = FONT_WIDTH (f->output_data.x->font);
12112 f->scroll_bar_cols = (14 + wid - 1) / wid;
12113 }
b2cad826 12114
f676886a 12115 /* Now make the frame display the given font. */
c118dd06 12116 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 12117 {
7556890b
RS
12118 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
12119 f->output_data.x->font->fid);
12120 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
12121 f->output_data.x->font->fid);
12122 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
12123 f->output_data.x->font->fid);
f676886a 12124
a27f9f86 12125 frame_update_line_height (f);
3497f73e
GM
12126
12127 /* Don't change the size of a tip frame; there's no point in
12128 doing it because it's done in Fx_show_tip, and it leads to
12129 problems because the tip frame has no widget. */
12130 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
12131 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 12132 }
a27f9f86
RS
12133 else
12134 /* If we are setting a new frame's font for the first time,
12135 there are no faces yet, so this font's height is the line height. */
7556890b 12136 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 12137
dc43ef94
KH
12138 return build_string (fontp->full_name);
12139}
12140
12141/* Give frame F the fontset named FONTSETNAME as its default font, and
12142 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
12143 pattern; in that case, we choose some fontset that fits the pattern.
12144 The return value shows which fontset we chose. */
b5cf7a0e 12145
dc43ef94
KH
12146Lisp_Object
12147x_new_fontset (f, fontsetname)
12148 struct frame *f;
12149 char *fontsetname;
12150{
ee569018 12151 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 12152 Lisp_Object result;
b5cf7a0e 12153
dc43ef94
KH
12154 if (fontset < 0)
12155 return Qnil;
b5cf7a0e 12156
2da424f1
KH
12157 if (f->output_data.x->fontset == fontset)
12158 /* This fontset is already set in frame F. There's nothing more
12159 to do. */
ee569018 12160 return fontset_name (fontset);
dc43ef94 12161
ee569018 12162 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
12163
12164 if (!STRINGP (result))
12165 /* Can't load ASCII font. */
12166 return Qnil;
12167
12168 /* Since x_new_font doesn't update any fontset information, do it now. */
12169 f->output_data.x->fontset = fontset;
dc43ef94 12170
f5d11644
GM
12171#ifdef HAVE_X_I18N
12172 if (FRAME_XIC (f)
12173 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 12174 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
12175#endif
12176
dc43ef94 12177 return build_string (fontsetname);
dc6f92b8 12178}
f5d11644
GM
12179
12180\f
12181/***********************************************************************
12182 X Input Methods
12183 ***********************************************************************/
12184
12185#ifdef HAVE_X_I18N
12186
12187#ifdef HAVE_X11R6
12188
12189/* XIM destroy callback function, which is called whenever the
12190 connection to input method XIM dies. CLIENT_DATA contains a
12191 pointer to the x_display_info structure corresponding to XIM. */
12192
12193static void
12194xim_destroy_callback (xim, client_data, call_data)
12195 XIM xim;
12196 XPointer client_data;
12197 XPointer call_data;
12198{
12199 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
12200 Lisp_Object frame, tail;
12201
12202 BLOCK_INPUT;
12203
12204 /* No need to call XDestroyIC.. */
12205 FOR_EACH_FRAME (tail, frame)
12206 {
12207 struct frame *f = XFRAME (frame);
12208 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
12209 {
12210 FRAME_XIC (f) = NULL;
12211 if (FRAME_XIC_FONTSET (f))
12212 {
12213 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
12214 FRAME_XIC_FONTSET (f) = NULL;
12215 }
12216 }
12217 }
12218
12219 /* No need to call XCloseIM. */
12220 dpyinfo->xim = NULL;
12221 XFree (dpyinfo->xim_styles);
12222 UNBLOCK_INPUT;
12223}
12224
12225#endif /* HAVE_X11R6 */
12226
12227/* Open the connection to the XIM server on display DPYINFO.
12228 RESOURCE_NAME is the resource name Emacs uses. */
12229
12230static void
12231xim_open_dpy (dpyinfo, resource_name)
12232 struct x_display_info *dpyinfo;
12233 char *resource_name;
12234{
287f7dd6 12235#ifdef USE_XIM
f5d11644
GM
12236 XIM xim;
12237
12238 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
12239 dpyinfo->xim = xim;
12240
12241 if (xim)
12242 {
f5d11644
GM
12243#ifdef HAVE_X11R6
12244 XIMCallback destroy;
12245#endif
12246
12247 /* Get supported styles and XIM values. */
12248 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
12249
12250#ifdef HAVE_X11R6
12251 destroy.callback = xim_destroy_callback;
12252 destroy.client_data = (XPointer)dpyinfo;
cea2ad76 12253 /* This isn't prototyped in OSF 5.0. */
f5d11644
GM
12254 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
12255#endif
12256 }
287f7dd6
GM
12257
12258#else /* not USE_XIM */
12259 dpyinfo->xim = NULL;
12260#endif /* not USE_XIM */
f5d11644
GM
12261}
12262
12263
b9de836c 12264#ifdef HAVE_X11R6_XIM
f5d11644
GM
12265
12266struct xim_inst_t
12267{
12268 struct x_display_info *dpyinfo;
12269 char *resource_name;
12270};
12271
12272/* XIM instantiate callback function, which is called whenever an XIM
12273 server is available. DISPLAY is teh display of the XIM.
12274 CLIENT_DATA contains a pointer to an xim_inst_t structure created
12275 when the callback was registered. */
12276
12277static void
12278xim_instantiate_callback (display, client_data, call_data)
12279 Display *display;
12280 XPointer client_data;
12281 XPointer call_data;
12282{
12283 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
12284 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
12285
12286 /* We don't support multiple XIM connections. */
12287 if (dpyinfo->xim)
12288 return;
12289
12290 xim_open_dpy (dpyinfo, xim_inst->resource_name);
12291
12292 /* Create XIC for the existing frames on the same display, as long
12293 as they have no XIC. */
12294 if (dpyinfo->xim && dpyinfo->reference_count > 0)
12295 {
12296 Lisp_Object tail, frame;
12297
12298 BLOCK_INPUT;
12299 FOR_EACH_FRAME (tail, frame)
12300 {
12301 struct frame *f = XFRAME (frame);
12302
12303 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
12304 if (FRAME_XIC (f) == NULL)
12305 {
12306 create_frame_xic (f);
12307 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
12308 xic_set_statusarea (f);
12309 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
12310 {
12311 struct window *w = XWINDOW (f->selected_window);
12312 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
12313 }
12314 }
12315 }
12316
12317 UNBLOCK_INPUT;
12318 }
12319}
12320
b9de836c 12321#endif /* HAVE_X11R6_XIM */
f5d11644
GM
12322
12323
12324/* Open a connection to the XIM server on display DPYINFO.
12325 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
12326 connection only at the first time. On X11R6, open the connection
12327 in the XIM instantiate callback function. */
12328
12329static void
12330xim_initialize (dpyinfo, resource_name)
12331 struct x_display_info *dpyinfo;
12332 char *resource_name;
12333{
287f7dd6 12334#ifdef USE_XIM
b9de836c 12335#ifdef HAVE_X11R6_XIM
f5d11644
GM
12336 struct xim_inst_t *xim_inst;
12337 int len;
12338
12339 dpyinfo->xim = NULL;
12340 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
12341 xim_inst->dpyinfo = dpyinfo;
12342 len = strlen (resource_name);
12343 xim_inst->resource_name = (char *) xmalloc (len + 1);
12344 bcopy (resource_name, xim_inst->resource_name, len + 1);
12345 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12346 resource_name, EMACS_CLASS,
12347 xim_instantiate_callback,
2ebb2f8b
DL
12348 /* Fixme: This is XPointer in
12349 XFree86 but (XPointer *) on
12350 Tru64, at least. */
12351 (XPointer) xim_inst);
b9de836c 12352#else /* not HAVE_X11R6_XIM */
f5d11644
GM
12353 dpyinfo->xim = NULL;
12354 xim_open_dpy (dpyinfo, resource_name);
b9de836c 12355#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
12356
12357#else /* not USE_XIM */
12358 dpyinfo->xim = NULL;
12359#endif /* not USE_XIM */
f5d11644
GM
12360}
12361
12362
12363/* Close the connection to the XIM server on display DPYINFO. */
12364
12365static void
12366xim_close_dpy (dpyinfo)
12367 struct x_display_info *dpyinfo;
12368{
287f7dd6 12369#ifdef USE_XIM
b9de836c 12370#ifdef HAVE_X11R6_XIM
8a4f36cc
GM
12371 if (dpyinfo->display)
12372 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12373 NULL, EMACS_CLASS,
12374 xim_instantiate_callback, NULL);
b9de836c 12375#endif /* not HAVE_X11R6_XIM */
8a4f36cc
GM
12376 if (dpyinfo->display)
12377 XCloseIM (dpyinfo->xim);
f5d11644
GM
12378 dpyinfo->xim = NULL;
12379 XFree (dpyinfo->xim_styles);
287f7dd6 12380#endif /* USE_XIM */
f5d11644
GM
12381}
12382
b9de836c 12383#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
12384
12385
dc6f92b8 12386\f
2e365682
RS
12387/* Calculate the absolute position in frame F
12388 from its current recorded position values and gravity. */
12389
dfcf069d 12390void
43bca5d5 12391x_calc_absolute_position (f)
f676886a 12392 struct frame *f;
dc6f92b8 12393{
06a2c219 12394 Window child;
6dba1858 12395 int win_x = 0, win_y = 0;
7556890b 12396 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
12397 int this_window;
12398
9829ddba
RS
12399 /* We have nothing to do if the current position
12400 is already for the top-left corner. */
12401 if (! ((flags & XNegative) || (flags & YNegative)))
12402 return;
12403
c81412a0 12404#ifdef USE_X_TOOLKIT
7556890b 12405 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
12406#else
12407 this_window = FRAME_X_WINDOW (f);
12408#endif
6dba1858
RS
12409
12410 /* Find the position of the outside upper-left corner of
9829ddba
RS
12411 the inner window, with respect to the outer window.
12412 But do this only if we will need the results. */
7556890b 12413 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 12414 {
9829ddba
RS
12415 int count;
12416
6dba1858 12417 BLOCK_INPUT;
9829ddba
RS
12418 count = x_catch_errors (FRAME_X_DISPLAY (f));
12419 while (1)
12420 {
12421 x_clear_errors (FRAME_X_DISPLAY (f));
12422 XTranslateCoordinates (FRAME_X_DISPLAY (f),
12423
12424 /* From-window, to-window. */
12425 this_window,
12426 f->output_data.x->parent_desc,
12427
12428 /* From-position, to-position. */
12429 0, 0, &win_x, &win_y,
12430
12431 /* Child of win. */
12432 &child);
12433 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12434 {
12435 Window newroot, newparent = 0xdeadbeef;
12436 Window *newchildren;
2ebb2f8b 12437 unsigned int nchildren;
9829ddba
RS
12438
12439 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
12440 &newparent, &newchildren, &nchildren))
12441 break;
58769bee 12442
7c3c78a3 12443 XFree ((char *) newchildren);
6dba1858 12444
9829ddba
RS
12445 f->output_data.x->parent_desc = newparent;
12446 }
12447 else
12448 break;
12449 }
6dba1858 12450
9829ddba 12451 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
12452 UNBLOCK_INPUT;
12453 }
12454
12455 /* Treat negative positions as relative to the leftmost bottommost
12456 position that fits on the screen. */
20f55f9a 12457 if (flags & XNegative)
7556890b 12458 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
12459 - 2 * f->output_data.x->border_width - win_x
12460 - PIXEL_WIDTH (f)
12461 + f->output_data.x->left_pos);
dc6f92b8 12462
7708ced0
GM
12463 {
12464 int height = PIXEL_HEIGHT (f);
06a2c219 12465
7708ced0
GM
12466#if defined USE_X_TOOLKIT && defined USE_MOTIF
12467 /* Something is fishy here. When using Motif, starting Emacs with
12468 `-g -0-0', the frame appears too low by a few pixels.
12469
12470 This seems to be so because initially, while Emacs is starting,
12471 the column widget's height and the frame's pixel height are
12472 different. The column widget's height is the right one. In
12473 later invocations, when Emacs is up, the frame's pixel height
12474 is right, though.
12475
12476 It's not obvious where the initial small difference comes from.
12477 2000-12-01, gerd. */
12478
12479 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
06a2c219 12480#endif
2e365682 12481
7708ced0
GM
12482 if (flags & YNegative)
12483 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
12484 - 2 * f->output_data.x->border_width
12485 - win_y
12486 - height
12487 + f->output_data.x->top_pos);
12488 }
12489
3a35ab44
RS
12490 /* The left_pos and top_pos
12491 are now relative to the top and left screen edges,
12492 so the flags should correspond. */
7556890b 12493 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
12494}
12495
3a35ab44
RS
12496/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
12497 to really change the position, and 0 when calling from
12498 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
12499 position values). It is -1 when calling from x_set_frame_parameters,
12500 which means, do adjust for borders but don't change the gravity. */
3a35ab44 12501
dfcf069d 12502void
dc05a16b 12503x_set_offset (f, xoff, yoff, change_gravity)
f676886a 12504 struct frame *f;
dc6f92b8 12505 register int xoff, yoff;
dc05a16b 12506 int change_gravity;
dc6f92b8 12507{
4a4cbdd5
KH
12508 int modified_top, modified_left;
12509
aa3ff7c9 12510 if (change_gravity > 0)
3a35ab44 12511 {
7556890b
RS
12512 f->output_data.x->top_pos = yoff;
12513 f->output_data.x->left_pos = xoff;
12514 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 12515 if (xoff < 0)
7556890b 12516 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 12517 if (yoff < 0)
7556890b
RS
12518 f->output_data.x->size_hint_flags |= YNegative;
12519 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 12520 }
43bca5d5 12521 x_calc_absolute_position (f);
dc6f92b8
JB
12522
12523 BLOCK_INPUT;
c32cdd9a 12524 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 12525
7556890b
RS
12526 modified_left = f->output_data.x->left_pos;
12527 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
12528#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
12529 this seems to be unnecessary and incorrect. rms, 4/17/97. */
12530 /* It is a mystery why we need to add the border_width here
12531 when the frame is already visible, but experiment says we do. */
aa3ff7c9 12532 if (change_gravity != 0)
4a4cbdd5 12533 {
7556890b
RS
12534 modified_left += f->output_data.x->border_width;
12535 modified_top += f->output_data.x->border_width;
4a4cbdd5 12536 }
e73ec6fa 12537#endif
4a4cbdd5 12538
3afe33e7 12539#ifdef USE_X_TOOLKIT
7556890b 12540 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 12541 modified_left, modified_top);
3afe33e7 12542#else /* not USE_X_TOOLKIT */
334208b7 12543 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 12544 modified_left, modified_top);
3afe33e7 12545#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12546 UNBLOCK_INPUT;
12547}
12548
dc6f92b8 12549
499b1844
GM
12550/* Change the size of frame F's X window to COLS/ROWS in the case F
12551 doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
12552 top-left-corner window gravity for this size change and subsequent
12553 size changes. Otherwise we leave the window gravity unchanged. */
12554
12555static void
12556x_set_window_size_1 (f, change_gravity, cols, rows)
f676886a 12557 struct frame *f;
bc20ebbf 12558 int change_gravity;
b1c884c3 12559 int cols, rows;
dc6f92b8
JB
12560{
12561 int pixelwidth, pixelheight;
80fd1fe2 12562
b1c884c3 12563 check_frame_size (f, &rows, &cols);
7556890b 12564 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
12565 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
12566 ? 0
12567 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 12568 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 12569 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
3f332ef3
KS
12570 f->output_data.x->fringes_extra
12571 = FRAME_FRINGE_WIDTH (f);
f451eb13
JB
12572 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
12573 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 12574
7556890b 12575 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 12576 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 12577
334208b7
RS
12578 XSync (FRAME_X_DISPLAY (f), False);
12579 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12580 pixelwidth, pixelheight);
b1c884c3
JB
12581
12582 /* Now, strictly speaking, we can't be sure that this is accurate,
12583 but the window manager will get around to dealing with the size
12584 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
12585 ConfigureNotify event gets here.
12586
12587 We could just not bother storing any of this information here,
12588 and let the ConfigureNotify event set everything up, but that
fddd5ceb 12589 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 12590 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
12591 point in the future when the ConfigureNotify event arrives.
12592
12593 We pass 1 for DELAY since we can't run Lisp code inside of
12594 a BLOCK_INPUT. */
7d1e984f 12595 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
12596 PIXEL_WIDTH (f) = pixelwidth;
12597 PIXEL_HEIGHT (f) = pixelheight;
12598
aee9a898
RS
12599 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
12600 receive in the ConfigureNotify event; if we get what we asked
12601 for, then the event won't cause the screen to become garbaged, so
12602 we have to make sure to do it here. */
12603 SET_FRAME_GARBAGED (f);
12604
12605 XFlush (FRAME_X_DISPLAY (f));
499b1844
GM
12606}
12607
12608
12609/* Call this to change the size of frame F's x-window.
12610 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
12611 for this size change and subsequent size changes.
12612 Otherwise we leave the window gravity unchanged. */
aee9a898 12613
499b1844
GM
12614void
12615x_set_window_size (f, change_gravity, cols, rows)
12616 struct frame *f;
12617 int change_gravity;
12618 int cols, rows;
12619{
12620 BLOCK_INPUT;
12621
12622#ifdef USE_X_TOOLKIT
12623
f1f4d345 12624 if (f->output_data.x->widget != NULL)
499b1844
GM
12625 {
12626 /* The x and y position of the widget is clobbered by the
12627 call to XtSetValues within EmacsFrameSetCharSize.
12628 This is a real kludge, but I don't understand Xt so I can't
12629 figure out a correct fix. Can anyone else tell me? -- rms. */
12630 int xpos = f->output_data.x->widget->core.x;
12631 int ypos = f->output_data.x->widget->core.y;
12632 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
12633 f->output_data.x->widget->core.x = xpos;
12634 f->output_data.x->widget->core.y = ypos;
12635 }
12636 else
12637 x_set_window_size_1 (f, change_gravity, cols, rows);
12638
12639#else /* not USE_X_TOOLKIT */
12640
12641 x_set_window_size_1 (f, change_gravity, cols, rows);
12642
aee9a898
RS
12643#endif /* not USE_X_TOOLKIT */
12644
4d73d038 12645 /* If cursor was outside the new size, mark it as off. */
06a2c219 12646 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 12647
aee9a898
RS
12648 /* Clear out any recollection of where the mouse highlighting was,
12649 since it might be in a place that's outside the new frame size.
12650 Actually checking whether it is outside is a pain in the neck,
12651 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 12652 cancel_mouse_face (f);
dbc4e1c1 12653
dc6f92b8
JB
12654 UNBLOCK_INPUT;
12655}
dc6f92b8 12656\f
d047c4eb 12657/* Mouse warping. */
dc6f92b8 12658
9b378208 12659void
f676886a
JB
12660x_set_mouse_position (f, x, y)
12661 struct frame *f;
dc6f92b8
JB
12662 int x, y;
12663{
12664 int pix_x, pix_y;
12665
7556890b
RS
12666 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
12667 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
12668
12669 if (pix_x < 0) pix_x = 0;
12670 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
12671
12672 if (pix_y < 0) pix_y = 0;
12673 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
12674
12675 BLOCK_INPUT;
dc6f92b8 12676
334208b7
RS
12677 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12678 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
12679 UNBLOCK_INPUT;
12680}
12681
9b378208
RS
12682/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
12683
12684void
12685x_set_mouse_pixel_position (f, pix_x, pix_y)
12686 struct frame *f;
12687 int pix_x, pix_y;
12688{
12689 BLOCK_INPUT;
12690
334208b7
RS
12691 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12692 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
12693 UNBLOCK_INPUT;
12694}
d047c4eb
KH
12695\f
12696/* focus shifting, raising and lowering. */
9b378208 12697
dfcf069d 12698void
f676886a
JB
12699x_focus_on_frame (f)
12700 struct frame *f;
dc6f92b8 12701{
1fb20991 12702#if 0 /* This proves to be unpleasant. */
f676886a 12703 x_raise_frame (f);
1fb20991 12704#endif
6d4238f3
JB
12705#if 0
12706 /* I don't think that the ICCCM allows programs to do things like this
12707 without the interaction of the window manager. Whatever you end up
f676886a 12708 doing with this code, do it to x_unfocus_frame too. */
334208b7 12709 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 12710 RevertToPointerRoot, CurrentTime);
c118dd06 12711#endif /* ! 0 */
dc6f92b8
JB
12712}
12713
dfcf069d 12714void
f676886a
JB
12715x_unfocus_frame (f)
12716 struct frame *f;
dc6f92b8 12717{
6d4238f3 12718#if 0
f676886a 12719 /* Look at the remarks in x_focus_on_frame. */
0f941935 12720 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 12721 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 12722 RevertToPointerRoot, CurrentTime);
c118dd06 12723#endif /* ! 0 */
dc6f92b8
JB
12724}
12725
f676886a 12726/* Raise frame F. */
dc6f92b8 12727
dfcf069d 12728void
f676886a
JB
12729x_raise_frame (f)
12730 struct frame *f;
dc6f92b8 12731{
3a88c238 12732 if (f->async_visible)
dc6f92b8
JB
12733 {
12734 BLOCK_INPUT;
3afe33e7 12735#ifdef USE_X_TOOLKIT
7556890b 12736 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12737#else /* not USE_X_TOOLKIT */
334208b7 12738 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12739#endif /* not USE_X_TOOLKIT */
334208b7 12740 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12741 UNBLOCK_INPUT;
12742 }
12743}
12744
f676886a 12745/* Lower frame F. */
dc6f92b8 12746
dfcf069d 12747void
f676886a
JB
12748x_lower_frame (f)
12749 struct frame *f;
dc6f92b8 12750{
3a88c238 12751 if (f->async_visible)
dc6f92b8
JB
12752 {
12753 BLOCK_INPUT;
3afe33e7 12754#ifdef USE_X_TOOLKIT
7556890b 12755 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12756#else /* not USE_X_TOOLKIT */
334208b7 12757 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12758#endif /* not USE_X_TOOLKIT */
334208b7 12759 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12760 UNBLOCK_INPUT;
12761 }
12762}
12763
dbc4e1c1 12764static void
6b0442dc 12765XTframe_raise_lower (f, raise_flag)
dbc4e1c1 12766 FRAME_PTR f;
6b0442dc 12767 int raise_flag;
dbc4e1c1 12768{
6b0442dc 12769 if (raise_flag)
dbc4e1c1
JB
12770 x_raise_frame (f);
12771 else
12772 x_lower_frame (f);
12773}
d047c4eb
KH
12774\f
12775/* Change of visibility. */
dc6f92b8 12776
9382638d
KH
12777/* This tries to wait until the frame is really visible.
12778 However, if the window manager asks the user where to position
12779 the frame, this will return before the user finishes doing that.
12780 The frame will not actually be visible at that time,
12781 but it will become visible later when the window manager
12782 finishes with it. */
12783
dfcf069d 12784void
f676886a
JB
12785x_make_frame_visible (f)
12786 struct frame *f;
dc6f92b8 12787{
990ba854 12788 Lisp_Object type;
1aa6072f 12789 int original_top, original_left;
31be9251
GM
12790 int retry_count = 2;
12791
12792 retry:
dc6f92b8 12793
dc6f92b8 12794 BLOCK_INPUT;
dc6f92b8 12795
990ba854
RS
12796 type = x_icon_type (f);
12797 if (!NILP (type))
12798 x_bitmap_icon (f, type);
bdcd49ba 12799
f676886a 12800 if (! FRAME_VISIBLE_P (f))
90e65f07 12801 {
1aa6072f
RS
12802 /* We test FRAME_GARBAGED_P here to make sure we don't
12803 call x_set_offset a second time
12804 if we get to x_make_frame_visible a second time
12805 before the window gets really visible. */
12806 if (! FRAME_ICONIFIED_P (f)
12807 && ! f->output_data.x->asked_for_visible)
12808 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
12809
12810 f->output_data.x->asked_for_visible = 1;
12811
90e65f07 12812 if (! EQ (Vx_no_window_manager, Qt))
f676886a 12813 x_wm_set_window_state (f, NormalState);
3afe33e7 12814#ifdef USE_X_TOOLKIT
d7a38a2e 12815 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 12816 XtMapWidget (f->output_data.x->widget);
3afe33e7 12817#else /* not USE_X_TOOLKIT */
7f9c7f94 12818 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12819#endif /* not USE_X_TOOLKIT */
0134a210
RS
12820#if 0 /* This seems to bring back scroll bars in the wrong places
12821 if the window configuration has changed. They seem
12822 to come back ok without this. */
ab648270 12823 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 12824 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 12825#endif
90e65f07 12826 }
dc6f92b8 12827
334208b7 12828 XFlush (FRAME_X_DISPLAY (f));
90e65f07 12829
0dacf791
RS
12830 /* Synchronize to ensure Emacs knows the frame is visible
12831 before we do anything else. We do this loop with input not blocked
12832 so that incoming events are handled. */
12833 {
12834 Lisp_Object frame;
12ce2351 12835 int count;
28c01ffe
RS
12836 /* This must be before UNBLOCK_INPUT
12837 since events that arrive in response to the actions above
12838 will set it when they are handled. */
12839 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
12840
12841 original_left = f->output_data.x->left_pos;
12842 original_top = f->output_data.x->top_pos;
c0a04927
RS
12843
12844 /* This must come after we set COUNT. */
12845 UNBLOCK_INPUT;
12846
2745e6c4 12847 /* We unblock here so that arriving X events are processed. */
1aa6072f 12848
dcb07ae9
RS
12849 /* Now move the window back to where it was "supposed to be".
12850 But don't do it if the gravity is negative.
12851 When the gravity is negative, this uses a position
28c01ffe
RS
12852 that is 3 pixels too low. Perhaps that's really the border width.
12853
12854 Don't do this if the window has never been visible before,
12855 because the window manager may choose the position
12856 and we don't want to override it. */
1aa6072f 12857
4d3f5d9a 12858 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 12859 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 12860 && previously_visible)
1aa6072f 12861 {
2745e6c4
RS
12862 Drawable rootw;
12863 int x, y;
12864 unsigned int width, height, border, depth;
06a2c219 12865
1aa6072f 12866 BLOCK_INPUT;
9829ddba 12867
06a2c219
GM
12868 /* On some window managers (such as FVWM) moving an existing
12869 window, even to the same place, causes the window manager
12870 to introduce an offset. This can cause the window to move
12871 to an unexpected location. Check the geometry (a little
12872 slow here) and then verify that the window is in the right
12873 place. If the window is not in the right place, move it
12874 there, and take the potential window manager hit. */
2745e6c4
RS
12875 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12876 &rootw, &x, &y, &width, &height, &border, &depth);
12877
12878 if (original_left != x || original_top != y)
12879 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12880 original_left, original_top);
12881
1aa6072f
RS
12882 UNBLOCK_INPUT;
12883 }
9829ddba 12884
e0c1aef2 12885 XSETFRAME (frame, f);
c0a04927 12886
12ce2351
GM
12887 /* Wait until the frame is visible. Process X events until a
12888 MapNotify event has been seen, or until we think we won't get a
12889 MapNotify at all.. */
12890 for (count = input_signal_count + 10;
12891 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 12892 {
12ce2351 12893 /* Force processing of queued events. */
334208b7 12894 x_sync (f);
12ce2351
GM
12895
12896 /* Machines that do polling rather than SIGIO have been
12897 observed to go into a busy-wait here. So we'll fake an
12898 alarm signal to let the handler know that there's something
12899 to be read. We used to raise a real alarm, but it seems
12900 that the handler isn't always enabled here. This is
12901 probably a bug. */
8b2f8d4e 12902 if (input_polling_used ())
3b2fa4e6 12903 {
12ce2351
GM
12904 /* It could be confusing if a real alarm arrives while
12905 processing the fake one. Turn it off and let the
12906 handler reset it. */
3e71d8f2 12907 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
12908 int old_poll_suppress_count = poll_suppress_count;
12909 poll_suppress_count = 1;
12910 poll_for_input_1 ();
12911 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 12912 }
12ce2351
GM
12913
12914 /* See if a MapNotify event has been processed. */
12915 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 12916 }
31be9251
GM
12917
12918 /* 2000-09-28: In
12919
12920 (let ((f (selected-frame)))
12921 (iconify-frame f)
12922 (raise-frame f))
12923
12924 the frame is not raised with various window managers on
12925 FreeBSD, Linux and Solaris. It turns out that, for some
12926 unknown reason, the call to XtMapWidget is completely ignored.
12927 Mapping the widget a second time works. */
12928
12929 if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
12930 goto retry;
0dacf791 12931 }
dc6f92b8
JB
12932}
12933
06a2c219 12934/* Change from mapped state to withdrawn state. */
dc6f92b8 12935
d047c4eb
KH
12936/* Make the frame visible (mapped and not iconified). */
12937
dfcf069d 12938void
f676886a
JB
12939x_make_frame_invisible (f)
12940 struct frame *f;
dc6f92b8 12941{
546e6d5b
RS
12942 Window window;
12943
12944#ifdef USE_X_TOOLKIT
12945 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 12946 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
12947#else /* not USE_X_TOOLKIT */
12948 window = FRAME_X_WINDOW (f);
12949#endif /* not USE_X_TOOLKIT */
dc6f92b8 12950
9319ae23 12951 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
12952 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
12953 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 12954
5627c40e 12955#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 12956 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 12957 return;
5627c40e 12958#endif
dc6f92b8
JB
12959
12960 BLOCK_INPUT;
c118dd06 12961
af31d76f
RS
12962 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
12963 that the current position of the window is user-specified, rather than
12964 program-specified, so that when the window is mapped again, it will be
12965 placed at the same location, without forcing the user to position it
12966 by hand again (they have already done that once for this window.) */
c32cdd9a 12967 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 12968
c118dd06
JB
12969#ifdef HAVE_X11R4
12970
334208b7
RS
12971 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
12972 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
12973 {
12974 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12975 error ("Can't notify window manager of window withdrawal");
c118dd06 12976 }
c118dd06 12977#else /* ! defined (HAVE_X11R4) */
16bd92ea 12978
c118dd06 12979 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
12980 if (! EQ (Vx_no_window_manager, Qt))
12981 {
16bd92ea 12982 XEvent unmap;
dc6f92b8 12983
16bd92ea 12984 unmap.xunmap.type = UnmapNotify;
546e6d5b 12985 unmap.xunmap.window = window;
334208b7 12986 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 12987 unmap.xunmap.from_configure = False;
334208b7
RS
12988 if (! XSendEvent (FRAME_X_DISPLAY (f),
12989 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 12990 False,
06a2c219 12991 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
12992 &unmap))
12993 {
12994 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12995 error ("Can't notify window manager of withdrawal");
16bd92ea 12996 }
dc6f92b8
JB
12997 }
12998
16bd92ea 12999 /* Unmap the window ourselves. Cheeky! */
334208b7 13000 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 13001#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 13002
5627c40e
RS
13003 /* We can't distinguish this from iconification
13004 just by the event that we get from the server.
13005 So we can't win using the usual strategy of letting
13006 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
13007 and synchronize with the server to make sure we agree. */
13008 f->visible = 0;
13009 FRAME_ICONIFIED_P (f) = 0;
13010 f->async_visible = 0;
13011 f->async_iconified = 0;
13012
334208b7 13013 x_sync (f);
5627c40e 13014
dc6f92b8
JB
13015 UNBLOCK_INPUT;
13016}
13017
06a2c219 13018/* Change window state from mapped to iconified. */
dc6f92b8 13019
dfcf069d 13020void
f676886a
JB
13021x_iconify_frame (f)
13022 struct frame *f;
dc6f92b8 13023{
3afe33e7 13024 int result;
990ba854 13025 Lisp_Object type;
dc6f92b8 13026
9319ae23 13027 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
13028 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
13029 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 13030
3a88c238 13031 if (f->async_iconified)
dc6f92b8
JB
13032 return;
13033
3afe33e7 13034 BLOCK_INPUT;
546e6d5b 13035
9af3143a
RS
13036 FRAME_SAMPLE_VISIBILITY (f);
13037
990ba854
RS
13038 type = x_icon_type (f);
13039 if (!NILP (type))
13040 x_bitmap_icon (f, type);
bdcd49ba
RS
13041
13042#ifdef USE_X_TOOLKIT
13043
546e6d5b
RS
13044 if (! FRAME_VISIBLE_P (f))
13045 {
13046 if (! EQ (Vx_no_window_manager, Qt))
13047 x_wm_set_window_state (f, IconicState);
13048 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 13049 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
13050 /* The server won't give us any event to indicate
13051 that an invisible frame was changed to an icon,
13052 so we have to record it here. */
13053 f->iconified = 1;
1e6bc770 13054 f->visible = 1;
9cf30a30 13055 f->async_iconified = 1;
1e6bc770 13056 f->async_visible = 0;
546e6d5b
RS
13057 UNBLOCK_INPUT;
13058 return;
13059 }
13060
334208b7 13061 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 13062 XtWindow (f->output_data.x->widget),
334208b7 13063 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
13064 UNBLOCK_INPUT;
13065
13066 if (!result)
546e6d5b 13067 error ("Can't notify window manager of iconification");
3afe33e7
RS
13068
13069 f->async_iconified = 1;
1e6bc770
RS
13070 f->async_visible = 0;
13071
8c002a25
KH
13072
13073 BLOCK_INPUT;
334208b7 13074 XFlush (FRAME_X_DISPLAY (f));
8c002a25 13075 UNBLOCK_INPUT;
3afe33e7
RS
13076#else /* not USE_X_TOOLKIT */
13077
fd13dbb2
RS
13078 /* Make sure the X server knows where the window should be positioned,
13079 in case the user deiconifies with the window manager. */
13080 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 13081 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 13082
16bd92ea
JB
13083 /* Since we don't know which revision of X we're running, we'll use both
13084 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
13085
13086 /* X11R4: send a ClientMessage to the window manager using the
13087 WM_CHANGE_STATE type. */
13088 {
13089 XEvent message;
58769bee 13090
c118dd06 13091 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 13092 message.xclient.type = ClientMessage;
334208b7 13093 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
13094 message.xclient.format = 32;
13095 message.xclient.data.l[0] = IconicState;
13096
334208b7
RS
13097 if (! XSendEvent (FRAME_X_DISPLAY (f),
13098 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
13099 False,
13100 SubstructureRedirectMask | SubstructureNotifyMask,
13101 &message))
dc6f92b8
JB
13102 {
13103 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13104 error ("Can't notify window manager of iconification");
dc6f92b8 13105 }
16bd92ea 13106 }
dc6f92b8 13107
58769bee 13108 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
13109 IconicState. */
13110 x_wm_set_window_state (f, IconicState);
dc6f92b8 13111
a9c00105
RS
13112 if (!FRAME_VISIBLE_P (f))
13113 {
13114 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 13115 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
13116 }
13117
3a88c238 13118 f->async_iconified = 1;
1e6bc770 13119 f->async_visible = 0;
dc6f92b8 13120
334208b7 13121 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 13122 UNBLOCK_INPUT;
8c002a25 13123#endif /* not USE_X_TOOLKIT */
dc6f92b8 13124}
19f71add 13125
d047c4eb 13126\f
19f71add 13127/* Free X resources of frame F. */
dc6f92b8 13128
dfcf069d 13129void
19f71add 13130x_free_frame_resources (f)
f676886a 13131 struct frame *f;
dc6f92b8 13132{
7f9c7f94
RS
13133 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13134
dc6f92b8 13135 BLOCK_INPUT;
c0ff3fab 13136
6186a4a0
RS
13137 /* If a display connection is dead, don't try sending more
13138 commands to the X server. */
19f71add 13139 if (dpyinfo->display)
6186a4a0 13140 {
19f71add 13141 if (f->output_data.x->icon_desc)
6186a4a0 13142 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
19f71add 13143
31f41daf 13144#ifdef HAVE_X_I18N
f5d11644
GM
13145 if (FRAME_XIC (f))
13146 free_frame_xic (f);
31f41daf 13147#endif
19f71add 13148
2662734b 13149 if (FRAME_X_WINDOW (f))
19f71add
GM
13150 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13151
3afe33e7 13152#ifdef USE_X_TOOLKIT
06a2c219 13153 if (f->output_data.x->widget)
30ca89f5
GM
13154 {
13155 XtDestroyWidget (f->output_data.x->widget);
13156 f->output_data.x->widget = NULL;
13157 }
6186a4a0 13158 free_frame_menubar (f);
3afe33e7
RS
13159#endif /* USE_X_TOOLKIT */
13160
3e71d8f2
GM
13161 unload_color (f, f->output_data.x->foreground_pixel);
13162 unload_color (f, f->output_data.x->background_pixel);
13163 unload_color (f, f->output_data.x->cursor_pixel);
13164 unload_color (f, f->output_data.x->cursor_foreground_pixel);
13165 unload_color (f, f->output_data.x->border_pixel);
13166 unload_color (f, f->output_data.x->mouse_pixel);
19f71add 13167
3e71d8f2
GM
13168 if (f->output_data.x->scroll_bar_background_pixel != -1)
13169 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
13170 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
13171 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
7c1bef7a
MB
13172#ifdef USE_TOOLKIT_SCROLL_BARS
13173 /* Scrollbar shadow colors. */
13174 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
13175 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
13176 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
13177 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
13178#endif /* USE_TOOLKIT_SCROLL_BARS */
3e71d8f2
GM
13179 if (f->output_data.x->white_relief.allocated_p)
13180 unload_color (f, f->output_data.x->white_relief.pixel);
13181 if (f->output_data.x->black_relief.allocated_p)
13182 unload_color (f, f->output_data.x->black_relief.pixel);
4ca78676 13183
19f71add
GM
13184 if (FRAME_FACE_CACHE (f))
13185 free_frame_faces (f);
13186
4ca78676 13187 x_free_gcs (f);
6186a4a0
RS
13188 XFlush (FRAME_X_DISPLAY (f));
13189 }
dc6f92b8 13190
df89d8a4 13191 if (f->output_data.x->saved_menu_event)
06a2c219 13192 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 13193
7556890b 13194 xfree (f->output_data.x);
19f71add
GM
13195 f->output_data.x = NULL;
13196
0f941935
KH
13197 if (f == dpyinfo->x_focus_frame)
13198 dpyinfo->x_focus_frame = 0;
13199 if (f == dpyinfo->x_focus_event_frame)
13200 dpyinfo->x_focus_event_frame = 0;
13201 if (f == dpyinfo->x_highlight_frame)
13202 dpyinfo->x_highlight_frame = 0;
c0ff3fab 13203
7f9c7f94 13204 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 13205 {
7f9c7f94
RS
13206 dpyinfo->mouse_face_beg_row
13207 = dpyinfo->mouse_face_beg_col = -1;
13208 dpyinfo->mouse_face_end_row
13209 = dpyinfo->mouse_face_end_col = -1;
13210 dpyinfo->mouse_face_window = Qnil;
21323706
RS
13211 dpyinfo->mouse_face_deferred_gc = 0;
13212 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 13213 }
0134a210 13214
c0ff3fab 13215 UNBLOCK_INPUT;
dc6f92b8 13216}
19f71add
GM
13217
13218
13219/* Destroy the X window of frame F. */
13220
13221void
13222x_destroy_window (f)
13223 struct frame *f;
13224{
13225 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13226
13227 /* If a display connection is dead, don't try sending more
13228 commands to the X server. */
13229 if (dpyinfo->display != 0)
13230 x_free_frame_resources (f);
13231
13232 dpyinfo->reference_count--;
13233}
13234
dc6f92b8 13235\f
f451eb13
JB
13236/* Setting window manager hints. */
13237
af31d76f
RS
13238/* Set the normal size hints for the window manager, for frame F.
13239 FLAGS is the flags word to use--or 0 meaning preserve the flags
13240 that the window now has.
13241 If USER_POSITION is nonzero, we set the USPosition
13242 flag (this is useful when FLAGS is 0). */
6dba1858 13243
dfcf069d 13244void
af31d76f 13245x_wm_set_size_hint (f, flags, user_position)
f676886a 13246 struct frame *f;
af31d76f
RS
13247 long flags;
13248 int user_position;
dc6f92b8
JB
13249{
13250 XSizeHints size_hints;
3afe33e7
RS
13251
13252#ifdef USE_X_TOOLKIT
7e4f2521
FP
13253 Arg al[2];
13254 int ac = 0;
13255 Dimension widget_width, widget_height;
7556890b 13256 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 13257#else /* not USE_X_TOOLKIT */
c118dd06 13258 Window window = FRAME_X_WINDOW (f);
3afe33e7 13259#endif /* not USE_X_TOOLKIT */
dc6f92b8 13260
b72a58fd
RS
13261 /* Setting PMaxSize caused various problems. */
13262 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 13263
7556890b
RS
13264 size_hints.x = f->output_data.x->left_pos;
13265 size_hints.y = f->output_data.x->top_pos;
7553a6b7 13266
7e4f2521
FP
13267#ifdef USE_X_TOOLKIT
13268 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
13269 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 13270 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
13271 size_hints.height = widget_height;
13272 size_hints.width = widget_width;
13273#else /* not USE_X_TOOLKIT */
f676886a
JB
13274 size_hints.height = PIXEL_HEIGHT (f);
13275 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 13276#endif /* not USE_X_TOOLKIT */
7553a6b7 13277
7556890b
RS
13278 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
13279 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
13280 size_hints.max_width
13281 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
13282 size_hints.max_height
13283 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 13284
d067ea8b
KH
13285 /* Calculate the base and minimum sizes.
13286
13287 (When we use the X toolkit, we don't do it here.
13288 Instead we copy the values that the widgets are using, below.) */
13289#ifndef USE_X_TOOLKIT
b1c884c3 13290 {
b0342f17 13291 int base_width, base_height;
0134a210 13292 int min_rows = 0, min_cols = 0;
b0342f17 13293
f451eb13
JB
13294 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
13295 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 13296
0134a210 13297 check_frame_size (f, &min_rows, &min_cols);
b0342f17 13298
0134a210
RS
13299 /* The window manager uses the base width hints to calculate the
13300 current number of rows and columns in the frame while
13301 resizing; min_width and min_height aren't useful for this
13302 purpose, since they might not give the dimensions for a
13303 zero-row, zero-column frame.
58769bee 13304
0134a210
RS
13305 We use the base_width and base_height members if we have
13306 them; otherwise, we set the min_width and min_height members
13307 to the size for a zero x zero frame. */
b0342f17
JB
13308
13309#ifdef HAVE_X11R4
0134a210
RS
13310 size_hints.flags |= PBaseSize;
13311 size_hints.base_width = base_width;
13312 size_hints.base_height = base_height;
13313 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
13314 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 13315#else
0134a210
RS
13316 size_hints.min_width = base_width;
13317 size_hints.min_height = base_height;
b0342f17 13318#endif
b1c884c3 13319 }
dc6f92b8 13320
d067ea8b 13321 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 13322 if (flags)
dc6f92b8 13323 {
d067ea8b
KH
13324 size_hints.flags |= flags;
13325 goto no_read;
13326 }
13327#endif /* not USE_X_TOOLKIT */
13328
13329 {
13330 XSizeHints hints; /* Sometimes I hate X Windows... */
13331 long supplied_return;
13332 int value;
af31d76f
RS
13333
13334#ifdef HAVE_X11R4
d067ea8b
KH
13335 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
13336 &supplied_return);
af31d76f 13337#else
d067ea8b 13338 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 13339#endif
58769bee 13340
d067ea8b
KH
13341#ifdef USE_X_TOOLKIT
13342 size_hints.base_height = hints.base_height;
13343 size_hints.base_width = hints.base_width;
13344 size_hints.min_height = hints.min_height;
13345 size_hints.min_width = hints.min_width;
13346#endif
13347
13348 if (flags)
13349 size_hints.flags |= flags;
13350 else
13351 {
13352 if (value == 0)
13353 hints.flags = 0;
13354 if (hints.flags & PSize)
13355 size_hints.flags |= PSize;
13356 if (hints.flags & PPosition)
13357 size_hints.flags |= PPosition;
13358 if (hints.flags & USPosition)
13359 size_hints.flags |= USPosition;
13360 if (hints.flags & USSize)
13361 size_hints.flags |= USSize;
13362 }
13363 }
13364
06a2c219 13365#ifndef USE_X_TOOLKIT
d067ea8b 13366 no_read:
06a2c219 13367#endif
0134a210 13368
af31d76f 13369#ifdef PWinGravity
7556890b 13370 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 13371 size_hints.flags |= PWinGravity;
dc05a16b 13372
af31d76f 13373 if (user_position)
6dba1858 13374 {
af31d76f
RS
13375 size_hints.flags &= ~ PPosition;
13376 size_hints.flags |= USPosition;
6dba1858 13377 }
2554751d 13378#endif /* PWinGravity */
6dba1858 13379
b0342f17 13380#ifdef HAVE_X11R4
334208b7 13381 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13382#else
334208b7 13383 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13384#endif
dc6f92b8
JB
13385}
13386
13387/* Used for IconicState or NormalState */
06a2c219 13388
dfcf069d 13389void
f676886a
JB
13390x_wm_set_window_state (f, state)
13391 struct frame *f;
dc6f92b8
JB
13392 int state;
13393{
3afe33e7 13394#ifdef USE_X_TOOLKIT
546e6d5b
RS
13395 Arg al[1];
13396
13397 XtSetArg (al[0], XtNinitialState, state);
7556890b 13398 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 13399#else /* not USE_X_TOOLKIT */
c118dd06 13400 Window window = FRAME_X_WINDOW (f);
dc6f92b8 13401
7556890b
RS
13402 f->output_data.x->wm_hints.flags |= StateHint;
13403 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 13404
7556890b 13405 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 13406#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13407}
13408
dfcf069d 13409void
7f2ae036 13410x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 13411 struct frame *f;
7f2ae036 13412 int pixmap_id;
dc6f92b8 13413{
d2bd6bc4
RS
13414 Pixmap icon_pixmap;
13415
06a2c219 13416#ifndef USE_X_TOOLKIT
c118dd06 13417 Window window = FRAME_X_WINDOW (f);
75231bad 13418#endif
dc6f92b8 13419
7f2ae036 13420 if (pixmap_id > 0)
dbc4e1c1 13421 {
d2bd6bc4 13422 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 13423 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
13424 }
13425 else
68568555
RS
13426 {
13427 /* It seems there is no way to turn off use of an icon pixmap.
13428 The following line does it, only if no icon has yet been created,
13429 for some window managers. But with mwm it crashes.
13430 Some people say it should clear the IconPixmapHint bit in this case,
13431 but that doesn't work, and the X consortium said it isn't the
13432 right thing at all. Since there is no way to win,
13433 best to explicitly give up. */
13434#if 0
13435 f->output_data.x->wm_hints.icon_pixmap = None;
13436#else
13437 return;
13438#endif
13439 }
b1c884c3 13440
d2bd6bc4
RS
13441#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
13442
13443 {
13444 Arg al[1];
13445 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
13446 XtSetValues (f->output_data.x->widget, al, 1);
13447 }
13448
13449#else /* not USE_X_TOOLKIT */
13450
7556890b
RS
13451 f->output_data.x->wm_hints.flags |= IconPixmapHint;
13452 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
13453
13454#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13455}
13456
dfcf069d 13457void
f676886a
JB
13458x_wm_set_icon_position (f, icon_x, icon_y)
13459 struct frame *f;
dc6f92b8
JB
13460 int icon_x, icon_y;
13461{
75231bad 13462#ifdef USE_X_TOOLKIT
7556890b 13463 Window window = XtWindow (f->output_data.x->widget);
75231bad 13464#else
c118dd06 13465 Window window = FRAME_X_WINDOW (f);
75231bad 13466#endif
dc6f92b8 13467
7556890b
RS
13468 f->output_data.x->wm_hints.flags |= IconPositionHint;
13469 f->output_data.x->wm_hints.icon_x = icon_x;
13470 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 13471
7556890b 13472 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
13473}
13474
13475\f
06a2c219
GM
13476/***********************************************************************
13477 Fonts
13478 ***********************************************************************/
dc43ef94
KH
13479
13480/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 13481
dc43ef94
KH
13482struct font_info *
13483x_get_font_info (f, font_idx)
13484 FRAME_PTR f;
13485 int font_idx;
13486{
13487 return (FRAME_X_FONT_TABLE (f) + font_idx);
13488}
13489
13490
9c11f79e
GM
13491/* Return a list of names of available fonts matching PATTERN on frame F.
13492
13493 If SIZE is > 0, it is the size (maximum bounds width) of fonts
13494 to be listed.
13495
13496 SIZE < 0 means include scalable fonts.
13497
13498 Frame F null means we have not yet created any frame on X, and
13499 consult the first display in x_display_list. MAXNAMES sets a limit
13500 on how many fonts to match. */
dc43ef94
KH
13501
13502Lisp_Object
13503x_list_fonts (f, pattern, size, maxnames)
9c11f79e 13504 struct frame *f;
dc43ef94
KH
13505 Lisp_Object pattern;
13506 int size;
13507 int maxnames;
13508{
06a2c219
GM
13509 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
13510 Lisp_Object tem, second_best;
9c11f79e
GM
13511 struct x_display_info *dpyinfo
13512 = f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
13513 Display *dpy = dpyinfo->display;
09c6077f 13514 int try_XLoadQueryFont = 0;
53ca4657 13515 int count;
9c11f79e
GM
13516 int allow_scalable_fonts_p = 0;
13517
13518 if (size < 0)
13519 {
13520 allow_scalable_fonts_p = 1;
13521 size = 0;
13522 }
dc43ef94 13523
6b0efe73 13524 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
13525 if (NILP (patterns))
13526 patterns = Fcons (pattern, Qnil);
81ba44e5 13527
09c6077f
KH
13528 if (maxnames == 1 && !size)
13529 /* We can return any single font matching PATTERN. */
13530 try_XLoadQueryFont = 1;
9a32686f 13531
8e713be6 13532 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 13533 {
dc43ef94 13534 int num_fonts;
3e71d8f2 13535 char **names = NULL;
dc43ef94 13536
8e713be6 13537 pattern = XCAR (patterns);
536f4067
RS
13538 /* See if we cached the result for this particular query.
13539 The cache is an alist of the form:
9c11f79e
GM
13540 ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */
13541 tem = XCDR (dpyinfo->name_list_element);
13542 key = Fcons (Fcons (pattern, make_number (maxnames)),
13543 allow_scalable_fonts_p ? Qt : Qnil);
13544 list = Fassoc (key, tem);
13545 if (!NILP (list))
b5210ea7
KH
13546 {
13547 list = Fcdr_safe (list);
13548 /* We have a cashed list. Don't have to get the list again. */
13549 goto label_cached;
13550 }
13551
13552 /* At first, put PATTERN in the cache. */
09c6077f 13553
dc43ef94 13554 BLOCK_INPUT;
17d85edc
KH
13555 count = x_catch_errors (dpy);
13556
09c6077f
KH
13557 if (try_XLoadQueryFont)
13558 {
13559 XFontStruct *font;
13560 unsigned long value;
13561
13562 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
13563 if (x_had_errors_p (dpy))
13564 {
13565 /* This error is perhaps due to insufficient memory on X
13566 server. Let's just ignore it. */
13567 font = NULL;
13568 x_clear_errors (dpy);
13569 }
13570
09c6077f
KH
13571 if (font
13572 && XGetFontProperty (font, XA_FONT, &value))
13573 {
13574 char *name = (char *) XGetAtomName (dpy, (Atom) value);
13575 int len = strlen (name);
01c752b5 13576 char *tmp;
09c6077f 13577
6f6512e8
KH
13578 /* If DXPC (a Differential X Protocol Compressor)
13579 Ver.3.7 is running, XGetAtomName will return null
13580 string. We must avoid such a name. */
13581 if (len == 0)
13582 try_XLoadQueryFont = 0;
13583 else
13584 {
13585 num_fonts = 1;
13586 names = (char **) alloca (sizeof (char *));
13587 /* Some systems only allow alloca assigned to a
13588 simple var. */
13589 tmp = (char *) alloca (len + 1); names[0] = tmp;
13590 bcopy (name, names[0], len + 1);
13591 XFree (name);
13592 }
09c6077f
KH
13593 }
13594 else
13595 try_XLoadQueryFont = 0;
a083fd23
RS
13596
13597 if (font)
13598 XFreeFont (dpy, font);
09c6077f
KH
13599 }
13600
13601 if (!try_XLoadQueryFont)
17d85edc
KH
13602 {
13603 /* We try at least 10 fonts because XListFonts will return
13604 auto-scaled fonts at the head. */
13605 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
13606 &num_fonts);
13607 if (x_had_errors_p (dpy))
13608 {
13609 /* This error is perhaps due to insufficient memory on X
13610 server. Let's just ignore it. */
13611 names = NULL;
13612 x_clear_errors (dpy);
13613 }
13614 }
13615
13616 x_uncatch_errors (dpy, count);
dc43ef94
KH
13617 UNBLOCK_INPUT;
13618
13619 if (names)
13620 {
13621 int i;
dc43ef94
KH
13622
13623 /* Make a list of all the fonts we got back.
13624 Store that in the font cache for the display. */
13625 for (i = 0; i < num_fonts; i++)
13626 {
06a2c219 13627 int width = 0;
dc43ef94 13628 char *p = names[i];
06a2c219
GM
13629 int average_width = -1, dashes = 0;
13630
dc43ef94 13631 /* Count the number of dashes in NAMES[I]. If there are
9c11f79e
GM
13632 14 dashes, and the field value following 12th dash
13633 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
13634 is usually too ugly to be used for editing. Let's
13635 ignore it. */
dc43ef94
KH
13636 while (*p)
13637 if (*p++ == '-')
13638 {
13639 dashes++;
13640 if (dashes == 7) /* PIXEL_SIZE field */
13641 width = atoi (p);
13642 else if (dashes == 12) /* AVERAGE_WIDTH field */
13643 average_width = atoi (p);
13644 }
9c11f79e
GM
13645
13646 if (allow_scalable_fonts_p
13647 || dashes < 14 || average_width != 0)
dc43ef94
KH
13648 {
13649 tem = build_string (names[i]);
13650 if (NILP (Fassoc (tem, list)))
13651 {
13652 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
13653 && ((fast_c_string_match_ignore_case
13654 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
13655 >= 0))
13656 /* We can set the value of PIXEL_SIZE to the
b5210ea7 13657 width of this font. */
dc43ef94
KH
13658 list = Fcons (Fcons (tem, make_number (width)), list);
13659 else
13660 /* For the moment, width is not known. */
13661 list = Fcons (Fcons (tem, Qnil), list);
13662 }
13663 }
13664 }
e38f4136 13665
09c6077f 13666 if (!try_XLoadQueryFont)
e38f4136
GM
13667 {
13668 BLOCK_INPUT;
13669 XFreeFontNames (names);
13670 UNBLOCK_INPUT;
13671 }
dc43ef94
KH
13672 }
13673
b5210ea7 13674 /* Now store the result in the cache. */
f3fbd155
KR
13675 XSETCDR (dpyinfo->name_list_element,
13676 Fcons (Fcons (key, list), XCDR (dpyinfo->name_list_element)));
dc43ef94 13677
b5210ea7
KH
13678 label_cached:
13679 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 13680
b5210ea7
KH
13681 newlist = second_best = Qnil;
13682 /* Make a list of the fonts that have the right width. */
8e713be6 13683 for (; CONSP (list); list = XCDR (list))
b5210ea7 13684 {
536f4067
RS
13685 int found_size;
13686
8e713be6 13687 tem = XCAR (list);
dc43ef94 13688
8e713be6 13689 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
13690 continue;
13691 if (!size)
13692 {
8e713be6 13693 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
13694 continue;
13695 }
dc43ef94 13696
8e713be6 13697 if (!INTEGERP (XCDR (tem)))
dc43ef94 13698 {
b5210ea7 13699 /* Since we have not yet known the size of this font, we
9c11f79e 13700 must try slow function call XLoadQueryFont. */
dc43ef94
KH
13701 XFontStruct *thisinfo;
13702
13703 BLOCK_INPUT;
17d85edc 13704 count = x_catch_errors (dpy);
dc43ef94 13705 thisinfo = XLoadQueryFont (dpy,
8e713be6 13706 XSTRING (XCAR (tem))->data);
17d85edc
KH
13707 if (x_had_errors_p (dpy))
13708 {
13709 /* This error is perhaps due to insufficient memory on X
13710 server. Let's just ignore it. */
13711 thisinfo = NULL;
13712 x_clear_errors (dpy);
13713 }
13714 x_uncatch_errors (dpy, count);
dc43ef94
KH
13715 UNBLOCK_INPUT;
13716
13717 if (thisinfo)
13718 {
f3fbd155
KR
13719 XSETCDR (tem,
13720 (thisinfo->min_bounds.width == 0
13721 ? make_number (0)
13722 : make_number (thisinfo->max_bounds.width)));
e38f4136 13723 BLOCK_INPUT;
dc43ef94 13724 XFreeFont (dpy, thisinfo);
e38f4136 13725 UNBLOCK_INPUT;
dc43ef94
KH
13726 }
13727 else
b5210ea7 13728 /* For unknown reason, the previous call of XListFont had
06a2c219 13729 returned a font which can't be opened. Record the size
b5210ea7 13730 as 0 not to try to open it again. */
f3fbd155 13731 XSETCDR (tem, make_number (0));
dc43ef94 13732 }
536f4067 13733
8e713be6 13734 found_size = XINT (XCDR (tem));
536f4067 13735 if (found_size == size)
8e713be6 13736 newlist = Fcons (XCAR (tem), newlist);
536f4067 13737 else if (found_size > 0)
b5210ea7 13738 {
536f4067 13739 if (NILP (second_best))
b5210ea7 13740 second_best = tem;
536f4067
RS
13741 else if (found_size < size)
13742 {
8e713be6
KR
13743 if (XINT (XCDR (second_best)) > size
13744 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
13745 second_best = tem;
13746 }
13747 else
13748 {
8e713be6
KR
13749 if (XINT (XCDR (second_best)) > size
13750 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
13751 second_best = tem;
13752 }
b5210ea7
KH
13753 }
13754 }
13755 if (!NILP (newlist))
13756 break;
13757 else if (!NILP (second_best))
13758 {
8e713be6 13759 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 13760 break;
dc43ef94 13761 }
dc43ef94
KH
13762 }
13763
13764 return newlist;
13765}
13766
06a2c219
GM
13767
13768#if GLYPH_DEBUG
13769
13770/* Check that FONT is valid on frame F. It is if it can be found in F's
13771 font table. */
13772
13773static void
13774x_check_font (f, font)
13775 struct frame *f;
13776 XFontStruct *font;
13777{
13778 int i;
13779 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13780
13781 xassert (font != NULL);
13782
13783 for (i = 0; i < dpyinfo->n_fonts; i++)
13784 if (dpyinfo->font_table[i].name
13785 && font == dpyinfo->font_table[i].font)
13786 break;
13787
13788 xassert (i < dpyinfo->n_fonts);
13789}
13790
13791#endif /* GLYPH_DEBUG != 0 */
13792
13793/* Set *W to the minimum width, *H to the minimum font height of FONT.
13794 Note: There are (broken) X fonts out there with invalid XFontStruct
13795 min_bounds contents. For example, handa@etl.go.jp reports that
13796 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
13797 have font->min_bounds.width == 0. */
13798
13799static INLINE void
13800x_font_min_bounds (font, w, h)
13801 XFontStruct *font;
13802 int *w, *h;
13803{
13804 *h = FONT_HEIGHT (font);
13805 *w = font->min_bounds.width;
13806
13807 /* Try to handle the case where FONT->min_bounds has invalid
13808 contents. Since the only font known to have invalid min_bounds
13809 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
13810 if (*w <= 0)
13811 *w = font->max_bounds.width;
13812}
13813
13814
13815/* Compute the smallest character width and smallest font height over
13816 all fonts available on frame F. Set the members smallest_char_width
13817 and smallest_font_height in F's x_display_info structure to
13818 the values computed. Value is non-zero if smallest_font_height or
13819 smallest_char_width become smaller than they were before. */
13820
13821static int
13822x_compute_min_glyph_bounds (f)
13823 struct frame *f;
13824{
13825 int i;
13826 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13827 XFontStruct *font;
13828 int old_width = dpyinfo->smallest_char_width;
13829 int old_height = dpyinfo->smallest_font_height;
13830
13831 dpyinfo->smallest_font_height = 100000;
13832 dpyinfo->smallest_char_width = 100000;
13833
13834 for (i = 0; i < dpyinfo->n_fonts; ++i)
13835 if (dpyinfo->font_table[i].name)
13836 {
13837 struct font_info *fontp = dpyinfo->font_table + i;
13838 int w, h;
13839
13840 font = (XFontStruct *) fontp->font;
13841 xassert (font != (XFontStruct *) ~0);
13842 x_font_min_bounds (font, &w, &h);
13843
13844 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
13845 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
13846 }
13847
13848 xassert (dpyinfo->smallest_char_width > 0
13849 && dpyinfo->smallest_font_height > 0);
13850
13851 return (dpyinfo->n_fonts == 1
13852 || dpyinfo->smallest_char_width < old_width
13853 || dpyinfo->smallest_font_height < old_height);
13854}
13855
13856
dc43ef94
KH
13857/* Load font named FONTNAME of the size SIZE for frame F, and return a
13858 pointer to the structure font_info while allocating it dynamically.
13859 If SIZE is 0, load any size of font.
13860 If loading is failed, return NULL. */
13861
13862struct font_info *
13863x_load_font (f, fontname, size)
13864 struct frame *f;
13865 register char *fontname;
13866 int size;
13867{
13868 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13869 Lisp_Object font_names;
d645aaa4 13870 int count;
dc43ef94
KH
13871
13872 /* Get a list of all the fonts that match this name. Once we
13873 have a list of matching fonts, we compare them against the fonts
13874 we already have by comparing names. */
09c6077f 13875 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
13876
13877 if (!NILP (font_names))
13878 {
13879 Lisp_Object tail;
13880 int i;
13881
13882 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 13883 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
13884 if (dpyinfo->font_table[i].name
13885 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 13886 XSTRING (XCAR (tail))->data)
06a2c219 13887 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 13888 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
13889 return (dpyinfo->font_table + i);
13890 }
13891
13892 /* Load the font and add it to the table. */
13893 {
13894 char *full_name;
13895 XFontStruct *font;
13896 struct font_info *fontp;
13897 unsigned long value;
06a2c219 13898 int i;
dc43ef94 13899
2da424f1
KH
13900 /* If we have found fonts by x_list_font, load one of them. If
13901 not, we still try to load a font by the name given as FONTNAME
13902 because XListFonts (called in x_list_font) of some X server has
13903 a bug of not finding a font even if the font surely exists and
13904 is loadable by XLoadQueryFont. */
e1d6d5b9 13905 if (size > 0 && !NILP (font_names))
8e713be6 13906 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
13907
13908 BLOCK_INPUT;
d645aaa4 13909 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 13910 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
13911 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
13912 {
13913 /* This error is perhaps due to insufficient memory on X
13914 server. Let's just ignore it. */
13915 font = NULL;
13916 x_clear_errors (FRAME_X_DISPLAY (f));
13917 }
13918 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 13919 UNBLOCK_INPUT;
b5210ea7 13920 if (!font)
dc43ef94
KH
13921 return NULL;
13922
06a2c219
GM
13923 /* Find a free slot in the font table. */
13924 for (i = 0; i < dpyinfo->n_fonts; ++i)
13925 if (dpyinfo->font_table[i].name == NULL)
13926 break;
13927
13928 /* If no free slot found, maybe enlarge the font table. */
13929 if (i == dpyinfo->n_fonts
13930 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 13931 {
06a2c219
GM
13932 int sz;
13933 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
13934 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 13935 dpyinfo->font_table
06a2c219 13936 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
13937 }
13938
06a2c219
GM
13939 fontp = dpyinfo->font_table + i;
13940 if (i == dpyinfo->n_fonts)
13941 ++dpyinfo->n_fonts;
dc43ef94
KH
13942
13943 /* Now fill in the slots of *FONTP. */
13944 BLOCK_INPUT;
13945 fontp->font = font;
06a2c219 13946 fontp->font_idx = i;
dc43ef94
KH
13947 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
13948 bcopy (fontname, fontp->name, strlen (fontname) + 1);
13949
13950 /* Try to get the full name of FONT. Put it in FULL_NAME. */
13951 full_name = 0;
13952 if (XGetFontProperty (font, XA_FONT, &value))
13953 {
13954 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
13955 char *p = name;
13956 int dashes = 0;
13957
13958 /* Count the number of dashes in the "full name".
13959 If it is too few, this isn't really the font's full name,
13960 so don't use it.
13961 In X11R4, the fonts did not come with their canonical names
13962 stored in them. */
13963 while (*p)
13964 {
13965 if (*p == '-')
13966 dashes++;
13967 p++;
13968 }
13969
13970 if (dashes >= 13)
13971 {
13972 full_name = (char *) xmalloc (p - name + 1);
13973 bcopy (name, full_name, p - name + 1);
13974 }
13975
13976 XFree (name);
13977 }
13978
13979 if (full_name != 0)
13980 fontp->full_name = full_name;
13981 else
13982 fontp->full_name = fontp->name;
13983
13984 fontp->size = font->max_bounds.width;
d5749adb 13985 fontp->height = FONT_HEIGHT (font);
dc43ef94 13986
2da424f1
KH
13987 if (NILP (font_names))
13988 {
13989 /* We come here because of a bug of XListFonts mentioned at
13990 the head of this block. Let's store this information in
13991 the cache for x_list_fonts. */
13992 Lisp_Object lispy_name = build_string (fontname);
13993 Lisp_Object lispy_full_name = build_string (fontp->full_name);
9c11f79e
GM
13994 Lisp_Object key = Fcons (Fcons (lispy_name, make_number (256)),
13995 Qnil);
2da424f1 13996
f3fbd155
KR
13997 XSETCDR (dpyinfo->name_list_element,
13998 Fcons (Fcons (key,
13999 Fcons (Fcons (lispy_full_name,
14000 make_number (fontp->size)),
14001 Qnil)),
14002 XCDR (dpyinfo->name_list_element)));
2da424f1 14003 if (full_name)
9c11f79e
GM
14004 {
14005 key = Fcons (Fcons (lispy_full_name, make_number (256)),
14006 Qnil);
f3fbd155
KR
14007 XSETCDR (dpyinfo->name_list_element,
14008 Fcons (Fcons (key,
14009 Fcons (Fcons (lispy_full_name,
14010 make_number (fontp->size)),
14011 Qnil)),
14012 XCDR (dpyinfo->name_list_element)));
9c11f79e 14013 }
2da424f1
KH
14014 }
14015
dc43ef94
KH
14016 /* The slot `encoding' specifies how to map a character
14017 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
14018 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
14019 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 14020 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 14021 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
14022 which is never used by any charset. If mapping can't be
14023 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
14024 fontp->encoding[1]
14025 = (font->max_byte1 == 0
14026 /* 1-byte font */
14027 ? (font->min_char_or_byte2 < 0x80
14028 ? (font->max_char_or_byte2 < 0x80
14029 ? 0 /* 0x20..0x7F */
8ff102bd 14030 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
14031 : 1) /* 0xA0..0xFF */
14032 /* 2-byte font */
14033 : (font->min_byte1 < 0x80
14034 ? (font->max_byte1 < 0x80
14035 ? (font->min_char_or_byte2 < 0x80
14036 ? (font->max_char_or_byte2 < 0x80
14037 ? 0 /* 0x2020..0x7F7F */
8ff102bd 14038 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 14039 : 3) /* 0x20A0..0x7FFF */
8ff102bd 14040 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
14041 : (font->min_char_or_byte2 < 0x80
14042 ? (font->max_char_or_byte2 < 0x80
14043 ? 2 /* 0xA020..0xFF7F */
8ff102bd 14044 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
14045 : 1))); /* 0xA0A0..0xFFFF */
14046
14047 fontp->baseline_offset
14048 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
14049 ? (long) value : 0);
14050 fontp->relative_compose
14051 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
14052 ? (long) value : 0);
f78798df
KH
14053 fontp->default_ascent
14054 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
14055 ? (long) value : 0);
dc43ef94 14056
06a2c219
GM
14057 /* Set global flag fonts_changed_p to non-zero if the font loaded
14058 has a character with a smaller width than any other character
14059 before, or if the font loaded has a smalle>r height than any
14060 other font loaded before. If this happens, it will make a
14061 glyph matrix reallocation necessary. */
14062 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 14063 UNBLOCK_INPUT;
dc43ef94
KH
14064 return fontp;
14065 }
14066}
14067
06a2c219
GM
14068
14069/* Return a pointer to struct font_info of a font named FONTNAME for
14070 frame F. If no such font is loaded, return NULL. */
14071
dc43ef94
KH
14072struct font_info *
14073x_query_font (f, fontname)
14074 struct frame *f;
14075 register char *fontname;
14076{
14077 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14078 int i;
14079
14080 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
14081 if (dpyinfo->font_table[i].name
14082 && (!strcmp (dpyinfo->font_table[i].name, fontname)
14083 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
14084 return (dpyinfo->font_table + i);
14085 return NULL;
14086}
14087
06a2c219
GM
14088
14089/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
14090 `encoder' of the structure. */
14091
14092void
14093x_find_ccl_program (fontp)
14094 struct font_info *fontp;
14095{
a42f54e6 14096 Lisp_Object list, elt;
a6582676 14097
f9b5db02 14098 elt = Qnil;
8e713be6 14099 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 14100 {
8e713be6 14101 elt = XCAR (list);
a6582676 14102 if (CONSP (elt)
8e713be6 14103 && STRINGP (XCAR (elt))
9f2feff6
KH
14104 && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
14105 >= 0)
14106 || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
14107 >= 0)))
a42f54e6
KH
14108 break;
14109 }
f9b5db02 14110
a42f54e6
KH
14111 if (! NILP (list))
14112 {
d27f8ca7
KH
14113 struct ccl_program *ccl
14114 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 14115
8e713be6 14116 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
14117 xfree (ccl);
14118 else
14119 fontp->font_encoder = ccl;
a6582676
KH
14120 }
14121}
14122
06a2c219 14123
dc43ef94 14124\f
06a2c219
GM
14125/***********************************************************************
14126 Initialization
14127 ***********************************************************************/
f451eb13 14128
3afe33e7
RS
14129#ifdef USE_X_TOOLKIT
14130static XrmOptionDescRec emacs_options[] = {
14131 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
14132 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
14133
14134 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
14135 XrmoptionSepArg, NULL},
14136 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
14137
14138 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14139 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14140 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14141 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14142 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14143 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
14144 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
14145};
14146#endif /* USE_X_TOOLKIT */
14147
7a13e894
RS
14148static int x_initialized;
14149
29b38361
KH
14150#ifdef MULTI_KBOARD
14151/* Test whether two display-name strings agree up to the dot that separates
14152 the screen number from the server number. */
14153static int
14154same_x_server (name1, name2)
14155 char *name1, *name2;
14156{
14157 int seen_colon = 0;
cf591cc1
RS
14158 unsigned char *system_name = XSTRING (Vsystem_name)->data;
14159 int system_name_length = strlen (system_name);
14160 int length_until_period = 0;
14161
14162 while (system_name[length_until_period] != 0
14163 && system_name[length_until_period] != '.')
14164 length_until_period++;
14165
14166 /* Treat `unix' like an empty host name. */
14167 if (! strncmp (name1, "unix:", 5))
14168 name1 += 4;
14169 if (! strncmp (name2, "unix:", 5))
14170 name2 += 4;
14171 /* Treat this host's name like an empty host name. */
14172 if (! strncmp (name1, system_name, system_name_length)
14173 && name1[system_name_length] == ':')
14174 name1 += system_name_length;
14175 if (! strncmp (name2, system_name, system_name_length)
14176 && name2[system_name_length] == ':')
14177 name2 += system_name_length;
14178 /* Treat this host's domainless name like an empty host name. */
14179 if (! strncmp (name1, system_name, length_until_period)
14180 && name1[length_until_period] == ':')
14181 name1 += length_until_period;
14182 if (! strncmp (name2, system_name, length_until_period)
14183 && name2[length_until_period] == ':')
14184 name2 += length_until_period;
14185
29b38361
KH
14186 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
14187 {
14188 if (*name1 == ':')
14189 seen_colon++;
14190 if (seen_colon && *name1 == '.')
14191 return 1;
14192 }
14193 return (seen_colon
14194 && (*name1 == '.' || *name1 == '\0')
14195 && (*name2 == '.' || *name2 == '\0'));
14196}
14197#endif
14198
334208b7 14199struct x_display_info *
1f8255f2 14200x_term_init (display_name, xrm_option, resource_name)
334208b7 14201 Lisp_Object display_name;
1f8255f2
RS
14202 char *xrm_option;
14203 char *resource_name;
dc6f92b8 14204{
334208b7 14205 int connection;
7a13e894 14206 Display *dpy;
334208b7
RS
14207 struct x_display_info *dpyinfo;
14208 XrmDatabase xrdb;
14209
60439948
KH
14210 BLOCK_INPUT;
14211
7a13e894
RS
14212 if (!x_initialized)
14213 {
14214 x_initialize ();
14215 x_initialized = 1;
14216 }
dc6f92b8 14217
3afe33e7 14218#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
14219 /* weiner@footloose.sps.mot.com reports that this causes
14220 errors with X11R5:
14221 X protocol error: BadAtom (invalid Atom parameter)
14222 on protocol request 18skiloaf.
14223 So let's not use it until R6. */
14224#ifdef HAVE_X11XTR6
bdcd49ba
RS
14225 XtSetLanguageProc (NULL, NULL, NULL);
14226#endif
14227
7f9c7f94
RS
14228 {
14229 int argc = 0;
14230 char *argv[3];
14231
14232 argv[0] = "";
14233 argc = 1;
14234 if (xrm_option)
14235 {
14236 argv[argc++] = "-xrm";
14237 argv[argc++] = xrm_option;
14238 }
14239 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
14240 resource_name, EMACS_CLASS,
14241 emacs_options, XtNumber (emacs_options),
14242 &argc, argv);
39d8bb4d
KH
14243
14244#ifdef HAVE_X11XTR6
10537cb1 14245 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 14246 fixup_locale ();
39d8bb4d 14247#endif
7f9c7f94 14248 }
3afe33e7
RS
14249
14250#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
14251#ifdef HAVE_X11R5
14252 XSetLocaleModifiers ("");
14253#endif
7a13e894 14254 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 14255#endif /* not USE_X_TOOLKIT */
334208b7 14256
7a13e894
RS
14257 /* Detect failure. */
14258 if (dpy == 0)
60439948
KH
14259 {
14260 UNBLOCK_INPUT;
14261 return 0;
14262 }
7a13e894
RS
14263
14264 /* We have definitely succeeded. Record the new connection. */
14265
14266 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
f04e1297 14267 bzero (dpyinfo, sizeof *dpyinfo);
7a13e894 14268
29b38361
KH
14269#ifdef MULTI_KBOARD
14270 {
14271 struct x_display_info *share;
14272 Lisp_Object tail;
14273
14274 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
14275 share = share->next, tail = XCDR (tail))
14276 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
14277 XSTRING (display_name)->data))
14278 break;
14279 if (share)
14280 dpyinfo->kboard = share->kboard;
14281 else
14282 {
14283 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
14284 init_kboard (dpyinfo->kboard);
59e755be
KH
14285 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
14286 {
14287 char *vendor = ServerVendor (dpy);
9b6ed9f3 14288 UNBLOCK_INPUT;
59e755be
KH
14289 dpyinfo->kboard->Vsystem_key_alist
14290 = call1 (Qvendor_specific_keysyms,
14291 build_string (vendor ? vendor : ""));
9b6ed9f3 14292 BLOCK_INPUT;
59e755be
KH
14293 }
14294
29b38361
KH
14295 dpyinfo->kboard->next_kboard = all_kboards;
14296 all_kboards = dpyinfo->kboard;
0ad5446c
KH
14297 /* Don't let the initial kboard remain current longer than necessary.
14298 That would cause problems if a file loaded on startup tries to
06a2c219 14299 prompt in the mini-buffer. */
0ad5446c
KH
14300 if (current_kboard == initial_kboard)
14301 current_kboard = dpyinfo->kboard;
29b38361
KH
14302 }
14303 dpyinfo->kboard->reference_count++;
14304 }
b9737ad3
KH
14305#endif
14306
7a13e894
RS
14307 /* Put this display on the chain. */
14308 dpyinfo->next = x_display_list;
14309 x_display_list = dpyinfo;
14310
14311 /* Put it on x_display_name_list as well, to keep them parallel. */
14312 x_display_name_list = Fcons (Fcons (display_name, Qnil),
14313 x_display_name_list);
8e713be6 14314 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
14315
14316 dpyinfo->display = dpy;
dc6f92b8 14317
dc6f92b8 14318#if 0
7a13e894 14319 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 14320#endif /* ! 0 */
7a13e894
RS
14321
14322 dpyinfo->x_id_name
fc932ac6
RS
14323 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
14324 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
14325 + 2);
14326 sprintf (dpyinfo->x_id_name, "%s@%s",
14327 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
14328
14329 /* Figure out which modifier bits mean what. */
334208b7 14330 x_find_modifier_meanings (dpyinfo);
f451eb13 14331
ab648270 14332 /* Get the scroll bar cursor. */
7a13e894 14333 dpyinfo->vertical_scroll_bar_cursor
334208b7 14334 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 14335
334208b7
RS
14336 xrdb = x_load_resources (dpyinfo->display, xrm_option,
14337 resource_name, EMACS_CLASS);
14338#ifdef HAVE_XRMSETDATABASE
14339 XrmSetDatabase (dpyinfo->display, xrdb);
14340#else
14341 dpyinfo->display->db = xrdb;
14342#endif
547d9db8 14343 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
14344 all versions. */
14345 dpyinfo->xrdb = xrdb;
334208b7
RS
14346
14347 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
14348 DefaultScreen (dpyinfo->display));
5ff67d81 14349 select_visual (dpyinfo);
43bd1b2b 14350 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
14351 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
14352 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
14353 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
14354 dpyinfo->grabbed = 0;
14355 dpyinfo->reference_count = 0;
14356 dpyinfo->icon_bitmap_id = -1;
06a2c219 14357 dpyinfo->font_table = NULL;
7a13e894
RS
14358 dpyinfo->n_fonts = 0;
14359 dpyinfo->font_table_size = 0;
14360 dpyinfo->bitmaps = 0;
14361 dpyinfo->bitmaps_size = 0;
14362 dpyinfo->bitmaps_last = 0;
14363 dpyinfo->scratch_cursor_gc = 0;
14364 dpyinfo->mouse_face_mouse_frame = 0;
14365 dpyinfo->mouse_face_deferred_gc = 0;
14366 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
14367 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 14368 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894 14369 dpyinfo->mouse_face_window = Qnil;
0a61c667 14370 dpyinfo->mouse_face_overlay = Qnil;
7a13e894
RS
14371 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
14372 dpyinfo->mouse_face_defer = 0;
0f941935
KH
14373 dpyinfo->x_focus_frame = 0;
14374 dpyinfo->x_focus_event_frame = 0;
14375 dpyinfo->x_highlight_frame = 0;
06a2c219 14376 dpyinfo->image_cache = make_image_cache ();
334208b7 14377
43bd1b2b 14378 /* See if a private colormap is requested. */
5ff67d81
GM
14379 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
14380 {
14381 if (dpyinfo->visual->class == PseudoColor)
14382 {
14383 Lisp_Object value;
14384 value = display_x_get_resource (dpyinfo,
14385 build_string ("privateColormap"),
14386 build_string ("PrivateColormap"),
14387 Qnil, Qnil);
14388 if (STRINGP (value)
14389 && (!strcmp (XSTRING (value)->data, "true")
14390 || !strcmp (XSTRING (value)->data, "on")))
14391 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
14392 }
43bd1b2b 14393 }
5ff67d81
GM
14394 else
14395 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
14396 dpyinfo->visual, AllocNone);
43bd1b2b 14397
06a2c219
GM
14398 {
14399 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
14400 double pixels = DisplayHeight (dpyinfo->display, screen_number);
14401 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
14402 dpyinfo->resy = pixels * 25.4 / mm;
14403 pixels = DisplayWidth (dpyinfo->display, screen_number);
14404 mm = DisplayWidthMM (dpyinfo->display, screen_number);
14405 dpyinfo->resx = pixels * 25.4 / mm;
14406 }
14407
334208b7
RS
14408 dpyinfo->Xatom_wm_protocols
14409 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
14410 dpyinfo->Xatom_wm_take_focus
14411 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
14412 dpyinfo->Xatom_wm_save_yourself
14413 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
14414 dpyinfo->Xatom_wm_delete_window
14415 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
14416 dpyinfo->Xatom_wm_change_state
14417 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
14418 dpyinfo->Xatom_wm_configure_denied
14419 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
14420 dpyinfo->Xatom_wm_window_moved
14421 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
14422 dpyinfo->Xatom_editres
14423 = XInternAtom (dpyinfo->display, "Editres", False);
14424 dpyinfo->Xatom_CLIPBOARD
14425 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
14426 dpyinfo->Xatom_TIMESTAMP
14427 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
14428 dpyinfo->Xatom_TEXT
14429 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
14430 dpyinfo->Xatom_COMPOUND_TEXT
14431 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
14432 dpyinfo->Xatom_DELETE
14433 = XInternAtom (dpyinfo->display, "DELETE", False);
14434 dpyinfo->Xatom_MULTIPLE
14435 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
14436 dpyinfo->Xatom_INCR
14437 = XInternAtom (dpyinfo->display, "INCR", False);
14438 dpyinfo->Xatom_EMACS_TMP
14439 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
14440 dpyinfo->Xatom_TARGETS
14441 = XInternAtom (dpyinfo->display, "TARGETS", False);
14442 dpyinfo->Xatom_NULL
14443 = XInternAtom (dpyinfo->display, "NULL", False);
14444 dpyinfo->Xatom_ATOM_PAIR
14445 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
14446 /* For properties of font. */
14447 dpyinfo->Xatom_PIXEL_SIZE
14448 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
14449 dpyinfo->Xatom_MULE_BASELINE_OFFSET
14450 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
14451 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
14452 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
14453 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
14454 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 14455
06a2c219
GM
14456 /* Ghostscript support. */
14457 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
14458 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
14459
14460 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
14461 False);
14462
547d9db8
KH
14463 dpyinfo->cut_buffers_initialized = 0;
14464
334208b7
RS
14465 connection = ConnectionNumber (dpyinfo->display);
14466 dpyinfo->connection = connection;
14467
dc43ef94 14468 {
5d7cc324
RS
14469 char null_bits[1];
14470
14471 null_bits[0] = 0x00;
dc43ef94
KH
14472
14473 dpyinfo->null_pixel
14474 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14475 null_bits, 1, 1, (long) 0, (long) 0,
14476 1);
14477 }
14478
06a2c219
GM
14479 {
14480 extern int gray_bitmap_width, gray_bitmap_height;
10659c77 14481 extern char *gray_bitmap_bits;
06a2c219
GM
14482 dpyinfo->gray
14483 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14484 gray_bitmap_bits,
14485 gray_bitmap_width, gray_bitmap_height,
14486 (unsigned long) 1, (unsigned long) 0, 1);
14487 }
14488
f5d11644
GM
14489#ifdef HAVE_X_I18N
14490 xim_initialize (dpyinfo, resource_name);
14491#endif
14492
87485d6f
MW
14493#ifdef subprocesses
14494 /* This is only needed for distinguishing keyboard and process input. */
334208b7 14495 if (connection != 0)
7a13e894 14496 add_keyboard_wait_descriptor (connection);
87485d6f 14497#endif
6d4238f3 14498
041b69ac 14499#ifndef F_SETOWN_BUG
dc6f92b8 14500#ifdef F_SETOWN
dc6f92b8 14501#ifdef F_SETOWN_SOCK_NEG
61c3ce62 14502 /* stdin is a socket here */
334208b7 14503 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 14504#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 14505 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
14506#endif /* ! defined (F_SETOWN_SOCK_NEG) */
14507#endif /* ! defined (F_SETOWN) */
041b69ac 14508#endif /* F_SETOWN_BUG */
dc6f92b8
JB
14509
14510#ifdef SIGIO
eee20f6a
KH
14511 if (interrupt_input)
14512 init_sigio (connection);
c118dd06 14513#endif /* ! defined (SIGIO) */
dc6f92b8 14514
51b592fb 14515#ifdef USE_LUCID
f8c39f51 14516#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
14517 /* Make sure that we have a valid font for dialog boxes
14518 so that Xt does not crash. */
14519 {
14520 Display *dpy = dpyinfo->display;
14521 XrmValue d, fr, to;
14522 Font font;
e99db5a1 14523 int count;
51b592fb
RS
14524
14525 d.addr = (XPointer)&dpy;
14526 d.size = sizeof (Display *);
14527 fr.addr = XtDefaultFont;
14528 fr.size = sizeof (XtDefaultFont);
14529 to.size = sizeof (Font *);
14530 to.addr = (XPointer)&font;
e99db5a1 14531 count = x_catch_errors (dpy);
51b592fb
RS
14532 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
14533 abort ();
14534 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
14535 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 14536 x_uncatch_errors (dpy, count);
51b592fb
RS
14537 }
14538#endif
f8c39f51 14539#endif
51b592fb 14540
34e23e5a
GM
14541 /* See if we should run in synchronous mode. This is useful
14542 for debugging X code. */
14543 {
14544 Lisp_Object value;
14545 value = display_x_get_resource (dpyinfo,
14546 build_string ("synchronous"),
14547 build_string ("Synchronous"),
14548 Qnil, Qnil);
14549 if (STRINGP (value)
14550 && (!strcmp (XSTRING (value)->data, "true")
14551 || !strcmp (XSTRING (value)->data, "on")))
14552 XSynchronize (dpyinfo->display, True);
14553 }
14554
60439948
KH
14555 UNBLOCK_INPUT;
14556
7a13e894
RS
14557 return dpyinfo;
14558}
14559\f
14560/* Get rid of display DPYINFO, assuming all frames are already gone,
14561 and without sending any more commands to the X server. */
dc6f92b8 14562
7a13e894
RS
14563void
14564x_delete_display (dpyinfo)
14565 struct x_display_info *dpyinfo;
14566{
14567 delete_keyboard_wait_descriptor (dpyinfo->connection);
14568
14569 /* Discard this display from x_display_name_list and x_display_list.
14570 We can't use Fdelq because that can quit. */
14571 if (! NILP (x_display_name_list)
8e713be6
KR
14572 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
14573 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
14574 else
14575 {
14576 Lisp_Object tail;
14577
14578 tail = x_display_name_list;
8e713be6 14579 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 14580 {
bffcfca9 14581 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 14582 {
f3fbd155 14583 XSETCDR (tail, XCDR (XCDR (tail)));
7a13e894
RS
14584 break;
14585 }
8e713be6 14586 tail = XCDR (tail);
7a13e894
RS
14587 }
14588 }
14589
9bda743f
GM
14590 if (next_noop_dpyinfo == dpyinfo)
14591 next_noop_dpyinfo = dpyinfo->next;
14592
7a13e894
RS
14593 if (x_display_list == dpyinfo)
14594 x_display_list = dpyinfo->next;
7f9c7f94
RS
14595 else
14596 {
14597 struct x_display_info *tail;
7a13e894 14598
7f9c7f94
RS
14599 for (tail = x_display_list; tail; tail = tail->next)
14600 if (tail->next == dpyinfo)
14601 tail->next = tail->next->next;
14602 }
7a13e894 14603
0d777288
RS
14604#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
14605#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
14606 XrmDestroyDatabase (dpyinfo->xrdb);
14607#endif
0d777288 14608#endif
29b38361
KH
14609#ifdef MULTI_KBOARD
14610 if (--dpyinfo->kboard->reference_count == 0)
39f79001 14611 delete_kboard (dpyinfo->kboard);
b9737ad3 14612#endif
f5d11644
GM
14613#ifdef HAVE_X_I18N
14614 if (dpyinfo->xim)
14615 xim_close_dpy (dpyinfo);
14616#endif
14617
b9737ad3
KH
14618 xfree (dpyinfo->font_table);
14619 xfree (dpyinfo->x_id_name);
f04e1297 14620 xfree (dpyinfo->color_cells);
b9737ad3 14621 xfree (dpyinfo);
7a13e894 14622}
f04e1297 14623
7a13e894
RS
14624\f
14625/* Set up use of X before we make the first connection. */
14626
06a2c219
GM
14627static struct redisplay_interface x_redisplay_interface =
14628{
14629 x_produce_glyphs,
14630 x_write_glyphs,
14631 x_insert_glyphs,
14632 x_clear_end_of_line,
14633 x_scroll_run,
14634 x_after_update_window_line,
14635 x_update_window_begin,
14636 x_update_window_end,
14637 XTcursor_to,
14638 x_flush,
71b8321e 14639 x_clear_mouse_face,
66ac4b0e
GM
14640 x_get_glyph_overhangs,
14641 x_fix_overlapping_area
06a2c219
GM
14642};
14643
dfcf069d 14644void
7a13e894
RS
14645x_initialize ()
14646{
06a2c219
GM
14647 rif = &x_redisplay_interface;
14648
14649 clear_frame_hook = x_clear_frame;
14650 ins_del_lines_hook = x_ins_del_lines;
06a2c219 14651 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
14652 ring_bell_hook = XTring_bell;
14653 reset_terminal_modes_hook = XTreset_terminal_modes;
14654 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
14655 update_begin_hook = x_update_begin;
14656 update_end_hook = x_update_end;
dc6f92b8
JB
14657 set_terminal_window_hook = XTset_terminal_window;
14658 read_socket_hook = XTread_socket;
b8009dd1 14659 frame_up_to_date_hook = XTframe_up_to_date;
90e65f07 14660 mouse_position_hook = XTmouse_position;
f451eb13 14661 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 14662 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
14663 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
14664 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
14665 redeem_scroll_bar_hook = XTredeem_scroll_bar;
14666 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 14667 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 14668
f676886a 14669 scroll_region_ok = 1; /* we'll scroll partial frames */
9017309f 14670 char_ins_del_ok = 1;
dc6f92b8
JB
14671 line_ins_del_ok = 1; /* we'll just blt 'em */
14672 fast_clear_end_of_line = 1; /* X does this well */
58769bee 14673 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
14674 off the bottom */
14675 baud_rate = 19200;
14676
7a13e894 14677 x_noop_count = 0;
9ea173e8 14678 last_tool_bar_item = -1;
06a2c219
GM
14679 any_help_event_p = 0;
14680
b30b24cb
RS
14681 /* Try to use interrupt input; if we can't, then start polling. */
14682 Fset_input_mode (Qt, Qnil, Qt, Qnil);
14683
7f9c7f94
RS
14684#ifdef USE_X_TOOLKIT
14685 XtToolkitInitialize ();
651f03b6 14686
7f9c7f94 14687 Xt_app_con = XtCreateApplicationContext ();
651f03b6
GM
14688
14689 /* Register a converter from strings to pixels, which uses
14690 Emacs' color allocation infrastructure. */
14691 XtAppSetTypeConverter (Xt_app_con,
14692 XtRString, XtRPixel, cvt_string_to_pixel,
14693 cvt_string_to_pixel_args,
14694 XtNumber (cvt_string_to_pixel_args),
14695 XtCacheByDisplay, cvt_pixel_dtor);
14696
665881ad 14697 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
14698
14699 /* Install an asynchronous timer that processes Xt timeout events
14700 every 0.1s. This is necessary because some widget sets use
14701 timeouts internally, for example the LessTif menu bar, or the
14702 Xaw3d scroll bar. When Xt timouts aren't processed, these
14703 widgets don't behave normally. */
14704 {
14705 EMACS_TIME interval;
14706 EMACS_SET_SECS_USECS (interval, 0, 100000);
14707 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
14708 }
db74249b 14709#endif
bffcfca9 14710
eccc05db 14711#ifdef USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
14712 xaw3d_arrow_scroll = False;
14713 xaw3d_pick_top = True;
7f9c7f94
RS
14714#endif
14715
58769bee 14716 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 14717 original error handler. */
e99db5a1 14718 XSetErrorHandler (x_error_handler);
334208b7 14719 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 14720
06a2c219 14721 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
14722#ifdef SIGWINCH
14723 signal (SIGWINCH, SIG_DFL);
c118dd06 14724#endif /* ! defined (SIGWINCH) */
dc6f92b8 14725
92e2441b 14726 signal (SIGPIPE, x_connection_signal);
dc6f92b8 14727}
55123275 14728
06a2c219 14729
55123275
JB
14730void
14731syms_of_xterm ()
14732{
e99db5a1
RS
14733 staticpro (&x_error_message_string);
14734 x_error_message_string = Qnil;
14735
7a13e894
RS
14736 staticpro (&x_display_name_list);
14737 x_display_name_list = Qnil;
334208b7 14738
ab648270 14739 staticpro (&last_mouse_scroll_bar);
e53cb100 14740 last_mouse_scroll_bar = Qnil;
59e755be
KH
14741
14742 staticpro (&Qvendor_specific_keysyms);
14743 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
14744
14745 staticpro (&last_mouse_press_frame);
14746 last_mouse_press_frame = Qnil;
06a2c219 14747
06a2c219 14748 help_echo = Qnil;
be010514
GM
14749 staticpro (&help_echo);
14750 help_echo_object = Qnil;
14751 staticpro (&help_echo_object);
7cea38bc
GM
14752 help_echo_window = Qnil;
14753 staticpro (&help_echo_window);
06a2c219 14754 previous_help_echo = Qnil;
be010514
GM
14755 staticpro (&previous_help_echo);
14756 help_echo_pos = -1;
06a2c219 14757
7ee72033
MB
14758 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
14759 doc: /* *Non-nil means draw block cursor as wide as the glyph under it.
228299fa
GM
14760For example, if a block cursor is over a tab, it will be drawn as
14761wide as that tab on the display. */);
06a2c219
GM
14762 x_stretch_cursor_p = 0;
14763
a72d5ce5 14764 DEFVAR_BOOL ("x-use-underline-position-properties",
7ee72033
MB
14765 &x_use_underline_position_properties,
14766 doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
228299fa
GM
14767Nil means ignore them. If you encounter fonts with bogus
14768UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
14769to 4.1, set this to nil. */);
a72d5ce5
GM
14770 x_use_underline_position_properties = 1;
14771
7ee72033
MB
14772 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
14773 doc: /* What X toolkit scroll bars Emacs uses.
228299fa
GM
14774A value of nil means Emacs doesn't use X toolkit scroll bars.
14775Otherwise, value is a symbol describing the X toolkit. */);
eccc05db 14776#ifdef USE_TOOLKIT_SCROLL_BARS
5bf04520
GM
14777#ifdef USE_MOTIF
14778 Vx_toolkit_scroll_bars = intern ("motif");
14779#elif defined HAVE_XAW3D
14780 Vx_toolkit_scroll_bars = intern ("xaw3d");
14781#else
14782 Vx_toolkit_scroll_bars = intern ("xaw");
14783#endif
06a2c219 14784#else
5bf04520 14785 Vx_toolkit_scroll_bars = Qnil;
06a2c219
GM
14786#endif
14787
06a2c219
GM
14788 staticpro (&last_mouse_motion_frame);
14789 last_mouse_motion_frame = Qnil;
55123275 14790}
6cf0ae86 14791
1d6c120a 14792#endif /* HAVE_X_WINDOWS */