(struct x_display_info): Add mouse_face_overlay.
[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"
79#if 0
80#include "sink.h"
81#include "sinkmask.h"
c118dd06 82#endif /* ! 0 */
dc6f92b8 83#include "gnu.h"
dc6f92b8 84#include "disptab.h"
dc6f92b8 85#include "buffer.h"
f451eb13 86#include "window.h"
3b2fa4e6 87#include "keyboard.h"
bde7c500 88#include "intervals.h"
dfcf069d 89#include "process.h"
bffcfca9 90#include "atimer.h"
dc6f92b8 91
d2bd6bc4
RS
92#ifdef USE_X_TOOLKIT
93#include <X11/Shell.h>
94#endif
95
06a2c219
GM
96#ifdef HAVE_SYS_TIME_H
97#include <sys/time.h>
98#endif
99#ifdef HAVE_UNISTD_H
100#include <unistd.h>
101#endif
102
3afe33e7 103#ifdef USE_X_TOOLKIT
06a2c219 104
952291d9
GM
105extern void free_frame_menubar P_ ((struct frame *));
106extern struct frame *x_menubar_window_to_frame P_ ((struct x_display_info *,
107 int));
06a2c219 108
0fdff6bb
RS
109#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
110#define HACK_EDITRES
111extern void _XEditResCheckMessages ();
112#endif /* not NO_EDITRES */
06a2c219
GM
113
114/* Include toolkit specific headers for the scroll bar widget. */
115
116#ifdef USE_TOOLKIT_SCROLL_BARS
117#if defined USE_MOTIF
118#include <Xm/Xm.h> /* for LESSTIF_VERSION */
119#include <Xm/ScrollBar.h>
120#include <Xm/ScrollBarP.h>
ec18280f
SM
121#else /* !USE_MOTIF i.e. use Xaw */
122
123#ifdef HAVE_XAW3D
06a2c219 124#include <X11/Xaw3d/Simple.h>
06a2c219
GM
125#include <X11/Xaw3d/Scrollbar.h>
126#define ARROW_SCROLLBAR
127#include <X11/Xaw3d/ScrollbarP.h>
ec18280f
SM
128#else /* !HAVE_XAW3D */
129#include <X11/Xaw/Simple.h>
130#include <X11/Xaw/Scrollbar.h>
131#endif /* !HAVE_XAW3D */
132#ifndef XtNpickTop
133#define XtNpickTop "pickTop"
134#endif /* !XtNpickTop */
135#endif /* !USE_MOTIF */
06a2c219
GM
136#endif /* USE_TOOLKIT_SCROLL_BARS */
137
3afe33e7
RS
138#endif /* USE_X_TOOLKIT */
139
b849c413
RS
140#ifndef USE_X_TOOLKIT
141#define x_any_window_to_frame x_window_to_frame
5627c40e 142#define x_top_window_to_frame x_window_to_frame
b849c413
RS
143#endif
144
546e6d5b 145#ifdef USE_X_TOOLKIT
d067ea8b 146#include "widget.h"
546e6d5b
RS
147#ifndef XtNinitialState
148#define XtNinitialState "initialState"
149#endif
150#endif
151
e4b68333 152#ifndef min
06a2c219 153#define min(a,b) ((a) < (b) ? (a) : (b))
e4b68333
RS
154#endif
155#ifndef max
06a2c219
GM
156#define max(a,b) ((a) > (b) ? (a) : (b))
157#endif
158
159#define abs(x) ((x) < 0 ? -(x) : (x))
160
161#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
162
163\f
164/* Bitmaps for truncated lines. */
165
166enum bitmap_type
167{
168 NO_BITMAP,
169 LEFT_TRUNCATION_BITMAP,
170 RIGHT_TRUNCATION_BITMAP,
171 OVERLAY_ARROW_BITMAP,
172 CONTINUED_LINE_BITMAP,
173 CONTINUATION_LINE_BITMAP,
174 ZV_LINE_BITMAP
175};
176
177/* Bitmap drawn to indicate lines not displaying text if
178 `indicate-empty-lines' is non-nil. */
179
180#define zv_width 8
181#define zv_height 8
182static unsigned char zv_bits[] = {
183 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00};
184
185/* An arrow like this: `<-'. */
186
187#define left_width 8
188#define left_height 8
189static unsigned char left_bits[] = {
190 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
191
110859fc
GM
192/* Right truncation arrow bitmap `->'. */
193
194#define right_width 8
195#define right_height 8
196static unsigned char right_bits[] = {
197 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
198
06a2c219
GM
199/* Marker for continued lines. */
200
201#define continued_width 8
202#define continued_height 8
203static unsigned char continued_bits[] = {
110859fc
GM
204 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
205
206/* Marker for continuation lines. */
06a2c219
GM
207
208#define continuation_width 8
209#define continuation_height 8
210static unsigned char continuation_bits[] = {
110859fc 211 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
06a2c219 212
110859fc 213/* Overlay arrow bitmap. */
06a2c219 214
110859fc
GM
215#if 0
216/* A bomb. */
06a2c219
GM
217#define ov_width 8
218#define ov_height 8
219static unsigned char ov_bits[] = {
220 0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
06a2c219 221#else
110859fc 222/* A triangular arrow. */
06a2c219
GM
223#define ov_width 8
224#define ov_height 8
225static unsigned char ov_bits[] = {
110859fc
GM
226 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
227
e4b68333 228#endif
06a2c219
GM
229
230extern Lisp_Object Qhelp_echo;
231
69388238 232\f
5bf04520 233/* Non-nil means Emacs uses toolkit scroll bars. */
06a2c219 234
5bf04520 235Lisp_Object Vx_toolkit_scroll_bars;
06a2c219
GM
236
237/* If a string, XTread_socket generates an event to display that string.
238 (The display is done in read_char.) */
239
240static Lisp_Object help_echo;
7cea38bc 241static Lisp_Object help_echo_window;
be010514
GM
242static Lisp_Object help_echo_object;
243static int help_echo_pos;
06a2c219
GM
244
245/* Temporary variable for XTread_socket. */
246
247static Lisp_Object previous_help_echo;
248
249/* Non-zero means that a HELP_EVENT has been generated since Emacs
250 start. */
251
252static int any_help_event_p;
253
254/* Non-zero means draw block and hollow cursor as wide as the glyph
255 under it. For example, if a block cursor is over a tab, it will be
256 drawn as wide as that tab on the display. */
257
258int x_stretch_cursor_p;
259
260/* This is a chain of structures for all the X displays currently in
261 use. */
262
334208b7 263struct x_display_info *x_display_list;
dc6f92b8 264
06a2c219
GM
265/* This is a list of cons cells, each of the form (NAME
266 . FONT-LIST-CACHE), one for each element of x_display_list and in
267 the same order. NAME is the name of the frame. FONT-LIST-CACHE
268 records previous values returned by x-list-fonts. */
269
7a13e894 270Lisp_Object x_display_name_list;
f451eb13 271
987d2ad1 272/* Frame being updated by update_frame. This is declared in term.c.
06a2c219
GM
273 This is set by update_begin and looked at by all the XT functions.
274 It is zero while not inside an update. In that case, the XT
275 functions assume that `selected_frame' is the frame to apply to. */
276
d0386f2a 277extern struct frame *updating_frame;
dc6f92b8 278
dfcf069d 279extern int waiting_for_input;
0e81d8cd 280
06a2c219
GM
281/* This is a frame waiting to be auto-raised, within XTread_socket. */
282
0134a210
RS
283struct frame *pending_autoraise_frame;
284
7f9c7f94
RS
285#ifdef USE_X_TOOLKIT
286/* The application context for Xt use. */
287XtAppContext Xt_app_con;
06a2c219
GM
288static String Xt_default_resources[] = {0};
289#endif /* USE_X_TOOLKIT */
665881ad 290
06a2c219
GM
291/* Nominal cursor position -- where to draw output.
292 HPOS and VPOS are window relative glyph matrix coordinates.
293 X and Y are window relative pixel coordinates. */
dc6f92b8 294
06a2c219 295struct cursor_pos output_cursor;
dc6f92b8 296
bffcfca9
GM
297/* Non-zero means user is interacting with a toolkit scroll bar. */
298
299static int toolkit_scroll_bar_interaction;
dc6f92b8 300
69388238
RS
301/* Mouse movement.
302
06a2c219 303 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
304 so that we would have to call XQueryPointer after each MotionNotify
305 event to ask for another such event. However, this made mouse tracking
306 slow, and there was a bug that made it eventually stop.
307
308 Simply asking for MotionNotify all the time seems to work better.
309
69388238
RS
310 In order to avoid asking for motion events and then throwing most
311 of them away or busy-polling the server for mouse positions, we ask
312 the server for pointer motion hints. This means that we get only
313 one event per group of mouse movements. "Groups" are delimited by
314 other kinds of events (focus changes and button clicks, for
315 example), or by XQueryPointer calls; when one of these happens, we
316 get another MotionNotify event the next time the mouse moves. This
317 is at least as efficient as getting motion events when mouse
318 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 319 is off. */
69388238
RS
320
321/* Where the mouse was last time we reported a mouse event. */
69388238 322
06a2c219
GM
323FRAME_PTR last_mouse_frame;
324static XRectangle last_mouse_glyph;
2237cac9
RS
325static Lisp_Object last_mouse_press_frame;
326
69388238
RS
327/* The scroll bar in which the last X motion event occurred.
328
06a2c219
GM
329 If the last X motion event occurred in a scroll bar, we set this so
330 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
331 an ordinary motion.
332
06a2c219
GM
333 If the last X motion event didn't occur in a scroll bar, we set
334 this to Qnil, to tell XTmouse_position to return an ordinary motion
335 event. */
336
69388238
RS
337static Lisp_Object last_mouse_scroll_bar;
338
69388238
RS
339/* This is a hack. We would really prefer that XTmouse_position would
340 return the time associated with the position it returns, but there
06a2c219 341 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
342 along with the position query. So, we just keep track of the time
343 of the last movement we received, and return that in hopes that
344 it's somewhat accurate. */
06a2c219 345
69388238
RS
346static Time last_mouse_movement_time;
347
06a2c219
GM
348/* Incremented by XTread_socket whenever it really tries to read
349 events. */
350
c0a04927
RS
351#ifdef __STDC__
352static int volatile input_signal_count;
353#else
354static int input_signal_count;
355#endif
356
7a13e894 357/* Used locally within XTread_socket. */
06a2c219 358
7a13e894 359static int x_noop_count;
dc6f92b8 360
7a13e894 361/* Initial values of argv and argc. */
06a2c219 362
7a13e894
RS
363extern char **initial_argv;
364extern int initial_argc;
dc6f92b8 365
7a13e894 366extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 367
06a2c219 368/* Tells if a window manager is present or not. */
7a13e894
RS
369
370extern Lisp_Object Vx_no_window_manager;
dc6f92b8 371
c2df547c 372extern Lisp_Object Qface, Qmouse_face;
b8009dd1 373
dc6f92b8
JB
374extern int errno;
375
dfeccd2d 376/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 377
64bb1782
RS
378extern int extra_keyboard_modifiers;
379
59e755be
KH
380static Lisp_Object Qvendor_specific_keysyms;
381
952291d9
GM
382extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
383extern Lisp_Object x_icon_type P_ ((struct frame *));
c32cdd9a 384
7a13e894 385
06a2c219
GM
386/* Enumeration for overriding/changing the face to use for drawing
387 glyphs in x_draw_glyphs. */
388
389enum draw_glyphs_face
390{
391 DRAW_NORMAL_TEXT,
392 DRAW_INVERSE_VIDEO,
393 DRAW_CURSOR,
394 DRAW_MOUSE_FACE,
395 DRAW_IMAGE_RAISED,
396 DRAW_IMAGE_SUNKEN
397};
398
499b1844 399static void x_set_window_size_1 P_ ((struct frame *, int, int, int));
f04e1297 400static const XColor *x_color_cells P_ ((struct frame *, int *));
71b8321e 401static void x_update_window_end P_ ((struct window *, int, int));
06a2c219
GM
402static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
403void x_delete_display P_ ((struct x_display_info *));
404static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
405 unsigned));
406static int fast_find_position P_ ((struct window *, int, int *, int *,
407 int *, int *));
408static void set_output_cursor P_ ((struct cursor_pos *));
409static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
410 int *, int *, int *));
411static void note_mode_line_highlight P_ ((struct window *, int, int));
06a2c219 412static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
413static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
414static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
415static void show_mouse_face P_ ((struct x_display_info *,
416 enum draw_glyphs_face));
417static int x_io_error_quitter P_ ((Display *));
418int x_catch_errors P_ ((Display *));
419void x_uncatch_errors P_ ((Display *, int));
420void x_lower_frame P_ ((struct frame *));
421void x_scroll_bar_clear P_ ((struct frame *));
422int x_had_errors_p P_ ((Display *));
423void x_wm_set_size_hint P_ ((struct frame *, long, int));
424void x_raise_frame P_ ((struct frame *));
425void x_set_window_size P_ ((struct frame *, int, int, int));
426void x_wm_set_window_state P_ ((struct frame *, int));
427void x_wm_set_icon_pixmap P_ ((struct frame *, int));
428void x_initialize P_ ((void));
429static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
430static int x_compute_min_glyph_bounds P_ ((struct frame *));
431static void x_draw_phys_cursor_glyph P_ ((struct window *,
432 struct glyph_row *,
433 enum draw_glyphs_face));
434static void x_update_end P_ ((struct frame *));
435static void XTframe_up_to_date P_ ((struct frame *));
436static void XTreassert_line_highlight P_ ((int, int));
437static void x_change_line_highlight P_ ((int, int, int, int));
438static void XTset_terminal_modes P_ ((void));
439static void XTreset_terminal_modes P_ ((void));
440static void XTcursor_to P_ ((int, int, int, int));
441static void x_write_glyphs P_ ((struct glyph *, int));
442static void x_clear_end_of_line P_ ((int));
443static void x_clear_frame P_ ((void));
444static void x_clear_cursor P_ ((struct window *));
445static void frame_highlight P_ ((struct frame *));
446static void frame_unhighlight P_ ((struct frame *));
447static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
448static void XTframe_rehighlight P_ ((struct frame *));
449static void x_frame_rehighlight P_ ((struct x_display_info *));
450static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
f02d8aa0 451static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
06a2c219
GM
452static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
453 XRectangle *));
454static void expose_frame P_ ((struct frame *, int, int, int, int));
455static void expose_window_tree P_ ((struct window *, XRectangle *));
456static void expose_window P_ ((struct window *, XRectangle *));
457static void expose_area P_ ((struct window *, struct glyph_row *,
458 XRectangle *, enum glyph_row_area));
459static void expose_line P_ ((struct window *, struct glyph_row *,
460 XRectangle *));
461static void x_update_cursor_in_window_tree P_ ((struct window *, int));
462static void x_update_window_cursor P_ ((struct window *, int));
463static void x_erase_phys_cursor P_ ((struct window *));
464void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
465static void x_draw_bitmap P_ ((struct window *, struct glyph_row *,
466 enum bitmap_type));
467
468static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
469 GC, int));
470static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
471static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
472static void note_overwritten_text_cursor P_ ((struct window *, int, int));
473static void x_flush P_ ((struct frame *f));
952291d9
GM
474static void x_update_begin P_ ((struct frame *));
475static void x_update_window_begin P_ ((struct window *));
476static void x_draw_vertical_border P_ ((struct window *));
477static void x_after_update_window_line P_ ((struct glyph_row *));
478static INLINE void take_vertical_position_into_account P_ ((struct it *));
479static void x_produce_stretch_glyph P_ ((struct it *));
b52b65bd
GM
480static struct scroll_bar *x_window_to_scroll_bar P_ ((Window));
481static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
482 enum scroll_bar_part *,
483 Lisp_Object *, Lisp_Object *,
484 unsigned long *));
06a2c219
GM
485
486/* Flush display of frame F, or of all frames if F is null. */
487
488static void
489x_flush (f)
490 struct frame *f;
491{
492 BLOCK_INPUT;
493 if (f == NULL)
494 {
495 Lisp_Object rest, frame;
496 FOR_EACH_FRAME (rest, frame)
497 x_flush (XFRAME (frame));
498 }
499 else if (FRAME_X_P (f))
500 XFlush (FRAME_X_DISPLAY (f));
501 UNBLOCK_INPUT;
502}
503
dc6f92b8 504
06a2c219
GM
505/* Remove calls to XFlush by defining XFlush to an empty replacement.
506 Calls to XFlush should be unnecessary because the X output buffer
507 is flushed automatically as needed by calls to XPending,
508 XNextEvent, or XWindowEvent according to the XFlush man page.
509 XTread_socket calls XPending. Removing XFlush improves
510 performance. */
511
512#define XFlush(DISPLAY) (void) 0
b8009dd1 513
334208b7 514\f
06a2c219
GM
515/***********************************************************************
516 Debugging
517 ***********************************************************************/
518
9382638d 519#if 0
06a2c219
GM
520
521/* This is a function useful for recording debugging information about
522 the sequence of occurrences in this file. */
9382638d
KH
523
524struct record
525{
526 char *locus;
527 int type;
528};
529
530struct record event_record[100];
531
532int event_record_index;
533
534record_event (locus, type)
535 char *locus;
536 int type;
537{
538 if (event_record_index == sizeof (event_record) / sizeof (struct record))
539 event_record_index = 0;
540
541 event_record[event_record_index].locus = locus;
542 event_record[event_record_index].type = type;
543 event_record_index++;
544}
545
546#endif /* 0 */
06a2c219
GM
547
548
9382638d 549\f
334208b7
RS
550/* Return the struct x_display_info corresponding to DPY. */
551
552struct x_display_info *
553x_display_info_for_display (dpy)
554 Display *dpy;
555{
556 struct x_display_info *dpyinfo;
557
558 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
559 if (dpyinfo->display == dpy)
560 return dpyinfo;
16bd92ea 561
334208b7
RS
562 return 0;
563}
f451eb13 564
06a2c219
GM
565
566\f
567/***********************************************************************
568 Starting and ending an update
569 ***********************************************************************/
570
571/* Start an update of frame F. This function is installed as a hook
572 for update_begin, i.e. it is called when update_begin is called.
573 This function is called prior to calls to x_update_window_begin for
574 each window being updated. Currently, there is nothing to do here
575 because all interesting stuff is done on a window basis. */
dc6f92b8 576
dfcf069d 577static void
06a2c219 578x_update_begin (f)
f676886a 579 struct frame *f;
58769bee 580{
06a2c219
GM
581 /* Nothing to do. */
582}
dc6f92b8 583
dc6f92b8 584
06a2c219
GM
585/* Start update of window W. Set the global variable updated_window
586 to the window being updated and set output_cursor to the cursor
587 position of W. */
dc6f92b8 588
06a2c219
GM
589static void
590x_update_window_begin (w)
591 struct window *w;
592{
593 struct frame *f = XFRAME (WINDOW_FRAME (w));
594 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
595
596 updated_window = w;
597 set_output_cursor (&w->cursor);
b8009dd1 598
06a2c219 599 BLOCK_INPUT;
d1bc4182 600
06a2c219 601 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 602 {
514e4681 603 /* Don't do highlighting for mouse motion during the update. */
06a2c219 604 display_info->mouse_face_defer = 1;
37c2c98b 605
06a2c219
GM
606 /* If F needs to be redrawn, simply forget about any prior mouse
607 highlighting. */
9f67f20b 608 if (FRAME_GARBAGED_P (f))
06a2c219
GM
609 display_info->mouse_face_window = Qnil;
610
64f26cf5
GM
611#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
612 their mouse_face_p flag set, which means that they are always
613 unequal to rows in a desired matrix which never have that
614 flag set. So, rows containing mouse-face glyphs are never
615 scrolled, and we don't have to switch the mouse highlight off
616 here to prevent it from being scrolled. */
617
06a2c219
GM
618 /* Can we tell that this update does not affect the window
619 where the mouse highlight is? If so, no need to turn off.
620 Likewise, don't do anything if the frame is garbaged;
621 in that case, the frame's current matrix that we would use
622 is all wrong, and we will redisplay that line anyway. */
623 if (!NILP (display_info->mouse_face_window)
624 && w == XWINDOW (display_info->mouse_face_window))
514e4681 625 {
06a2c219 626 int i;
514e4681 627
06a2c219
GM
628 for (i = 0; i < w->desired_matrix->nrows; ++i)
629 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
630 break;
631
06a2c219
GM
632 if (i < w->desired_matrix->nrows)
633 clear_mouse_face (display_info);
514e4681 634 }
64f26cf5 635#endif /* 0 */
b8009dd1 636 }
6ccf47d1 637
dc6f92b8
JB
638 UNBLOCK_INPUT;
639}
640
06a2c219
GM
641
642/* Draw a vertical window border to the right of window W if W doesn't
643 have vertical scroll bars. */
644
dfcf069d 645static void
06a2c219
GM
646x_draw_vertical_border (w)
647 struct window *w;
58769bee 648{
06a2c219
GM
649 struct frame *f = XFRAME (WINDOW_FRAME (w));
650
651 /* Redraw borders between horizontally adjacent windows. Don't
652 do it for frames with vertical scroll bars because either the
653 right scroll bar of a window, or the left scroll bar of its
654 neighbor will suffice as a border. */
655 if (!WINDOW_RIGHTMOST_P (w)
656 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
657 {
658 int x0, x1, y0, y1;
dc6f92b8 659
06a2c219 660 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
110859fc 661 x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
662 y1 -= 1;
663
664 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
665 f->output_data.x->normal_gc, x1, y0, x1, y1);
666 }
667}
668
669
71b8321e
GM
670/* End update of window W (which is equal to updated_window).
671
672 Draw vertical borders between horizontally adjacent windows, and
673 display W's cursor if CURSOR_ON_P is non-zero.
674
675 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
676 glyphs in mouse-face were overwritten. In that case we have to
677 make sure that the mouse-highlight is properly redrawn.
678
679 W may be a menu bar pseudo-window in case we don't have X toolkit
680 support. Such windows don't have a cursor, so don't display it
681 here. */
06a2c219
GM
682
683static void
71b8321e 684x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 685 struct window *w;
71b8321e 686 int cursor_on_p, mouse_face_overwritten_p;
06a2c219
GM
687{
688 if (!w->pseudo_window_p)
689 {
71b8321e
GM
690 struct x_display_info *dpyinfo
691 = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
692
06a2c219 693 BLOCK_INPUT;
71b8321e
GM
694
695 /* If a row with mouse-face was overwritten, arrange for
696 XTframe_up_to_date to redisplay the mouse highlight. */
697 if (mouse_face_overwritten_p)
698 {
699 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
700 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
701 dpyinfo->mouse_face_window = Qnil;
702 }
703
06a2c219
GM
704 if (cursor_on_p)
705 x_display_and_set_cursor (w, 1, output_cursor.hpos,
706 output_cursor.vpos,
707 output_cursor.x, output_cursor.y);
71b8321e 708
06a2c219
GM
709 x_draw_vertical_border (w);
710 UNBLOCK_INPUT;
711 }
712
713 updated_window = NULL;
714}
dc6f92b8 715
dc6f92b8 716
06a2c219
GM
717/* End update of frame F. This function is installed as a hook in
718 update_end. */
719
720static void
721x_update_end (f)
722 struct frame *f;
723{
724 /* Mouse highlight may be displayed again. */
aa8bff2e 725 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 726
06a2c219 727 BLOCK_INPUT;
334208b7 728 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
729 UNBLOCK_INPUT;
730}
b8009dd1 731
06a2c219
GM
732
733/* This function is called from various places in xdisp.c whenever a
734 complete update has been performed. The global variable
735 updated_window is not available here. */
b8009dd1 736
dfcf069d 737static void
b8009dd1 738XTframe_up_to_date (f)
06a2c219 739 struct frame *f;
b8009dd1 740{
06a2c219 741 if (FRAME_X_P (f))
514e4681 742 {
06a2c219 743 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 744
06a2c219
GM
745 if (dpyinfo->mouse_face_deferred_gc
746 || f == dpyinfo->mouse_face_mouse_frame)
747 {
748 BLOCK_INPUT;
749 if (dpyinfo->mouse_face_mouse_frame)
750 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
751 dpyinfo->mouse_face_mouse_x,
752 dpyinfo->mouse_face_mouse_y);
753 dpyinfo->mouse_face_deferred_gc = 0;
754 UNBLOCK_INPUT;
755 }
514e4681 756 }
b8009dd1 757}
06a2c219
GM
758
759
760/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
761 arrow bitmaps, or clear the areas where they would be displayed
762 before DESIRED_ROW is made current. The window being updated is
763 found in updated_window. This function It is called from
764 update_window_line only if it is known that there are differences
765 between bitmaps to be drawn between current row and DESIRED_ROW. */
766
767static void
768x_after_update_window_line (desired_row)
769 struct glyph_row *desired_row;
770{
771 struct window *w = updated_window;
772
773 xassert (w);
774
775 if (!desired_row->mode_line_p && !w->pseudo_window_p)
776 {
c5e6e06b
GM
777 struct frame *f;
778 int width;
779
06a2c219
GM
780 BLOCK_INPUT;
781 x_draw_row_bitmaps (w, desired_row);
782
783 /* When a window has disappeared, make sure that no rest of
784 full-width rows stays visible in the internal border. */
c5e6e06b
GM
785 if (windows_or_buffers_changed
786 && (f = XFRAME (w->frame),
787 width = FRAME_INTERNAL_BORDER_WIDTH (f),
788 width != 0))
06a2c219 789 {
06a2c219 790 int height = desired_row->visible_height;
110859fc
GM
791 int x = (window_box_right (w, -1)
792 + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
793 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
794
c5e6e06b
GM
795 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
796 x, y, width, height, False);
06a2c219
GM
797 }
798
799 UNBLOCK_INPUT;
800 }
801}
802
803
804/* Draw the bitmap WHICH in one of the areas to the left or right of
805 window W. ROW is the glyph row for which to display the bitmap; it
806 determines the vertical position at which the bitmap has to be
807 drawn. */
808
809static void
810x_draw_bitmap (w, row, which)
811 struct window *w;
812 struct glyph_row *row;
813 enum bitmap_type which;
814{
815 struct frame *f = XFRAME (WINDOW_FRAME (w));
816 Display *display = FRAME_X_DISPLAY (f);
817 Window window = FRAME_X_WINDOW (f);
818 int x, y, wd, h, dy;
819 unsigned char *bits;
820 Pixmap pixmap;
821 GC gc = f->output_data.x->normal_gc;
822 struct face *face;
823 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
824
825 /* Must clip because of partially visible lines. */
826 x_clip_to_row (w, row, gc, 1);
827
828 switch (which)
829 {
830 case LEFT_TRUNCATION_BITMAP:
831 wd = left_width;
832 h = left_height;
833 bits = left_bits;
834 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
835 - wd
110859fc 836 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
837 break;
838
839 case OVERLAY_ARROW_BITMAP:
840 wd = left_width;
841 h = left_height;
842 bits = ov_bits;
843 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
844 - wd
110859fc 845 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
846 break;
847
848 case RIGHT_TRUNCATION_BITMAP:
849 wd = right_width;
850 h = right_height;
851 bits = right_bits;
852 x = window_box_right (w, -1);
110859fc 853 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
854 break;
855
856 case CONTINUED_LINE_BITMAP:
857 wd = right_width;
858 h = right_height;
859 bits = continued_bits;
860 x = window_box_right (w, -1);
110859fc 861 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
862 break;
863
864 case CONTINUATION_LINE_BITMAP:
865 wd = continuation_width;
866 h = continuation_height;
867 bits = continuation_bits;
868 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
869 - wd
110859fc 870 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
871 break;
872
873 case ZV_LINE_BITMAP:
874 wd = zv_width;
875 h = zv_height;
876 bits = zv_bits;
877 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
878 - wd
110859fc 879 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
880 break;
881
882 default:
883 abort ();
884 }
885
886 /* Convert to frame coordinates. Set dy to the offset in the row to
887 start drawing the bitmap. */
888 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
889 dy = (row->height - h) / 2;
890
891 /* Draw the bitmap. I believe these small pixmaps can be cached
892 by the server. */
893 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
894 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
895 face->foreground,
896 face->background, depth);
897 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
898 XFreePixmap (display, pixmap);
899 XSetClipMask (display, gc, None);
900}
901
902
903/* Draw flags bitmaps for glyph row ROW on window W. Call this
904 function with input blocked. */
905
906static void
907x_draw_row_bitmaps (w, row)
908 struct window *w;
909 struct glyph_row *row;
910{
911 struct frame *f = XFRAME (w->frame);
912 enum bitmap_type bitmap;
913 struct face *face;
045dee35 914 int header_line_height = -1;
06a2c219
GM
915
916 xassert (interrupt_input_blocked);
917
918 /* If row is completely invisible, because of vscrolling, we
919 don't have to draw anything. */
920 if (row->visible_height <= 0)
921 return;
922
923 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
924 PREPARE_FACE_FOR_DISPLAY (f, face);
925
926 /* Decide which bitmap to draw at the left side. */
927 if (row->overlay_arrow_p)
928 bitmap = OVERLAY_ARROW_BITMAP;
929 else if (row->truncated_on_left_p)
930 bitmap = LEFT_TRUNCATION_BITMAP;
931 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
932 bitmap = CONTINUATION_LINE_BITMAP;
933 else if (row->indicate_empty_line_p)
934 bitmap = ZV_LINE_BITMAP;
935 else
936 bitmap = NO_BITMAP;
937
938 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
939 the flags area. */
940 if (bitmap == NO_BITMAP
110859fc 941 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
942 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
943 {
944 /* If W has a vertical border to its left, don't draw over it. */
945 int border = ((XFASTINT (w->left) > 0
946 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
947 ? 1 : 0);
948 int left = window_box_left (w, -1);
949
045dee35
GM
950 if (header_line_height < 0)
951 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
952
953 /* In case the same realized face is used for bitmap areas and
954 for something displayed in the text (e.g. face `region' on
955 mono-displays, the fill style may have been changed to
956 FillSolid in x_draw_glyph_string_background. */
957 if (face->stipple)
958 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
959 else
960 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
961
06a2c219
GM
962 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
963 face->gc,
964 (left
110859fc 965 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219 966 + border),
045dee35 967 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 968 row->y)),
110859fc 969 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
06a2c219 970 row->visible_height);
dcd08bfb
GM
971 if (!face->stipple)
972 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
973 }
974
975 /* Draw the left bitmap. */
976 if (bitmap != NO_BITMAP)
977 x_draw_bitmap (w, row, bitmap);
978
979 /* Decide which bitmap to draw at the right side. */
980 if (row->truncated_on_right_p)
981 bitmap = RIGHT_TRUNCATION_BITMAP;
982 else if (row->continued_p)
983 bitmap = CONTINUED_LINE_BITMAP;
984 else
985 bitmap = NO_BITMAP;
986
987 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
988 the flags area. */
989 if (bitmap == NO_BITMAP
110859fc 990 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
991 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
992 {
993 int right = window_box_right (w, -1);
994
045dee35
GM
995 if (header_line_height < 0)
996 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
997
998 /* In case the same realized face is used for bitmap areas and
999 for something displayed in the text (e.g. face `region' on
1000 mono-displays, the fill style may have been changed to
1001 FillSolid in x_draw_glyph_string_background. */
1002 if (face->stipple)
1003 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
1004 else
1005 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
1006 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1007 face->gc,
1008 right,
045dee35 1009 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 1010 row->y)),
110859fc 1011 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
06a2c219 1012 row->visible_height);
dcd08bfb
GM
1013 if (!face->stipple)
1014 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
1015 }
1016
1017 /* Draw the right bitmap. */
1018 if (bitmap != NO_BITMAP)
1019 x_draw_bitmap (w, row, bitmap);
1020}
1021
dc6f92b8 1022\f
06a2c219
GM
1023/***********************************************************************
1024 Line Highlighting
1025 ***********************************************************************/
dc6f92b8 1026
06a2c219
GM
1027/* External interface to control of standout mode. Not used for X
1028 frames. Aborts when called. */
1029
1030static void
dc6f92b8
JB
1031XTreassert_line_highlight (new, vpos)
1032 int new, vpos;
1033{
06a2c219 1034 abort ();
dc6f92b8
JB
1035}
1036
06a2c219
GM
1037
1038/* Call this when about to modify line at position VPOS and change
1039 whether it is highlighted. Not used for X frames. Aborts when
1040 called. */
dc6f92b8 1041
dfcf069d 1042static void
06a2c219
GM
1043x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1044 int new_highlight, vpos, y, first_unused_hpos;
dc6f92b8 1045{
06a2c219 1046 abort ();
dc6f92b8
JB
1047}
1048
06a2c219
GM
1049
1050/* This is called when starting Emacs and when restarting after
1051 suspend. When starting Emacs, no X window is mapped. And nothing
1052 must be done to Emacs's own window if it is suspended (though that
1053 rarely happens). */
dc6f92b8 1054
dfcf069d 1055static void
dc6f92b8
JB
1056XTset_terminal_modes ()
1057{
1058}
1059
06a2c219
GM
1060/* This is called when exiting or suspending Emacs. Exiting will make
1061 the X-windows go away, and suspending requires no action. */
dc6f92b8 1062
dfcf069d 1063static void
dc6f92b8
JB
1064XTreset_terminal_modes ()
1065{
dc6f92b8 1066}
06a2c219
GM
1067
1068
dc6f92b8 1069\f
06a2c219
GM
1070/***********************************************************************
1071 Output Cursor
1072 ***********************************************************************/
1073
1074/* Set the global variable output_cursor to CURSOR. All cursor
1075 positions are relative to updated_window. */
dc6f92b8 1076
dfcf069d 1077static void
06a2c219
GM
1078set_output_cursor (cursor)
1079 struct cursor_pos *cursor;
dc6f92b8 1080{
06a2c219
GM
1081 output_cursor.hpos = cursor->hpos;
1082 output_cursor.vpos = cursor->vpos;
1083 output_cursor.x = cursor->x;
1084 output_cursor.y = cursor->y;
1085}
1086
1087
1088/* Set a nominal cursor position.
dc6f92b8 1089
06a2c219
GM
1090 HPOS and VPOS are column/row positions in a window glyph matrix. X
1091 and Y are window text area relative pixel positions.
1092
1093 If this is done during an update, updated_window will contain the
1094 window that is being updated and the position is the future output
1095 cursor position for that window. If updated_window is null, use
1096 selected_window and display the cursor at the given position. */
1097
1098static void
1099XTcursor_to (vpos, hpos, y, x)
1100 int vpos, hpos, y, x;
1101{
1102 struct window *w;
1103
1104 /* If updated_window is not set, work on selected_window. */
1105 if (updated_window)
1106 w = updated_window;
1107 else
1108 w = XWINDOW (selected_window);
dbcb258a 1109
06a2c219
GM
1110 /* Set the output cursor. */
1111 output_cursor.hpos = hpos;
1112 output_cursor.vpos = vpos;
1113 output_cursor.x = x;
1114 output_cursor.y = y;
dc6f92b8 1115
06a2c219
GM
1116 /* If not called as part of an update, really display the cursor.
1117 This will also set the cursor position of W. */
1118 if (updated_window == NULL)
dc6f92b8
JB
1119 {
1120 BLOCK_INPUT;
06a2c219 1121 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1122 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1123 UNBLOCK_INPUT;
1124 }
1125}
dc43ef94 1126
06a2c219
GM
1127
1128\f
1129/***********************************************************************
1130 Display Iterator
1131 ***********************************************************************/
1132
1133/* Function prototypes of this page. */
1134
1135static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1136 struct glyph *,
ee569018
KH
1137 XChar2b *,
1138 int *));
06a2c219
GM
1139static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1140 int, XChar2b *, int));
1141static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1142static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1143static void x_append_glyph P_ ((struct it *));
b4192550 1144static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1145static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1146 int, int, double));
1147static void x_produce_glyphs P_ ((struct it *));
06a2c219 1148static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1149
1150
e2ef8ee6
GM
1151/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1152 is not contained in the font. */
dc43ef94 1153
06a2c219 1154static INLINE XCharStruct *
ee569018 1155x_per_char_metric (font, char2b)
06a2c219
GM
1156 XFontStruct *font;
1157 XChar2b *char2b;
1158{
1159 /* The result metric information. */
1160 XCharStruct *pcm = NULL;
dc6f92b8 1161
06a2c219 1162 xassert (font && char2b);
dc6f92b8 1163
06a2c219 1164 if (font->per_char != NULL)
dc6f92b8 1165 {
06a2c219 1166 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1167 {
06a2c219
GM
1168 /* min_char_or_byte2 specifies the linear character index
1169 corresponding to the first element of the per_char array,
1170 max_char_or_byte2 is the index of the last character. A
1171 character with non-zero CHAR2B->byte1 is not in the font.
1172 A character with byte2 less than min_char_or_byte2 or
1173 greater max_char_or_byte2 is not in the font. */
1174 if (char2b->byte1 == 0
1175 && char2b->byte2 >= font->min_char_or_byte2
1176 && char2b->byte2 <= font->max_char_or_byte2)
1177 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1178 }
06a2c219 1179 else
dc6f92b8 1180 {
06a2c219
GM
1181 /* If either min_byte1 or max_byte1 are nonzero, both
1182 min_char_or_byte2 and max_char_or_byte2 are less than
1183 256, and the 2-byte character index values corresponding
1184 to the per_char array element N (counting from 0) are:
1185
1186 byte1 = N/D + min_byte1
1187 byte2 = N\D + min_char_or_byte2
1188
1189 where:
1190
1191 D = max_char_or_byte2 - min_char_or_byte2 + 1
1192 / = integer division
1193 \ = integer modulus */
1194 if (char2b->byte1 >= font->min_byte1
1195 && char2b->byte1 <= font->max_byte1
1196 && char2b->byte2 >= font->min_char_or_byte2
1197 && char2b->byte2 <= font->max_char_or_byte2)
1198 {
1199 pcm = (font->per_char
1200 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1201 * (char2b->byte1 - font->min_byte1))
1202 + (char2b->byte2 - font->min_char_or_byte2));
1203 }
dc6f92b8 1204 }
06a2c219
GM
1205 }
1206 else
1207 {
1208 /* If the per_char pointer is null, all glyphs between the first
1209 and last character indexes inclusive have the same
1210 information, as given by both min_bounds and max_bounds. */
1211 if (char2b->byte2 >= font->min_char_or_byte2
1212 && char2b->byte2 <= font->max_char_or_byte2)
1213 pcm = &font->max_bounds;
1214 }
dc6f92b8 1215
ee569018 1216 return ((pcm == NULL
3e71d8f2 1217 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1218 ? NULL : pcm);
06a2c219 1219}
b73b6aaf 1220
57b03282 1221
06a2c219
GM
1222/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1223 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1224
06a2c219
GM
1225static INLINE void
1226x_encode_char (c, char2b, font_info)
1227 int c;
1228 XChar2b *char2b;
1229 struct font_info *font_info;
1230{
1231 int charset = CHAR_CHARSET (c);
1232 XFontStruct *font = font_info->font;
1233
1234 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1235 This may be either a program in a special encoder language or a
1236 fixed encoding. */
1237 if (font_info->font_encoder)
1238 {
1239 /* It's a program. */
1240 struct ccl_program *ccl = font_info->font_encoder;
1241
1242 if (CHARSET_DIMENSION (charset) == 1)
1243 {
1244 ccl->reg[0] = charset;
1245 ccl->reg[1] = char2b->byte2;
1246 }
1247 else
1248 {
1249 ccl->reg[0] = charset;
1250 ccl->reg[1] = char2b->byte1;
1251 ccl->reg[2] = char2b->byte2;
1252 }
1253
1254 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1255
1256 /* We assume that MSBs are appropriately set/reset by CCL
1257 program. */
1258 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1259 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1260 else
1261 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1262 }
1263 else if (font_info->encoding[charset])
1264 {
1265 /* Fixed encoding scheme. See fontset.h for the meaning of the
1266 encoding numbers. */
1267 int enc = font_info->encoding[charset];
1268
1269 if ((enc == 1 || enc == 2)
1270 && CHARSET_DIMENSION (charset) == 2)
1271 char2b->byte1 |= 0x80;
1272
1273 if (enc == 1 || enc == 3)
1274 char2b->byte2 |= 0x80;
1275 }
1276}
1277
1278
1279/* Get face and two-byte form of character C in face FACE_ID on frame
1280 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1281 means we want to display multibyte text. Value is a pointer to a
1282 realized face that is ready for display. */
1283
1284static INLINE struct face *
1285x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1286 struct frame *f;
1287 int c, face_id;
1288 XChar2b *char2b;
1289 int multibyte_p;
1290{
1291 struct face *face = FACE_FROM_ID (f, face_id);
1292
1293 if (!multibyte_p)
1294 {
1295 /* Unibyte case. We don't have to encode, but we have to make
1296 sure to use a face suitable for unibyte. */
1297 char2b->byte1 = 0;
1298 char2b->byte2 = c;
ee569018
KH
1299 face_id = FACE_FOR_CHAR (f, face, c);
1300 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1301 }
1302 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1303 {
1304 /* Case of ASCII in a face known to fit ASCII. */
1305 char2b->byte1 = 0;
1306 char2b->byte2 = c;
1307 }
1308 else
1309 {
1310 int c1, c2, charset;
1311
1312 /* Split characters into bytes. If c2 is -1 afterwards, C is
1313 really a one-byte character so that byte1 is zero. */
1314 SPLIT_CHAR (c, charset, c1, c2);
1315 if (c2 > 0)
1316 char2b->byte1 = c1, char2b->byte2 = c2;
1317 else
1318 char2b->byte1 = 0, char2b->byte2 = c1;
1319
06a2c219 1320 /* Maybe encode the character in *CHAR2B. */
ee569018 1321 if (face->font != NULL)
06a2c219
GM
1322 {
1323 struct font_info *font_info
1324 = FONT_INFO_FROM_ID (f, face->font_info_id);
1325 if (font_info)
ee569018 1326 x_encode_char (c, char2b, font_info);
06a2c219
GM
1327 }
1328 }
1329
1330 /* Make sure X resources of the face are allocated. */
1331 xassert (face != NULL);
1332 PREPARE_FACE_FOR_DISPLAY (f, face);
1333
1334 return face;
1335}
1336
1337
1338/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1339 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1340 a pointer to a realized face that is ready for display. */
1341
1342static INLINE struct face *
ee569018 1343x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1344 struct frame *f;
1345 struct glyph *glyph;
1346 XChar2b *char2b;
ee569018 1347 int *two_byte_p;
06a2c219
GM
1348{
1349 struct face *face;
1350
1351 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1352 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1353
ee569018
KH
1354 if (two_byte_p)
1355 *two_byte_p = 0;
1356
06a2c219
GM
1357 if (!glyph->multibyte_p)
1358 {
1359 /* Unibyte case. We don't have to encode, but we have to make
1360 sure to use a face suitable for unibyte. */
1361 char2b->byte1 = 0;
43d120d8 1362 char2b->byte2 = glyph->u.ch;
06a2c219 1363 }
43d120d8
KH
1364 else if (glyph->u.ch < 128
1365 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1366 {
1367 /* Case of ASCII in a face known to fit ASCII. */
1368 char2b->byte1 = 0;
43d120d8 1369 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1370 }
1371 else
1372 {
1373 int c1, c2, charset;
1374
1375 /* Split characters into bytes. If c2 is -1 afterwards, C is
1376 really a one-byte character so that byte1 is zero. */
43d120d8 1377 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1378 if (c2 > 0)
1379 char2b->byte1 = c1, char2b->byte2 = c2;
1380 else
1381 char2b->byte1 = 0, char2b->byte2 = c1;
1382
1383 /* Maybe encode the character in *CHAR2B. */
1384 if (charset != CHARSET_ASCII)
1385 {
1386 struct font_info *font_info
1387 = FONT_INFO_FROM_ID (f, face->font_info_id);
1388 if (font_info)
1389 {
43d120d8 1390 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1391 if (two_byte_p)
1392 *two_byte_p
1393 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1394 }
1395 }
1396 }
1397
1398 /* Make sure X resources of the face are allocated. */
1399 xassert (face != NULL);
1400 PREPARE_FACE_FOR_DISPLAY (f, face);
1401 return face;
1402}
1403
1404
1405/* Store one glyph for IT->char_to_display in IT->glyph_row.
1406 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1407
1408static INLINE void
1409x_append_glyph (it)
1410 struct it *it;
1411{
1412 struct glyph *glyph;
1413 enum glyph_row_area area = it->area;
1414
1415 xassert (it->glyph_row);
1416 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1417
1418 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1419 if (glyph < it->glyph_row->glyphs[area + 1])
1420 {
06a2c219
GM
1421 glyph->charpos = CHARPOS (it->position);
1422 glyph->object = it->object;
88d75730 1423 glyph->pixel_width = it->pixel_width;
06a2c219 1424 glyph->voffset = it->voffset;
88d75730 1425 glyph->type = CHAR_GLYPH;
06a2c219 1426 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1427 glyph->left_box_line_p = it->start_of_box_run_p;
1428 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1429 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1430 || it->phys_descent > it->descent);
88d75730 1431 glyph->padding_p = 0;
ee569018 1432 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1433 glyph->face_id = it->face_id;
1434 glyph->u.ch = it->char_to_display;
06a2c219
GM
1435 ++it->glyph_row->used[area];
1436 }
1437}
1438
b4192550
KH
1439/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1440 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1441
1442static INLINE void
1443x_append_composite_glyph (it)
1444 struct it *it;
1445{
1446 struct glyph *glyph;
1447 enum glyph_row_area area = it->area;
1448
1449 xassert (it->glyph_row);
1450
1451 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1452 if (glyph < it->glyph_row->glyphs[area + 1])
1453 {
b4192550
KH
1454 glyph->charpos = CHARPOS (it->position);
1455 glyph->object = it->object;
88d75730 1456 glyph->pixel_width = it->pixel_width;
b4192550 1457 glyph->voffset = it->voffset;
88d75730 1458 glyph->type = COMPOSITE_GLYPH;
b4192550 1459 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1460 glyph->left_box_line_p = it->start_of_box_run_p;
1461 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1462 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1463 || it->phys_descent > it->descent);
88d75730
GM
1464 glyph->padding_p = 0;
1465 glyph->glyph_not_available_p = 0;
1466 glyph->face_id = it->face_id;
1467 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1468 ++it->glyph_row->used[area];
1469 }
1470}
1471
06a2c219
GM
1472
1473/* Change IT->ascent and IT->height according to the setting of
1474 IT->voffset. */
1475
1476static INLINE void
1477take_vertical_position_into_account (it)
1478 struct it *it;
1479{
1480 if (it->voffset)
1481 {
1482 if (it->voffset < 0)
1483 /* Increase the ascent so that we can display the text higher
1484 in the line. */
1485 it->ascent += abs (it->voffset);
1486 else
1487 /* Increase the descent so that we can display the text lower
1488 in the line. */
1489 it->descent += it->voffset;
1490 }
1491}
1492
1493
1494/* Produce glyphs/get display metrics for the image IT is loaded with.
1495 See the description of struct display_iterator in dispextern.h for
1496 an overview of struct display_iterator. */
1497
1498static void
1499x_produce_image_glyph (it)
1500 struct it *it;
1501{
1502 struct image *img;
1503 struct face *face;
1504
1505 xassert (it->what == IT_IMAGE);
1506
1507 face = FACE_FROM_ID (it->f, it->face_id);
1508 img = IMAGE_FROM_ID (it->f, it->image_id);
1509 xassert (img);
1510
1511 /* Make sure X resources of the face and image are loaded. */
1512 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1513 prepare_image_for_display (it->f, img);
1514
95af8492 1515 it->ascent = it->phys_ascent = image_ascent (img, face);
22d650b8
GM
1516 it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
1517 it->pixel_width = img->width + 2 * img->hmargin;
06a2c219
GM
1518
1519 it->nglyphs = 1;
1520
1521 if (face->box != FACE_NO_BOX)
1522 {
ea2ba0d4
KH
1523 if (face->box_line_width > 0)
1524 {
1525 it->ascent += face->box_line_width;
1526 it->descent += face->box_line_width;
1527 }
06a2c219
GM
1528
1529 if (it->start_of_box_run_p)
ea2ba0d4 1530 it->pixel_width += abs (face->box_line_width);
06a2c219 1531 if (it->end_of_box_run_p)
ea2ba0d4 1532 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1533 }
1534
1535 take_vertical_position_into_account (it);
1536
1537 if (it->glyph_row)
1538 {
1539 struct glyph *glyph;
1540 enum glyph_row_area area = it->area;
1541
1542 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1543 if (glyph < it->glyph_row->glyphs[area + 1])
1544 {
06a2c219
GM
1545 glyph->charpos = CHARPOS (it->position);
1546 glyph->object = it->object;
88d75730 1547 glyph->pixel_width = it->pixel_width;
06a2c219 1548 glyph->voffset = it->voffset;
88d75730 1549 glyph->type = IMAGE_GLYPH;
06a2c219 1550 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1551 glyph->left_box_line_p = it->start_of_box_run_p;
1552 glyph->right_box_line_p = it->end_of_box_run_p;
1553 glyph->overlaps_vertically_p = 0;
1554 glyph->padding_p = 0;
1555 glyph->glyph_not_available_p = 0;
1556 glyph->face_id = it->face_id;
1557 glyph->u.img_id = img->id;
06a2c219
GM
1558 ++it->glyph_row->used[area];
1559 }
1560 }
1561}
1562
1563
1564/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1565 of the glyph, WIDTH and HEIGHT are the width and height of the
1566 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1567 ascent of the glyph (0 <= ASCENT <= 1). */
1568
1569static void
1570x_append_stretch_glyph (it, object, width, height, ascent)
1571 struct it *it;
1572 Lisp_Object object;
1573 int width, height;
1574 double ascent;
1575{
1576 struct glyph *glyph;
1577 enum glyph_row_area area = it->area;
1578
1579 xassert (ascent >= 0 && ascent <= 1);
1580
1581 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1582 if (glyph < it->glyph_row->glyphs[area + 1])
1583 {
06a2c219
GM
1584 glyph->charpos = CHARPOS (it->position);
1585 glyph->object = object;
88d75730 1586 glyph->pixel_width = width;
06a2c219 1587 glyph->voffset = it->voffset;
88d75730 1588 glyph->type = STRETCH_GLYPH;
06a2c219 1589 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1590 glyph->left_box_line_p = it->start_of_box_run_p;
1591 glyph->right_box_line_p = it->end_of_box_run_p;
1592 glyph->overlaps_vertically_p = 0;
1593 glyph->padding_p = 0;
1594 glyph->glyph_not_available_p = 0;
1595 glyph->face_id = it->face_id;
1596 glyph->u.stretch.ascent = height * ascent;
1597 glyph->u.stretch.height = height;
06a2c219
GM
1598 ++it->glyph_row->used[area];
1599 }
1600}
1601
1602
1603/* Produce a stretch glyph for iterator IT. IT->object is the value
1604 of the glyph property displayed. The value must be a list
1605 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1606 being recognized:
1607
1608 1. `:width WIDTH' specifies that the space should be WIDTH *
1609 canonical char width wide. WIDTH may be an integer or floating
1610 point number.
1611
1612 2. `:relative-width FACTOR' specifies that the width of the stretch
1613 should be computed from the width of the first character having the
1614 `glyph' property, and should be FACTOR times that width.
1615
1616 3. `:align-to HPOS' specifies that the space should be wide enough
1617 to reach HPOS, a value in canonical character units.
1618
1619 Exactly one of the above pairs must be present.
1620
1621 4. `:height HEIGHT' specifies that the height of the stretch produced
1622 should be HEIGHT, measured in canonical character units.
1623
1624 5. `:relative-height FACTOR' specifies that the height of the the
1625 stretch should be FACTOR times the height of the characters having
1626 the glyph property.
1627
1628 Either none or exactly one of 4 or 5 must be present.
1629
1630 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1631 of the stretch should be used for the ascent of the stretch.
1632 ASCENT must be in the range 0 <= ASCENT <= 100. */
1633
1634#define NUMVAL(X) \
1635 ((INTEGERP (X) || FLOATP (X)) \
1636 ? XFLOATINT (X) \
1637 : - 1)
1638
1639
1640static void
1641x_produce_stretch_glyph (it)
1642 struct it *it;
1643{
1644 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1645#if GLYPH_DEBUG
1646 extern Lisp_Object Qspace;
1647#endif
1648 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1649 extern Lisp_Object QCrelative_width, QCrelative_height;
1650 extern Lisp_Object QCalign_to;
1651 Lisp_Object prop, plist;
1652 double width = 0, height = 0, ascent = 0;
1653 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1654 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1655
1656 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1657
1658 /* List should start with `space'. */
1659 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1660 plist = XCDR (it->object);
1661
1662 /* Compute the width of the stretch. */
1663 if (prop = Fplist_get (plist, QCwidth),
1664 NUMVAL (prop) > 0)
1665 /* Absolute width `:width WIDTH' specified and valid. */
1666 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1667 else if (prop = Fplist_get (plist, QCrelative_width),
1668 NUMVAL (prop) > 0)
1669 {
1670 /* Relative width `:relative-width FACTOR' specified and valid.
1671 Compute the width of the characters having the `glyph'
1672 property. */
1673 struct it it2;
1674 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1675
1676 it2 = *it;
1677 if (it->multibyte_p)
1678 {
1679 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1680 - IT_BYTEPOS (*it));
1681 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1682 }
1683 else
1684 it2.c = *p, it2.len = 1;
1685
1686 it2.glyph_row = NULL;
1687 it2.what = IT_CHARACTER;
1688 x_produce_glyphs (&it2);
1689 width = NUMVAL (prop) * it2.pixel_width;
1690 }
1691 else if (prop = Fplist_get (plist, QCalign_to),
1692 NUMVAL (prop) > 0)
1693 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1694 else
1695 /* Nothing specified -> width defaults to canonical char width. */
1696 width = CANON_X_UNIT (it->f);
1697
1698 /* Compute height. */
1699 if (prop = Fplist_get (plist, QCheight),
1700 NUMVAL (prop) > 0)
1701 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1702 else if (prop = Fplist_get (plist, QCrelative_height),
1703 NUMVAL (prop) > 0)
1704 height = FONT_HEIGHT (font) * NUMVAL (prop);
1705 else
1706 height = FONT_HEIGHT (font);
1707
1708 /* Compute percentage of height used for ascent. If
1709 `:ascent ASCENT' is present and valid, use that. Otherwise,
1710 derive the ascent from the font in use. */
1711 if (prop = Fplist_get (plist, QCascent),
1712 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1713 ascent = NUMVAL (prop) / 100.0;
1714 else
1715 ascent = (double) font->ascent / FONT_HEIGHT (font);
1716
1717 if (width <= 0)
1718 width = 1;
1719 if (height <= 0)
1720 height = 1;
1721
1722 if (it->glyph_row)
1723 {
1724 Lisp_Object object = it->stack[it->sp - 1].string;
1725 if (!STRINGP (object))
1726 object = it->w->buffer;
1727 x_append_stretch_glyph (it, object, width, height, ascent);
1728 }
1729
1730 it->pixel_width = width;
66ac4b0e
GM
1731 it->ascent = it->phys_ascent = height * ascent;
1732 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1733 it->nglyphs = 1;
1734
1735 if (face->box != FACE_NO_BOX)
1736 {
ea2ba0d4
KH
1737 if (face->box_line_width > 0)
1738 {
1739 it->ascent += face->box_line_width;
1740 it->descent += face->box_line_width;
1741 }
06a2c219
GM
1742
1743 if (it->start_of_box_run_p)
ea2ba0d4 1744 it->pixel_width += abs (face->box_line_width);
06a2c219 1745 if (it->end_of_box_run_p)
ea2ba0d4 1746 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1747 }
1748
1749 take_vertical_position_into_account (it);
1750}
1751
b4192550
KH
1752/* Return proper value to be used as baseline offset of font that has
1753 ASCENT and DESCENT to draw characters by the font at the vertical
1754 center of the line of frame F.
1755
1756 Here, out task is to find the value of BOFF in the following figure;
1757
1758 -------------------------+-----------+-
1759 -+-+---------+-+ | |
1760 | | | | | |
1761 | | | | F_ASCENT F_HEIGHT
1762 | | | ASCENT | |
1763 HEIGHT | | | | |
1764 | | |-|-+------+-----------|------- baseline
1765 | | | | BOFF | |
1766 | |---------|-+-+ | |
1767 | | | DESCENT | |
1768 -+-+---------+-+ F_DESCENT |
1769 -------------------------+-----------+-
1770
1771 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1772 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1773 DESCENT = FONT->descent
1774 HEIGHT = FONT_HEIGHT (FONT)
1775 F_DESCENT = (F->output_data.x->font->descent
1776 - F->output_data.x->baseline_offset)
1777 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1778*/
1779
458f45fa
KH
1780#define VCENTER_BASELINE_OFFSET(FONT, F) \
1781 ((FONT)->descent \
1782 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT)) \
1783 + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \
1784 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1785
1786/* Produce glyphs/get display metrics for the display element IT is
1787 loaded with. See the description of struct display_iterator in
1788 dispextern.h for an overview of struct display_iterator. */
1789
1790static void
1791x_produce_glyphs (it)
1792 struct it *it;
1793{
ee569018
KH
1794 it->glyph_not_available_p = 0;
1795
06a2c219
GM
1796 if (it->what == IT_CHARACTER)
1797 {
1798 XChar2b char2b;
1799 XFontStruct *font;
ee569018 1800 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1801 XCharStruct *pcm;
06a2c219 1802 int font_not_found_p;
b4192550
KH
1803 struct font_info *font_info;
1804 int boff; /* baseline offset */
a4249304
KH
1805 /* We may change it->multibyte_p upon unibyte<->multibyte
1806 conversion. So, save the current value now and restore it
1807 later.
1808
1809 Note: It seems that we don't have to record multibyte_p in
1810 struct glyph because the character code itself tells if or
1811 not the character is multibyte. Thus, in the future, we must
1812 consider eliminating the field `multibyte_p' in the struct
1813 glyph.
1814 */
1815 int saved_multibyte_p = it->multibyte_p;
06a2c219 1816
ee569018
KH
1817 /* Maybe translate single-byte characters to multibyte, or the
1818 other way. */
06a2c219 1819 it->char_to_display = it->c;
ee569018 1820 if (!ASCII_BYTE_P (it->c))
06a2c219 1821 {
ee569018
KH
1822 if (unibyte_display_via_language_environment
1823 && SINGLE_BYTE_CHAR_P (it->c)
1824 && (it->c >= 0240
1825 || !NILP (Vnonascii_translation_table)))
1826 {
1827 it->char_to_display = unibyte_char_to_multibyte (it->c);
a4249304 1828 it->multibyte_p = 1;
ee569018
KH
1829 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1830 face = FACE_FROM_ID (it->f, it->face_id);
1831 }
1832 else if (!SINGLE_BYTE_CHAR_P (it->c)
1833 && !it->multibyte_p)
1834 {
1835 it->char_to_display = multibyte_char_to_unibyte (it->c, Qnil);
a4249304 1836 it->multibyte_p = 0;
ee569018
KH
1837 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1838 face = FACE_FROM_ID (it->f, it->face_id);
1839 }
06a2c219
GM
1840 }
1841
ee569018
KH
1842 /* Get font to use. Encode IT->char_to_display. */
1843 x_get_char_face_and_encoding (it->f, it->char_to_display,
1844 it->face_id, &char2b,
1845 it->multibyte_p);
06a2c219
GM
1846 font = face->font;
1847
1848 /* When no suitable font found, use the default font. */
1849 font_not_found_p = font == NULL;
1850 if (font_not_found_p)
b4192550
KH
1851 {
1852 font = FRAME_FONT (it->f);
1853 boff = it->f->output_data.x->baseline_offset;
1854 font_info = NULL;
1855 }
1856 else
1857 {
1858 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1859 boff = font_info->baseline_offset;
1860 if (font_info->vertical_centering)
1861 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1862 }
06a2c219
GM
1863
1864 if (it->char_to_display >= ' '
1865 && (!it->multibyte_p || it->char_to_display < 128))
1866 {
1867 /* Either unibyte or ASCII. */
1868 int stretched_p;
1869
1870 it->nglyphs = 1;
06a2c219
GM
1871
1872 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1873 it->ascent = font->ascent + boff;
1874 it->descent = font->descent - boff;
474848ac
GM
1875
1876 if (pcm)
1877 {
1878 it->phys_ascent = pcm->ascent + boff;
1879 it->phys_descent = pcm->descent - boff;
1880 it->pixel_width = pcm->width;
1881 }
1882 else
1883 {
1884 it->glyph_not_available_p = 1;
1885 it->phys_ascent = font->ascent + boff;
1886 it->phys_descent = font->descent - boff;
1887 it->pixel_width = FONT_WIDTH (font);
1888 }
06a2c219
GM
1889
1890 /* If this is a space inside a region of text with
1891 `space-width' property, change its width. */
1892 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1893 if (stretched_p)
1894 it->pixel_width *= XFLOATINT (it->space_width);
1895
1896 /* If face has a box, add the box thickness to the character
1897 height. If character has a box line to the left and/or
1898 right, add the box line width to the character's width. */
1899 if (face->box != FACE_NO_BOX)
1900 {
1901 int thick = face->box_line_width;
1902
ea2ba0d4
KH
1903 if (thick > 0)
1904 {
1905 it->ascent += thick;
1906 it->descent += thick;
1907 }
1908 else
1909 thick = -thick;
1910
06a2c219
GM
1911 if (it->start_of_box_run_p)
1912 it->pixel_width += thick;
1913 if (it->end_of_box_run_p)
1914 it->pixel_width += thick;
1915 }
1916
1917 /* If face has an overline, add the height of the overline
1918 (1 pixel) and a 1 pixel margin to the character height. */
1919 if (face->overline_p)
1920 it->ascent += 2;
1921
1922 take_vertical_position_into_account (it);
1923
1924 /* If we have to actually produce glyphs, do it. */
1925 if (it->glyph_row)
1926 {
1927 if (stretched_p)
1928 {
1929 /* Translate a space with a `space-width' property
1930 into a stretch glyph. */
1931 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1932 x_append_stretch_glyph (it, it->object, it->pixel_width,
1933 it->ascent + it->descent, ascent);
1934 }
1935 else
1936 x_append_glyph (it);
1937
1938 /* If characters with lbearing or rbearing are displayed
1939 in this line, record that fact in a flag of the
1940 glyph row. This is used to optimize X output code. */
1c7e22fd 1941 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1942 it->glyph_row->contains_overlapping_glyphs_p = 1;
1943 }
1944 }
1945 else if (it->char_to_display == '\n')
1946 {
1947 /* A newline has no width but we need the height of the line. */
1948 it->pixel_width = 0;
1949 it->nglyphs = 0;
b4192550
KH
1950 it->ascent = it->phys_ascent = font->ascent + boff;
1951 it->descent = it->phys_descent = font->descent - boff;
06a2c219 1952
ea2ba0d4
KH
1953 if (face->box != FACE_NO_BOX
1954 && face->box_line_width > 0)
06a2c219 1955 {
ea2ba0d4
KH
1956 it->ascent += face->box_line_width;
1957 it->descent += face->box_line_width;
06a2c219
GM
1958 }
1959 }
1960 else if (it->char_to_display == '\t')
1961 {
1962 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1963 int x = it->current_x + it->continuation_lines_width;
06a2c219 1964 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
2a32b5ea
GM
1965
1966 /* If the distance from the current position to the next tab
1967 stop is less than a canonical character width, use the
1968 tab stop after that. */
1969 if (next_tab_x - x < CANON_X_UNIT (it->f))
1970 next_tab_x += tab_width;
06a2c219
GM
1971
1972 it->pixel_width = next_tab_x - x;
1973 it->nglyphs = 1;
b4192550
KH
1974 it->ascent = it->phys_ascent = font->ascent + boff;
1975 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1976
1977 if (it->glyph_row)
1978 {
1979 double ascent = (double) it->ascent / (it->ascent + it->descent);
1980 x_append_stretch_glyph (it, it->object, it->pixel_width,
1981 it->ascent + it->descent, ascent);
1982 }
1983 }
1984 else
1985 {
1986 /* A multi-byte character. Assume that the display width of the
1987 character is the width of the character multiplied by the
b4192550 1988 width of the font. */
06a2c219 1989
b4192550
KH
1990 /* If we found a font, this font should give us the right
1991 metrics. If we didn't find a font, use the frame's
1992 default font and calculate the width of the character
1993 from the charset width; this is what old redisplay code
1994 did. */
1995 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
1996 if (font_not_found_p || !pcm)
1997 {
1998 int charset = CHAR_CHARSET (it->char_to_display);
1999
2000 it->glyph_not_available_p = 1;
2001 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
2002 * CHARSET_WIDTH (charset));
2003 it->phys_ascent = font->ascent + boff;
2004 it->phys_descent = font->descent - boff;
2005 }
2006 else
2007 {
2008 it->pixel_width = pcm->width;
2009 it->phys_ascent = pcm->ascent + boff;
2010 it->phys_descent = pcm->descent - boff;
2011 if (it->glyph_row
2012 && (pcm->lbearing < 0
2013 || pcm->rbearing > pcm->width))
2014 it->glyph_row->contains_overlapping_glyphs_p = 1;
2015 }
b4192550
KH
2016 it->nglyphs = 1;
2017 it->ascent = font->ascent + boff;
2018 it->descent = font->descent - boff;
06a2c219
GM
2019 if (face->box != FACE_NO_BOX)
2020 {
2021 int thick = face->box_line_width;
ea2ba0d4
KH
2022
2023 if (thick > 0)
2024 {
2025 it->ascent += thick;
2026 it->descent += thick;
2027 }
2028 else
2029 thick = - thick;
06a2c219
GM
2030
2031 if (it->start_of_box_run_p)
2032 it->pixel_width += thick;
2033 if (it->end_of_box_run_p)
2034 it->pixel_width += thick;
2035 }
2036
2037 /* If face has an overline, add the height of the overline
2038 (1 pixel) and a 1 pixel margin to the character height. */
2039 if (face->overline_p)
2040 it->ascent += 2;
2041
2042 take_vertical_position_into_account (it);
2043
2044 if (it->glyph_row)
2045 x_append_glyph (it);
2046 }
a4249304 2047 it->multibyte_p = saved_multibyte_p;
06a2c219 2048 }
b4192550
KH
2049 else if (it->what == IT_COMPOSITION)
2050 {
2051 /* Note: A composition is represented as one glyph in the
2052 glyph matrix. There are no padding glyphs. */
2053 XChar2b char2b;
2054 XFontStruct *font;
ee569018 2055 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2056 XCharStruct *pcm;
2057 int font_not_found_p;
2058 struct font_info *font_info;
2059 int boff; /* baseline offset */
2060 struct composition *cmp = composition_table[it->cmp_id];
2061
2062 /* Maybe translate single-byte characters to multibyte. */
2063 it->char_to_display = it->c;
2064 if (unibyte_display_via_language_environment
2065 && SINGLE_BYTE_CHAR_P (it->c)
2066 && (it->c >= 0240
2067 || (it->c >= 0200
2068 && !NILP (Vnonascii_translation_table))))
2069 {
2070 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2071 }
2072
2073 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2074 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2075 face = FACE_FROM_ID (it->f, it->face_id);
2076 x_get_char_face_and_encoding (it->f, it->char_to_display,
2077 it->face_id, &char2b, it->multibyte_p);
b4192550
KH
2078 font = face->font;
2079
2080 /* When no suitable font found, use the default font. */
2081 font_not_found_p = font == NULL;
2082 if (font_not_found_p)
2083 {
2084 font = FRAME_FONT (it->f);
2085 boff = it->f->output_data.x->baseline_offset;
2086 font_info = NULL;
2087 }
2088 else
2089 {
2090 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2091 boff = font_info->baseline_offset;
2092 if (font_info->vertical_centering)
2093 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2094 }
2095
2096 /* There are no padding glyphs, so there is only one glyph to
2097 produce for the composition. Important is that pixel_width,
2098 ascent and descent are the values of what is drawn by
2099 draw_glyphs (i.e. the values of the overall glyphs composed). */
2100 it->nglyphs = 1;
2101
2102 /* If we have not yet calculated pixel size data of glyphs of
2103 the composition for the current face font, calculate them
2104 now. Theoretically, we have to check all fonts for the
2105 glyphs, but that requires much time and memory space. So,
2106 here we check only the font of the first glyph. This leads
2107 to incorrect display very rarely, and C-l (recenter) can
2108 correct the display anyway. */
2109 if (cmp->font != (void *) font)
2110 {
2111 /* Ascent and descent of the font of the first character of
2112 this composition (adjusted by baseline offset). Ascent
2113 and descent of overall glyphs should not be less than
2114 them respectively. */
2115 int font_ascent = font->ascent + boff;
2116 int font_descent = font->descent - boff;
2117 /* Bounding box of the overall glyphs. */
2118 int leftmost, rightmost, lowest, highest;
329bed06 2119 int i, width, ascent, descent;
b4192550
KH
2120
2121 cmp->font = (void *) font;
2122
2123 /* Initialize the bounding box. */
1bdeec2e
KH
2124 if (font_info
2125 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2126 {
2127 width = pcm->width;
2128 ascent = pcm->ascent;
2129 descent = pcm->descent;
2130 }
2131 else
2132 {
2133 width = FONT_WIDTH (font);
2134 ascent = font->ascent;
2135 descent = font->descent;
2136 }
2137
2138 rightmost = width;
2139 lowest = - descent + boff;
2140 highest = ascent + boff;
b4192550 2141 leftmost = 0;
329bed06 2142
b4192550
KH
2143 if (font_info
2144 && font_info->default_ascent
2145 && CHAR_TABLE_P (Vuse_default_ascent)
2146 && !NILP (Faref (Vuse_default_ascent,
2147 make_number (it->char_to_display))))
2148 highest = font_info->default_ascent + boff;
2149
2150 /* Draw the first glyph at the normal position. It may be
2151 shifted to right later if some other glyphs are drawn at
2152 the left. */
2153 cmp->offsets[0] = 0;
2154 cmp->offsets[1] = boff;
2155
2156 /* Set cmp->offsets for the remaining glyphs. */
2157 for (i = 1; i < cmp->glyph_len; i++)
2158 {
2159 int left, right, btm, top;
2160 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2161 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2162
2163 face = FACE_FROM_ID (it->f, face_id);
2164 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2165 it->multibyte_p);
b4192550
KH
2166 font = face->font;
2167 if (font == NULL)
2168 {
2169 font = FRAME_FONT (it->f);
2170 boff = it->f->output_data.x->baseline_offset;
2171 font_info = NULL;
2172 }
2173 else
2174 {
2175 font_info
2176 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2177 boff = font_info->baseline_offset;
2178 if (font_info->vertical_centering)
2179 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2180 }
2181
1bdeec2e
KH
2182 if (font_info
2183 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2184 {
2185 width = pcm->width;
2186 ascent = pcm->ascent;
2187 descent = pcm->descent;
2188 }
2189 else
2190 {
2191 width = FONT_WIDTH (font);
1bdeec2e
KH
2192 ascent = 1;
2193 descent = 0;
329bed06 2194 }
b4192550
KH
2195
2196 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2197 {
2198 /* Relative composition with or without
2199 alternate chars. */
329bed06
GM
2200 left = (leftmost + rightmost - width) / 2;
2201 btm = - descent + boff;
b4192550
KH
2202 if (font_info && font_info->relative_compose
2203 && (! CHAR_TABLE_P (Vignore_relative_composition)
2204 || NILP (Faref (Vignore_relative_composition,
2205 make_number (ch)))))
2206 {
2207
329bed06 2208 if (- descent >= font_info->relative_compose)
b4192550
KH
2209 /* One extra pixel between two glyphs. */
2210 btm = highest + 1;
329bed06 2211 else if (ascent <= 0)
b4192550 2212 /* One extra pixel between two glyphs. */
329bed06 2213 btm = lowest - 1 - ascent - descent;
b4192550
KH
2214 }
2215 }
2216 else
2217 {
2218 /* A composition rule is specified by an integer
2219 value that encodes global and new reference
2220 points (GREF and NREF). GREF and NREF are
2221 specified by numbers as below:
2222
2223 0---1---2 -- ascent
2224 | |
2225 | |
2226 | |
2227 9--10--11 -- center
2228 | |
2229 ---3---4---5--- baseline
2230 | |
2231 6---7---8 -- descent
2232 */
2233 int rule = COMPOSITION_RULE (cmp, i);
2234 int gref, nref, grefx, grefy, nrefx, nrefy;
2235
2236 COMPOSITION_DECODE_RULE (rule, gref, nref);
2237 grefx = gref % 3, nrefx = nref % 3;
2238 grefy = gref / 3, nrefy = nref / 3;
2239
2240 left = (leftmost
2241 + grefx * (rightmost - leftmost) / 2
329bed06 2242 - nrefx * width / 2);
b4192550
KH
2243 btm = ((grefy == 0 ? highest
2244 : grefy == 1 ? 0
2245 : grefy == 2 ? lowest
2246 : (highest + lowest) / 2)
329bed06
GM
2247 - (nrefy == 0 ? ascent + descent
2248 : nrefy == 1 ? descent - boff
b4192550 2249 : nrefy == 2 ? 0
329bed06 2250 : (ascent + descent) / 2));
b4192550
KH
2251 }
2252
2253 cmp->offsets[i * 2] = left;
329bed06 2254 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2255
2256 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2257 right = left + width;
2258 top = btm + descent + ascent;
b4192550
KH
2259 if (left < leftmost)
2260 leftmost = left;
2261 if (right > rightmost)
2262 rightmost = right;
2263 if (top > highest)
2264 highest = top;
2265 if (btm < lowest)
2266 lowest = btm;
2267 }
2268
2269 /* If there are glyphs whose x-offsets are negative,
2270 shift all glyphs to the right and make all x-offsets
2271 non-negative. */
2272 if (leftmost < 0)
2273 {
2274 for (i = 0; i < cmp->glyph_len; i++)
2275 cmp->offsets[i * 2] -= leftmost;
2276 rightmost -= leftmost;
2277 }
2278
2279 cmp->pixel_width = rightmost;
2280 cmp->ascent = highest;
2281 cmp->descent = - lowest;
2282 if (cmp->ascent < font_ascent)
2283 cmp->ascent = font_ascent;
2284 if (cmp->descent < font_descent)
2285 cmp->descent = font_descent;
2286 }
2287
2288 it->pixel_width = cmp->pixel_width;
2289 it->ascent = it->phys_ascent = cmp->ascent;
2290 it->descent = it->phys_descent = cmp->descent;
2291
2292 if (face->box != FACE_NO_BOX)
2293 {
2294 int thick = face->box_line_width;
ea2ba0d4
KH
2295
2296 if (thick > 0)
2297 {
2298 it->ascent += thick;
2299 it->descent += thick;
2300 }
2301 else
2302 thick = - thick;
b4192550
KH
2303
2304 if (it->start_of_box_run_p)
2305 it->pixel_width += thick;
2306 if (it->end_of_box_run_p)
2307 it->pixel_width += thick;
2308 }
2309
2310 /* If face has an overline, add the height of the overline
2311 (1 pixel) and a 1 pixel margin to the character height. */
2312 if (face->overline_p)
2313 it->ascent += 2;
2314
2315 take_vertical_position_into_account (it);
2316
2317 if (it->glyph_row)
2318 x_append_composite_glyph (it);
2319 }
06a2c219
GM
2320 else if (it->what == IT_IMAGE)
2321 x_produce_image_glyph (it);
2322 else if (it->what == IT_STRETCH)
2323 x_produce_stretch_glyph (it);
2324
3017fdd1
GM
2325 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2326 because this isn't true for images with `:ascent 100'. */
2327 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2328 if (it->area == TEXT_AREA)
2329 it->current_x += it->pixel_width;
66ac4b0e 2330
d365f5bb
GM
2331 it->descent += it->extra_line_spacing;
2332
06a2c219
GM
2333 it->max_ascent = max (it->max_ascent, it->ascent);
2334 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2335 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2336 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2337}
2338
2339
2340/* Estimate the pixel height of the mode or top line on frame F.
2341 FACE_ID specifies what line's height to estimate. */
2342
2343int
2344x_estimate_mode_line_height (f, face_id)
2345 struct frame *f;
2346 enum face_id face_id;
2347{
43281ee3 2348 int height = FONT_HEIGHT (FRAME_FONT (f));
06a2c219
GM
2349
2350 /* This function is called so early when Emacs starts that the face
2351 cache and mode line face are not yet initialized. */
2352 if (FRAME_FACE_CACHE (f))
2353 {
2354 struct face *face = FACE_FROM_ID (f, face_id);
2355 if (face)
43281ee3
GM
2356 {
2357 if (face->font)
2358 height = FONT_HEIGHT (face->font);
ea2ba0d4
KH
2359 if (face->box_line_width > 0)
2360 height += 2 * face->box_line_width;
43281ee3 2361 }
06a2c219
GM
2362 }
2363
2364 return height;
2365}
2366
2367\f
2368/***********************************************************************
2369 Glyph display
2370 ***********************************************************************/
2371
2372/* A sequence of glyphs to be drawn in the same face.
2373
2374 This data structure is not really completely X specific, so it
2375 could possibly, at least partially, be useful for other systems. It
2376 is currently not part of the external redisplay interface because
2377 it's not clear what other systems will need. */
2378
2379struct glyph_string
2380{
2381 /* X-origin of the string. */
2382 int x;
2383
2384 /* Y-origin and y-position of the base line of this string. */
2385 int y, ybase;
2386
2387 /* The width of the string, not including a face extension. */
2388 int width;
2389
2390 /* The width of the string, including a face extension. */
2391 int background_width;
2392
2393 /* The height of this string. This is the height of the line this
2394 string is drawn in, and can be different from the height of the
2395 font the string is drawn in. */
2396 int height;
2397
2398 /* Number of pixels this string overwrites in front of its x-origin.
2399 This number is zero if the string has an lbearing >= 0; it is
2400 -lbearing, if the string has an lbearing < 0. */
2401 int left_overhang;
2402
2403 /* Number of pixels this string overwrites past its right-most
2404 nominal x-position, i.e. x + width. Zero if the string's
2405 rbearing is <= its nominal width, rbearing - width otherwise. */
2406 int right_overhang;
2407
2408 /* The frame on which the glyph string is drawn. */
2409 struct frame *f;
2410
2411 /* The window on which the glyph string is drawn. */
2412 struct window *w;
2413
2414 /* X display and window for convenience. */
2415 Display *display;
2416 Window window;
2417
2418 /* The glyph row for which this string was built. It determines the
2419 y-origin and height of the string. */
2420 struct glyph_row *row;
2421
2422 /* The area within row. */
2423 enum glyph_row_area area;
2424
2425 /* Characters to be drawn, and number of characters. */
2426 XChar2b *char2b;
2427 int nchars;
2428
06a2c219
GM
2429 /* A face-override for drawing cursors, mouse face and similar. */
2430 enum draw_glyphs_face hl;
2431
2432 /* Face in which this string is to be drawn. */
2433 struct face *face;
2434
2435 /* Font in which this string is to be drawn. */
2436 XFontStruct *font;
2437
2438 /* Font info for this string. */
2439 struct font_info *font_info;
2440
b4192550
KH
2441 /* Non-null means this string describes (part of) a composition.
2442 All characters from char2b are drawn composed. */
2443 struct composition *cmp;
06a2c219
GM
2444
2445 /* Index of this glyph string's first character in the glyph
b4192550
KH
2446 definition of CMP. If this is zero, this glyph string describes
2447 the first character of a composition. */
06a2c219
GM
2448 int gidx;
2449
2450 /* 1 means this glyph strings face has to be drawn to the right end
2451 of the window's drawing area. */
2452 unsigned extends_to_end_of_line_p : 1;
2453
2454 /* 1 means the background of this string has been drawn. */
2455 unsigned background_filled_p : 1;
2456
2457 /* 1 means glyph string must be drawn with 16-bit functions. */
2458 unsigned two_byte_p : 1;
2459
2460 /* 1 means that the original font determined for drawing this glyph
2461 string could not be loaded. The member `font' has been set to
2462 the frame's default font in this case. */
2463 unsigned font_not_found_p : 1;
2464
2465 /* 1 means that the face in which this glyph string is drawn has a
2466 stipple pattern. */
2467 unsigned stippled_p : 1;
2468
66ac4b0e
GM
2469 /* 1 means only the foreground of this glyph string must be drawn,
2470 and we should use the physical height of the line this glyph
2471 string appears in as clip rect. */
2472 unsigned for_overlaps_p : 1;
2473
06a2c219
GM
2474 /* The GC to use for drawing this glyph string. */
2475 GC gc;
2476
2477 /* A pointer to the first glyph in the string. This glyph
2478 corresponds to char2b[0]. Needed to draw rectangles if
2479 font_not_found_p is 1. */
2480 struct glyph *first_glyph;
2481
2482 /* Image, if any. */
2483 struct image *img;
2484
2485 struct glyph_string *next, *prev;
2486};
2487
2488
5c187dee 2489#if 0
06a2c219
GM
2490
2491static void
2492x_dump_glyph_string (s)
2493 struct glyph_string *s;
2494{
2495 fprintf (stderr, "glyph string\n");
2496 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2497 s->x, s->y, s->width, s->height);
2498 fprintf (stderr, " ybase = %d\n", s->ybase);
2499 fprintf (stderr, " hl = %d\n", s->hl);
2500 fprintf (stderr, " left overhang = %d, right = %d\n",
2501 s->left_overhang, s->right_overhang);
2502 fprintf (stderr, " nchars = %d\n", s->nchars);
2503 fprintf (stderr, " extends to end of line = %d\n",
2504 s->extends_to_end_of_line_p);
2505 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2506 fprintf (stderr, " bg width = %d\n", s->background_width);
2507}
2508
2509#endif /* GLYPH_DEBUG */
2510
2511
2512
2513static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2514 struct glyph_string **,
2515 struct glyph_string *,
2516 struct glyph_string *));
2517static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2518 struct glyph_string **,
2519 struct glyph_string *,
2520 struct glyph_string *));
2521static void x_append_glyph_string P_ ((struct glyph_string **,
2522 struct glyph_string **,
2523 struct glyph_string *));
2524static int x_left_overwritten P_ ((struct glyph_string *));
2525static int x_left_overwriting P_ ((struct glyph_string *));
2526static int x_right_overwritten P_ ((struct glyph_string *));
2527static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2528static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2529 int));
06a2c219
GM
2530static void x_init_glyph_string P_ ((struct glyph_string *,
2531 XChar2b *, struct window *,
2532 struct glyph_row *,
2533 enum glyph_row_area, int,
2534 enum draw_glyphs_face));
2535static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2536 enum glyph_row_area, int, int,
66ac4b0e 2537 enum draw_glyphs_face, int *, int *, int));
06a2c219
GM
2538static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2539static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2540static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2541 int));
2542static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2543static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2544static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2545static void x_draw_glyph_string P_ ((struct glyph_string *));
2546static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2547static void x_set_cursor_gc P_ ((struct glyph_string *));
2548static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2549static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2550static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2551 int *, int *));
2552static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2553static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2554 unsigned long *, double, int));
06a2c219 2555static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2556 double, int, unsigned long));
06a2c219
GM
2557static void x_setup_relief_colors P_ ((struct glyph_string *));
2558static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2559static void x_draw_image_relief P_ ((struct glyph_string *));
2560static void x_draw_image_foreground P_ ((struct glyph_string *));
2561static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2562static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2563static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2564 int, int, int));
2565static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2566 int, int, int, int, XRectangle *));
2567static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2568 int, int, int, XRectangle *));
66ac4b0e
GM
2569static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2570 enum glyph_row_area));
209f68d9
GM
2571static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2572 struct glyph_row *,
2573 enum glyph_row_area, int, int));
06a2c219 2574
163dcff3
GM
2575#if GLYPH_DEBUG
2576static void x_check_font P_ ((struct frame *, XFontStruct *));
2577#endif
2578
06a2c219 2579
06a2c219
GM
2580/* Append the list of glyph strings with head H and tail T to the list
2581 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2582
2583static INLINE void
2584x_append_glyph_string_lists (head, tail, h, t)
2585 struct glyph_string **head, **tail;
2586 struct glyph_string *h, *t;
2587{
2588 if (h)
2589 {
2590 if (*head)
2591 (*tail)->next = h;
2592 else
2593 *head = h;
2594 h->prev = *tail;
2595 *tail = t;
2596 }
2597}
2598
2599
2600/* Prepend the list of glyph strings with head H and tail T to the
2601 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2602 result. */
2603
2604static INLINE void
2605x_prepend_glyph_string_lists (head, tail, h, t)
2606 struct glyph_string **head, **tail;
2607 struct glyph_string *h, *t;
2608{
2609 if (h)
2610 {
2611 if (*head)
2612 (*head)->prev = t;
2613 else
2614 *tail = t;
2615 t->next = *head;
2616 *head = h;
2617 }
2618}
2619
2620
2621/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2622 Set *HEAD and *TAIL to the resulting list. */
2623
2624static INLINE void
2625x_append_glyph_string (head, tail, s)
2626 struct glyph_string **head, **tail;
2627 struct glyph_string *s;
2628{
2629 s->next = s->prev = NULL;
2630 x_append_glyph_string_lists (head, tail, s, s);
2631}
2632
2633
2634/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2635 face. */
2636
2637static void
2638x_set_cursor_gc (s)
2639 struct glyph_string *s;
2640{
2641 if (s->font == FRAME_FONT (s->f)
2642 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2643 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2644 && !s->cmp)
06a2c219
GM
2645 s->gc = s->f->output_data.x->cursor_gc;
2646 else
2647 {
2648 /* Cursor on non-default face: must merge. */
2649 XGCValues xgcv;
2650 unsigned long mask;
2651
2652 xgcv.background = s->f->output_data.x->cursor_pixel;
2653 xgcv.foreground = s->face->background;
2654
2655 /* If the glyph would be invisible, try a different foreground. */
2656 if (xgcv.foreground == xgcv.background)
2657 xgcv.foreground = s->face->foreground;
2658 if (xgcv.foreground == xgcv.background)
2659 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2660 if (xgcv.foreground == xgcv.background)
2661 xgcv.foreground = s->face->foreground;
2662
2663 /* Make sure the cursor is distinct from text in this face. */
2664 if (xgcv.background == s->face->background
2665 && xgcv.foreground == s->face->foreground)
2666 {
2667 xgcv.background = s->face->foreground;
2668 xgcv.foreground = s->face->background;
2669 }
2670
2671 IF_DEBUG (x_check_font (s->f, s->font));
2672 xgcv.font = s->font->fid;
2673 xgcv.graphics_exposures = False;
2674 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2675
2676 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2677 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2678 mask, &xgcv);
2679 else
2680 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2681 = XCreateGC (s->display, s->window, mask, &xgcv);
2682
2683 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2684 }
2685}
2686
2687
2688/* Set up S->gc of glyph string S for drawing text in mouse face. */
2689
2690static void
2691x_set_mouse_face_gc (s)
2692 struct glyph_string *s;
2693{
2694 int face_id;
ee569018 2695 struct face *face;
06a2c219 2696
e4ded23c 2697 /* What face has to be used last for the mouse face? */
06a2c219 2698 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2699 face = FACE_FROM_ID (s->f, face_id);
e4ded23c
GM
2700 if (face == NULL)
2701 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2702
033e3e18
GM
2703 if (s->first_glyph->type == CHAR_GLYPH)
2704 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2705 else
2706 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2707 s->face = FACE_FROM_ID (s->f, face_id);
2708 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2709
2710 /* If font in this face is same as S->font, use it. */
2711 if (s->font == s->face->font)
2712 s->gc = s->face->gc;
2713 else
2714 {
2715 /* Otherwise construct scratch_cursor_gc with values from FACE
2716 but font FONT. */
2717 XGCValues xgcv;
2718 unsigned long mask;
2719
2720 xgcv.background = s->face->background;
2721 xgcv.foreground = s->face->foreground;
2722 IF_DEBUG (x_check_font (s->f, s->font));
2723 xgcv.font = s->font->fid;
2724 xgcv.graphics_exposures = False;
2725 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2726
2727 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2728 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2729 mask, &xgcv);
2730 else
2731 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2732 = XCreateGC (s->display, s->window, mask, &xgcv);
2733
2734 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2735 }
2736
2737 xassert (s->gc != 0);
2738}
2739
2740
2741/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2742 Faces to use in the mode line have already been computed when the
2743 matrix was built, so there isn't much to do, here. */
2744
2745static INLINE void
2746x_set_mode_line_face_gc (s)
2747 struct glyph_string *s;
2748{
2749 s->gc = s->face->gc;
06a2c219
GM
2750}
2751
2752
2753/* Set S->gc of glyph string S for drawing that glyph string. Set
2754 S->stippled_p to a non-zero value if the face of S has a stipple
2755 pattern. */
2756
2757static INLINE void
2758x_set_glyph_string_gc (s)
2759 struct glyph_string *s;
2760{
209f68d9
GM
2761 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2762
06a2c219
GM
2763 if (s->hl == DRAW_NORMAL_TEXT)
2764 {
2765 s->gc = s->face->gc;
2766 s->stippled_p = s->face->stipple != 0;
2767 }
2768 else if (s->hl == DRAW_INVERSE_VIDEO)
2769 {
2770 x_set_mode_line_face_gc (s);
2771 s->stippled_p = s->face->stipple != 0;
2772 }
2773 else if (s->hl == DRAW_CURSOR)
2774 {
2775 x_set_cursor_gc (s);
2776 s->stippled_p = 0;
2777 }
2778 else if (s->hl == DRAW_MOUSE_FACE)
2779 {
2780 x_set_mouse_face_gc (s);
2781 s->stippled_p = s->face->stipple != 0;
2782 }
2783 else if (s->hl == DRAW_IMAGE_RAISED
2784 || s->hl == DRAW_IMAGE_SUNKEN)
2785 {
2786 s->gc = s->face->gc;
2787 s->stippled_p = s->face->stipple != 0;
2788 }
2789 else
2790 {
2791 s->gc = s->face->gc;
2792 s->stippled_p = s->face->stipple != 0;
2793 }
2794
2795 /* GC must have been set. */
2796 xassert (s->gc != 0);
2797}
2798
2799
2800/* Return in *R the clipping rectangle for glyph string S. */
2801
2802static void
2803x_get_glyph_string_clip_rect (s, r)
2804 struct glyph_string *s;
2805 XRectangle *r;
2806{
2807 if (s->row->full_width_p)
2808 {
2809 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2810 int canon_x = CANON_X_UNIT (s->f);
2811
2812 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2813 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2814
2815 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2816 {
1da3fd71 2817 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2818 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2819 r->x -= width;
2820 }
2821
b9432a85 2822 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2823
06a2c219
GM
2824 /* Unless displaying a mode or menu bar line, which are always
2825 fully visible, clip to the visible part of the row. */
2826 if (s->w->pseudo_window_p)
2827 r->height = s->row->visible_height;
2828 else
2829 r->height = s->height;
2830 }
2831 else
2832 {
2833 /* This is a text line that may be partially visible. */
2834 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2835 r->width = window_box_width (s->w, s->area);
2836 r->height = s->row->visible_height;
2837 }
2838
2839 /* Don't use S->y for clipping because it doesn't take partially
2840 visible lines into account. For example, it can be negative for
2841 partially visible lines at the top of a window. */
2842 if (!s->row->full_width_p
2843 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
045dee35 2844 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
06a2c219
GM
2845 else
2846 r->y = max (0, s->row->y);
06a2c219 2847
9ea173e8 2848 /* If drawing a tool-bar window, draw it over the internal border
06a2c219 2849 at the top of the window. */
9ea173e8 2850 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219 2851 r->y -= s->f->output_data.x->internal_border_width;
66ac4b0e
GM
2852
2853 /* If S draws overlapping rows, it's sufficient to use the top and
2854 bottom of the window for clipping because this glyph string
2855 intentionally draws over other lines. */
2856 if (s->for_overlaps_p)
2857 {
045dee35 2858 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2859 r->height = window_text_bottom_y (s->w) - r->y;
2860 }
2861
2862 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2863}
2864
2865
2866/* Set clipping for output of glyph string S. S may be part of a mode
2867 line or menu if we don't have X toolkit support. */
2868
2869static INLINE void
2870x_set_glyph_string_clipping (s)
2871 struct glyph_string *s;
2872{
2873 XRectangle r;
2874 x_get_glyph_string_clip_rect (s, &r);
2875 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2876}
2877
2878
2879/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2880 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2881
2882static INLINE void
2883x_compute_glyph_string_overhangs (s)
2884 struct glyph_string *s;
2885{
b4192550 2886 if (s->cmp == NULL
06a2c219
GM
2887 && s->first_glyph->type == CHAR_GLYPH)
2888 {
2889 XCharStruct cs;
2890 int direction, font_ascent, font_descent;
2891 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2892 &font_ascent, &font_descent, &cs);
2893 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2894 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2895 }
2896}
2897
2898
2899/* Compute overhangs and x-positions for glyph string S and its
2900 predecessors, or successors. X is the starting x-position for S.
2901 BACKWARD_P non-zero means process predecessors. */
2902
2903static void
2904x_compute_overhangs_and_x (s, x, backward_p)
2905 struct glyph_string *s;
2906 int x;
2907 int backward_p;
2908{
2909 if (backward_p)
2910 {
2911 while (s)
2912 {
2913 x_compute_glyph_string_overhangs (s);
2914 x -= s->width;
2915 s->x = x;
2916 s = s->prev;
2917 }
2918 }
2919 else
2920 {
2921 while (s)
2922 {
2923 x_compute_glyph_string_overhangs (s);
2924 s->x = x;
2925 x += s->width;
2926 s = s->next;
2927 }
2928 }
2929}
2930
2931
2932/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2933 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2934 assumed to be zero. */
06a2c219
GM
2935
2936static void
2937x_get_glyph_overhangs (glyph, f, left, right)
2938 struct glyph *glyph;
2939 struct frame *f;
2940 int *left, *right;
2941{
06a2c219
GM
2942 *left = *right = 0;
2943
b4192550 2944 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2945 {
2946 XFontStruct *font;
2947 struct face *face;
2948 struct font_info *font_info;
2949 XChar2b char2b;
ee569018
KH
2950 XCharStruct *pcm;
2951
2952 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2953 font = face->font;
2954 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2955 if (font
2956 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2957 {
06a2c219
GM
2958 if (pcm->rbearing > pcm->width)
2959 *right = pcm->rbearing - pcm->width;
2960 if (pcm->lbearing < 0)
2961 *left = -pcm->lbearing;
2962 }
2963 }
2964}
2965
2966
2967/* Return the index of the first glyph preceding glyph string S that
2968 is overwritten by S because of S's left overhang. Value is -1
2969 if no glyphs are overwritten. */
2970
2971static int
2972x_left_overwritten (s)
2973 struct glyph_string *s;
2974{
2975 int k;
2976
2977 if (s->left_overhang)
2978 {
2979 int x = 0, i;
2980 struct glyph *glyphs = s->row->glyphs[s->area];
2981 int first = s->first_glyph - glyphs;
2982
2983 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2984 x -= glyphs[i].pixel_width;
2985
2986 k = i + 1;
2987 }
2988 else
2989 k = -1;
2990
2991 return k;
2992}
2993
2994
2995/* Return the index of the first glyph preceding glyph string S that
2996 is overwriting S because of its right overhang. Value is -1 if no
2997 glyph in front of S overwrites S. */
2998
2999static int
3000x_left_overwriting (s)
3001 struct glyph_string *s;
3002{
3003 int i, k, x;
3004 struct glyph *glyphs = s->row->glyphs[s->area];
3005 int first = s->first_glyph - glyphs;
3006
3007 k = -1;
3008 x = 0;
3009 for (i = first - 1; i >= 0; --i)
3010 {
3011 int left, right;
3012 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3013 if (x + right > 0)
3014 k = i;
3015 x -= glyphs[i].pixel_width;
3016 }
3017
3018 return k;
3019}
3020
3021
3022/* Return the index of the last glyph following glyph string S that is
3023 not overwritten by S because of S's right overhang. Value is -1 if
3024 no such glyph is found. */
3025
3026static int
3027x_right_overwritten (s)
3028 struct glyph_string *s;
3029{
3030 int k = -1;
3031
3032 if (s->right_overhang)
3033 {
3034 int x = 0, i;
3035 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3036 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3037 int end = s->row->used[s->area];
3038
3039 for (i = first; i < end && s->right_overhang > x; ++i)
3040 x += glyphs[i].pixel_width;
3041
3042 k = i;
3043 }
3044
3045 return k;
3046}
3047
3048
3049/* Return the index of the last glyph following glyph string S that
3050 overwrites S because of its left overhang. Value is negative
3051 if no such glyph is found. */
3052
3053static int
3054x_right_overwriting (s)
3055 struct glyph_string *s;
3056{
3057 int i, k, x;
3058 int end = s->row->used[s->area];
3059 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3060 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3061
3062 k = -1;
3063 x = 0;
3064 for (i = first; i < end; ++i)
3065 {
3066 int left, right;
3067 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3068 if (x - left < 0)
3069 k = i;
3070 x += glyphs[i].pixel_width;
3071 }
3072
3073 return k;
3074}
3075
3076
3077/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3078
3079static INLINE void
3080x_clear_glyph_string_rect (s, x, y, w, h)
3081 struct glyph_string *s;
3082 int x, y, w, h;
3083{
3084 XGCValues xgcv;
3085 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3086 XSetForeground (s->display, s->gc, xgcv.background);
3087 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3088 XSetForeground (s->display, s->gc, xgcv.foreground);
3089}
3090
3091
3092/* Draw the background of glyph_string S. If S->background_filled_p
3093 is non-zero don't draw it. FORCE_P non-zero means draw the
3094 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3095 when a string preceding S draws into the background of S, or S
3096 contains the first component of a composition. */
06a2c219
GM
3097
3098static void
3099x_draw_glyph_string_background (s, force_p)
3100 struct glyph_string *s;
3101 int force_p;
3102{
3103 /* Nothing to do if background has already been drawn or if it
3104 shouldn't be drawn in the first place. */
3105 if (!s->background_filled_p)
3106 {
ea2ba0d4
KH
3107 int box_line_width = max (s->face->box_line_width, 0);
3108
b4192550 3109 if (s->stippled_p)
06a2c219
GM
3110 {
3111 /* Fill background with a stipple pattern. */
3112 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3113 XFillRectangle (s->display, s->window, s->gc, s->x,
ea2ba0d4 3114 s->y + box_line_width,
06a2c219 3115 s->background_width,
ea2ba0d4 3116 s->height - 2 * box_line_width);
06a2c219
GM
3117 XSetFillStyle (s->display, s->gc, FillSolid);
3118 s->background_filled_p = 1;
3119 }
ea2ba0d4 3120 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
06a2c219
GM
3121 || s->font_not_found_p
3122 || s->extends_to_end_of_line_p
06a2c219
GM
3123 || force_p)
3124 {
ea2ba0d4 3125 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
06a2c219 3126 s->background_width,
ea2ba0d4 3127 s->height - 2 * box_line_width);
06a2c219
GM
3128 s->background_filled_p = 1;
3129 }
3130 }
3131}
3132
3133
3134/* Draw the foreground of glyph string S. */
3135
3136static void
3137x_draw_glyph_string_foreground (s)
3138 struct glyph_string *s;
3139{
3140 int i, x;
3141
3142 /* If first glyph of S has a left box line, start drawing the text
3143 of S to the right of that box line. */
3144 if (s->face->box != FACE_NO_BOX
3145 && s->first_glyph->left_box_line_p)
ea2ba0d4 3146 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
3147 else
3148 x = s->x;
3149
b4192550
KH
3150 /* Draw characters of S as rectangles if S's font could not be
3151 loaded. */
3152 if (s->font_not_found_p)
06a2c219 3153 {
b4192550 3154 for (i = 0; i < s->nchars; ++i)
06a2c219 3155 {
b4192550
KH
3156 struct glyph *g = s->first_glyph + i;
3157 XDrawRectangle (s->display, s->window,
3158 s->gc, x, s->y, g->pixel_width - 1,
3159 s->height - 1);
3160 x += g->pixel_width;
06a2c219
GM
3161 }
3162 }
3163 else
3164 {
b4192550
KH
3165 char *char1b = (char *) s->char2b;
3166 int boff = s->font_info->baseline_offset;
06a2c219 3167
b4192550
KH
3168 if (s->font_info->vertical_centering)
3169 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3170
3171 /* If we can use 8-bit functions, condense S->char2b. */
3172 if (!s->two_byte_p)
3173 for (i = 0; i < s->nchars; ++i)
3174 char1b[i] = s->char2b[i].byte2;
3175
3176 /* Draw text with XDrawString if background has already been
3177 filled. Otherwise, use XDrawImageString. (Note that
3178 XDrawImageString is usually faster than XDrawString.) Always
3179 use XDrawImageString when drawing the cursor so that there is
3180 no chance that characters under a box cursor are invisible. */
3181 if (s->for_overlaps_p
3182 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3183 {
3184 /* Draw characters with 16-bit or 8-bit functions. */
3185 if (s->two_byte_p)
3186 XDrawString16 (s->display, s->window, s->gc, x,
3187 s->ybase - boff, s->char2b, s->nchars);
3188 else
3189 XDrawString (s->display, s->window, s->gc, x,
3190 s->ybase - boff, char1b, s->nchars);
3191 }
06a2c219
GM
3192 else
3193 {
b4192550
KH
3194 if (s->two_byte_p)
3195 XDrawImageString16 (s->display, s->window, s->gc, x,
3196 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3197 else
b4192550
KH
3198 XDrawImageString (s->display, s->window, s->gc, x,
3199 s->ybase - boff, char1b, s->nchars);
3200 }
3201 }
3202}
06a2c219 3203
b4192550 3204/* Draw the foreground of composite glyph string S. */
06a2c219 3205
b4192550
KH
3206static void
3207x_draw_composite_glyph_string_foreground (s)
3208 struct glyph_string *s;
3209{
3210 int i, x;
06a2c219 3211
b4192550
KH
3212 /* If first glyph of S has a left box line, start drawing the text
3213 of S to the right of that box line. */
3214 if (s->face->box != FACE_NO_BOX
3215 && s->first_glyph->left_box_line_p)
ea2ba0d4 3216 x = s->x + abs (s->face->box_line_width);
b4192550
KH
3217 else
3218 x = s->x;
06a2c219 3219
b4192550
KH
3220 /* S is a glyph string for a composition. S->gidx is the index of
3221 the first character drawn for glyphs of this composition.
3222 S->gidx == 0 means we are drawing the very first character of
3223 this composition. */
06a2c219 3224
b4192550
KH
3225 /* Draw a rectangle for the composition if the font for the very
3226 first character of the composition could not be loaded. */
3227 if (s->font_not_found_p)
3228 {
3229 if (s->gidx == 0)
3230 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3231 s->width - 1, s->height - 1);
3232 }
3233 else
3234 {
3235 for (i = 0; i < s->nchars; i++, ++s->gidx)
3236 XDrawString16 (s->display, s->window, s->gc,
3237 x + s->cmp->offsets[s->gidx * 2],
3238 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3239 s->char2b + i, 1);
06a2c219
GM
3240 }
3241}
3242
3243
80c32bcc
GM
3244#ifdef USE_X_TOOLKIT
3245
3e71d8f2 3246static struct frame *x_frame_of_widget P_ ((Widget));
80c32bcc 3247
3e71d8f2
GM
3248
3249/* Return the frame on which widget WIDGET is used.. Abort if frame
3250 cannot be determined. */
3251
e851c833 3252static struct frame *
3e71d8f2 3253x_frame_of_widget (widget)
80c32bcc 3254 Widget widget;
80c32bcc 3255{
80c32bcc 3256 struct x_display_info *dpyinfo;
5c187dee 3257 Lisp_Object tail;
3e71d8f2
GM
3258 struct frame *f;
3259
80c32bcc
GM
3260 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3261
3262 /* Find the top-level shell of the widget. Note that this function
3263 can be called when the widget is not yet realized, so XtWindow
3264 (widget) == 0. That's the reason we can't simply use
3265 x_any_window_to_frame. */
3266 while (!XtIsTopLevelShell (widget))
3267 widget = XtParent (widget);
3268
3269 /* Look for a frame with that top-level widget. Allocate the color
3270 on that frame to get the right gamma correction value. */
3271 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3272 if (GC_FRAMEP (XCAR (tail))
3273 && (f = XFRAME (XCAR (tail)),
3274 (f->output_data.nothing != 1
3275 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3276 && f->output_data.x->widget == widget)
3e71d8f2 3277 return f;
80c32bcc
GM
3278
3279 abort ();
3280}
3281
3e71d8f2
GM
3282
3283/* Allocate the color COLOR->pixel on the screen and display of
3284 widget WIDGET in colormap CMAP. If an exact match cannot be
3285 allocated, try the nearest color available. Value is non-zero
3286 if successful. This is called from lwlib. */
3287
3288int
3289x_alloc_nearest_color_for_widget (widget, cmap, color)
3290 Widget widget;
3291 Colormap cmap;
3292 XColor *color;
3293{
3294 struct frame *f = x_frame_of_widget (widget);
3295 return x_alloc_nearest_color (f, cmap, color);
3296}
3297
3298
46d516e5
MB
3299/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3300 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3301 If this produces the same color as PIXEL, try a color where all RGB
3302 values have DELTA added. Return the allocated color in *PIXEL.
3303 DISPLAY is the X display, CMAP is the colormap to operate on.
3304 Value is non-zero if successful. */
3305
3306int
3307x_alloc_lighter_color_for_widget (widget, display, cmap, pixel, factor, delta)
3308 Widget widget;
3309 Display *display;
3310 Colormap cmap;
3311 unsigned long *pixel;
3312 double factor;
3313 int delta;
3314{
3315 struct frame *f = x_frame_of_widget (widget);
3316 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
3317}
3318
3319
80c32bcc
GM
3320#endif /* USE_X_TOOLKIT */
3321
3322
f04e1297
GM
3323/* Value is an array of XColor structures for the contents of the
3324 color map of frame F. Set *NCELLS to the size of the array.
3325 Note that this probably shouldn't be called for large color maps,
3326 say a 24-bit TrueColor map. */
3327
3328static const XColor *
3329x_color_cells (f, ncells)
3330 struct frame *f;
3331 int *ncells;
3332{
3333 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3334
3335 if (dpyinfo->color_cells == NULL)
3336 {
3337 Display *display = FRAME_X_DISPLAY (f);
3338 Screen *screen = FRAME_X_SCREEN (f);
3339 int i;
3340
3341 dpyinfo->ncolor_cells
3342 = XDisplayCells (display, XScreenNumberOfScreen (screen));
3343 dpyinfo->color_cells
3344 = (XColor *) xmalloc (dpyinfo->ncolor_cells
3345 * sizeof *dpyinfo->color_cells);
3346
3347 for (i = 0; i < dpyinfo->ncolor_cells; ++i)
3348 dpyinfo->color_cells[i].pixel = i;
3349
3350 XQueryColors (display, FRAME_X_COLORMAP (f),
3351 dpyinfo->color_cells, dpyinfo->ncolor_cells);
3352 }
3353
3354 *ncells = dpyinfo->ncolor_cells;
3355 return dpyinfo->color_cells;
3356}
3357
3358
3359/* On frame F, translate pixel colors to RGB values for the NCOLORS
3360 colors in COLORS. Use cached information, if available. */
3361
3362void
3363x_query_colors (f, colors, ncolors)
3364 struct frame *f;
3365 XColor *colors;
3366 int ncolors;
3367{
3368 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3369
3370 if (dpyinfo->color_cells)
3371 {
3372 int i;
3373 for (i = 0; i < ncolors; ++i)
3374 {
3375 unsigned long pixel = colors[i].pixel;
3376 xassert (pixel < dpyinfo->ncolor_cells);
3377 xassert (dpyinfo->color_cells[pixel].pixel == pixel);
3378 colors[i] = dpyinfo->color_cells[pixel];
3379 }
3380 }
3381 else
3382 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
3383}
3384
3385
3386/* On frame F, translate pixel color to RGB values for the color in
3387 COLOR. Use cached information, if available. */
3388
3389void
3390x_query_color (f, color)
3391 struct frame *f;
3392 XColor *color;
3393{
3394 x_query_colors (f, color, 1);
3395}
3396
3397
06a2c219
GM
3398/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
3399 CMAP. If an exact match can't be allocated, try the nearest color
3400 available. Value is non-zero if successful. Set *COLOR to the
3401 color allocated. */
3402
3403int
80c32bcc
GM
3404x_alloc_nearest_color (f, cmap, color)
3405 struct frame *f;
06a2c219
GM
3406 Colormap cmap;
3407 XColor *color;
3408{
80c32bcc
GM
3409 Display *display = FRAME_X_DISPLAY (f);
3410 Screen *screen = FRAME_X_SCREEN (f);
3411 int rc;
3412
3413 gamma_correct (f, color);
3414 rc = XAllocColor (display, cmap, color);
06a2c219
GM
3415 if (rc == 0)
3416 {
3417 /* If we got to this point, the colormap is full, so we're going
3418 to try to get the next closest color. The algorithm used is
3419 a least-squares matching, which is what X uses for closest
3420 color matching with StaticColor visuals. */
3421 int nearest, i;
3422 unsigned long nearest_delta = ~0;
f04e1297
GM
3423 int ncells;
3424 const XColor *cells = x_color_cells (f, &ncells);
06a2c219
GM
3425
3426 for (nearest = i = 0; i < ncells; ++i)
3427 {
3428 long dred = (color->red >> 8) - (cells[i].red >> 8);
3429 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3430 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3431 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3432
3433 if (delta < nearest_delta)
3434 {
3435 nearest = i;
3436 nearest_delta = delta;
3437 }
3438 }
3439
3440 color->red = cells[nearest].red;
3441 color->green = cells[nearest].green;
3442 color->blue = cells[nearest].blue;
3443 rc = XAllocColor (display, cmap, color);
3444 }
35efe0a1
GM
3445 else
3446 {
3447 /* If allocation succeeded, and the allocated pixel color is not
3448 equal to a cached pixel color recorded earlier, there was a
3449 change in the colormap, so clear the color cache. */
3450 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3451 XColor *cached_color;
3452
3453 if (dpyinfo->color_cells
3454 && (cached_color = &dpyinfo->color_cells[color->pixel],
cae71efe
GM
3455 (cached_color->red != color->red
3456 || cached_color->blue != color->blue
3457 || cached_color->green != color->green)))
35efe0a1
GM
3458 {
3459 xfree (dpyinfo->color_cells);
3460 dpyinfo->color_cells = NULL;
3461 dpyinfo->ncolor_cells = 0;
3462 }
3463 }
06a2c219 3464
d9c545da
GM
3465#ifdef DEBUG_X_COLORS
3466 if (rc)
3467 register_color (color->pixel);
3468#endif /* DEBUG_X_COLORS */
3469
06a2c219
GM
3470 return rc;
3471}
3472
3473
d9c545da
GM
3474/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3475 It's necessary to do this instead of just using PIXEL directly to
3476 get color reference counts right. */
3477
3478unsigned long
3479x_copy_color (f, pixel)
3480 struct frame *f;
3481 unsigned long pixel;
3482{
3483 XColor color;
3484
3485 color.pixel = pixel;
3486 BLOCK_INPUT;
f04e1297 3487 x_query_color (f, &color);
d9c545da
GM
3488 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3489 UNBLOCK_INPUT;
3490#ifdef DEBUG_X_COLORS
3491 register_color (pixel);
3492#endif
3493 return color.pixel;
3494}
3495
3496
3e71d8f2
GM
3497/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3498 It's necessary to do this instead of just using PIXEL directly to
3499 get color reference counts right. */
3500
3501unsigned long
3502x_copy_dpy_color (dpy, cmap, pixel)
3503 Display *dpy;
3504 Colormap cmap;
3505 unsigned long pixel;
3506{
3507 XColor color;
3508
3509 color.pixel = pixel;
3510 BLOCK_INPUT;
3511 XQueryColor (dpy, cmap, &color);
3512 XAllocColor (dpy, cmap, &color);
3513 UNBLOCK_INPUT;
3514#ifdef DEBUG_X_COLORS
3515 register_color (pixel);
3516#endif
3517 return color.pixel;
3518}
3519
3520
6d8b0acd 3521/* Brightness beyond which a color won't have its highlight brightness
d7361edf 3522 boosted.
6d8b0acd 3523
d7361edf
MB
3524 Nominally, highlight colors for `3d' faces are calculated by
3525 brightening an object's color by a constant scale factor, but this
3526 doesn't yield good results for dark colors, so for colors who's
3527 brightness is less than this value (on a scale of 0-65535) have an
3528 use an additional additive factor.
6d8b0acd
MB
3529
3530 The value here is set so that the default menu-bar/mode-line color
3531 (grey75) will not have its highlights changed at all. */
3532#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
3533
3534
06a2c219
GM
3535/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3536 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3537 If this produces the same color as PIXEL, try a color where all RGB
3538 values have DELTA added. Return the allocated color in *PIXEL.
3539 DISPLAY is the X display, CMAP is the colormap to operate on.
3540 Value is non-zero if successful. */
3541
3542static int
3543x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3544 struct frame *f;
3545 Display *display;
3546 Colormap cmap;
3547 unsigned long *pixel;
68c45bf0 3548 double factor;
06a2c219
GM
3549 int delta;
3550{
3551 XColor color, new;
6d8b0acd 3552 long bright;
06a2c219
GM
3553 int success_p;
3554
3555 /* Get RGB color values. */
3556 color.pixel = *pixel;
f04e1297 3557 x_query_color (f, &color);
06a2c219
GM
3558
3559 /* Change RGB values by specified FACTOR. Avoid overflow! */
3560 xassert (factor >= 0);
3561 new.red = min (0xffff, factor * color.red);
3562 new.green = min (0xffff, factor * color.green);
3563 new.blue = min (0xffff, factor * color.blue);
3564
d7361edf
MB
3565 /* Calculate brightness of COLOR. */
3566 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
6d8b0acd
MB
3567
3568 /* We only boost colors that are darker than
3569 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3570 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3571 /* Make an additive adjustment to NEW, because it's dark enough so
3572 that scaling by FACTOR alone isn't enough. */
3573 {
3574 /* How far below the limit this color is (0 - 1, 1 being darker). */
3575 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3576 /* The additive adjustment. */
d7361edf 3577 int min_delta = delta * dimness * factor / 2;
6d8b0acd
MB
3578
3579 if (factor < 1)
3580 {
6d8b0acd
MB
3581 new.red = max (0, new.red - min_delta);
3582 new.green = max (0, new.green - min_delta);
3583 new.blue = max (0, new.blue - min_delta);
3584 }
3585 else
3586 {
3587 new.red = min (0xffff, min_delta + new.red);
3588 new.green = min (0xffff, min_delta + new.green);
3589 new.blue = min (0xffff, min_delta + new.blue);
3590 }
3591 }
3592
06a2c219 3593 /* Try to allocate the color. */
80c32bcc 3594 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3595 if (success_p)
3596 {
3597 if (new.pixel == *pixel)
3598 {
3599 /* If we end up with the same color as before, try adding
3600 delta to the RGB values. */
0d605c67 3601 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3602
3603 new.red = min (0xffff, delta + color.red);
3604 new.green = min (0xffff, delta + color.green);
3605 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3606 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3607 }
3608 else
3609 success_p = 1;
3610 *pixel = new.pixel;
3611 }
3612
3613 return success_p;
3614}
3615
3616
3617/* Set up the foreground color for drawing relief lines of glyph
3618 string S. RELIEF is a pointer to a struct relief containing the GC
3619 with which lines will be drawn. Use a color that is FACTOR or
3620 DELTA lighter or darker than the relief's background which is found
3621 in S->f->output_data.x->relief_background. If such a color cannot
3622 be allocated, use DEFAULT_PIXEL, instead. */
3623
3624static void
3625x_setup_relief_color (f, relief, factor, delta, default_pixel)
3626 struct frame *f;
3627 struct relief *relief;
68c45bf0 3628 double factor;
06a2c219
GM
3629 int delta;
3630 unsigned long default_pixel;
3631{
3632 XGCValues xgcv;
3633 struct x_output *di = f->output_data.x;
3634 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3635 unsigned long pixel;
3636 unsigned long background = di->relief_background;
43bd1b2b 3637 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3638 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3639 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3640
3641 xgcv.graphics_exposures = False;
3642 xgcv.line_width = 1;
3643
3644 /* Free previously allocated color. The color cell will be reused
3645 when it has been freed as many times as it was allocated, so this
3646 doesn't affect faces using the same colors. */
3647 if (relief->gc
3648 && relief->allocated_p)
3649 {
0d605c67 3650 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3651 relief->allocated_p = 0;
3652 }
3653
3654 /* Allocate new color. */
3655 xgcv.foreground = default_pixel;
3656 pixel = background;
dcd08bfb
GM
3657 if (dpyinfo->n_planes != 1
3658 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3659 {
3660 relief->allocated_p = 1;
3661 xgcv.foreground = relief->pixel = pixel;
3662 }
3663
3664 if (relief->gc == 0)
3665 {
dcd08bfb 3666 xgcv.stipple = dpyinfo->gray;
06a2c219 3667 mask |= GCStipple;
dcd08bfb 3668 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3669 }
3670 else
dcd08bfb 3671 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3672}
3673
3674
3675/* Set up colors for the relief lines around glyph string S. */
3676
3677static void
3678x_setup_relief_colors (s)
3679 struct glyph_string *s;
3680{
3681 struct x_output *di = s->f->output_data.x;
3682 unsigned long color;
3683
3684 if (s->face->use_box_color_for_shadows_p)
3685 color = s->face->box_color;
3686 else
3687 {
3688 XGCValues xgcv;
3689
3690 /* Get the background color of the face. */
3691 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3692 color = xgcv.background;
3693 }
3694
3695 if (di->white_relief.gc == 0
3696 || color != di->relief_background)
3697 {
3698 di->relief_background = color;
3699 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3700 WHITE_PIX_DEFAULT (s->f));
3701 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3702 BLACK_PIX_DEFAULT (s->f));
3703 }
3704}
3705
3706
3707/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3708 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3709 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3710 relief. LEFT_P non-zero means draw a relief on the left side of
3711 the rectangle. RIGHT_P non-zero means draw a relief on the right
3712 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3713 when drawing. */
3714
3715static void
3716x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3717 raised_p, left_p, right_p, clip_rect)
3718 struct frame *f;
3719 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3720 XRectangle *clip_rect;
3721{
3722 int i;
3723 GC gc;
3724
3725 if (raised_p)
3726 gc = f->output_data.x->white_relief.gc;
3727 else
3728 gc = f->output_data.x->black_relief.gc;
3729 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3730
3731 /* Top. */
3732 for (i = 0; i < width; ++i)
3733 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3734 left_x + i * left_p, top_y + i,
3735 right_x + 1 - i * right_p, top_y + i);
3736
3737 /* Left. */
3738 if (left_p)
3739 for (i = 0; i < width; ++i)
3740 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3741 left_x + i, top_y + i, left_x + i, bottom_y - i);
3742
3743 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3744 if (raised_p)
3745 gc = f->output_data.x->black_relief.gc;
3746 else
3747 gc = f->output_data.x->white_relief.gc;
3748 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3749
3750 /* Bottom. */
3751 for (i = 0; i < width; ++i)
3752 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3753 left_x + i * left_p, bottom_y - i,
3754 right_x + 1 - i * right_p, bottom_y - i);
3755
3756 /* Right. */
3757 if (right_p)
3758 for (i = 0; i < width; ++i)
3759 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3760 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3761
3762 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3763}
3764
3765
3766/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3767 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3768 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3769 left side of the rectangle. RIGHT_P non-zero means draw a line
3770 on the right side of the rectangle. CLIP_RECT is the clipping
3771 rectangle to use when drawing. */
3772
3773static void
3774x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3775 left_p, right_p, clip_rect)
3776 struct glyph_string *s;
3777 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3778 XRectangle *clip_rect;
3779{
3780 XGCValues xgcv;
3781
3782 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3783 XSetForeground (s->display, s->gc, s->face->box_color);
3784 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3785
3786 /* Top. */
3787 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3788 left_x, top_y, right_x - left_x + 1, width);
06a2c219
GM
3789
3790 /* Left. */
3791 if (left_p)
3792 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3793 left_x, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3794
3795 /* Bottom. */
3796 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3797 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
06a2c219
GM
3798
3799 /* Right. */
3800 if (right_p)
3801 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3802 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3803
3804 XSetForeground (s->display, s->gc, xgcv.foreground);
3805 XSetClipMask (s->display, s->gc, None);
3806}
3807
3808
3809/* Draw a box around glyph string S. */
3810
3811static void
3812x_draw_glyph_string_box (s)
3813 struct glyph_string *s;
3814{
3815 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3816 int left_p, right_p;
3817 struct glyph *last_glyph;
3818 XRectangle clip_rect;
3819
3820 last_x = window_box_right (s->w, s->area);
3821 if (s->row->full_width_p
3822 && !s->w->pseudo_window_p)
3823 {
110859fc 3824 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
06a2c219
GM
3825 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3826 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3827 }
3828
3829 /* The glyph that may have a right box line. */
b4192550 3830 last_glyph = (s->cmp || s->img
06a2c219
GM
3831 ? s->first_glyph
3832 : s->first_glyph + s->nchars - 1);
3833
ea2ba0d4 3834 width = abs (s->face->box_line_width);
06a2c219
GM
3835 raised_p = s->face->box == FACE_RAISED_BOX;
3836 left_x = s->x;
3837 right_x = ((s->row->full_width_p
1da3fd71 3838 ? last_x - 1
a7aeb2de 3839 : min (last_x, s->x + s->background_width) - 1));
06a2c219
GM
3840 top_y = s->y;
3841 bottom_y = top_y + s->height - 1;
3842
3843 left_p = (s->first_glyph->left_box_line_p
3844 || (s->hl == DRAW_MOUSE_FACE
3845 && (s->prev == NULL
3846 || s->prev->hl != s->hl)));
3847 right_p = (last_glyph->right_box_line_p
3848 || (s->hl == DRAW_MOUSE_FACE
3849 && (s->next == NULL
3850 || s->next->hl != s->hl)));
3851
3852 x_get_glyph_string_clip_rect (s, &clip_rect);
3853
3854 if (s->face->box == FACE_SIMPLE_BOX)
3855 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3856 left_p, right_p, &clip_rect);
3857 else
3858 {
3859 x_setup_relief_colors (s);
3860 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
3861 width, raised_p, left_p, right_p, &clip_rect);
3862 }
3863}
3864
3865
3866/* Draw foreground of image glyph string S. */
3867
3868static void
3869x_draw_image_foreground (s)
3870 struct glyph_string *s;
3871{
3872 int x;
95af8492 3873 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
3874
3875 /* If first glyph of S has a left box line, start drawing it to the
3876 right of that line. */
3877 if (s->face->box != FACE_NO_BOX
3878 && s->first_glyph->left_box_line_p)
ea2ba0d4 3879 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
3880 else
3881 x = s->x;
3882
3883 /* If there is a margin around the image, adjust x- and y-position
3884 by that margin. */
22d650b8
GM
3885 x += s->img->hmargin;
3886 y += s->img->vmargin;
06a2c219
GM
3887
3888 if (s->img->pixmap)
3889 {
3890 if (s->img->mask)
3891 {
3892 /* We can't set both a clip mask and use XSetClipRectangles
3893 because the latter also sets a clip mask. We also can't
3894 trust on the shape extension to be available
3895 (XShapeCombineRegion). So, compute the rectangle to draw
3896 manually. */
3897 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
3898 | GCFunction);
3899 XGCValues xgcv;
3900 XRectangle clip_rect, image_rect, r;
3901
3902 xgcv.clip_mask = s->img->mask;
3903 xgcv.clip_x_origin = x;
3904 xgcv.clip_y_origin = y;
3905 xgcv.function = GXcopy;
3906 XChangeGC (s->display, s->gc, mask, &xgcv);
3907
3908 x_get_glyph_string_clip_rect (s, &clip_rect);
3909 image_rect.x = x;
3910 image_rect.y = y;
3911 image_rect.width = s->img->width;
3912 image_rect.height = s->img->height;
3913 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
3914 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3915 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
3916 }
3917 else
3918 {
49ad1d99
GM
3919 unsigned long mask = GCClipXOrigin | GCClipYOrigin | GCFunction;
3920 XGCValues xgcv;
3921 XRectangle clip_rect, image_rect, r;
3922
3923 x_get_glyph_string_clip_rect (s, &clip_rect);
3924 image_rect.x = x;
3925 image_rect.y = y;
3926 image_rect.width = s->img->width;
3927 image_rect.height = s->img->height;
3928 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
3929 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
3930 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
06a2c219
GM
3931
3932 /* When the image has a mask, we can expect that at
3933 least part of a mouse highlight or a block cursor will
3934 be visible. If the image doesn't have a mask, make
3935 a block cursor visible by drawing a rectangle around
3936 the image. I believe it's looking better if we do
3937 nothing here for mouse-face. */
3938 if (s->hl == DRAW_CURSOR)
3939 XDrawRectangle (s->display, s->window, s->gc, x, y,
3940 s->img->width - 1, s->img->height - 1);
3941 }
3942 }
3943 else
3944 /* Draw a rectangle if image could not be loaded. */
3945 XDrawRectangle (s->display, s->window, s->gc, x, y,
3946 s->img->width - 1, s->img->height - 1);
3947}
3948
3949
3950/* Draw a relief around the image glyph string S. */
3951
3952static void
3953x_draw_image_relief (s)
3954 struct glyph_string *s;
3955{
3956 int x0, y0, x1, y1, thick, raised_p;
3957 XRectangle r;
3958 int x;
95af8492 3959 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
3960
3961 /* If first glyph of S has a left box line, start drawing it to the
3962 right of that line. */
3963 if (s->face->box != FACE_NO_BOX
3964 && s->first_glyph->left_box_line_p)
ea2ba0d4 3965 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
3966 else
3967 x = s->x;
3968
3969 /* If there is a margin around the image, adjust x- and y-position
3970 by that margin. */
22d650b8
GM
3971 x += s->img->hmargin;
3972 y += s->img->vmargin;
06a2c219
GM
3973
3974 if (s->hl == DRAW_IMAGE_SUNKEN
3975 || s->hl == DRAW_IMAGE_RAISED)
3976 {
9ea173e8 3977 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
06a2c219
GM
3978 raised_p = s->hl == DRAW_IMAGE_RAISED;
3979 }
3980 else
3981 {
3982 thick = abs (s->img->relief);
3983 raised_p = s->img->relief > 0;
3984 }
3985
3986 x0 = x - thick;
3987 y0 = y - thick;
3988 x1 = x + s->img->width + thick - 1;
3989 y1 = y + s->img->height + thick - 1;
3990
3991 x_setup_relief_colors (s);
3992 x_get_glyph_string_clip_rect (s, &r);
3993 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
3994}
3995
3996
3997/* Draw the foreground of image glyph string S to PIXMAP. */
3998
3999static void
4000x_draw_image_foreground_1 (s, pixmap)
4001 struct glyph_string *s;
4002 Pixmap pixmap;
4003{
4004 int x;
95af8492 4005 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
4006
4007 /* If first glyph of S has a left box line, start drawing it to the
4008 right of that line. */
4009 if (s->face->box != FACE_NO_BOX
4010 && s->first_glyph->left_box_line_p)
ea2ba0d4 4011 x = abs (s->face->box_line_width);
06a2c219
GM
4012 else
4013 x = 0;
4014
4015 /* If there is a margin around the image, adjust x- and y-position
4016 by that margin. */
22d650b8
GM
4017 x += s->img->hmargin;
4018 y += s->img->vmargin;
dc43ef94 4019
06a2c219
GM
4020 if (s->img->pixmap)
4021 {
4022 if (s->img->mask)
4023 {
4024 /* We can't set both a clip mask and use XSetClipRectangles
4025 because the latter also sets a clip mask. We also can't
4026 trust on the shape extension to be available
4027 (XShapeCombineRegion). So, compute the rectangle to draw
4028 manually. */
4029 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4030 | GCFunction);
4031 XGCValues xgcv;
4032
4033 xgcv.clip_mask = s->img->mask;
4034 xgcv.clip_x_origin = x;
4035 xgcv.clip_y_origin = y;
4036 xgcv.function = GXcopy;
4037 XChangeGC (s->display, s->gc, mask, &xgcv);
4038
4039 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4040 0, 0, s->img->width, s->img->height, x, y);
4041 XSetClipMask (s->display, s->gc, None);
4042 }
4043 else
4044 {
4045 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4046 0, 0, s->img->width, s->img->height, x, y);
4047
4048 /* When the image has a mask, we can expect that at
4049 least part of a mouse highlight or a block cursor will
4050 be visible. If the image doesn't have a mask, make
4051 a block cursor visible by drawing a rectangle around
4052 the image. I believe it's looking better if we do
4053 nothing here for mouse-face. */
4054 if (s->hl == DRAW_CURSOR)
4055 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4056 s->img->width - 1, s->img->height - 1);
4057 }
4058 }
4059 else
4060 /* Draw a rectangle if image could not be loaded. */
4061 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4062 s->img->width - 1, s->img->height - 1);
4063}
dc43ef94 4064
990ba854 4065
06a2c219
GM
4066/* Draw part of the background of glyph string S. X, Y, W, and H
4067 give the rectangle to draw. */
a9a5b0a5 4068
06a2c219
GM
4069static void
4070x_draw_glyph_string_bg_rect (s, x, y, w, h)
4071 struct glyph_string *s;
4072 int x, y, w, h;
4073{
4074 if (s->stippled_p)
4075 {
4076 /* Fill background with a stipple pattern. */
4077 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4078 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4079 XSetFillStyle (s->display, s->gc, FillSolid);
4080 }
4081 else
4082 x_clear_glyph_string_rect (s, x, y, w, h);
4083}
07e34cb0 4084
b5210ea7 4085
06a2c219 4086/* Draw image glyph string S.
dc43ef94 4087
06a2c219
GM
4088 s->y
4089 s->x +-------------------------
4090 | s->face->box
4091 |
4092 | +-------------------------
4093 | | s->img->margin
4094 | |
4095 | | +-------------------
4096 | | | the image
dc43ef94 4097
06a2c219 4098 */
dc43ef94 4099
06a2c219
GM
4100static void
4101x_draw_image_glyph_string (s)
4102 struct glyph_string *s;
4103{
4104 int x, y;
ea2ba0d4
KH
4105 int box_line_hwidth = abs (s->face->box_line_width);
4106 int box_line_vwidth = max (s->face->box_line_width, 0);
06a2c219
GM
4107 int height;
4108 Pixmap pixmap = None;
4109
ea2ba0d4 4110 height = s->height - 2 * box_line_vwidth;
06a2c219
GM
4111
4112 /* Fill background with face under the image. Do it only if row is
4113 taller than image or if image has a clip mask to reduce
4114 flickering. */
4115 s->stippled_p = s->face->stipple != 0;
4116 if (height > s->img->height
22d650b8
GM
4117 || s->img->hmargin
4118 || s->img->vmargin
06a2c219
GM
4119 || s->img->mask
4120 || s->img->pixmap == 0
4121 || s->width != s->background_width)
4122 {
ea2ba0d4
KH
4123 if (box_line_hwidth && s->first_glyph->left_box_line_p)
4124 x = s->x + box_line_hwidth;
06a2c219
GM
4125 else
4126 x = s->x;
4127
ea2ba0d4 4128 y = s->y + box_line_vwidth;
06a2c219
GM
4129
4130 if (s->img->mask)
4131 {
f9b5db02
GM
4132 /* Create a pixmap as large as the glyph string. Fill it
4133 with the background color. Copy the image to it, using
4134 its mask. Copy the temporary pixmap to the display. */
06a2c219
GM
4135 Screen *screen = FRAME_X_SCREEN (s->f);
4136 int depth = DefaultDepthOfScreen (screen);
4137
4138 /* Create a pixmap as large as the glyph string. */
4139 pixmap = XCreatePixmap (s->display, s->window,
4140 s->background_width,
4141 s->height, depth);
4142
4143 /* Don't clip in the following because we're working on the
4144 pixmap. */
4145 XSetClipMask (s->display, s->gc, None);
4146
4147 /* Fill the pixmap with the background color/stipple. */
4148 if (s->stippled_p)
4149 {
4150 /* Fill background with a stipple pattern. */
4151 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4152 XFillRectangle (s->display, pixmap, s->gc,
4153 0, 0, s->background_width, s->height);
4154 XSetFillStyle (s->display, s->gc, FillSolid);
4155 }
4156 else
4157 {
4158 XGCValues xgcv;
4159 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4160 &xgcv);
4161 XSetForeground (s->display, s->gc, xgcv.background);
4162 XFillRectangle (s->display, pixmap, s->gc,
4163 0, 0, s->background_width, s->height);
4164 XSetForeground (s->display, s->gc, xgcv.foreground);
4165 }
4166 }
4167 else
06a2c219
GM
4168 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
4169
4170 s->background_filled_p = 1;
4171 }
dc43ef94 4172
06a2c219
GM
4173 /* Draw the foreground. */
4174 if (pixmap != None)
4175 {
4176 x_draw_image_foreground_1 (s, pixmap);
4177 x_set_glyph_string_clipping (s);
4178 XCopyArea (s->display, pixmap, s->window, s->gc,
4179 0, 0, s->background_width, s->height, s->x, s->y);
4180 XFreePixmap (s->display, pixmap);
4181 }
4182 else
4183 x_draw_image_foreground (s);
b5210ea7 4184
06a2c219
GM
4185 /* If we must draw a relief around the image, do it. */
4186 if (s->img->relief
4187 || s->hl == DRAW_IMAGE_RAISED
4188 || s->hl == DRAW_IMAGE_SUNKEN)
4189 x_draw_image_relief (s);
4190}
8c1a6a84 4191
990ba854 4192
06a2c219 4193/* Draw stretch glyph string S. */
dc43ef94 4194
06a2c219
GM
4195static void
4196x_draw_stretch_glyph_string (s)
4197 struct glyph_string *s;
4198{
4199 xassert (s->first_glyph->type == STRETCH_GLYPH);
4200 s->stippled_p = s->face->stipple != 0;
990ba854 4201
06a2c219
GM
4202 if (s->hl == DRAW_CURSOR
4203 && !x_stretch_cursor_p)
4204 {
4205 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4206 as wide as the stretch glyph. */
4207 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4208
06a2c219
GM
4209 /* Draw cursor. */
4210 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4211
06a2c219
GM
4212 /* Clear rest using the GC of the original non-cursor face. */
4213 if (width < s->background_width)
4214 {
4215 GC gc = s->face->gc;
4216 int x = s->x + width, y = s->y;
4217 int w = s->background_width - width, h = s->height;
4218 XRectangle r;
dc43ef94 4219
06a2c219
GM
4220 x_get_glyph_string_clip_rect (s, &r);
4221 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
97210f4e 4222
06a2c219
GM
4223 if (s->face->stipple)
4224 {
4225 /* Fill background with a stipple pattern. */
4226 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4227 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4228 XSetFillStyle (s->display, gc, FillSolid);
4229 }
4230 else
4231 {
4232 XGCValues xgcv;
4233 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4234 XSetForeground (s->display, gc, xgcv.background);
4235 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4236 XSetForeground (s->display, gc, xgcv.foreground);
4237 }
4238 }
4239 }
4240 else
4241 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4242 s->height);
4243
4244 s->background_filled_p = 1;
4245}
4246
4247
4248/* Draw glyph string S. */
4249
4250static void
4251x_draw_glyph_string (s)
4252 struct glyph_string *s;
4253{
4254 /* If S draws into the background of its successor, draw the
4255 background of the successor first so that S can draw into it.
4256 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4257 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4258 {
4259 xassert (s->next->img == NULL);
4260 x_set_glyph_string_gc (s->next);
4261 x_set_glyph_string_clipping (s->next);
4262 x_draw_glyph_string_background (s->next, 1);
4263 }
97210f4e 4264
06a2c219
GM
4265 /* Set up S->gc, set clipping and draw S. */
4266 x_set_glyph_string_gc (s);
4267 x_set_glyph_string_clipping (s);
4268
4269 switch (s->first_glyph->type)
4270 {
4271 case IMAGE_GLYPH:
4272 x_draw_image_glyph_string (s);
4273 break;
4274
4275 case STRETCH_GLYPH:
4276 x_draw_stretch_glyph_string (s);
4277 break;
4278
4279 case CHAR_GLYPH:
66ac4b0e
GM
4280 if (s->for_overlaps_p)
4281 s->background_filled_p = 1;
4282 else
4283 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4284 x_draw_glyph_string_foreground (s);
4285 break;
4286
b4192550
KH
4287 case COMPOSITE_GLYPH:
4288 if (s->for_overlaps_p || s->gidx > 0)
4289 s->background_filled_p = 1;
4290 else
4291 x_draw_glyph_string_background (s, 1);
4292 x_draw_composite_glyph_string_foreground (s);
4293 break;
4294
06a2c219
GM
4295 default:
4296 abort ();
4297 }
4298
66ac4b0e 4299 if (!s->for_overlaps_p)
06a2c219 4300 {
66ac4b0e
GM
4301 /* Draw underline. */
4302 if (s->face->underline_p)
4303 {
e24e84cc
GM
4304 unsigned long tem, h;
4305 int y;
06a2c219 4306
e24e84cc 4307 /* Get the underline thickness. Default is 1 pixel. */
66ac4b0e
GM
4308 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4309 h = 1;
e24e84cc
GM
4310
4311 /* Get the underline position. This is the recommended
4312 vertical offset in pixels from the baseline to the top of
4313 the underline. This is a signed value according to the
4314 specs, and its default is
4315
4316 ROUND ((maximum descent) / 2), with
4317 ROUND(x) = floor (x + 0.5) */
4318
4319 if (XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
4320 y = s->ybase + (long) tem;
4321 else if (s->face->font)
4322 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4323 else
4324 y = s->height - h;
06a2c219 4325
66ac4b0e 4326 if (s->face->underline_defaulted_p)
e24e84cc
GM
4327 XFillRectangle (s->display, s->window, s->gc,
4328 s->x, y, s->width, h);
66ac4b0e
GM
4329 else
4330 {
4331 XGCValues xgcv;
4332 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4333 XSetForeground (s->display, s->gc, s->face->underline_color);
e24e84cc
GM
4334 XFillRectangle (s->display, s->window, s->gc,
4335 s->x, y, s->width, h);
66ac4b0e
GM
4336 XSetForeground (s->display, s->gc, xgcv.foreground);
4337 }
dc6f92b8 4338 }
07e34cb0 4339
66ac4b0e
GM
4340 /* Draw overline. */
4341 if (s->face->overline_p)
06a2c219 4342 {
66ac4b0e
GM
4343 unsigned long dy = 0, h = 1;
4344
4345 if (s->face->overline_color_defaulted_p)
4346 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4347 s->width, h);
4348 else
4349 {
4350 XGCValues xgcv;
4351 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4352 XSetForeground (s->display, s->gc, s->face->overline_color);
4353 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4354 s->width, h);
4355 XSetForeground (s->display, s->gc, xgcv.foreground);
4356 }
06a2c219 4357 }
06a2c219 4358
66ac4b0e
GM
4359 /* Draw strike-through. */
4360 if (s->face->strike_through_p)
06a2c219 4361 {
66ac4b0e
GM
4362 unsigned long h = 1;
4363 unsigned long dy = (s->height - h) / 2;
4364
4365 if (s->face->strike_through_color_defaulted_p)
4366 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4367 s->width, h);
4368 else
4369 {
4370 XGCValues xgcv;
4371 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4372 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4373 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4374 s->width, h);
4375 XSetForeground (s->display, s->gc, xgcv.foreground);
4376 }
06a2c219 4377 }
06a2c219 4378
66ac4b0e
GM
4379 /* Draw relief. */
4380 if (s->face->box != FACE_NO_BOX)
4381 x_draw_glyph_string_box (s);
4382 }
06a2c219
GM
4383
4384 /* Reset clipping. */
4385 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4386}
07e34cb0 4387
06a2c219 4388
b4192550
KH
4389static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4390 struct face **, int));
06a2c219 4391
06a2c219 4392
209f68d9
GM
4393/* Fill glyph string S with composition components specified by S->cmp.
4394
b4192550
KH
4395 FACES is an array of faces for all components of this composition.
4396 S->gidx is the index of the first component for S.
4397 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4398 use its physical height for clipping.
06a2c219 4399
b4192550 4400 Value is the index of a component not in S. */
07e34cb0 4401
b4192550
KH
4402static int
4403x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4404 struct glyph_string *s;
b4192550 4405 struct face **faces;
66ac4b0e 4406 int overlaps_p;
07e34cb0 4407{
b4192550 4408 int i;
06a2c219 4409
b4192550 4410 xassert (s);
06a2c219 4411
b4192550 4412 s->for_overlaps_p = overlaps_p;
06a2c219 4413
b4192550
KH
4414 s->face = faces[s->gidx];
4415 s->font = s->face->font;
4416 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4417
b4192550
KH
4418 /* For all glyphs of this composition, starting at the offset
4419 S->gidx, until we reach the end of the definition or encounter a
4420 glyph that requires the different face, add it to S. */
4421 ++s->nchars;
4422 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4423 ++s->nchars;
06a2c219 4424
b4192550
KH
4425 /* All glyph strings for the same composition has the same width,
4426 i.e. the width set for the first component of the composition. */
06a2c219 4427
06a2c219
GM
4428 s->width = s->first_glyph->pixel_width;
4429
4430 /* If the specified font could not be loaded, use the frame's
4431 default font, but record the fact that we couldn't load it in
4432 the glyph string so that we can draw rectangles for the
4433 characters of the glyph string. */
4434 if (s->font == NULL)
4435 {
4436 s->font_not_found_p = 1;
4437 s->font = FRAME_FONT (s->f);
4438 }
4439
4440 /* Adjust base line for subscript/superscript text. */
4441 s->ybase += s->first_glyph->voffset;
4442
4443 xassert (s->face && s->face->gc);
4444
4445 /* This glyph string must always be drawn with 16-bit functions. */
4446 s->two_byte_p = 1;
b4192550
KH
4447
4448 return s->gidx + s->nchars;
06a2c219
GM
4449}
4450
4451
209f68d9
GM
4452/* Fill glyph string S from a sequence of character glyphs.
4453
06a2c219 4454 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4455 first glyph to consider, END is the index of the last + 1.
4456 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4457 use its physical height for clipping.
66ac4b0e
GM
4458
4459 Value is the index of the first glyph not in S. */
06a2c219
GM
4460
4461static int
66ac4b0e 4462x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4463 struct glyph_string *s;
4464 int face_id;
66ac4b0e 4465 int start, end, overlaps_p;
06a2c219
GM
4466{
4467 struct glyph *glyph, *last;
4468 int voffset;
ee569018 4469 int glyph_not_available_p;
06a2c219 4470
06a2c219
GM
4471 xassert (s->f == XFRAME (s->w->frame));
4472 xassert (s->nchars == 0);
4473 xassert (start >= 0 && end > start);
4474
66ac4b0e 4475 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4476 glyph = s->row->glyphs[s->area] + start;
4477 last = s->row->glyphs[s->area] + end;
4478 voffset = glyph->voffset;
4479
ee569018
KH
4480 glyph_not_available_p = glyph->glyph_not_available_p;
4481
06a2c219
GM
4482 while (glyph < last
4483 && glyph->type == CHAR_GLYPH
4484 && glyph->voffset == voffset
ee569018
KH
4485 /* Same face id implies same font, nowadays. */
4486 && glyph->face_id == face_id
4487 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4488 {
ee569018
KH
4489 int two_byte_p;
4490
06a2c219 4491 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4492 s->char2b + s->nchars,
4493 &two_byte_p);
4494 s->two_byte_p = two_byte_p;
06a2c219
GM
4495 ++s->nchars;
4496 xassert (s->nchars <= end - start);
4497 s->width += glyph->pixel_width;
4498 ++glyph;
4499 }
4500
4501 s->font = s->face->font;
4502 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4503
4504 /* If the specified font could not be loaded, use the frame's font,
4505 but record the fact that we couldn't load it in
4506 S->font_not_found_p so that we can draw rectangles for the
4507 characters of the glyph string. */
ee569018 4508 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4509 {
4510 s->font_not_found_p = 1;
4511 s->font = FRAME_FONT (s->f);
4512 }
4513
4514 /* Adjust base line for subscript/superscript text. */
4515 s->ybase += voffset;
66ac4b0e 4516
06a2c219
GM
4517 xassert (s->face && s->face->gc);
4518 return glyph - s->row->glyphs[s->area];
07e34cb0 4519}
dc6f92b8 4520
06a2c219
GM
4521
4522/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4523
dfcf069d 4524static void
06a2c219
GM
4525x_fill_image_glyph_string (s)
4526 struct glyph_string *s;
4527{
4528 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4529 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4530 xassert (s->img);
43d120d8 4531 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4532 s->font = s->face->font;
4533 s->width = s->first_glyph->pixel_width;
4534
4535 /* Adjust base line for subscript/superscript text. */
4536 s->ybase += s->first_glyph->voffset;
4537}
4538
4539
209f68d9 4540/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4541
209f68d9
GM
4542 ROW is the glyph row in which the glyphs are found, AREA is the
4543 area within the row. START is the index of the first glyph to
4544 consider, END is the index of the last + 1.
4545
4546 Value is the index of the first glyph not in S. */
4547
4548static int
4549x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4550 struct glyph_string *s;
209f68d9
GM
4551 struct glyph_row *row;
4552 enum glyph_row_area area;
4553 int start, end;
06a2c219 4554{
209f68d9
GM
4555 struct glyph *glyph, *last;
4556 int voffset, face_id;
4557
06a2c219 4558 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4559
4560 glyph = s->row->glyphs[s->area] + start;
4561 last = s->row->glyphs[s->area] + end;
4562 face_id = glyph->face_id;
4563 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4564 s->font = s->face->font;
209f68d9
GM
4565 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4566 s->width = glyph->pixel_width;
4567 voffset = glyph->voffset;
4568
4569 for (++glyph;
4570 (glyph < last
4571 && glyph->type == STRETCH_GLYPH
4572 && glyph->voffset == voffset
4573 && glyph->face_id == face_id);
4574 ++glyph)
4575 s->width += glyph->pixel_width;
06a2c219
GM
4576
4577 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4578 s->ybase += voffset;
4579
4580 xassert (s->face && s->face->gc);
4581 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4582}
4583
4584
4585/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4586 of XChar2b structures for S; it can't be allocated in
4587 x_init_glyph_string because it must be allocated via `alloca'. W
4588 is the window on which S is drawn. ROW and AREA are the glyph row
4589 and area within the row from which S is constructed. START is the
4590 index of the first glyph structure covered by S. HL is a
4591 face-override for drawing S. */
4592
4593static void
4594x_init_glyph_string (s, char2b, w, row, area, start, hl)
4595 struct glyph_string *s;
4596 XChar2b *char2b;
4597 struct window *w;
4598 struct glyph_row *row;
4599 enum glyph_row_area area;
4600 int start;
4601 enum draw_glyphs_face hl;
4602{
4603 bzero (s, sizeof *s);
4604 s->w = w;
4605 s->f = XFRAME (w->frame);
4606 s->display = FRAME_X_DISPLAY (s->f);
4607 s->window = FRAME_X_WINDOW (s->f);
4608 s->char2b = char2b;
4609 s->hl = hl;
4610 s->row = row;
4611 s->area = area;
4612 s->first_glyph = row->glyphs[area] + start;
4613 s->height = row->height;
4614 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4615
9ea173e8
GM
4616 /* Display the internal border below the tool-bar window. */
4617 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4618 s->y -= s->f->output_data.x->internal_border_width;
4619
4620 s->ybase = s->y + row->ascent;
4621}
4622
4623
4624/* Set background width of glyph string S. START is the index of the
4625 first glyph following S. LAST_X is the right-most x-position + 1
4626 in the drawing area. */
4627
4628static INLINE void
4629x_set_glyph_string_background_width (s, start, last_x)
4630 struct glyph_string *s;
4631 int start;
4632 int last_x;
4633{
4634 /* If the face of this glyph string has to be drawn to the end of
4635 the drawing area, set S->extends_to_end_of_line_p. */
4636 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4637
4638 if (start == s->row->used[s->area]
4639 && s->hl == DRAW_NORMAL_TEXT
eb79f5cc
GM
4640 && s->area == TEXT_AREA
4641 && (s->row->fill_line_p
06a2c219
GM
4642 || s->face->background != default_face->background
4643 || s->face->stipple != default_face->stipple))
4644 s->extends_to_end_of_line_p = 1;
4645
4646 /* If S extends its face to the end of the line, set its
4647 background_width to the distance to the right edge of the drawing
4648 area. */
4649 if (s->extends_to_end_of_line_p)
1da3fd71 4650 s->background_width = last_x - s->x + 1;
06a2c219
GM
4651 else
4652 s->background_width = s->width;
4653}
4654
4655
4656/* Add a glyph string for a stretch glyph to the list of strings
4657 between HEAD and TAIL. START is the index of the stretch glyph in
4658 row area AREA of glyph row ROW. END is the index of the last glyph
4659 in that glyph row area. X is the current output position assigned
4660 to the new glyph string constructed. HL overrides that face of the
4661 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4662 is the right-most x-position of the drawing area. */
4663
8abee2e1
DL
4664/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4665 and below -- keep them on one line. */
4666#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4667 do \
4668 { \
4669 s = (struct glyph_string *) alloca (sizeof *s); \
4670 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4671 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4672 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4673 s->x = (X); \
4674 } \
4675 while (0)
4676
4677
4678/* Add a glyph string for an image glyph to the list of strings
4679 between HEAD and TAIL. START is the index of the image glyph in
4680 row area AREA of glyph row ROW. END is the index of the last glyph
4681 in that glyph row area. X is the current output position assigned
4682 to the new glyph string constructed. HL overrides that face of the
4683 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4684 is the right-most x-position of the drawing area. */
4685
8abee2e1 4686#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4687 do \
4688 { \
4689 s = (struct glyph_string *) alloca (sizeof *s); \
4690 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4691 x_fill_image_glyph_string (s); \
4692 x_append_glyph_string (&HEAD, &TAIL, s); \
4693 ++START; \
4694 s->x = (X); \
4695 } \
4696 while (0)
4697
4698
4699/* Add a glyph string for a sequence of character glyphs to the list
4700 of strings between HEAD and TAIL. START is the index of the first
4701 glyph in row area AREA of glyph row ROW that is part of the new
4702 glyph string. END is the index of the last glyph in that glyph row
4703 area. X is the current output position assigned to the new glyph
4704 string constructed. HL overrides that face of the glyph; e.g. it
4705 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4706 right-most x-position of the drawing area. */
4707
8abee2e1 4708#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4709 do \
4710 { \
3e71d8f2 4711 int c, face_id; \
06a2c219
GM
4712 XChar2b *char2b; \
4713 \
43d120d8 4714 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4715 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4716 \
b4192550
KH
4717 s = (struct glyph_string *) alloca (sizeof *s); \
4718 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4719 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4720 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4721 s->x = (X); \
4722 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4723 OVERLAPS_P); \
06a2c219
GM
4724 } \
4725 while (0)
4726
4727
b4192550
KH
4728/* Add a glyph string for a composite sequence to the list of strings
4729 between HEAD and TAIL. START is the index of the first glyph in
4730 row area AREA of glyph row ROW that is part of the new glyph
4731 string. END is the index of the last glyph in that glyph row area.
4732 X is the current output position assigned to the new glyph string
4733 constructed. HL overrides that face of the glyph; e.g. it is
4734 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4735 x-position of the drawing area. */
4736
6c27ec25 4737#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4738 do { \
43d120d8
KH
4739 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4740 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4741 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4742 struct composition *cmp = composition_table[cmp_id]; \
4743 int glyph_len = cmp->glyph_len; \
4744 XChar2b *char2b; \
4745 struct face **faces; \
4746 struct glyph_string *first_s = NULL; \
4747 int n; \
4748 \
ee569018 4749 base_face = base_face->ascii_face; \
b4192550
KH
4750 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4751 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4752 /* At first, fill in `char2b' and `faces'. */ \
4753 for (n = 0; n < glyph_len; n++) \
4754 { \
43d120d8 4755 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4756 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4757 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4758 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4759 this_face_id, char2b + n, 1); \
b4192550
KH
4760 } \
4761 \
4762 /* Make glyph_strings for each glyph sequence that is drawable by \
4763 the same face, and append them to HEAD/TAIL. */ \
4764 for (n = 0; n < cmp->glyph_len;) \
4765 { \
4766 s = (struct glyph_string *) alloca (sizeof *s); \
4767 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4768 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4769 s->cmp = cmp; \
4770 s->gidx = n; \
b4192550
KH
4771 s->x = (X); \
4772 \
4773 if (n == 0) \
4774 first_s = s; \
4775 \
4776 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4777 } \
4778 \
4779 ++START; \
4780 s = first_s; \
4781 } while (0)
4782
4783
06a2c219
GM
4784/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4785 of AREA of glyph row ROW on window W between indices START and END.
4786 HL overrides the face for drawing glyph strings, e.g. it is
4787 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4788 x-positions of the drawing area.
4789
4790 This is an ugly monster macro construct because we must use alloca
4791 to allocate glyph strings (because x_draw_glyphs can be called
4792 asynchronously). */
4793
8abee2e1 4794#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4795 do \
4796 { \
4797 HEAD = TAIL = NULL; \
4798 while (START < END) \
4799 { \
4800 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
4801 switch (first_glyph->type) \
4802 { \
4803 case CHAR_GLYPH: \
4804 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
4805 TAIL, HL, X, LAST_X, \
4806 OVERLAPS_P); \
06a2c219
GM
4807 break; \
4808 \
b4192550
KH
4809 case COMPOSITE_GLYPH: \
4810 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
4811 HEAD, TAIL, HL, X, LAST_X,\
4812 OVERLAPS_P); \
4813 break; \
4814 \
06a2c219
GM
4815 case STRETCH_GLYPH: \
4816 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
4817 HEAD, TAIL, HL, X, LAST_X); \
4818 break; \
4819 \
4820 case IMAGE_GLYPH: \
4821 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
4822 TAIL, HL, X, LAST_X); \
4823 break; \
4824 \
4825 default: \
4826 abort (); \
4827 } \
4828 \
4829 x_set_glyph_string_background_width (s, START, LAST_X); \
4830 (X) += s->width; \
4831 } \
4832 } \
4833 while (0)
4834
4835
4836/* Draw glyphs between START and END in AREA of ROW on window W,
4837 starting at x-position X. X is relative to AREA in W. HL is a
4838 face-override with the following meaning:
4839
4840 DRAW_NORMAL_TEXT draw normally
4841 DRAW_CURSOR draw in cursor face
4842 DRAW_MOUSE_FACE draw in mouse face.
4843 DRAW_INVERSE_VIDEO draw in mode line face
4844 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
4845 DRAW_IMAGE_RAISED draw an image with a raised relief around it
4846
4847 If REAL_START is non-null, return in *REAL_START the real starting
4848 position for display. This can be different from START in case
4849 overlapping glyphs must be displayed. If REAL_END is non-null,
4850 return in *REAL_END the real end position for display. This can be
4851 different from END in case overlapping glyphs must be displayed.
4852
66ac4b0e
GM
4853 If OVERLAPS_P is non-zero, draw only the foreground of characters
4854 and clip to the physical height of ROW.
4855
06a2c219
GM
4856 Value is the x-position reached, relative to AREA of W. */
4857
4858static int
66ac4b0e
GM
4859x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end,
4860 overlaps_p)
06a2c219
GM
4861 struct window *w;
4862 int x;
4863 struct glyph_row *row;
4864 enum glyph_row_area area;
4865 int start, end;
4866 enum draw_glyphs_face hl;
4867 int *real_start, *real_end;
66ac4b0e 4868 int overlaps_p;
dc6f92b8 4869{
06a2c219
GM
4870 struct glyph_string *head, *tail;
4871 struct glyph_string *s;
4872 int last_x, area_width;
4873 int x_reached;
4874 int i, j;
4875
4876 /* Let's rather be paranoid than getting a SEGV. */
06a2c219 4877 end = min (end, row->used[area]);
a8710abf
GM
4878 start = max (0, start);
4879 start = min (end, start);
06a2c219
GM
4880 if (real_start)
4881 *real_start = start;
4882 if (real_end)
4883 *real_end = end;
4884
4885 /* Translate X to frame coordinates. Set last_x to the right
4886 end of the drawing area. */
4887 if (row->full_width_p)
4888 {
4889 /* X is relative to the left edge of W, without scroll bars
4890 or flag areas. */
4891 struct frame *f = XFRAME (w->frame);
110859fc 4892 /* int width = FRAME_FLAGS_AREA_WIDTH (f); */
06a2c219 4893 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 4894
06a2c219
GM
4895 x += window_left_x;
4896 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
4897 last_x = window_left_x + area_width;
4898
4899 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
4900 {
110859fc 4901 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
4902 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
4903 last_x += width;
4904 else
4905 x -= width;
4906 }
dc6f92b8 4907
b9432a85
GM
4908 x += FRAME_INTERNAL_BORDER_WIDTH (f);
4909 last_x -= FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
4910 }
4911 else
dc6f92b8 4912 {
06a2c219
GM
4913 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
4914 area_width = window_box_width (w, area);
4915 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
4916 }
4917
06a2c219
GM
4918 /* Build a doubly-linked list of glyph_string structures between
4919 head and tail from what we have to draw. Note that the macro
4920 BUILD_GLYPH_STRINGS will modify its start parameter. That's
4921 the reason we use a separate variable `i'. */
4922 i = start;
66ac4b0e
GM
4923 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
4924 overlaps_p);
06a2c219
GM
4925 if (tail)
4926 x_reached = tail->x + tail->background_width;
4927 else
4928 x_reached = x;
90e65f07 4929
06a2c219
GM
4930 /* If there are any glyphs with lbearing < 0 or rbearing > width in
4931 the row, redraw some glyphs in front or following the glyph
4932 strings built above. */
a8710abf 4933 if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
4934 {
4935 int dummy_x = 0;
4936 struct glyph_string *h, *t;
4937
4938 /* Compute overhangs for all glyph strings. */
4939 for (s = head; s; s = s->next)
4940 x_compute_glyph_string_overhangs (s);
4941
4942 /* Prepend glyph strings for glyphs in front of the first glyph
4943 string that are overwritten because of the first glyph
4944 string's left overhang. The background of all strings
4945 prepended must be drawn because the first glyph string
4946 draws over it. */
4947 i = x_left_overwritten (head);
4948 if (i >= 0)
4949 {
4950 j = i;
4951 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
4952 DRAW_NORMAL_TEXT, dummy_x, last_x,
4953 overlaps_p);
06a2c219
GM
4954 start = i;
4955 if (real_start)
4956 *real_start = start;
4957 x_compute_overhangs_and_x (t, head->x, 1);
4958 x_prepend_glyph_string_lists (&head, &tail, h, t);
4959 }
58769bee 4960
06a2c219
GM
4961 /* Prepend glyph strings for glyphs in front of the first glyph
4962 string that overwrite that glyph string because of their
4963 right overhang. For these strings, only the foreground must
4964 be drawn, because it draws over the glyph string at `head'.
4965 The background must not be drawn because this would overwrite
4966 right overhangs of preceding glyphs for which no glyph
4967 strings exist. */
4968 i = x_left_overwriting (head);
4969 if (i >= 0)
4970 {
4971 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
4972 DRAW_NORMAL_TEXT, dummy_x, last_x,
4973 overlaps_p);
06a2c219
GM
4974 for (s = h; s; s = s->next)
4975 s->background_filled_p = 1;
4976 if (real_start)
4977 *real_start = i;
4978 x_compute_overhangs_and_x (t, head->x, 1);
4979 x_prepend_glyph_string_lists (&head, &tail, h, t);
4980 }
dbcb258a 4981
06a2c219
GM
4982 /* Append glyphs strings for glyphs following the last glyph
4983 string tail that are overwritten by tail. The background of
4984 these strings has to be drawn because tail's foreground draws
4985 over it. */
4986 i = x_right_overwritten (tail);
4987 if (i >= 0)
4988 {
4989 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
4990 DRAW_NORMAL_TEXT, x, last_x,
4991 overlaps_p);
06a2c219
GM
4992 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
4993 x_append_glyph_string_lists (&head, &tail, h, t);
4994 if (real_end)
4995 *real_end = i;
4996 }
dc6f92b8 4997
06a2c219
GM
4998 /* Append glyph strings for glyphs following the last glyph
4999 string tail that overwrite tail. The foreground of such
5000 glyphs has to be drawn because it writes into the background
5001 of tail. The background must not be drawn because it could
5002 paint over the foreground of following glyphs. */
5003 i = x_right_overwriting (tail);
5004 if (i >= 0)
5005 {
5006 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5007 DRAW_NORMAL_TEXT, x, last_x,
5008 overlaps_p);
06a2c219
GM
5009 for (s = h; s; s = s->next)
5010 s->background_filled_p = 1;
5011 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5012 x_append_glyph_string_lists (&head, &tail, h, t);
5013 if (real_end)
5014 *real_end = i;
5015 }
5016 }
58769bee 5017
06a2c219
GM
5018 /* Draw all strings. */
5019 for (s = head; s; s = s->next)
5020 x_draw_glyph_string (s);
dc6f92b8 5021
06a2c219
GM
5022 /* Value is the x-position up to which drawn, relative to AREA of W.
5023 This doesn't include parts drawn because of overhangs. */
5024 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
5025 if (!row->full_width_p)
5026 {
5027 if (area > LEFT_MARGIN_AREA)
5028 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
5029 if (area > TEXT_AREA)
5030 x_reached -= window_box_width (w, TEXT_AREA);
5031 }
a8710abf 5032
06a2c219
GM
5033 return x_reached;
5034}
dc6f92b8 5035
dc6f92b8 5036
66ac4b0e
GM
5037/* Fix the display of area AREA of overlapping row ROW in window W. */
5038
5039static void
5040x_fix_overlapping_area (w, row, area)
5041 struct window *w;
5042 struct glyph_row *row;
5043 enum glyph_row_area area;
5044{
5045 int i, x;
5046
5047 BLOCK_INPUT;
5048
5049 if (area == LEFT_MARGIN_AREA)
5050 x = 0;
5051 else if (area == TEXT_AREA)
5052 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5053 else
5054 x = (window_box_width (w, LEFT_MARGIN_AREA)
5055 + window_box_width (w, TEXT_AREA));
5056
5057 for (i = 0; i < row->used[area];)
5058 {
5059 if (row->glyphs[area][i].overlaps_vertically_p)
5060 {
5061 int start = i, start_x = x;
5062
5063 do
5064 {
5065 x += row->glyphs[area][i].pixel_width;
5066 ++i;
5067 }
5068 while (i < row->used[area]
5069 && row->glyphs[area][i].overlaps_vertically_p);
5070
5071 x_draw_glyphs (w, start_x, row, area, start, i,
5072 (row->inverse_p
5073 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
5074 NULL, NULL, 1);
5075 }
5076 else
5077 {
5078 x += row->glyphs[area][i].pixel_width;
5079 ++i;
5080 }
5081 }
5082
5083 UNBLOCK_INPUT;
5084}
5085
5086
06a2c219
GM
5087/* Output LEN glyphs starting at START at the nominal cursor position.
5088 Advance the nominal cursor over the text. The global variable
5089 updated_window contains the window being updated, updated_row is
5090 the glyph row being updated, and updated_area is the area of that
5091 row being updated. */
dc6f92b8 5092
06a2c219
GM
5093static void
5094x_write_glyphs (start, len)
5095 struct glyph *start;
5096 int len;
5097{
5098 int x, hpos, real_start, real_end;
d9cdbb3d 5099
06a2c219 5100 xassert (updated_window && updated_row);
dc6f92b8 5101 BLOCK_INPUT;
06a2c219
GM
5102
5103 /* Write glyphs. */
dc6f92b8 5104
06a2c219
GM
5105 hpos = start - updated_row->glyphs[updated_area];
5106 x = x_draw_glyphs (updated_window, output_cursor.x,
5107 updated_row, updated_area,
5108 hpos, hpos + len,
5109 (updated_row->inverse_p
5110 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
66ac4b0e 5111 &real_start, &real_end, 0);
b30ec466 5112
06a2c219
GM
5113 /* If we drew over the cursor, note that it is not visible any more. */
5114 note_overwritten_text_cursor (updated_window, real_start,
5115 real_end - real_start);
dc6f92b8
JB
5116
5117 UNBLOCK_INPUT;
06a2c219
GM
5118
5119 /* Advance the output cursor. */
5120 output_cursor.hpos += len;
5121 output_cursor.x = x;
dc6f92b8
JB
5122}
5123
0cdd0c9f 5124
06a2c219 5125/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 5126
06a2c219
GM
5127static void
5128x_insert_glyphs (start, len)
5129 struct glyph *start;
5130 register int len;
5131{
5132 struct frame *f;
5133 struct window *w;
5134 int line_height, shift_by_width, shifted_region_width;
5135 struct glyph_row *row;
5136 struct glyph *glyph;
5137 int frame_x, frame_y, hpos, real_start, real_end;
58769bee 5138
06a2c219 5139 xassert (updated_window && updated_row);
0cdd0c9f 5140 BLOCK_INPUT;
06a2c219
GM
5141 w = updated_window;
5142 f = XFRAME (WINDOW_FRAME (w));
5143
5144 /* Get the height of the line we are in. */
5145 row = updated_row;
5146 line_height = row->height;
5147
5148 /* Get the width of the glyphs to insert. */
5149 shift_by_width = 0;
5150 for (glyph = start; glyph < start + len; ++glyph)
5151 shift_by_width += glyph->pixel_width;
5152
5153 /* Get the width of the region to shift right. */
5154 shifted_region_width = (window_box_width (w, updated_area)
5155 - output_cursor.x
5156 - shift_by_width);
5157
5158 /* Shift right. */
bf0ab8a2 5159 frame_x = window_box_left (w, updated_area) + output_cursor.x;
06a2c219
GM
5160 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
5161 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5162 f->output_data.x->normal_gc,
5163 frame_x, frame_y,
5164 shifted_region_width, line_height,
5165 frame_x + shift_by_width, frame_y);
5166
5167 /* Write the glyphs. */
5168 hpos = start - row->glyphs[updated_area];
5169 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
66ac4b0e 5170 DRAW_NORMAL_TEXT, &real_start, &real_end, 0);
06a2c219
GM
5171 note_overwritten_text_cursor (w, real_start, real_end - real_start);
5172
5173 /* Advance the output cursor. */
5174 output_cursor.hpos += len;
5175 output_cursor.x += shift_by_width;
0cdd0c9f
RS
5176 UNBLOCK_INPUT;
5177}
0cdd0c9f 5178
0cdd0c9f 5179
06a2c219
GM
5180/* Delete N glyphs at the nominal cursor position. Not implemented
5181 for X frames. */
c83febd7
RS
5182
5183static void
06a2c219
GM
5184x_delete_glyphs (n)
5185 register int n;
c83febd7 5186{
06a2c219 5187 abort ();
c83febd7
RS
5188}
5189
0cdd0c9f 5190
c5e6e06b
GM
5191/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
5192 If they are <= 0, this is probably an error. */
5193
5194void
5195x_clear_area (dpy, window, x, y, width, height, exposures)
5196 Display *dpy;
5197 Window window;
5198 int x, y;
5199 int width, height;
5200 int exposures;
5201{
5202 xassert (width > 0 && height > 0);
5203 XClearArea (dpy, window, x, y, width, height, exposures);
5204}
5205
5206
06a2c219
GM
5207/* Erase the current text line from the nominal cursor position
5208 (inclusive) to pixel column TO_X (exclusive). The idea is that
5209 everything from TO_X onward is already erased.
5210
5211 TO_X is a pixel position relative to updated_area of
5212 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 5213
06a2c219
GM
5214static void
5215x_clear_end_of_line (to_x)
5216 int to_x;
5217{
5218 struct frame *f;
5219 struct window *w = updated_window;
5220 int max_x, min_y, max_y;
5221 int from_x, from_y, to_y;
5222
5223 xassert (updated_window && updated_row);
5224 f = XFRAME (w->frame);
5225
5226 if (updated_row->full_width_p)
5227 {
5228 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
5229 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5230 && !w->pseudo_window_p)
5231 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 5232 }
06a2c219
GM
5233 else
5234 max_x = window_box_width (w, updated_area);
5235 max_y = window_text_bottom_y (w);
dc6f92b8 5236
06a2c219
GM
5237 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5238 of window. For TO_X > 0, truncate to end of drawing area. */
5239 if (to_x == 0)
5240 return;
5241 else if (to_x < 0)
5242 to_x = max_x;
5243 else
5244 to_x = min (to_x, max_x);
dbc4e1c1 5245
06a2c219
GM
5246 to_y = min (max_y, output_cursor.y + updated_row->height);
5247
5248 /* Notice if the cursor will be cleared by this operation. */
5249 if (!updated_row->full_width_p)
5250 note_overwritten_text_cursor (w, output_cursor.hpos, -1);
dbc4e1c1 5251
06a2c219
GM
5252 from_x = output_cursor.x;
5253
5254 /* Translate to frame coordinates. */
5255 if (updated_row->full_width_p)
5256 {
5257 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5258 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5259 }
0cdd0c9f
RS
5260 else
5261 {
06a2c219
GM
5262 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5263 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5264 }
5265
045dee35 5266 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5267 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5268 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5269
5270 /* Prevent inadvertently clearing to end of the X window. */
5271 if (to_x > from_x && to_y > from_y)
5272 {
5273 BLOCK_INPUT;
c5e6e06b
GM
5274 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5275 from_x, from_y, to_x - from_x, to_y - from_y,
5276 False);
06a2c219 5277 UNBLOCK_INPUT;
0cdd0c9f 5278 }
0cdd0c9f 5279}
dbc4e1c1 5280
0cdd0c9f 5281
06a2c219 5282/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5283 frame. Otherwise clear the selected frame. */
06a2c219
GM
5284
5285static void
5286x_clear_frame ()
0cdd0c9f 5287{
06a2c219 5288 struct frame *f;
0cdd0c9f 5289
06a2c219
GM
5290 if (updating_frame)
5291 f = updating_frame;
0cdd0c9f 5292 else
b86bd3dd 5293 f = SELECTED_FRAME ();
58769bee 5294
06a2c219
GM
5295 /* Clearing the frame will erase any cursor, so mark them all as no
5296 longer visible. */
5297 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5298 output_cursor.hpos = output_cursor.vpos = 0;
5299 output_cursor.x = -1;
5300
5301 /* We don't set the output cursor here because there will always
5302 follow an explicit cursor_to. */
5303 BLOCK_INPUT;
5304 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5305
5306 /* We have to clear the scroll bars, too. If we have changed
5307 colors or something like that, then they should be notified. */
5308 x_scroll_bar_clear (f);
0cdd0c9f 5309
06a2c219
GM
5310 XFlush (FRAME_X_DISPLAY (f));
5311 UNBLOCK_INPUT;
dc6f92b8 5312}
06a2c219
GM
5313
5314
dc6f92b8 5315\f
dbc4e1c1
JB
5316/* Invert the middle quarter of the frame for .15 sec. */
5317
06a2c219
GM
5318/* We use the select system call to do the waiting, so we have to make
5319 sure it's available. If it isn't, we just won't do visual bells. */
5320
dbc4e1c1
JB
5321#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5322
06a2c219
GM
5323
5324/* Subtract the `struct timeval' values X and Y, storing the result in
5325 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5326
5327static int
5328timeval_subtract (result, x, y)
5329 struct timeval *result, x, y;
5330{
06a2c219
GM
5331 /* Perform the carry for the later subtraction by updating y. This
5332 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5333 if (x.tv_usec < y.tv_usec)
5334 {
5335 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5336 y.tv_usec -= 1000000 * nsec;
5337 y.tv_sec += nsec;
5338 }
06a2c219 5339
dbc4e1c1
JB
5340 if (x.tv_usec - y.tv_usec > 1000000)
5341 {
5342 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5343 y.tv_usec += 1000000 * nsec;
5344 y.tv_sec -= nsec;
5345 }
5346
06a2c219
GM
5347 /* Compute the time remaining to wait. tv_usec is certainly
5348 positive. */
dbc4e1c1
JB
5349 result->tv_sec = x.tv_sec - y.tv_sec;
5350 result->tv_usec = x.tv_usec - y.tv_usec;
5351
06a2c219
GM
5352 /* Return indication of whether the result should be considered
5353 negative. */
dbc4e1c1
JB
5354 return x.tv_sec < y.tv_sec;
5355}
dc6f92b8 5356
dfcf069d 5357void
f676886a
JB
5358XTflash (f)
5359 struct frame *f;
dc6f92b8 5360{
dbc4e1c1 5361 BLOCK_INPUT;
dc6f92b8 5362
dbc4e1c1
JB
5363 {
5364 GC gc;
dc6f92b8 5365
06a2c219
GM
5366 /* Create a GC that will use the GXxor function to flip foreground
5367 pixels into background pixels. */
dbc4e1c1
JB
5368 {
5369 XGCValues values;
dc6f92b8 5370
dbc4e1c1 5371 values.function = GXxor;
7556890b
RS
5372 values.foreground = (f->output_data.x->foreground_pixel
5373 ^ f->output_data.x->background_pixel);
58769bee 5374
334208b7 5375 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5376 GCFunction | GCForeground, &values);
5377 }
dc6f92b8 5378
dbc4e1c1 5379 {
e84e14c3
RS
5380 /* Get the height not including a menu bar widget. */
5381 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5382 /* Height of each line to flash. */
5383 int flash_height = FRAME_LINE_HEIGHT (f);
5384 /* These will be the left and right margins of the rectangles. */
5385 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5386 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5387
5388 int width;
5389
5390 /* Don't flash the area between a scroll bar and the frame
5391 edge it is next to. */
5392 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5393 {
5394 case vertical_scroll_bar_left:
5395 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5396 break;
5397
5398 case vertical_scroll_bar_right:
5399 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5400 break;
06a2c219
GM
5401
5402 default:
5403 break;
e84e14c3
RS
5404 }
5405
5406 width = flash_right - flash_left;
5407
5408 /* If window is tall, flash top and bottom line. */
5409 if (height > 3 * FRAME_LINE_HEIGHT (f))
5410 {
5411 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5412 flash_left,
5413 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5414 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5415 width, flash_height);
5416 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5417 flash_left,
5418 (height - flash_height
5419 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5420 width, flash_height);
5421 }
5422 else
5423 /* If it is short, flash it all. */
5424 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5425 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5426 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5427
06a2c219 5428 x_flush (f);
dc6f92b8 5429
dbc4e1c1 5430 {
06a2c219 5431 struct timeval wakeup;
dc6f92b8 5432
66c30ea1 5433 EMACS_GET_TIME (wakeup);
dc6f92b8 5434
dbc4e1c1
JB
5435 /* Compute time to wait until, propagating carry from usecs. */
5436 wakeup.tv_usec += 150000;
5437 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5438 wakeup.tv_usec %= 1000000;
5439
5440 /* Keep waiting until past the time wakeup. */
5441 while (1)
5442 {
5443 struct timeval timeout;
5444
66c30ea1 5445 EMACS_GET_TIME (timeout);
dbc4e1c1
JB
5446
5447 /* In effect, timeout = wakeup - timeout.
5448 Break if result would be negative. */
5449 if (timeval_subtract (&timeout, wakeup, timeout))
5450 break;
5451
5452 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5453 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5454 }
5455 }
58769bee 5456
e84e14c3
RS
5457 /* If window is tall, flash top and bottom line. */
5458 if (height > 3 * FRAME_LINE_HEIGHT (f))
5459 {
5460 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5461 flash_left,
5462 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5463 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5464 width, flash_height);
5465 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5466 flash_left,
5467 (height - flash_height
5468 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5469 width, flash_height);
5470 }
5471 else
5472 /* If it is short, flash it all. */
5473 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5474 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5475 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5476
334208b7 5477 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5478 x_flush (f);
dc6f92b8 5479 }
dbc4e1c1
JB
5480 }
5481
5482 UNBLOCK_INPUT;
dc6f92b8
JB
5483}
5484
06a2c219 5485#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5486
5487
dc6f92b8
JB
5488/* Make audible bell. */
5489
dfcf069d 5490void
dc6f92b8
JB
5491XTring_bell ()
5492{
b86bd3dd
GM
5493 struct frame *f = SELECTED_FRAME ();
5494
5495 if (FRAME_X_DISPLAY (f))
5496 {
dbc4e1c1 5497#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5498 if (visible_bell)
5499 XTflash (f);
5500 else
dbc4e1c1 5501#endif
b86bd3dd
GM
5502 {
5503 BLOCK_INPUT;
5504 XBell (FRAME_X_DISPLAY (f), 0);
5505 XFlush (FRAME_X_DISPLAY (f));
5506 UNBLOCK_INPUT;
5507 }
dc6f92b8
JB
5508 }
5509}
06a2c219 5510
dc6f92b8 5511\f
06a2c219
GM
5512/* Specify how many text lines, from the top of the window,
5513 should be affected by insert-lines and delete-lines operations.
5514 This, and those operations, are used only within an update
5515 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5516
dfcf069d 5517static void
06a2c219
GM
5518XTset_terminal_window (n)
5519 register int n;
dc6f92b8 5520{
06a2c219 5521 /* This function intentionally left blank. */
dc6f92b8
JB
5522}
5523
06a2c219
GM
5524
5525\f
5526/***********************************************************************
5527 Line Dance
5528 ***********************************************************************/
5529
5530/* Perform an insert-lines or delete-lines operation, inserting N
5531 lines or deleting -N lines at vertical position VPOS. */
5532
dfcf069d 5533static void
06a2c219
GM
5534x_ins_del_lines (vpos, n)
5535 int vpos, n;
dc6f92b8
JB
5536{
5537 abort ();
5538}
06a2c219
GM
5539
5540
5541/* Scroll part of the display as described by RUN. */
dc6f92b8 5542
dfcf069d 5543static void
06a2c219
GM
5544x_scroll_run (w, run)
5545 struct window *w;
5546 struct run *run;
dc6f92b8 5547{
06a2c219
GM
5548 struct frame *f = XFRAME (w->frame);
5549 int x, y, width, height, from_y, to_y, bottom_y;
5550
5551 /* Get frame-relative bounding box of the text display area of W,
5552 without mode lines. Include in this box the flags areas to the
5553 left and right of W. */
5554 window_box (w, -1, &x, &y, &width, &height);
110859fc
GM
5555 width += FRAME_X_FLAGS_AREA_WIDTH (f);
5556 x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
5557
5558 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5559 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5560 bottom_y = y + height;
dc6f92b8 5561
06a2c219
GM
5562 if (to_y < from_y)
5563 {
5564 /* Scrolling up. Make sure we don't copy part of the mode
5565 line at the bottom. */
5566 if (from_y + run->height > bottom_y)
5567 height = bottom_y - from_y;
5568 else
5569 height = run->height;
5570 }
dc6f92b8 5571 else
06a2c219
GM
5572 {
5573 /* Scolling down. Make sure we don't copy over the mode line.
5574 at the bottom. */
5575 if (to_y + run->height > bottom_y)
5576 height = bottom_y - to_y;
5577 else
5578 height = run->height;
5579 }
7a13e894 5580
06a2c219
GM
5581 BLOCK_INPUT;
5582
5583 /* Cursor off. Will be switched on again in x_update_window_end. */
5584 updated_window = w;
5585 x_clear_cursor (w);
5586
5587 XCopyArea (FRAME_X_DISPLAY (f),
5588 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5589 f->output_data.x->normal_gc,
5590 x, from_y,
5591 width, height,
5592 x, to_y);
5593
5594 UNBLOCK_INPUT;
5595}
dc6f92b8 5596
dc6f92b8 5597
06a2c219
GM
5598\f
5599/***********************************************************************
5600 Exposure Events
5601 ***********************************************************************/
5602
5603/* Redisplay an exposed area of frame F. X and Y are the upper-left
5604 corner of the exposed rectangle. W and H are width and height of
5605 the exposed area. All are pixel values. W or H zero means redraw
5606 the entire frame. */
dc6f92b8 5607
06a2c219
GM
5608static void
5609expose_frame (f, x, y, w, h)
5610 struct frame *f;
5611 int x, y, w, h;
dc6f92b8 5612{
06a2c219 5613 XRectangle r;
dc6f92b8 5614
06a2c219 5615 TRACE ((stderr, "expose_frame "));
dc6f92b8 5616
06a2c219
GM
5617 /* No need to redraw if frame will be redrawn soon. */
5618 if (FRAME_GARBAGED_P (f))
dc6f92b8 5619 {
06a2c219
GM
5620 TRACE ((stderr, " garbaged\n"));
5621 return;
5622 }
5623
5624 /* If basic faces haven't been realized yet, there is no point in
5625 trying to redraw anything. This can happen when we get an expose
5626 event while Emacs is starting, e.g. by moving another window. */
5627 if (FRAME_FACE_CACHE (f) == NULL
5628 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5629 {
5630 TRACE ((stderr, " no faces\n"));
5631 return;
58769bee 5632 }
06a2c219
GM
5633
5634 if (w == 0 || h == 0)
58769bee 5635 {
06a2c219
GM
5636 r.x = r.y = 0;
5637 r.width = CANON_X_UNIT (f) * f->width;
5638 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5639 }
5640 else
5641 {
06a2c219
GM
5642 r.x = x;
5643 r.y = y;
5644 r.width = w;
5645 r.height = h;
5646 }
5647
5648 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
5649 expose_window_tree (XWINDOW (f->root_window), &r);
5650
9ea173e8 5651 if (WINDOWP (f->tool_bar_window))
06a2c219 5652 {
9ea173e8 5653 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
5654 XRectangle window_rect;
5655 XRectangle intersection_rect;
5656 int window_x, window_y, window_width, window_height;
5657
5658
5659 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5660 window_rect.x = window_x;
5661 window_rect.y = window_y;
5662 window_rect.width = window_width;
5663 window_rect.height = window_height;
5664
5665 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5666 expose_window (w, &intersection_rect);
5667 }
5668
5669#ifndef USE_X_TOOLKIT
5670 if (WINDOWP (f->menu_bar_window))
5671 {
5672 struct window *w = XWINDOW (f->menu_bar_window);
5673 XRectangle window_rect;
5674 XRectangle intersection_rect;
5675 int window_x, window_y, window_width, window_height;
5676
5677
5678 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5679 window_rect.x = window_x;
5680 window_rect.y = window_y;
5681 window_rect.width = window_width;
5682 window_rect.height = window_height;
5683
5684 if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
5685 expose_window (w, &intersection_rect);
dc6f92b8 5686 }
06a2c219 5687#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5688}
5689
06a2c219
GM
5690
5691/* Redraw (parts) of all windows in the window tree rooted at W that
5692 intersect R. R contains frame pixel coordinates. */
5693
58769bee 5694static void
06a2c219
GM
5695expose_window_tree (w, r)
5696 struct window *w;
5697 XRectangle *r;
dc6f92b8 5698{
06a2c219
GM
5699 while (w)
5700 {
5701 if (!NILP (w->hchild))
5702 expose_window_tree (XWINDOW (w->hchild), r);
5703 else if (!NILP (w->vchild))
5704 expose_window_tree (XWINDOW (w->vchild), r);
5705 else
5706 {
5707 XRectangle window_rect;
5708 XRectangle intersection_rect;
5709 struct frame *f = XFRAME (w->frame);
5710 int window_x, window_y, window_width, window_height;
5711
5712 /* Frame-relative pixel rectangle of W. */
5713 window_box (w, -1, &window_x, &window_y, &window_width,
5714 &window_height);
5715 window_rect.x
5716 = (window_x
110859fc 5717 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
714dc26c 5718 - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
06a2c219
GM
5719 window_rect.y = window_y;
5720 window_rect.width
5721 = (window_width
110859fc 5722 + FRAME_X_FLAGS_AREA_WIDTH (f)
06a2c219
GM
5723 + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
5724 window_rect.height
5725 = window_height + CURRENT_MODE_LINE_HEIGHT (w);
5726
5727 if (x_intersect_rectangles (r, &window_rect, &intersection_rect))
5728 expose_window (w, &intersection_rect);
5729 }
58769bee 5730
06a2c219
GM
5731 w = NILP (w->next) ? 0 : XWINDOW (w->next);
5732 }
5733}
58769bee 5734
dc6f92b8 5735
06a2c219
GM
5736/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5737 which intersects rectangle R. R is in window-relative coordinates. */
5738
5739static void
5740expose_area (w, row, r, area)
5741 struct window *w;
5742 struct glyph_row *row;
5743 XRectangle *r;
5744 enum glyph_row_area area;
5745{
06a2c219
GM
5746 struct glyph *first = row->glyphs[area];
5747 struct glyph *end = row->glyphs[area] + row->used[area];
5748 struct glyph *last;
4bc6dcc7 5749 int first_x, start_x, x;
06a2c219 5750
6fb13182
GM
5751 if (area == TEXT_AREA && row->fill_line_p)
5752 /* If row extends face to end of line write the whole line. */
4bc6dcc7 5753 x_draw_glyphs (w, 0, row, area,
6fb13182 5754 0, row->used[area],
06a2c219 5755 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5756 NULL, NULL, 0);
6fb13182
GM
5757 else
5758 {
4bc6dcc7
GM
5759 /* Set START_X to the window-relative start position for drawing glyphs of
5760 AREA. The first glyph of the text area can be partially visible.
5761 The first glyphs of other areas cannot. */
5762 if (area == LEFT_MARGIN_AREA)
5763 start_x = 0;
5764 else if (area == TEXT_AREA)
5765 start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5766 else
5767 start_x = (window_box_width (w, LEFT_MARGIN_AREA)
5768 + window_box_width (w, TEXT_AREA));
5769 x = start_x;
5770
6fb13182
GM
5771 /* Find the first glyph that must be redrawn. */
5772 while (first < end
5773 && x + first->pixel_width < r->x)
5774 {
5775 x += first->pixel_width;
5776 ++first;
5777 }
5778
5779 /* Find the last one. */
5780 last = first;
5781 first_x = x;
5782 while (last < end
5783 && x < r->x + r->width)
5784 {
5785 x += last->pixel_width;
5786 ++last;
5787 }
5788
5789 /* Repaint. */
5790 if (last > first)
4bc6dcc7 5791 x_draw_glyphs (w, first_x - start_x, row, area,
6fb13182
GM
5792 first - row->glyphs[area],
5793 last - row->glyphs[area],
5794 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5795 NULL, NULL, 0);
5796 }
06a2c219
GM
5797}
5798
58769bee 5799
06a2c219
GM
5800/* Redraw the parts of the glyph row ROW on window W intersecting
5801 rectangle R. R is in window-relative coordinates. */
dc6f92b8 5802
06a2c219
GM
5803static void
5804expose_line (w, row, r)
5805 struct window *w;
5806 struct glyph_row *row;
5807 XRectangle *r;
5808{
5809 xassert (row->enabled_p);
5810
5811 if (row->mode_line_p || w->pseudo_window_p)
5812 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
5813 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5814 NULL, NULL, 0);
06a2c219
GM
5815 else
5816 {
5817 if (row->used[LEFT_MARGIN_AREA])
5818 expose_area (w, row, r, LEFT_MARGIN_AREA);
5819 if (row->used[TEXT_AREA])
5820 expose_area (w, row, r, TEXT_AREA);
5821 if (row->used[RIGHT_MARGIN_AREA])
5822 expose_area (w, row, r, RIGHT_MARGIN_AREA);
5823 x_draw_row_bitmaps (w, row);
5824 }
5825}
dc6f92b8 5826
58769bee 5827
06a2c219
GM
5828/* Return non-zero if W's cursor intersects rectangle R. */
5829
5830static int
5831x_phys_cursor_in_rect_p (w, r)
5832 struct window *w;
5833 XRectangle *r;
5834{
5835 XRectangle cr, result;
5836 struct glyph *cursor_glyph;
5837
5838 cursor_glyph = get_phys_cursor_glyph (w);
5839 if (cursor_glyph)
5840 {
5841 cr.x = w->phys_cursor.x;
5842 cr.y = w->phys_cursor.y;
5843 cr.width = cursor_glyph->pixel_width;
5844 cr.height = w->phys_cursor_height;
5845 return x_intersect_rectangles (&cr, r, &result);
5846 }
5847 else
5848 return 0;
dc6f92b8 5849}
dc6f92b8 5850
06a2c219
GM
5851
5852/* Redraw a rectangle of window W. R is a rectangle in window
5853 relative coordinates. Call this function with input blocked. */
dc6f92b8
JB
5854
5855static void
06a2c219
GM
5856expose_window (w, r)
5857 struct window *w;
5858 XRectangle *r;
dc6f92b8 5859{
06a2c219
GM
5860 struct glyph_row *row;
5861 int y;
5862 int yb = window_text_bottom_y (w);
5863 int cursor_cleared_p;
dc6f92b8 5864
80c32bcc
GM
5865 /* If window is not yet fully initialized, do nothing. This can
5866 happen when toolkit scroll bars are used and a window is split.
5867 Reconfiguring the scroll bar will generate an expose for a newly
5868 created window. */
c7911417 5869 if (w->current_matrix == NULL || w == updated_window)
80c32bcc
GM
5870 return;
5871
06a2c219
GM
5872 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
5873 r->x, r->y, r->width, r->height));
dc6f92b8 5874
06a2c219
GM
5875 /* Convert to window coordinates. */
5876 r->x = FRAME_TO_WINDOW_PIXEL_X (w, r->x);
5877 r->y = FRAME_TO_WINDOW_PIXEL_Y (w, r->y);
dc6f92b8 5878
06a2c219
GM
5879 /* Turn off the cursor. */
5880 if (!w->pseudo_window_p
5881 && x_phys_cursor_in_rect_p (w, r))
5882 {
5883 x_clear_cursor (w);
5884 cursor_cleared_p = 1;
5885 }
5886 else
5887 cursor_cleared_p = 0;
5888
5889 /* Find the first row intersecting the rectangle R. */
5890 row = w->current_matrix->rows;
5891 y = 0;
5892 while (row->enabled_p
5893 && y < yb
5894 && y + row->height < r->y)
5895 {
5896 y += row->height;
5897 ++row;
5898 }
5899
dc6f92b8 5900 /* Display the text in the rectangle, one text line at a time. */
06a2c219
GM
5901 while (row->enabled_p
5902 && y < yb
5903 && y < r->y + r->height)
5904 {
5905 expose_line (w, row, r);
5906 y += row->height;
5907 ++row;
5908 }
5909
5910 /* Display the mode line if there is one. */
5911 if (WINDOW_WANTS_MODELINE_P (w)
5912 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
5913 row->enabled_p)
5914 && row->y < r->y + r->height)
5915 expose_line (w, row, r);
dc6f92b8 5916
06a2c219 5917 if (!w->pseudo_window_p)
dc6f92b8 5918 {
06a2c219
GM
5919 /* Draw border between windows. */
5920 x_draw_vertical_border (w);
5921
5922 /* Turn the cursor on again. */
5923 if (cursor_cleared_p)
5924 x_update_window_cursor (w, 1);
5925 }
5926}
dc6f92b8 5927
dc6f92b8 5928
06a2c219
GM
5929/* Determine the intersection of two rectangles R1 and R2. Return
5930 the intersection in *RESULT. Value is non-zero if RESULT is not
5931 empty. */
5932
5933static int
5934x_intersect_rectangles (r1, r2, result)
5935 XRectangle *r1, *r2, *result;
5936{
5937 XRectangle *left, *right;
5938 XRectangle *upper, *lower;
5939 int intersection_p = 0;
5940
5941 /* Rearrange so that R1 is the left-most rectangle. */
5942 if (r1->x < r2->x)
5943 left = r1, right = r2;
5944 else
5945 left = r2, right = r1;
5946
5947 /* X0 of the intersection is right.x0, if this is inside R1,
5948 otherwise there is no intersection. */
5949 if (right->x <= left->x + left->width)
5950 {
5951 result->x = right->x;
5952
5953 /* The right end of the intersection is the minimum of the
5954 the right ends of left and right. */
5955 result->width = (min (left->x + left->width, right->x + right->width)
5956 - result->x);
5957
5958 /* Same game for Y. */
5959 if (r1->y < r2->y)
5960 upper = r1, lower = r2;
5961 else
5962 upper = r2, lower = r1;
5963
5964 /* The upper end of the intersection is lower.y0, if this is inside
5965 of upper. Otherwise, there is no intersection. */
5966 if (lower->y <= upper->y + upper->height)
dc43ef94 5967 {
06a2c219
GM
5968 result->y = lower->y;
5969
5970 /* The lower end of the intersection is the minimum of the lower
5971 ends of upper and lower. */
5972 result->height = (min (lower->y + lower->height,
5973 upper->y + upper->height)
5974 - result->y);
5975 intersection_p = 1;
dc43ef94 5976 }
dc6f92b8
JB
5977 }
5978
06a2c219 5979 return intersection_p;
dc6f92b8 5980}
06a2c219
GM
5981
5982
5983
5984
dc6f92b8 5985\f
dc6f92b8 5986static void
334208b7
RS
5987frame_highlight (f)
5988 struct frame *f;
dc6f92b8 5989{
b3e1e05c
JB
5990 /* We used to only do this if Vx_no_window_manager was non-nil, but
5991 the ICCCM (section 4.1.6) says that the window's border pixmap
5992 and border pixel are window attributes which are "private to the
5993 client", so we can always change it to whatever we want. */
5994 BLOCK_INPUT;
334208b7 5995 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 5996 f->output_data.x->border_pixel);
b3e1e05c 5997 UNBLOCK_INPUT;
5d46f928 5998 x_update_cursor (f, 1);
dc6f92b8
JB
5999}
6000
6001static void
334208b7
RS
6002frame_unhighlight (f)
6003 struct frame *f;
dc6f92b8 6004{
b3e1e05c
JB
6005 /* We used to only do this if Vx_no_window_manager was non-nil, but
6006 the ICCCM (section 4.1.6) says that the window's border pixmap
6007 and border pixel are window attributes which are "private to the
6008 client", so we can always change it to whatever we want. */
6009 BLOCK_INPUT;
334208b7 6010 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6011 f->output_data.x->border_tile);
b3e1e05c 6012 UNBLOCK_INPUT;
5d46f928 6013 x_update_cursor (f, 1);
dc6f92b8 6014}
dc6f92b8 6015
f676886a
JB
6016/* The focus has changed. Update the frames as necessary to reflect
6017 the new situation. Note that we can't change the selected frame
c5acd733 6018 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 6019 Each event gets marked with the frame in which it occurred, so the
c5acd733 6020 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 6021
6d4238f3 6022static void
0f941935
KH
6023x_new_focus_frame (dpyinfo, frame)
6024 struct x_display_info *dpyinfo;
f676886a 6025 struct frame *frame;
dc6f92b8 6026{
0f941935 6027 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 6028
0f941935 6029 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 6030 {
58769bee 6031 /* Set this before calling other routines, so that they see
f676886a 6032 the correct value of x_focus_frame. */
0f941935 6033 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
6034
6035 if (old_focus && old_focus->auto_lower)
f676886a 6036 x_lower_frame (old_focus);
dc6f92b8
JB
6037
6038#if 0
f676886a 6039 selected_frame = frame;
e0c1aef2
KH
6040 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6041 selected_frame);
f676886a
JB
6042 Fselect_window (selected_frame->selected_window);
6043 choose_minibuf_frame ();
c118dd06 6044#endif /* ! 0 */
dc6f92b8 6045
0f941935
KH
6046 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6047 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
6048 else
6049 pending_autoraise_frame = 0;
6d4238f3 6050 }
dc6f92b8 6051
0f941935 6052 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
6053}
6054
37c2c98b
RS
6055/* Handle an event saying the mouse has moved out of an Emacs frame. */
6056
6057void
0f941935
KH
6058x_mouse_leave (dpyinfo)
6059 struct x_display_info *dpyinfo;
37c2c98b 6060{
0f941935 6061 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 6062}
6d4238f3 6063
f451eb13
JB
6064/* The focus has changed, or we have redirected a frame's focus to
6065 another frame (this happens when a frame uses a surrogate
06a2c219 6066 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
6067
6068 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 6069 frame is being highlighted or un-highlighted; we only use it to find
0f941935 6070 the appropriate X display info. */
06a2c219 6071
6d4238f3 6072static void
0f941935
KH
6073XTframe_rehighlight (frame)
6074 struct frame *frame;
6d4238f3 6075{
0f941935
KH
6076 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6077}
6d4238f3 6078
0f941935
KH
6079static void
6080x_frame_rehighlight (dpyinfo)
6081 struct x_display_info *dpyinfo;
6082{
6083 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6084
6085 if (dpyinfo->x_focus_frame)
6d4238f3 6086 {
0f941935
KH
6087 dpyinfo->x_highlight_frame
6088 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6089 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6090 : dpyinfo->x_focus_frame);
6091 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 6092 {
0f941935
KH
6093 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6094 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 6095 }
dc6f92b8 6096 }
6d4238f3 6097 else
0f941935 6098 dpyinfo->x_highlight_frame = 0;
dc6f92b8 6099
0f941935 6100 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
6101 {
6102 if (old_highlight)
f676886a 6103 frame_unhighlight (old_highlight);
0f941935
KH
6104 if (dpyinfo->x_highlight_frame)
6105 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 6106 }
dc6f92b8 6107}
06a2c219
GM
6108
6109
dc6f92b8 6110\f
06a2c219 6111/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 6112
28430d3c
JB
6113/* Initialize mode_switch_bit and modifier_meaning. */
6114static void
334208b7
RS
6115x_find_modifier_meanings (dpyinfo)
6116 struct x_display_info *dpyinfo;
28430d3c 6117{
f689eb05 6118 int min_code, max_code;
28430d3c
JB
6119 KeySym *syms;
6120 int syms_per_code;
6121 XModifierKeymap *mods;
6122
334208b7
RS
6123 dpyinfo->meta_mod_mask = 0;
6124 dpyinfo->shift_lock_mask = 0;
6125 dpyinfo->alt_mod_mask = 0;
6126 dpyinfo->super_mod_mask = 0;
6127 dpyinfo->hyper_mod_mask = 0;
58769bee 6128
9658a521 6129#ifdef HAVE_X11R4
334208b7 6130 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 6131#else
4a60f8c5
RS
6132 min_code = dpyinfo->display->min_keycode;
6133 max_code = dpyinfo->display->max_keycode;
9658a521
JB
6134#endif
6135
334208b7 6136 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
6137 min_code, max_code - min_code + 1,
6138 &syms_per_code);
334208b7 6139 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 6140
58769bee 6141 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 6142 Alt keysyms are on. */
28430d3c 6143 {
06a2c219 6144 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
6145
6146 for (row = 3; row < 8; row++)
6147 for (col = 0; col < mods->max_keypermod; col++)
6148 {
0299d313
RS
6149 KeyCode code
6150 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 6151
af92970c
KH
6152 /* Zeroes are used for filler. Skip them. */
6153 if (code == 0)
6154 continue;
6155
28430d3c
JB
6156 /* Are any of this keycode's keysyms a meta key? */
6157 {
6158 int code_col;
6159
6160 for (code_col = 0; code_col < syms_per_code; code_col++)
6161 {
f689eb05 6162 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 6163
f689eb05 6164 switch (sym)
28430d3c 6165 {
f689eb05
JB
6166 case XK_Meta_L:
6167 case XK_Meta_R:
334208b7 6168 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 6169 break;
f689eb05
JB
6170
6171 case XK_Alt_L:
6172 case XK_Alt_R:
334208b7 6173 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
6174 break;
6175
6176 case XK_Hyper_L:
6177 case XK_Hyper_R:
334208b7 6178 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
6179 break;
6180
6181 case XK_Super_L:
6182 case XK_Super_R:
334208b7 6183 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 6184 break;
11edeb03
JB
6185
6186 case XK_Shift_Lock:
6187 /* Ignore this if it's not on the lock modifier. */
6188 if ((1 << row) == LockMask)
334208b7 6189 dpyinfo->shift_lock_mask = LockMask;
11edeb03 6190 break;
28430d3c
JB
6191 }
6192 }
6193 }
6194 }
6195 }
6196
f689eb05 6197 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 6198 if (! dpyinfo->meta_mod_mask)
a3c44b14 6199 {
334208b7
RS
6200 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6201 dpyinfo->alt_mod_mask = 0;
a3c44b14 6202 }
f689eb05 6203
148c4b70
RS
6204 /* If some keys are both alt and meta,
6205 make them just meta, not alt. */
334208b7 6206 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 6207 {
334208b7 6208 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 6209 }
58769bee 6210
28430d3c 6211 XFree ((char *) syms);
f689eb05 6212 XFreeModifiermap (mods);
28430d3c
JB
6213}
6214
dfeccd2d
JB
6215/* Convert between the modifier bits X uses and the modifier bits
6216 Emacs uses. */
06a2c219 6217
7c5283e4 6218static unsigned int
334208b7
RS
6219x_x_to_emacs_modifiers (dpyinfo, state)
6220 struct x_display_info *dpyinfo;
dc6f92b8
JB
6221 unsigned int state;
6222{
334208b7
RS
6223 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
6224 | ((state & ControlMask) ? ctrl_modifier : 0)
6225 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
6226 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
6227 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
6228 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
6229}
6230
dfeccd2d 6231static unsigned int
334208b7
RS
6232x_emacs_to_x_modifiers (dpyinfo, state)
6233 struct x_display_info *dpyinfo;
dfeccd2d
JB
6234 unsigned int state;
6235{
334208b7
RS
6236 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
6237 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6238 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6239 | ((state & shift_modifier) ? ShiftMask : 0)
6240 | ((state & ctrl_modifier) ? ControlMask : 0)
6241 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6242}
d047c4eb
KH
6243
6244/* Convert a keysym to its name. */
6245
6246char *
6247x_get_keysym_name (keysym)
6248 KeySym keysym;
6249{
6250 char *value;
6251
6252 BLOCK_INPUT;
6253 value = XKeysymToString (keysym);
6254 UNBLOCK_INPUT;
6255
6256 return value;
6257}
06a2c219
GM
6258
6259
e4571a43
JB
6260\f
6261/* Mouse clicks and mouse movement. Rah. */
e4571a43 6262
06a2c219
GM
6263/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6264 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6265 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6266 not force the value into range. */
69388238 6267
c8dba240 6268void
69388238 6269pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6270 FRAME_PTR f;
69388238 6271 register int pix_x, pix_y;
e4571a43
JB
6272 register int *x, *y;
6273 XRectangle *bounds;
69388238 6274 int noclip;
e4571a43 6275{
06a2c219 6276 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6277 even for negative values. */
6278 if (pix_x < 0)
7556890b 6279 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6280 if (pix_y < 0)
7556890b 6281 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6282
e4571a43
JB
6283 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6284 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6285
6286 if (bounds)
6287 {
7556890b
RS
6288 bounds->width = FONT_WIDTH (f->output_data.x->font);
6289 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6290 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6291 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6292 }
6293
69388238
RS
6294 if (!noclip)
6295 {
6296 if (pix_x < 0)
6297 pix_x = 0;
3cbd2e0b
RS
6298 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6299 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6300
6301 if (pix_y < 0)
6302 pix_y = 0;
6303 else if (pix_y > f->height)
6304 pix_y = f->height;
6305 }
e4571a43
JB
6306
6307 *x = pix_x;
6308 *y = pix_y;
6309}
6310
06a2c219
GM
6311
6312/* Given HPOS/VPOS in the current matrix of W, return corresponding
6313 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6314 can't tell the positions because W's display is not up to date,
6315 return 0. */
6316
6317int
6318glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6319 struct window *w;
6320 int hpos, vpos;
6321 int *frame_x, *frame_y;
2b5c9e71 6322{
06a2c219
GM
6323 int success_p;
6324
6325 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6326 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6327
6328 if (display_completed)
6329 {
6330 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6331 struct glyph *glyph = row->glyphs[TEXT_AREA];
6332 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6333
6334 *frame_y = row->y;
6335 *frame_x = row->x;
6336 while (glyph < end)
6337 {
6338 *frame_x += glyph->pixel_width;
6339 ++glyph;
6340 }
6341
6342 success_p = 1;
6343 }
6344 else
6345 {
6346 *frame_y = *frame_x = 0;
6347 success_p = 0;
6348 }
6349
6350 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6351 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6352 return success_p;
2b5c9e71
RS
6353}
6354
06a2c219 6355
dc6f92b8
JB
6356/* Prepare a mouse-event in *RESULT for placement in the input queue.
6357
6358 If the event is a button press, then note that we have grabbed
f451eb13 6359 the mouse. */
dc6f92b8
JB
6360
6361static Lisp_Object
f451eb13 6362construct_mouse_click (result, event, f)
dc6f92b8
JB
6363 struct input_event *result;
6364 XButtonEvent *event;
f676886a 6365 struct frame *f;
dc6f92b8 6366{
f451eb13 6367 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6368 otherwise. */
f451eb13 6369 result->kind = mouse_click;
69388238 6370 result->code = event->button - Button1;
1113d9db 6371 result->timestamp = event->time;
334208b7
RS
6372 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6373 event->state)
f689eb05 6374 | (event->type == ButtonRelease
58769bee 6375 ? up_modifier
f689eb05 6376 : down_modifier));
dc6f92b8 6377
06a2c219
GM
6378 XSETINT (result->x, event->x);
6379 XSETINT (result->y, event->y);
6380 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6381 result->arg = Qnil;
06a2c219 6382 return Qnil;
dc6f92b8 6383}
b849c413 6384
69388238 6385\f
90e65f07
JB
6386/* Function to report a mouse movement to the mainstream Emacs code.
6387 The input handler calls this.
6388
6389 We have received a mouse movement event, which is given in *event.
6390 If the mouse is over a different glyph than it was last time, tell
6391 the mainstream emacs code by setting mouse_moved. If not, ask for
6392 another motion event, so we can check again the next time it moves. */
b8009dd1 6393
06a2c219
GM
6394static XMotionEvent last_mouse_motion_event;
6395static Lisp_Object last_mouse_motion_frame;
6396
90e65f07 6397static void
12ba150f 6398note_mouse_movement (frame, event)
f676886a 6399 FRAME_PTR frame;
90e65f07 6400 XMotionEvent *event;
90e65f07 6401{
e5d77022 6402 last_mouse_movement_time = event->time;
06a2c219
GM
6403 last_mouse_motion_event = *event;
6404 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6405
27f338af
RS
6406 if (event->window != FRAME_X_WINDOW (frame))
6407 {
39d8bb4d 6408 frame->mouse_moved = 1;
27f338af 6409 last_mouse_scroll_bar = Qnil;
27f338af 6410 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6411 }
6412
90e65f07 6413 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6414 else if (event->x < last_mouse_glyph.x
6415 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6416 || event->y < last_mouse_glyph.y
6417 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6418 {
39d8bb4d 6419 frame->mouse_moved = 1;
ab648270 6420 last_mouse_scroll_bar = Qnil;
b8009dd1 6421 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6422 }
6423}
6424
bf1c0ba1 6425/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6426
06a2c219
GM
6427 int disable_mouse_highlight;
6428
6429
6430\f
6431/************************************************************************
6432 Mouse Face
6433 ************************************************************************/
6434
6435/* Find the glyph under window-relative coordinates X/Y in window W.
6436 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6437 strings. Return in *HPOS and *VPOS the row and column number of
6438 the glyph found. Return in *AREA the glyph area containing X.
6439 Value is a pointer to the glyph found or null if X/Y is not on
6440 text, or we can't tell because W's current matrix is not up to
6441 date. */
6442
6443static struct glyph *
6444x_y_to_hpos_vpos (w, x, y, hpos, vpos, area)
6445 struct window *w;
6446 int x, y;
6447 int *hpos, *vpos, *area;
6448{
6449 struct glyph *glyph, *end;
3e71d8f2 6450 struct glyph_row *row = NULL;
06a2c219
GM
6451 int x0, i, left_area_width;
6452
6453 /* Find row containing Y. Give up if some row is not enabled. */
6454 for (i = 0; i < w->current_matrix->nrows; ++i)
6455 {
6456 row = MATRIX_ROW (w->current_matrix, i);
6457 if (!row->enabled_p)
6458 return NULL;
6459 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6460 break;
6461 }
6462
6463 *vpos = i;
6464 *hpos = 0;
6465
6466 /* Give up if Y is not in the window. */
6467 if (i == w->current_matrix->nrows)
6468 return NULL;
6469
6470 /* Get the glyph area containing X. */
6471 if (w->pseudo_window_p)
6472 {
6473 *area = TEXT_AREA;
6474 x0 = 0;
6475 }
6476 else
6477 {
6478 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6479 if (x < left_area_width)
6480 {
6481 *area = LEFT_MARGIN_AREA;
6482 x0 = 0;
6483 }
6484 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6485 {
6486 *area = TEXT_AREA;
6487 x0 = row->x + left_area_width;
6488 }
6489 else
6490 {
6491 *area = RIGHT_MARGIN_AREA;
6492 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6493 }
6494 }
6495
6496 /* Find glyph containing X. */
6497 glyph = row->glyphs[*area];
6498 end = glyph + row->used[*area];
6499 while (glyph < end)
6500 {
6501 if (x < x0 + glyph->pixel_width)
6502 {
6503 if (w->pseudo_window_p)
6504 break;
6505 else if (BUFFERP (glyph->object))
6506 break;
6507 }
6508
6509 x0 += glyph->pixel_width;
6510 ++glyph;
6511 }
6512
6513 if (glyph == end)
6514 return NULL;
6515
6516 *hpos = glyph - row->glyphs[*area];
6517 return glyph;
6518}
6519
6520
6521/* Convert frame-relative x/y to coordinates relative to window W.
6522 Takes pseudo-windows into account. */
6523
6524static void
6525frame_to_window_pixel_xy (w, x, y)
6526 struct window *w;
6527 int *x, *y;
6528{
6529 if (w->pseudo_window_p)
6530 {
6531 /* A pseudo-window is always full-width, and starts at the
6532 left edge of the frame, plus a frame border. */
6533 struct frame *f = XFRAME (w->frame);
6534 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6535 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6536 }
6537 else
6538 {
6539 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6540 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6541 }
6542}
6543
6544
e371a781 6545/* Take proper action when mouse has moved to the mode or header line of
06a2c219
GM
6546 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6547 mode line. X is relative to the start of the text display area of
6548 W, so the width of bitmap areas and scroll bars must be subtracted
6549 to get a position relative to the start of the mode line. */
6550
6551static void
6552note_mode_line_highlight (w, x, mode_line_p)
6553 struct window *w;
6554 int x, mode_line_p;
6555{
6556 struct frame *f = XFRAME (w->frame);
6557 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6558 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6559 struct glyph_row *row;
6560
6561 if (mode_line_p)
6562 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6563 else
045dee35 6564 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
e371a781 6565
06a2c219
GM
6566 if (row->enabled_p)
6567 {
6568 struct glyph *glyph, *end;
6569 Lisp_Object help, map;
6570 int x0;
6571
6572 /* Find the glyph under X. */
6573 glyph = row->glyphs[TEXT_AREA];
6574 end = glyph + row->used[TEXT_AREA];
6575 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
110859fc 6576 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
e371a781 6577
06a2c219
GM
6578 while (glyph < end
6579 && x >= x0 + glyph->pixel_width)
6580 {
6581 x0 += glyph->pixel_width;
6582 ++glyph;
6583 }
6584
6585 if (glyph < end
6586 && STRINGP (glyph->object)
6587 && XSTRING (glyph->object)->intervals
6588 && glyph->charpos >= 0
6589 && glyph->charpos < XSTRING (glyph->object)->size)
6590 {
6591 /* If we're on a string with `help-echo' text property,
6592 arrange for the help to be displayed. This is done by
6593 setting the global variable help_echo to the help string. */
6594 help = Fget_text_property (make_number (glyph->charpos),
6595 Qhelp_echo, glyph->object);
b7e80413 6596 if (!NILP (help))
be010514
GM
6597 {
6598 help_echo = help;
7cea38bc 6599 XSETWINDOW (help_echo_window, w);
be010514
GM
6600 help_echo_object = glyph->object;
6601 help_echo_pos = glyph->charpos;
6602 }
06a2c219
GM
6603
6604 /* Change the mouse pointer according to what is under X/Y. */
6605 map = Fget_text_property (make_number (glyph->charpos),
6606 Qlocal_map, glyph->object);
02067692 6607 if (KEYMAPP (map))
06a2c219 6608 cursor = f->output_data.x->nontext_cursor;
be010514
GM
6609 else
6610 {
6611 map = Fget_text_property (make_number (glyph->charpos),
6612 Qkeymap, glyph->object);
02067692 6613 if (KEYMAPP (map))
be010514
GM
6614 cursor = f->output_data.x->nontext_cursor;
6615 }
06a2c219
GM
6616 }
6617 }
6618
6619 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6620}
6621
6622
6623/* Take proper action when the mouse has moved to position X, Y on
6624 frame F as regards highlighting characters that have mouse-face
6625 properties. Also de-highlighting chars where the mouse was before.
27f338af 6626 X and Y can be negative or out of range. */
b8009dd1
RS
6627
6628static void
6629note_mouse_highlight (f, x, y)
06a2c219 6630 struct frame *f;
c32cdd9a 6631 int x, y;
b8009dd1 6632{
06a2c219
GM
6633 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6634 int portion;
b8009dd1
RS
6635 Lisp_Object window;
6636 struct window *w;
6637
06a2c219
GM
6638 /* When a menu is active, don't highlight because this looks odd. */
6639#ifdef USE_X_TOOLKIT
6640 if (popup_activated ())
6641 return;
6642#endif
6643
04fff9c0
GM
6644 if (disable_mouse_highlight
6645 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6646 return;
6647
06a2c219
GM
6648 dpyinfo->mouse_face_mouse_x = x;
6649 dpyinfo->mouse_face_mouse_y = y;
6650 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6651
06a2c219 6652 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6653 return;
6654
514e4681
RS
6655 if (gc_in_progress)
6656 {
06a2c219 6657 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6658 return;
6659 }
6660
b8009dd1 6661 /* Which window is that in? */
06a2c219 6662 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6663
6664 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6665 if (! EQ (window, dpyinfo->mouse_face_window))
6666 clear_mouse_face (dpyinfo);
6667
6668 /* Not on a window -> return. */
6669 if (!WINDOWP (window))
6670 return;
6671
6672 /* Convert to window-relative pixel coordinates. */
6673 w = XWINDOW (window);
6674 frame_to_window_pixel_xy (w, &x, &y);
6675
9ea173e8 6676 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6677 buffer. */
9ea173e8 6678 if (EQ (window, f->tool_bar_window))
06a2c219 6679 {
9ea173e8 6680 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6681 return;
6682 }
6683
6684 if (portion == 1 || portion == 3)
6685 {
6686 /* Mouse is on the mode or top line. */
6687 note_mode_line_highlight (w, x, portion == 1);
6688 return;
6689 }
e371a781
GM
6690 else if (portion == 2)
6691 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6692 f->output_data.x->horizontal_drag_cursor);
06a2c219
GM
6693 else
6694 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
6695 f->output_data.x->text_cursor);
b8009dd1 6696
0cdd0c9f
RS
6697 /* Are we in a window whose display is up to date?
6698 And verify the buffer's text has not changed. */
06a2c219
GM
6699 if (/* Within text portion of the window. */
6700 portion == 0
0cdd0c9f 6701 && EQ (w->window_end_valid, w->buffer)
26459b28
KH
6702 && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
6703 && (XFASTINT (w->last_overlay_modified)
6704 == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
b8009dd1 6705 {
06a2c219
GM
6706 int hpos, vpos, pos, i, area;
6707 struct glyph *glyph;
b8009dd1 6708
06a2c219
GM
6709 /* Find the glyph under X/Y. */
6710 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area);
6711
6712 /* Clear mouse face if X/Y not over text. */
6713 if (glyph == NULL
6714 || area != TEXT_AREA
6715 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6716 {
06a2c219
GM
6717 clear_mouse_face (dpyinfo);
6718 return;
6719 }
6720
6721 pos = glyph->charpos;
6722 xassert (w->pseudo_window_p || BUFFERP (glyph->object));
6723
6724 /* Check for mouse-face and help-echo. */
6725 {
6726 Lisp_Object mouse_face, overlay, position;
6727 Lisp_Object *overlay_vec;
6728 int len, noverlays;
6729 struct buffer *obuf;
6730 int obegv, ozv;
6731
6732 /* If we get an out-of-range value, return now; avoid an error. */
6733 if (pos > BUF_Z (XBUFFER (w->buffer)))
6734 return;
6735
6736 /* Make the window's buffer temporarily current for
6737 overlays_at and compute_char_face. */
6738 obuf = current_buffer;
6739 current_buffer = XBUFFER (w->buffer);
6740 obegv = BEGV;
6741 ozv = ZV;
6742 BEGV = BEG;
6743 ZV = Z;
6744
6745 /* Is this char mouse-active or does it have help-echo? */
6746 XSETINT (position, pos);
6747
6748 /* Put all the overlays we want in a vector in overlay_vec.
6749 Store the length in len. If there are more than 10, make
6750 enough space for all, and try again. */
6751 len = 10;
6752 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
bc592036 6753 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
06a2c219
GM
6754 if (noverlays > len)
6755 {
6756 len = noverlays;
6757 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
bc592036 6758 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
06a2c219 6759 }
f8349001
GM
6760
6761 /* Sort overlays into increasing priority order. */
06a2c219
GM
6762 noverlays = sort_overlays (overlay_vec, noverlays, w);
6763
6764 /* Check mouse-face highlighting. */
6765 if (! (EQ (window, dpyinfo->mouse_face_window)
6766 && vpos >= dpyinfo->mouse_face_beg_row
6767 && vpos <= dpyinfo->mouse_face_end_row
6768 && (vpos > dpyinfo->mouse_face_beg_row
6769 || hpos >= dpyinfo->mouse_face_beg_col)
6770 && (vpos < dpyinfo->mouse_face_end_row
6771 || hpos < dpyinfo->mouse_face_end_col
6772 || dpyinfo->mouse_face_past_end)))
6773 {
6774 /* Clear the display of the old active region, if any. */
6775 clear_mouse_face (dpyinfo);
6776
6777 /* Find the highest priority overlay that has a mouse-face prop. */
6778 overlay = Qnil;
f8349001 6779 for (i = noverlays - 1; i >= 0; --i)
06a2c219
GM
6780 {
6781 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6782 if (!NILP (mouse_face))
6783 {
6784 overlay = overlay_vec[i];
6785 break;
6786 }
6787 }
6788
6789 /* If no overlay applies, get a text property. */
6790 if (NILP (overlay))
6791 mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
6792
6793 /* Handle the overlay case. */
6794 if (! NILP (overlay))
6795 {
6796 /* Find the range of text around this char that
6797 should be active. */
6798 Lisp_Object before, after;
6799 int ignore;
6800
6801 before = Foverlay_start (overlay);
6802 after = Foverlay_end (overlay);
6803 /* Record this as the current active region. */
6804 fast_find_position (w, XFASTINT (before),
6805 &dpyinfo->mouse_face_beg_col,
6806 &dpyinfo->mouse_face_beg_row,
6807 &dpyinfo->mouse_face_beg_x,
6808 &dpyinfo->mouse_face_beg_y);
6809 dpyinfo->mouse_face_past_end
6810 = !fast_find_position (w, XFASTINT (after),
6811 &dpyinfo->mouse_face_end_col,
6812 &dpyinfo->mouse_face_end_row,
6813 &dpyinfo->mouse_face_end_x,
6814 &dpyinfo->mouse_face_end_y);
6815 dpyinfo->mouse_face_window = window;
6816 dpyinfo->mouse_face_face_id
6817 = face_at_buffer_position (w, pos, 0, 0,
6818 &ignore, pos + 1, 1);
6819
6820 /* Display it as active. */
6821 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6822 }
6823 /* Handle the text property case. */
6824 else if (! NILP (mouse_face))
6825 {
6826 /* Find the range of text around this char that
6827 should be active. */
6828 Lisp_Object before, after, beginning, end;
6829 int ignore;
6830
6831 beginning = Fmarker_position (w->start);
6832 XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
6833 - XFASTINT (w->window_end_pos)));
6834 before
6835 = Fprevious_single_property_change (make_number (pos + 1),
6836 Qmouse_face,
6837 w->buffer, beginning);
6838 after
6839 = Fnext_single_property_change (position, Qmouse_face,
6840 w->buffer, end);
6841 /* Record this as the current active region. */
6842 fast_find_position (w, XFASTINT (before),
6843 &dpyinfo->mouse_face_beg_col,
6844 &dpyinfo->mouse_face_beg_row,
6845 &dpyinfo->mouse_face_beg_x,
6846 &dpyinfo->mouse_face_beg_y);
6847 dpyinfo->mouse_face_past_end
6848 = !fast_find_position (w, XFASTINT (after),
6849 &dpyinfo->mouse_face_end_col,
6850 &dpyinfo->mouse_face_end_row,
6851 &dpyinfo->mouse_face_end_x,
6852 &dpyinfo->mouse_face_end_y);
6853 dpyinfo->mouse_face_window = window;
6854 dpyinfo->mouse_face_face_id
6855 = face_at_buffer_position (w, pos, 0, 0,
6856 &ignore, pos + 1, 1);
6857
6858 /* Display it as active. */
6859 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
6860 }
6861 }
6862
6863 /* Look for a `help-echo' property. */
6864 {
743934db 6865 Lisp_Object help, overlay;
06a2c219
GM
6866
6867 /* Check overlays first. */
f9b5db02 6868 help = overlay = Qnil;
f8349001 6869 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
743934db
GM
6870 {
6871 overlay = overlay_vec[i];
6872 help = Foverlay_get (overlay, Qhelp_echo);
6873 }
be010514
GM
6874
6875 if (!NILP (help))
6876 {
6877 help_echo = help;
7cea38bc 6878 help_echo_window = window;
743934db 6879 help_echo_object = overlay;
be010514
GM
6880 help_echo_pos = pos;
6881 }
6882 else
6883 {
6884 /* Try text properties. */
6885 if ((STRINGP (glyph->object)
06a2c219
GM
6886 && glyph->charpos >= 0
6887 && glyph->charpos < XSTRING (glyph->object)->size)
6888 || (BUFFERP (glyph->object)
6889 && glyph->charpos >= BEGV
be010514
GM
6890 && glyph->charpos < ZV))
6891 help = Fget_text_property (make_number (glyph->charpos),
6892 Qhelp_echo, glyph->object);
06a2c219 6893
be010514
GM
6894 if (!NILP (help))
6895 {
6896 help_echo = help;
7cea38bc 6897 help_echo_window = window;
be010514
GM
6898 help_echo_object = glyph->object;
6899 help_echo_pos = glyph->charpos;
6900 }
6901 }
06a2c219
GM
6902 }
6903
6904 BEGV = obegv;
6905 ZV = ozv;
6906 current_buffer = obuf;
6907 }
6908 }
6909}
6910
6911static void
6912redo_mouse_highlight ()
6913{
6914 if (!NILP (last_mouse_motion_frame)
6915 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
6916 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
6917 last_mouse_motion_event.x,
6918 last_mouse_motion_event.y);
6919}
6920
6921
6922\f
6923/***********************************************************************
9ea173e8 6924 Tool-bars
06a2c219
GM
6925 ***********************************************************************/
6926
9ea173e8
GM
6927static int x_tool_bar_item P_ ((struct frame *, int, int,
6928 struct glyph **, int *, int *, int *));
06a2c219 6929
9ea173e8 6930/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
6931 or -1. */
6932
9ea173e8 6933static int last_tool_bar_item;
06a2c219
GM
6934
6935
9ea173e8
GM
6936/* Get information about the tool-bar item at position X/Y on frame F.
6937 Return in *GLYPH a pointer to the glyph of the tool-bar item in
6938 the current matrix of the tool-bar window of F, or NULL if not
6939 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
8daf1204 6940 item in F->tool_bar_items. Value is
06a2c219 6941
9ea173e8 6942 -1 if X/Y is not on a tool-bar item
06a2c219
GM
6943 0 if X/Y is on the same item that was highlighted before.
6944 1 otherwise. */
6945
6946static int
9ea173e8 6947x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
6948 struct frame *f;
6949 int x, y;
6950 struct glyph **glyph;
6951 int *hpos, *vpos, *prop_idx;
6952{
6953 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6954 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6955 int area;
6956
6957 /* Find the glyph under X/Y. */
6958 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area);
6959 if (*glyph == NULL)
6960 return -1;
6961
9ea173e8 6962 /* Get the start of this tool-bar item's properties in
8daf1204 6963 f->tool_bar_items. */
9ea173e8 6964 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
6965 return -1;
6966
6967 /* Is mouse on the highlighted item? */
9ea173e8 6968 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
6969 && *vpos >= dpyinfo->mouse_face_beg_row
6970 && *vpos <= dpyinfo->mouse_face_end_row
6971 && (*vpos > dpyinfo->mouse_face_beg_row
6972 || *hpos >= dpyinfo->mouse_face_beg_col)
6973 && (*vpos < dpyinfo->mouse_face_end_row
6974 || *hpos < dpyinfo->mouse_face_end_col
6975 || dpyinfo->mouse_face_past_end))
6976 return 0;
6977
6978 return 1;
6979}
6980
6981
9ea173e8 6982/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
6983 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
6984 or ButtonRelase. */
6985
6986static void
9ea173e8 6987x_handle_tool_bar_click (f, button_event)
06a2c219
GM
6988 struct frame *f;
6989 XButtonEvent *button_event;
6990{
6991 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 6992 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
6993 int hpos, vpos, prop_idx;
6994 struct glyph *glyph;
6995 Lisp_Object enabled_p;
6996 int x = button_event->x;
6997 int y = button_event->y;
6998
9ea173e8 6999 /* If not on the highlighted tool-bar item, return. */
06a2c219 7000 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 7001 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
7002 return;
7003
7004 /* If item is disabled, do nothing. */
8daf1204 7005 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7006 if (NILP (enabled_p))
7007 return;
7008
7009 if (button_event->type == ButtonPress)
7010 {
7011 /* Show item in pressed state. */
7012 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
7013 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 7014 last_tool_bar_item = prop_idx;
06a2c219
GM
7015 }
7016 else
7017 {
7018 Lisp_Object key, frame;
7019 struct input_event event;
7020
7021 /* Show item in released state. */
7022 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
7023 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
7024
8daf1204 7025 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
06a2c219
GM
7026
7027 XSETFRAME (frame, f);
9ea173e8 7028 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7029 event.frame_or_window = frame;
7030 event.arg = frame;
06a2c219
GM
7031 kbd_buffer_store_event (&event);
7032
9ea173e8 7033 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7034 event.frame_or_window = frame;
7035 event.arg = key;
06a2c219
GM
7036 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7037 button_event->state);
7038 kbd_buffer_store_event (&event);
9ea173e8 7039 last_tool_bar_item = -1;
06a2c219
GM
7040 }
7041}
7042
7043
9ea173e8
GM
7044/* Possibly highlight a tool-bar item on frame F when mouse moves to
7045 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
7046 note_mouse_highlight. */
7047
7048static void
9ea173e8 7049note_tool_bar_highlight (f, x, y)
06a2c219
GM
7050 struct frame *f;
7051 int x, y;
7052{
9ea173e8 7053 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
7054 struct window *w = XWINDOW (window);
7055 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7056 int hpos, vpos;
7057 struct glyph *glyph;
7058 struct glyph_row *row;
5c187dee 7059 int i;
06a2c219
GM
7060 Lisp_Object enabled_p;
7061 int prop_idx;
7062 enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
5c187dee 7063 int mouse_down_p, rc;
06a2c219
GM
7064
7065 /* Function note_mouse_highlight is called with negative x(y
7066 values when mouse moves outside of the frame. */
7067 if (x <= 0 || y <= 0)
7068 {
7069 clear_mouse_face (dpyinfo);
7070 return;
7071 }
7072
9ea173e8 7073 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
7074 if (rc < 0)
7075 {
9ea173e8 7076 /* Not on tool-bar item. */
06a2c219
GM
7077 clear_mouse_face (dpyinfo);
7078 return;
7079 }
7080 else if (rc == 0)
9ea173e8 7081 /* On same tool-bar item as before. */
06a2c219 7082 goto set_help_echo;
b8009dd1 7083
06a2c219
GM
7084 clear_mouse_face (dpyinfo);
7085
9ea173e8 7086 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
7087 mouse_down_p = (dpyinfo->grabbed
7088 && f == last_mouse_frame
7089 && FRAME_LIVE_P (f));
7090 if (mouse_down_p
9ea173e8 7091 && last_tool_bar_item != prop_idx)
06a2c219
GM
7092 return;
7093
7094 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7095 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7096
9ea173e8 7097 /* If tool-bar item is not enabled, don't highlight it. */
8daf1204 7098 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7099 if (!NILP (enabled_p))
7100 {
7101 /* Compute the x-position of the glyph. In front and past the
7102 image is a space. We include this is the highlighted area. */
7103 row = MATRIX_ROW (w->current_matrix, vpos);
7104 for (i = x = 0; i < hpos; ++i)
7105 x += row->glyphs[TEXT_AREA][i].pixel_width;
7106
7107 /* Record this as the current active region. */
7108 dpyinfo->mouse_face_beg_col = hpos;
7109 dpyinfo->mouse_face_beg_row = vpos;
7110 dpyinfo->mouse_face_beg_x = x;
7111 dpyinfo->mouse_face_beg_y = row->y;
7112 dpyinfo->mouse_face_past_end = 0;
7113
7114 dpyinfo->mouse_face_end_col = hpos + 1;
7115 dpyinfo->mouse_face_end_row = vpos;
7116 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7117 dpyinfo->mouse_face_end_y = row->y;
7118 dpyinfo->mouse_face_window = window;
9ea173e8 7119 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
7120
7121 /* Display it as active. */
7122 show_mouse_face (dpyinfo, draw);
7123 dpyinfo->mouse_face_image_state = draw;
b8009dd1 7124 }
06a2c219
GM
7125
7126 set_help_echo:
7127
9ea173e8 7128 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 7129 XTread_socket does the rest. */
7cea38bc 7130 help_echo_object = help_echo_window = Qnil;
be010514 7131 help_echo_pos = -1;
8daf1204 7132 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
b7e80413 7133 if (NILP (help_echo))
8daf1204 7134 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
b8009dd1 7135}
4d73d038 7136
06a2c219
GM
7137
7138\f
7139/* Find the glyph matrix position of buffer position POS in window W.
7140 *HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7141 current glyphs must be up to date. If POS is above window start
7142 return (0, 0, 0, 0). If POS is after end of W, return end of
7143 last line in W. */
b8009dd1
RS
7144
7145static int
06a2c219
GM
7146fast_find_position (w, pos, hpos, vpos, x, y)
7147 struct window *w;
b8009dd1 7148 int pos;
06a2c219 7149 int *hpos, *vpos, *x, *y;
b8009dd1 7150{
b8009dd1 7151 int i;
bf1c0ba1 7152 int lastcol;
06a2c219
GM
7153 int maybe_next_line_p = 0;
7154 int line_start_position;
7155 int yb = window_text_bottom_y (w);
7156 struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
7157 struct glyph_row *best_row = row;
7158 int row_vpos = 0, best_row_vpos = 0;
7159 int current_x;
7160
7161 while (row->y < yb)
b8009dd1 7162 {
06a2c219
GM
7163 if (row->used[TEXT_AREA])
7164 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7165 else
7166 line_start_position = 0;
7167
7168 if (line_start_position > pos)
b8009dd1 7169 break;
77b68646
RS
7170 /* If the position sought is the end of the buffer,
7171 don't include the blank lines at the bottom of the window. */
06a2c219
GM
7172 else if (line_start_position == pos
7173 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 7174 {
06a2c219 7175 maybe_next_line_p = 1;
77b68646
RS
7176 break;
7177 }
06a2c219
GM
7178 else if (line_start_position > 0)
7179 {
7180 best_row = row;
7181 best_row_vpos = row_vpos;
7182 }
4b0bb6f3
GM
7183
7184 if (row->y + row->height >= yb)
7185 break;
06a2c219
GM
7186
7187 ++row;
7188 ++row_vpos;
b8009dd1 7189 }
06a2c219
GM
7190
7191 /* Find the right column within BEST_ROW. */
7192 lastcol = 0;
7193 current_x = best_row->x;
7194 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 7195 {
06a2c219
GM
7196 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7197 int charpos;
7198
7199 charpos = glyph->charpos;
7200 if (charpos == pos)
bf1c0ba1 7201 {
06a2c219
GM
7202 *hpos = i;
7203 *vpos = best_row_vpos;
7204 *x = current_x;
7205 *y = best_row->y;
bf1c0ba1
RS
7206 return 1;
7207 }
06a2c219 7208 else if (charpos > pos)
4d73d038 7209 break;
06a2c219
GM
7210 else if (charpos > 0)
7211 lastcol = i;
7212
7213 current_x += glyph->pixel_width;
bf1c0ba1 7214 }
b8009dd1 7215
77b68646
RS
7216 /* If we're looking for the end of the buffer,
7217 and we didn't find it in the line we scanned,
7218 use the start of the following line. */
06a2c219 7219 if (maybe_next_line_p)
77b68646 7220 {
06a2c219
GM
7221 ++best_row;
7222 ++best_row_vpos;
7223 lastcol = 0;
7224 current_x = best_row->x;
77b68646
RS
7225 }
7226
06a2c219
GM
7227 *vpos = best_row_vpos;
7228 *hpos = lastcol + 1;
7229 *x = current_x;
7230 *y = best_row->y;
b8009dd1
RS
7231 return 0;
7232}
7233
06a2c219 7234
b8009dd1
RS
7235/* Display the active region described by mouse_face_*
7236 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7237
7238static void
06a2c219 7239show_mouse_face (dpyinfo, draw)
7a13e894 7240 struct x_display_info *dpyinfo;
06a2c219 7241 enum draw_glyphs_face draw;
b8009dd1 7242{
7a13e894 7243 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7244 struct frame *f = XFRAME (WINDOW_FRAME (w));
b8009dd1 7245 int i;
06a2c219
GM
7246 int cursor_off_p = 0;
7247 struct cursor_pos saved_cursor;
7248
7249 saved_cursor = output_cursor;
7250
7251 /* If window is in the process of being destroyed, don't bother
7252 to do anything. */
7253 if (w->current_matrix == NULL)
7254 goto set_x_cursor;
7255
7256 /* Recognize when we are called to operate on rows that don't exist
7257 anymore. This can happen when a window is split. */
7258 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
7259 goto set_x_cursor;
7260
7261 set_output_cursor (&w->phys_cursor);
7262
7263 /* Note that mouse_face_beg_row etc. are window relative. */
7264 for (i = dpyinfo->mouse_face_beg_row;
7265 i <= dpyinfo->mouse_face_end_row;
7266 i++)
7267 {
7268 int start_hpos, end_hpos, start_x;
7269 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
7270
7271 /* Don't do anything if row doesn't have valid contents. */
7272 if (!row->enabled_p)
7273 continue;
7274
7275 /* For all but the first row, the highlight starts at column 0. */
7276 if (i == dpyinfo->mouse_face_beg_row)
7277 {
7278 start_hpos = dpyinfo->mouse_face_beg_col;
7279 start_x = dpyinfo->mouse_face_beg_x;
7280 }
7281 else
7282 {
7283 start_hpos = 0;
7284 start_x = 0;
7285 }
7286
7287 if (i == dpyinfo->mouse_face_end_row)
7288 end_hpos = dpyinfo->mouse_face_end_col;
7289 else
7290 end_hpos = row->used[TEXT_AREA];
7291
7292 /* If the cursor's in the text we are about to rewrite, turn the
7293 cursor off. */
7294 if (!w->pseudo_window_p
7295 && i == output_cursor.vpos
7296 && output_cursor.hpos >= start_hpos - 1
7297 && output_cursor.hpos <= end_hpos)
514e4681 7298 {
06a2c219
GM
7299 x_update_window_cursor (w, 0);
7300 cursor_off_p = 1;
514e4681 7301 }
b8009dd1 7302
06a2c219 7303 if (end_hpos > start_hpos)
64f26cf5
GM
7304 {
7305 row->mouse_face_p = draw == DRAW_MOUSE_FACE;
7306 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7307 start_hpos, end_hpos, draw, NULL, NULL, 0);
7308 }
b8009dd1
RS
7309 }
7310
514e4681 7311 /* If we turned the cursor off, turn it back on. */
06a2c219
GM
7312 if (cursor_off_p)
7313 x_display_cursor (w, 1,
7314 output_cursor.hpos, output_cursor.vpos,
7315 output_cursor.x, output_cursor.y);
2729a2b5 7316
06a2c219 7317 output_cursor = saved_cursor;
fb3b7de5 7318
06a2c219
GM
7319 set_x_cursor:
7320
7321 /* Change the mouse cursor. */
7322 if (draw == DRAW_NORMAL_TEXT)
7323 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7324 f->output_data.x->text_cursor);
7325 else if (draw == DRAW_MOUSE_FACE)
334208b7 7326 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7327 f->output_data.x->cross_cursor);
27ead1d5 7328 else
334208b7 7329 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7330 f->output_data.x->nontext_cursor);
b8009dd1
RS
7331}
7332
7333/* Clear out the mouse-highlighted active region.
06a2c219 7334 Redraw it un-highlighted first. */
b8009dd1 7335
06a2c219 7336void
7a13e894
RS
7337clear_mouse_face (dpyinfo)
7338 struct x_display_info *dpyinfo;
b8009dd1 7339{
607d9f9f
GM
7340#if 0 /* This prevents redrawing tool bar items when changing from one
7341 to another while a tooltip is open, so don't do it. */
685f4368 7342 if (!NILP (tip_frame))
06a2c219 7343 return;
7948d50a 7344#endif
06a2c219 7345
7a13e894 7346 if (! NILP (dpyinfo->mouse_face_window))
06a2c219 7347 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
b8009dd1 7348
7a13e894
RS
7349 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7350 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7351 dpyinfo->mouse_face_window = Qnil;
b8009dd1 7352}
e687d06e 7353
71b8321e
GM
7354
7355/* Clear any mouse-face on window W. This function is part of the
7356 redisplay interface, and is called from try_window_id and similar
7357 functions to ensure the mouse-highlight is off. */
7358
7359static void
7360x_clear_mouse_face (w)
7361 struct window *w;
7362{
7363 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7364 Lisp_Object window;
7365
2e636f9d 7366 BLOCK_INPUT;
71b8321e
GM
7367 XSETWINDOW (window, w);
7368 if (EQ (window, dpyinfo->mouse_face_window))
7369 clear_mouse_face (dpyinfo);
2e636f9d 7370 UNBLOCK_INPUT;
71b8321e
GM
7371}
7372
7373
e687d06e
RS
7374/* Just discard the mouse face information for frame F, if any.
7375 This is used when the size of F is changed. */
7376
dfcf069d 7377void
e687d06e
RS
7378cancel_mouse_face (f)
7379 FRAME_PTR f;
7380{
7381 Lisp_Object window;
7382 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7383
7384 window = dpyinfo->mouse_face_window;
7385 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7386 {
7387 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7388 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7389 dpyinfo->mouse_face_window = Qnil;
7390 }
7391}
b52b65bd 7392
b8009dd1 7393\f
b52b65bd
GM
7394static int glyph_rect P_ ((struct frame *f, int, int, XRectangle *));
7395
7396
7397/* Try to determine frame pixel position and size of the glyph under
7398 frame pixel coordinates X/Y on frame F . Return the position and
7399 size in *RECT. Value is non-zero if we could compute these
7400 values. */
7401
7402static int
7403glyph_rect (f, x, y, rect)
7404 struct frame *f;
7405 int x, y;
7406 XRectangle *rect;
7407{
7408 Lisp_Object window;
7409 int part, found = 0;
7410
7411 window = window_from_coordinates (f, x, y, &part, 0);
7412 if (!NILP (window))
7413 {
7414 struct window *w = XWINDOW (window);
7415 struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7416 struct glyph_row *end = r + w->current_matrix->nrows - 1;
7417 int area;
7418
7419 frame_to_window_pixel_xy (w, &x, &y);
7420
7421 for (; !found && r < end && r->enabled_p; ++r)
7422 if (r->y >= y)
7423 {
7424 struct glyph *g = r->glyphs[TEXT_AREA];
7425 struct glyph *end = g + r->used[TEXT_AREA];
7426 int gx;
7427
7428 for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
7429 if (gx >= x)
7430 {
7431 rect->width = g->pixel_width;
7432 rect->height = r->height;
7433 rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
7434 rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
7435 found = 1;
7436 }
7437 }
7438 }
7439
7440 return found;
7441}
7442
12ba150f 7443
90e65f07 7444/* Return the current position of the mouse.
b52b65bd 7445 *FP should be a frame which indicates which display to ask about.
90e65f07 7446
b52b65bd
GM
7447 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
7448 and *PART to the frame, window, and scroll bar part that the mouse
7449 is over. Set *X and *Y to the portion and whole of the mouse's
ab648270 7450 position on the scroll bar.
12ba150f 7451
b52b65bd
GM
7452 If the mouse movement started elsewhere, set *FP to the frame the
7453 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
12ba150f
JB
7454 the mouse is over.
7455
b52b65bd 7456 Set *TIME to the server time-stamp for the time at which the mouse
12ba150f
JB
7457 was at this position.
7458
a135645a
RS
7459 Don't store anything if we don't have a valid set of values to report.
7460
90e65f07 7461 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7462 movement. */
90e65f07
JB
7463
7464static void
1cf412ec 7465XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7466 FRAME_PTR *fp;
1cf412ec 7467 int insist;
12ba150f 7468 Lisp_Object *bar_window;
ab648270 7469 enum scroll_bar_part *part;
90e65f07 7470 Lisp_Object *x, *y;
e5d77022 7471 unsigned long *time;
90e65f07 7472{
a135645a
RS
7473 FRAME_PTR f1;
7474
90e65f07
JB
7475 BLOCK_INPUT;
7476
8bcee03e 7477 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7478 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7479 else
7480 {
12ba150f
JB
7481 Window root;
7482 int root_x, root_y;
90e65f07 7483
12ba150f
JB
7484 Window dummy_window;
7485 int dummy;
7486
39d8bb4d
KH
7487 Lisp_Object frame, tail;
7488
7489 /* Clear the mouse-moved flag for every frame on this display. */
7490 FOR_EACH_FRAME (tail, frame)
7491 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7492 XFRAME (frame)->mouse_moved = 0;
7493
ab648270 7494 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7495
7496 /* Figure out which root window we're on. */
334208b7
RS
7497 XQueryPointer (FRAME_X_DISPLAY (*fp),
7498 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7499
7500 /* The root window which contains the pointer. */
7501 &root,
7502
7503 /* Trash which we can't trust if the pointer is on
7504 a different screen. */
7505 &dummy_window,
7506
7507 /* The position on that root window. */
58769bee 7508 &root_x, &root_y,
12ba150f
JB
7509
7510 /* More trash we can't trust. */
7511 &dummy, &dummy,
7512
7513 /* Modifier keys and pointer buttons, about which
7514 we don't care. */
7515 (unsigned int *) &dummy);
7516
7517 /* Now we have a position on the root; find the innermost window
7518 containing the pointer. */
7519 {
7520 Window win, child;
7521 int win_x, win_y;
06a2c219 7522 int parent_x = 0, parent_y = 0;
e99db5a1 7523 int count;
12ba150f
JB
7524
7525 win = root;
69388238 7526
2d7fc7e8
RS
7527 /* XTranslateCoordinates can get errors if the window
7528 structure is changing at the same time this function
7529 is running. So at least we must not crash from them. */
7530
e99db5a1 7531 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 7532
334208b7 7533 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 7534 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 7535 {
69388238
RS
7536 /* If mouse was grabbed on a frame, give coords for that frame
7537 even if the mouse is now outside it. */
334208b7 7538 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 7539
12ba150f 7540 /* From-window, to-window. */
69388238 7541 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
7542
7543 /* From-position, to-position. */
7544 root_x, root_y, &win_x, &win_y,
7545
7546 /* Child of win. */
7547 &child);
69388238
RS
7548 f1 = last_mouse_frame;
7549 }
7550 else
7551 {
7552 while (1)
7553 {
334208b7 7554 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 7555
69388238
RS
7556 /* From-window, to-window. */
7557 root, win,
12ba150f 7558
69388238
RS
7559 /* From-position, to-position. */
7560 root_x, root_y, &win_x, &win_y,
7561
7562 /* Child of win. */
7563 &child);
7564
9af3143a 7565 if (child == None || child == win)
69388238
RS
7566 break;
7567
7568 win = child;
7569 parent_x = win_x;
7570 parent_y = win_y;
7571 }
12ba150f 7572
69388238
RS
7573 /* Now we know that:
7574 win is the innermost window containing the pointer
7575 (XTC says it has no child containing the pointer),
7576 win_x and win_y are the pointer's position in it
7577 (XTC did this the last time through), and
7578 parent_x and parent_y are the pointer's position in win's parent.
7579 (They are what win_x and win_y were when win was child.
7580 If win is the root window, it has no parent, and
7581 parent_{x,y} are invalid, but that's okay, because we'll
7582 never use them in that case.) */
7583
7584 /* Is win one of our frames? */
19126e11 7585 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
aad0f6ab
GM
7586
7587#ifdef USE_X_TOOLKIT
7588 /* If we end up with the menu bar window, say it's not
7589 on the frame. */
7590 if (f1 != NULL
7591 && f1->output_data.x->menubar_widget
7592 && win == XtWindow (f1->output_data.x->menubar_widget))
7593 f1 = NULL;
7594#endif /* USE_X_TOOLKIT */
69388238 7595 }
58769bee 7596
2d7fc7e8
RS
7597 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
7598 f1 = 0;
7599
e99db5a1 7600 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 7601
ab648270 7602 /* If not, is it one of our scroll bars? */
a135645a 7603 if (! f1)
12ba150f 7604 {
ab648270 7605 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
7606
7607 if (bar)
7608 {
a135645a 7609 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
7610 win_x = parent_x;
7611 win_y = parent_y;
7612 }
7613 }
90e65f07 7614
8bcee03e 7615 if (f1 == 0 && insist > 0)
b86bd3dd 7616 f1 = SELECTED_FRAME ();
1cf412ec 7617
a135645a 7618 if (f1)
12ba150f 7619 {
06a2c219
GM
7620 /* Ok, we found a frame. Store all the values.
7621 last_mouse_glyph is a rectangle used to reduce the
7622 generation of mouse events. To not miss any motion
7623 events, we must divide the frame into rectangles of the
7624 size of the smallest character that could be displayed
7625 on it, i.e. into the same rectangles that matrices on
7626 the frame are divided into. */
7627
b52b65bd
GM
7628 int width, height, gx, gy;
7629 XRectangle rect;
7630
7631 if (glyph_rect (f1, win_x, win_y, &rect))
7632 last_mouse_glyph = rect;
7633 else
7634 {
7635 width = FRAME_SMALLEST_CHAR_WIDTH (f1);
7636 height = FRAME_SMALLEST_FONT_HEIGHT (f1);
7637 gx = win_x;
7638 gy = win_y;
06a2c219 7639
b52b65bd
GM
7640 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
7641 round down even for negative values. */
7642 if (gx < 0)
7643 gx -= width - 1;
4f00e84d 7644 if (gy < 0)
b52b65bd
GM
7645 gy -= height - 1;
7646 gx = (gx + width - 1) / width * width;
7647 gy = (gy + height - 1) / height * height;
7648
7649 last_mouse_glyph.width = width;
7650 last_mouse_glyph.height = height;
7651 last_mouse_glyph.x = gx;
7652 last_mouse_glyph.y = gy;
7653 }
12ba150f
JB
7654
7655 *bar_window = Qnil;
7656 *part = 0;
334208b7 7657 *fp = f1;
e0c1aef2
KH
7658 XSETINT (*x, win_x);
7659 XSETINT (*y, win_y);
12ba150f
JB
7660 *time = last_mouse_movement_time;
7661 }
7662 }
7663 }
90e65f07
JB
7664
7665 UNBLOCK_INPUT;
7666}
f451eb13 7667
06a2c219 7668
06a2c219 7669#ifdef USE_X_TOOLKIT
bffcfca9
GM
7670
7671/* Atimer callback function for TIMER. Called every 0.1s to process
7672 Xt timeouts, if needed. We must avoid calling XtAppPending as
7673 much as possible because that function does an implicit XFlush
7674 that slows us down. */
7675
7676static void
7677x_process_timeouts (timer)
7678 struct atimer *timer;
7679{
7680 if (toolkit_scroll_bar_interaction || popup_activated_flag)
7681 {
7682 BLOCK_INPUT;
7683 while (XtAppPending (Xt_app_con) & XtIMTimer)
7684 XtAppProcessEvent (Xt_app_con, XtIMTimer);
7685 UNBLOCK_INPUT;
7686 }
06a2c219
GM
7687}
7688
bffcfca9 7689#endif /* USE_X_TOOLKIT */
06a2c219
GM
7690
7691\f
7692/* Scroll bar support. */
7693
7694/* Given an X window ID, find the struct scroll_bar which manages it.
7695 This can be called in GC, so we have to make sure to strip off mark
7696 bits. */
bffcfca9 7697
06a2c219
GM
7698static struct scroll_bar *
7699x_window_to_scroll_bar (window_id)
7700 Window window_id;
7701{
7702 Lisp_Object tail;
7703
7704 for (tail = Vframe_list;
7705 XGCTYPE (tail) == Lisp_Cons;
8e713be6 7706 tail = XCDR (tail))
06a2c219
GM
7707 {
7708 Lisp_Object frame, bar, condemned;
7709
8e713be6 7710 frame = XCAR (tail);
06a2c219
GM
7711 /* All elements of Vframe_list should be frames. */
7712 if (! GC_FRAMEP (frame))
7713 abort ();
7714
7715 /* Scan this frame's scroll bar list for a scroll bar with the
7716 right window ID. */
7717 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
7718 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
7719 /* This trick allows us to search both the ordinary and
7720 condemned scroll bar lists with one loop. */
7721 ! GC_NILP (bar) || (bar = condemned,
7722 condemned = Qnil,
7723 ! GC_NILP (bar));
7724 bar = XSCROLL_BAR (bar)->next)
7725 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
7726 return XSCROLL_BAR (bar);
7727 }
7728
7729 return 0;
7730}
7731
7732
7733\f
7734/************************************************************************
7735 Toolkit scroll bars
7736 ************************************************************************/
7737
eccc05db 7738#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
7739
7740static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
7741static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
7742static void x_create_toolkit_scroll_bar P_ ((struct frame *,
7743 struct scroll_bar *));
7744static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
7745 int, int, int));
7746
7747
7748/* Id of action hook installed for scroll bars. */
7749
7750static XtActionHookId action_hook_id;
7751
7752/* Lisp window being scrolled. Set when starting to interact with
7753 a toolkit scroll bar, reset to nil when ending the interaction. */
7754
7755static Lisp_Object window_being_scrolled;
7756
7757/* Last scroll bar part sent in xm_scroll_callback. */
7758
7759static int last_scroll_bar_part;
7760
ec18280f
SM
7761/* Whether this is an Xaw with arrow-scrollbars. This should imply
7762 that movements of 1/20 of the screen size are mapped to up/down. */
7763
7764static Boolean xaw3d_arrow_scroll;
7765
7766/* Whether the drag scrolling maintains the mouse at the top of the
7767 thumb. If not, resizing the thumb needs to be done more carefully
7768 to avoid jerkyness. */
7769
7770static Boolean xaw3d_pick_top;
7771
06a2c219
GM
7772
7773/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 7774 bars are used.. The hook is responsible for detecting when
06a2c219
GM
7775 the user ends an interaction with the scroll bar, and generates
7776 a `end-scroll' scroll_bar_click' event if so. */
7777
7778static void
7779xt_action_hook (widget, client_data, action_name, event, params,
7780 num_params)
7781 Widget widget;
7782 XtPointer client_data;
7783 String action_name;
7784 XEvent *event;
7785 String *params;
7786 Cardinal *num_params;
7787{
7788 int scroll_bar_p;
7789 char *end_action;
7790
7791#ifdef USE_MOTIF
7792 scroll_bar_p = XmIsScrollBar (widget);
7793 end_action = "Release";
ec18280f 7794#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
7795 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
7796 end_action = "EndScroll";
ec18280f 7797#endif /* USE_MOTIF */
06a2c219 7798
06a2c219
GM
7799 if (scroll_bar_p
7800 && strcmp (action_name, end_action) == 0
7801 && WINDOWP (window_being_scrolled))
7802 {
7803 struct window *w;
7804
7805 x_send_scroll_bar_event (window_being_scrolled,
7806 scroll_bar_end_scroll, 0, 0);
7807 w = XWINDOW (window_being_scrolled);
7808 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
7809 window_being_scrolled = Qnil;
7810 last_scroll_bar_part = -1;
bffcfca9
GM
7811
7812 /* Xt timeouts no longer needed. */
7813 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
7814 }
7815}
7816
07b3d16e
GM
7817/* A vector of windows used for communication between
7818 x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
7819
7820static struct window **scroll_bar_windows;
7821static int scroll_bar_windows_size;
7822
06a2c219
GM
7823
7824/* Send a client message with message type Xatom_Scrollbar for a
7825 scroll action to the frame of WINDOW. PART is a value identifying
7826 the part of the scroll bar that was clicked on. PORTION is the
7827 amount to scroll of a whole of WHOLE. */
7828
7829static void
7830x_send_scroll_bar_event (window, part, portion, whole)
7831 Lisp_Object window;
7832 int part, portion, whole;
7833{
7834 XEvent event;
7835 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
07b3d16e
GM
7836 struct window *w = XWINDOW (window);
7837 struct frame *f = XFRAME (w->frame);
7838 int i;
06a2c219 7839
07b3d16e
GM
7840 BLOCK_INPUT;
7841
06a2c219
GM
7842 /* Construct a ClientMessage event to send to the frame. */
7843 ev->type = ClientMessage;
7844 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
7845 ev->display = FRAME_X_DISPLAY (f);
7846 ev->window = FRAME_X_WINDOW (f);
7847 ev->format = 32;
07b3d16e
GM
7848
7849 /* We can only transfer 32 bits in the XClientMessageEvent, which is
7850 not enough to store a pointer or Lisp_Object on a 64 bit system.
7851 So, store the window in scroll_bar_windows and pass the index
7852 into that array in the event. */
7853 for (i = 0; i < scroll_bar_windows_size; ++i)
7854 if (scroll_bar_windows[i] == NULL)
7855 break;
7856
7857 if (i == scroll_bar_windows_size)
7858 {
7859 int new_size = max (10, 2 * scroll_bar_windows_size);
7860 size_t nbytes = new_size * sizeof *scroll_bar_windows;
7861 size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows;
7862
7863 scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
7864 nbytes);
7865 bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
7866 scroll_bar_windows_size = new_size;
7867 }
7868
7869 scroll_bar_windows[i] = w;
7870 ev->data.l[0] = (long) i;
06a2c219
GM
7871 ev->data.l[1] = (long) part;
7872 ev->data.l[2] = (long) 0;
7873 ev->data.l[3] = (long) portion;
7874 ev->data.l[4] = (long) whole;
7875
bffcfca9
GM
7876 /* Make Xt timeouts work while the scroll bar is active. */
7877 toolkit_scroll_bar_interaction = 1;
7878
06a2c219
GM
7879 /* Setting the event mask to zero means that the message will
7880 be sent to the client that created the window, and if that
7881 window no longer exists, no event will be sent. */
06a2c219
GM
7882 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
7883 UNBLOCK_INPUT;
7884}
7885
7886
7887/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
7888 in *IEVENT. */
7889
7890static void
7891x_scroll_bar_to_input_event (event, ievent)
7892 XEvent *event;
7893 struct input_event *ievent;
7894{
7895 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
7896 Lisp_Object window;
7897 struct frame *f;
07b3d16e
GM
7898 struct window *w;
7899
7900 w = scroll_bar_windows[ev->data.l[0]];
7901 scroll_bar_windows[ev->data.l[0]] = NULL;
52e386c2 7902
07b3d16e
GM
7903 XSETWINDOW (window, w);
7904 f = XFRAME (w->frame);
06a2c219
GM
7905
7906 ievent->kind = scroll_bar_click;
7907 ievent->frame_or_window = window;
0f8aabe9 7908 ievent->arg = Qnil;
06a2c219
GM
7909 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
7910 ievent->part = ev->data.l[1];
7911 ievent->code = ev->data.l[2];
7912 ievent->x = make_number ((int) ev->data.l[3]);
7913 ievent->y = make_number ((int) ev->data.l[4]);
7914 ievent->modifiers = 0;
7915}
7916
7917
7918#ifdef USE_MOTIF
7919
7920/* Minimum and maximum values used for Motif scroll bars. */
7921
7922#define XM_SB_MIN 1
7923#define XM_SB_MAX 10000000
7924#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
7925
7926
7927/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
7928 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
7929 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
7930
7931static void
7932xm_scroll_callback (widget, client_data, call_data)
7933 Widget widget;
7934 XtPointer client_data, call_data;
7935{
7936 struct scroll_bar *bar = (struct scroll_bar *) client_data;
7937 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
7938 double percent;
7939 int part = -1, whole = 0, portion = 0;
7940
7941 switch (cs->reason)
7942 {
7943 case XmCR_DECREMENT:
7944 bar->dragging = Qnil;
7945 part = scroll_bar_up_arrow;
7946 break;
7947
7948 case XmCR_INCREMENT:
7949 bar->dragging = Qnil;
7950 part = scroll_bar_down_arrow;
7951 break;
7952
7953 case XmCR_PAGE_DECREMENT:
7954 bar->dragging = Qnil;
7955 part = scroll_bar_above_handle;
7956 break;
7957
7958 case XmCR_PAGE_INCREMENT:
7959 bar->dragging = Qnil;
7960 part = scroll_bar_below_handle;
7961 break;
7962
7963 case XmCR_TO_TOP:
7964 bar->dragging = Qnil;
7965 part = scroll_bar_to_top;
7966 break;
7967
7968 case XmCR_TO_BOTTOM:
7969 bar->dragging = Qnil;
7970 part = scroll_bar_to_bottom;
7971 break;
7972
7973 case XmCR_DRAG:
7974 {
7975 int slider_size;
7976 int dragging_down_p = (INTEGERP (bar->dragging)
7977 && XINT (bar->dragging) <= cs->value);
7978
7979 /* Get the slider size. */
7980 BLOCK_INPUT;
7981 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
7982 UNBLOCK_INPUT;
7983
7984 /* At the max position of the scroll bar, do a line-wise
7985 movement. Without doing anything, the LessTif scroll bar
7986 calls us with the same cs->value again and again. If we
7987 want to make sure that we can reach the end of the buffer,
7988 we have to do something.
7989
7990 Implementation note: setting bar->dragging always to
7991 cs->value gives a smoother movement at the max position.
7992 Setting it to nil when doing line-wise movement gives
7993 a better slider behavior. */
7994
7995 if (cs->value + slider_size == XM_SB_MAX
7996 || (dragging_down_p
7997 && last_scroll_bar_part == scroll_bar_down_arrow))
7998 {
7999 part = scroll_bar_down_arrow;
8000 bar->dragging = Qnil;
8001 }
8002 else
8003 {
8004 whole = XM_SB_RANGE;
8005 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
8006 part = scroll_bar_handle;
8007 bar->dragging = make_number (cs->value);
8008 }
8009 }
8010 break;
8011
8012 case XmCR_VALUE_CHANGED:
8013 break;
8014 };
8015
8016 if (part >= 0)
8017 {
8018 window_being_scrolled = bar->window;
8019 last_scroll_bar_part = part;
8020 x_send_scroll_bar_event (bar->window, part, portion, whole);
8021 }
8022}
8023
8024
ec18280f 8025#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
8026
8027
ec18280f 8028/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
8029 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
8030 scroll bar struct. CALL_DATA is a pointer to a float saying where
8031 the thumb is. */
8032
8033static void
ec18280f 8034xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
8035 Widget widget;
8036 XtPointer client_data, call_data;
8037{
8038 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8039 float top = *(float *) call_data;
8040 float shown;
ec18280f
SM
8041 int whole, portion, height;
8042 int part;
06a2c219
GM
8043
8044 /* Get the size of the thumb, a value between 0 and 1. */
8045 BLOCK_INPUT;
ec18280f 8046 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
8047 UNBLOCK_INPUT;
8048
8049 whole = 10000000;
8050 portion = shown < 1 ? top * whole : 0;
06a2c219 8051
ec18280f
SM
8052 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
8053 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
8054 the bottom, so we force the scrolling whenever we see that we're
8055 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
8056 we try to ensure that we always stay two pixels away from the
8057 bottom). */
06a2c219
GM
8058 part = scroll_bar_down_arrow;
8059 else
8060 part = scroll_bar_handle;
8061
8062 window_being_scrolled = bar->window;
8063 bar->dragging = make_number (portion);
8064 last_scroll_bar_part = part;
8065 x_send_scroll_bar_event (bar->window, part, portion, whole);
8066}
8067
8068
ec18280f
SM
8069/* Xaw scroll bar callback. Invoked for incremental scrolling.,
8070 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
8071 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
8072 the scroll bar. CALL_DATA is an integer specifying the action that
8073 has taken place. It's magnitude is in the range 0..height of the
8074 scroll bar. Negative values mean scroll towards buffer start.
8075 Values < height of scroll bar mean line-wise movement. */
8076
8077static void
ec18280f 8078xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
8079 Widget widget;
8080 XtPointer client_data, call_data;
8081{
8082 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8083 int position = (int) call_data;
8084 Dimension height;
8085 int part;
8086
8087 /* Get the height of the scroll bar. */
8088 BLOCK_INPUT;
8089 XtVaGetValues (widget, XtNheight, &height, NULL);
8090 UNBLOCK_INPUT;
8091
ec18280f
SM
8092 if (abs (position) >= height)
8093 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
8094
8095 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
8096 it maps line-movement to call_data = max(5, height/20). */
8097 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
8098 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 8099 else
ec18280f 8100 part = scroll_bar_move_ratio;
06a2c219
GM
8101
8102 window_being_scrolled = bar->window;
8103 bar->dragging = Qnil;
8104 last_scroll_bar_part = part;
ec18280f 8105 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
8106}
8107
8108
8109#endif /* not USE_MOTIF */
8110
8111
8112/* Create the widget for scroll bar BAR on frame F. Record the widget
8113 and X window of the scroll bar in BAR. */
8114
8115static void
8116x_create_toolkit_scroll_bar (f, bar)
8117 struct frame *f;
8118 struct scroll_bar *bar;
8119{
8120 Window xwindow;
8121 Widget widget;
8122 Arg av[20];
8123 int ac = 0;
8124 char *scroll_bar_name = "verticalScrollBar";
8125 unsigned long pixel;
8126
8127 BLOCK_INPUT;
8128
8129#ifdef USE_MOTIF
8130 /* LessTif 0.85, problems:
8131
8132 1. When the mouse if over the scroll bar, the scroll bar will
8133 get keyboard events. I didn't find a way to turn this off.
8134
8135 2. Do we have to explicitly set the cursor to get an arrow
8136 cursor (see below)? */
8137
8138 /* Set resources. Create the widget. */
8139 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8140 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
8141 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
8142 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
8143 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
8144 XtSetArg (av[ac], XmNincrement, 1); ++ac;
8145 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
8146
8147 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8148 if (pixel != -1)
8149 {
8150 XtSetArg (av[ac], XmNforeground, pixel);
8151 ++ac;
8152 }
8153
8154 pixel = f->output_data.x->scroll_bar_background_pixel;
8155 if (pixel != -1)
8156 {
8157 XtSetArg (av[ac], XmNbackground, pixel);
8158 ++ac;
8159 }
8160
8161 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
8162 scroll_bar_name, av, ac);
8163
8164 /* Add one callback for everything that can happen. */
8165 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
8166 (XtPointer) bar);
8167 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
8168 (XtPointer) bar);
8169 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
8170 (XtPointer) bar);
8171 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
8172 (XtPointer) bar);
8173 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
8174 (XtPointer) bar);
8175 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
8176 (XtPointer) bar);
8177 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
8178 (XtPointer) bar);
8179
8180 /* Realize the widget. Only after that is the X window created. */
8181 XtRealizeWidget (widget);
8182
8183 /* Set the cursor to an arrow. I didn't find a resource to do that.
8184 And I'm wondering why it hasn't an arrow cursor by default. */
8185 XDefineCursor (XtDisplay (widget), XtWindow (widget),
8186 f->output_data.x->nontext_cursor);
8187
ec18280f 8188#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8189
8190 /* Set resources. Create the widget. The background of the
8191 Xaw3d scroll bar widget is a little bit light for my taste.
8192 We don't alter it here to let users change it according
8193 to their taste with `emacs*verticalScrollBar.background: xxx'. */
8194 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8195 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
8196 /* For smoother scrolling with Xaw3d -sm */
8197 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
8198 /* XtSetArg (av[ac], XtNbeNiceToColormap, True); ++ac; */
06a2c219
GM
8199
8200 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8201 if (pixel != -1)
8202 {
8203 XtSetArg (av[ac], XtNforeground, pixel);
8204 ++ac;
8205 }
8206
8207 pixel = f->output_data.x->scroll_bar_background_pixel;
8208 if (pixel != -1)
8209 {
8210 XtSetArg (av[ac], XtNbackground, pixel);
8211 ++ac;
8212 }
8213
8214 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
8215 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
8216
8217 {
8218 char *initial = "";
8219 char *val = initial;
8220 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
8221 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
8222 if (val == initial)
8223 { /* ARROW_SCROLL */
8224 xaw3d_arrow_scroll = True;
8225 /* Isn't that just a personal preference ? -sm */
8226 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
8227 }
8228 }
06a2c219
GM
8229
8230 /* Define callbacks. */
ec18280f
SM
8231 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
8232 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
8233 (XtPointer) bar);
8234
8235 /* Realize the widget. Only after that is the X window created. */
8236 XtRealizeWidget (widget);
8237
ec18280f 8238#endif /* !USE_MOTIF */
06a2c219
GM
8239
8240 /* Install an action hook that let's us detect when the user
8241 finishes interacting with a scroll bar. */
8242 if (action_hook_id == 0)
8243 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
8244
8245 /* Remember X window and widget in the scroll bar vector. */
8246 SET_SCROLL_BAR_X_WIDGET (bar, widget);
8247 xwindow = XtWindow (widget);
8248 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
8249
8250 UNBLOCK_INPUT;
8251}
8252
8253
8254/* Set the thumb size and position of scroll bar BAR. We are currently
8255 displaying PORTION out of a whole WHOLE, and our position POSITION. */
8256
8257static void
8258x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
8259 struct scroll_bar *bar;
8260 int portion, position, whole;
f451eb13 8261{
e83dc917
GM
8262 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8263 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
06a2c219 8264 float top, shown;
f451eb13 8265
06a2c219
GM
8266 if (whole == 0)
8267 top = 0, shown = 1;
8268 else
f451eb13 8269 {
06a2c219
GM
8270 top = (float) position / whole;
8271 shown = (float) portion / whole;
8272 }
f451eb13 8273
06a2c219 8274 BLOCK_INPUT;
f451eb13 8275
06a2c219
GM
8276#ifdef USE_MOTIF
8277 {
8278 int size, value;
8279 Boolean arrow1_selected, arrow2_selected;
8280 unsigned char flags;
8281 XmScrollBarWidget sb;
8282
ec18280f 8283 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
8284 is the scroll bar's maximum and MIN is the scroll bar's minimum
8285 value. */
8286 size = shown * XM_SB_RANGE;
8287 size = min (size, XM_SB_RANGE);
8288 size = max (size, 1);
8289
8290 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
8291 value = top * XM_SB_RANGE;
8292 value = min (value, XM_SB_MAX - size);
8293 value = max (value, XM_SB_MIN);
8294
8295 /* LessTif: Calling XmScrollBarSetValues after an increment or
8296 decrement turns off auto-repeat LessTif-internally. This can
8297 be seen in ScrollBar.c which resets Arrow1Selected and
8298 Arrow2Selected. It also sets internal flags so that LessTif
8299 believes the mouse is in the slider. We either have to change
8300 our code, or work around that by accessing private data. */
8301
8302 sb = (XmScrollBarWidget) widget;
8303 arrow1_selected = sb->scrollBar.arrow1_selected;
8304 arrow2_selected = sb->scrollBar.arrow2_selected;
8305 flags = sb->scrollBar.flags;
8306
8307 if (NILP (bar->dragging))
8308 XmScrollBarSetValues (widget, value, size, 0, 0, False);
8309 else if (last_scroll_bar_part == scroll_bar_down_arrow)
8310 /* This has the negative side effect that the slider value is
ec18280f 8311 not what it would be if we scrolled here using line-wise or
06a2c219
GM
8312 page-wise movement. */
8313 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
8314 else
8315 {
8316 /* If currently dragging, only update the slider size.
8317 This reduces flicker effects. */
8318 int old_value, old_size, increment, page_increment;
8319
8320 XmScrollBarGetValues (widget, &old_value, &old_size,
8321 &increment, &page_increment);
8322 XmScrollBarSetValues (widget, old_value,
8323 min (size, XM_SB_RANGE - old_value),
8324 0, 0, False);
8325 }
8326
8327 sb->scrollBar.arrow1_selected = arrow1_selected;
8328 sb->scrollBar.arrow2_selected = arrow2_selected;
8329 sb->scrollBar.flags = flags;
8330 }
ec18280f 8331#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 8332 {
ec18280f
SM
8333 float old_top, old_shown;
8334 Dimension height;
8335 XtVaGetValues (widget,
8336 XtNtopOfThumb, &old_top,
8337 XtNshown, &old_shown,
8338 XtNheight, &height,
8339 NULL);
8340
8341 /* Massage the top+shown values. */
8342 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8343 top = max (0, min (1, top));
8344 else
8345 top = old_top;
8346 /* Keep two pixels available for moving the thumb down. */
8347 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8348
8349 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8350 check that your system's configuration file contains a define
8351 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8352 if (top != old_top || shown != old_shown)
eb393530 8353 {
ec18280f 8354 if (NILP (bar->dragging))
eb393530 8355 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8356 else
8357 {
ec18280f
SM
8358#ifdef HAVE_XAW3D
8359 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8360 int scroll_mode = 0;
ec18280f
SM
8361
8362 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8363 if (xaw3d_arrow_scroll)
8364 {
8365 /* Xaw3d stupidly ignores resize requests while dragging
8366 so we have to make it believe it's not in dragging mode. */
8367 scroll_mode = sb->scrollbar.scroll_mode;
8368 if (scroll_mode == 2)
8369 sb->scrollbar.scroll_mode = 0;
8370 }
8371#endif
8372 /* Try to make the scrolling a tad smoother. */
8373 if (!xaw3d_pick_top)
8374 shown = min (shown, old_shown);
8375
8376 XawScrollbarSetThumb (widget, top, shown);
8377
8378#ifdef HAVE_XAW3D
8379 if (xaw3d_arrow_scroll && scroll_mode == 2)
8380 sb->scrollbar.scroll_mode = scroll_mode;
8381#endif
06a2c219 8382 }
06a2c219
GM
8383 }
8384 }
ec18280f 8385#endif /* !USE_MOTIF */
06a2c219
GM
8386
8387 UNBLOCK_INPUT;
f451eb13
JB
8388}
8389
06a2c219
GM
8390#endif /* USE_TOOLKIT_SCROLL_BARS */
8391
8392
8393\f
8394/************************************************************************
8395 Scroll bars, general
8396 ************************************************************************/
8397
8398/* Create a scroll bar and return the scroll bar vector for it. W is
8399 the Emacs window on which to create the scroll bar. TOP, LEFT,
8400 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8401 scroll bar. */
8402
ab648270 8403static struct scroll_bar *
06a2c219
GM
8404x_scroll_bar_create (w, top, left, width, height)
8405 struct window *w;
f451eb13
JB
8406 int top, left, width, height;
8407{
06a2c219 8408 struct frame *f = XFRAME (w->frame);
334208b7
RS
8409 struct scroll_bar *bar
8410 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8411
8412 BLOCK_INPUT;
8413
eccc05db 8414#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8415 x_create_toolkit_scroll_bar (f, bar);
8416#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8417 {
8418 XSetWindowAttributes a;
8419 unsigned long mask;
5c187dee 8420 Window window;
06a2c219
GM
8421
8422 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8423 if (a.background_pixel == -1)
8424 a.background_pixel = f->output_data.x->background_pixel;
8425
12ba150f 8426 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 8427 | ButtonMotionMask | PointerMotionHintMask
12ba150f 8428 | ExposureMask);
7a13e894 8429 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 8430
dbc4e1c1 8431 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8432
06a2c219
GM
8433 /* Clear the area of W that will serve as a scroll bar. This is
8434 for the case that a window has been split horizontally. In
8435 this case, no clear_frame is generated to reduce flickering. */
c5e6e06b
GM
8436 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8437 left, top, width,
8438 window_box_height (w), False);
06a2c219
GM
8439
8440 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8441 /* Position and size of scroll bar. */
8442 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8443 top,
8444 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8445 height,
8446 /* Border width, depth, class, and visual. */
8447 0,
8448 CopyFromParent,
8449 CopyFromParent,
8450 CopyFromParent,
8451 /* Attributes. */
8452 mask, &a);
8453 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 8454 }
06a2c219 8455#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8456
06a2c219 8457 XSETWINDOW (bar->window, w);
e0c1aef2
KH
8458 XSETINT (bar->top, top);
8459 XSETINT (bar->left, left);
8460 XSETINT (bar->width, width);
8461 XSETINT (bar->height, height);
8462 XSETINT (bar->start, 0);
8463 XSETINT (bar->end, 0);
12ba150f 8464 bar->dragging = Qnil;
f451eb13
JB
8465
8466 /* Add bar to its frame's list of scroll bars. */
334208b7 8467 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8468 bar->prev = Qnil;
334208b7 8469 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 8470 if (!NILP (bar->next))
e0c1aef2 8471 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 8472
06a2c219 8473 /* Map the window/widget. */
eccc05db 8474#ifdef USE_TOOLKIT_SCROLL_BARS
f964b4d7
GM
8475 {
8476 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
8477 XtConfigureWidget (scroll_bar,
8478 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8479 top,
8480 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8481 max (height, 1), 0);
8482 XtMapWidget (scroll_bar);
8483 }
06a2c219 8484#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 8485 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 8486#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8487
8488 UNBLOCK_INPUT;
12ba150f 8489 return bar;
f451eb13
JB
8490}
8491
06a2c219 8492
12ba150f 8493/* Draw BAR's handle in the proper position.
06a2c219 8494
12ba150f
JB
8495 If the handle is already drawn from START to END, don't bother
8496 redrawing it, unless REBUILD is non-zero; in that case, always
8497 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 8498 events.)
12ba150f
JB
8499
8500 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
8501 fit inside its rectangle, but if the user is dragging the scroll
8502 bar handle, we want to let them drag it down all the way, so that
8503 the bar's top is as far down as it goes; otherwise, there's no way
8504 to move to the very end of the buffer. */
8505
5c187dee
GM
8506#ifndef USE_TOOLKIT_SCROLL_BARS
8507
f451eb13 8508static void
ab648270
JB
8509x_scroll_bar_set_handle (bar, start, end, rebuild)
8510 struct scroll_bar *bar;
f451eb13 8511 int start, end;
12ba150f 8512 int rebuild;
f451eb13 8513{
12ba150f 8514 int dragging = ! NILP (bar->dragging);
ab648270 8515 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8516 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8517 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
8518
8519 /* If the display is already accurate, do nothing. */
8520 if (! rebuild
8521 && start == XINT (bar->start)
8522 && end == XINT (bar->end))
8523 return;
8524
f451eb13
JB
8525 BLOCK_INPUT;
8526
8527 {
d9cdbb3d
RS
8528 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
8529 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
8530 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
8531
8532 /* Make sure the values are reasonable, and try to preserve
8533 the distance between start and end. */
12ba150f
JB
8534 {
8535 int length = end - start;
8536
8537 if (start < 0)
8538 start = 0;
8539 else if (start > top_range)
8540 start = top_range;
8541 end = start + length;
8542
8543 if (end < start)
8544 end = start;
8545 else if (end > top_range && ! dragging)
8546 end = top_range;
8547 }
f451eb13 8548
ab648270 8549 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
8550 XSETINT (bar->start, start);
8551 XSETINT (bar->end, end);
f451eb13 8552
12ba150f
JB
8553 /* Clip the end position, just for display. */
8554 if (end > top_range)
8555 end = top_range;
f451eb13 8556
ab648270 8557 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
8558 below top positions, to make sure the handle is always at least
8559 that many pixels tall. */
ab648270 8560 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 8561
12ba150f
JB
8562 /* Draw the empty space above the handle. Note that we can't clear
8563 zero-height areas; that means "clear to end of window." */
8564 if (0 < start)
c5e6e06b
GM
8565 x_clear_area (FRAME_X_DISPLAY (f), w,
8566 /* x, y, width, height, and exposures. */
8567 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8568 VERTICAL_SCROLL_BAR_TOP_BORDER,
8569 inside_width, start,
8570 False);
f451eb13 8571
06a2c219
GM
8572 /* Change to proper foreground color if one is specified. */
8573 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8574 XSetForeground (FRAME_X_DISPLAY (f), gc,
8575 f->output_data.x->scroll_bar_foreground_pixel);
8576
12ba150f 8577 /* Draw the handle itself. */
334208b7 8578 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13 8579
12ba150f 8580 /* x, y, width, height */
ab648270
JB
8581 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8582 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 8583 inside_width, end - start);
f451eb13 8584
06a2c219
GM
8585 /* Restore the foreground color of the GC if we changed it above. */
8586 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8587 XSetForeground (FRAME_X_DISPLAY (f), gc,
8588 f->output_data.x->foreground_pixel);
f451eb13 8589
12ba150f
JB
8590 /* Draw the empty space below the handle. Note that we can't
8591 clear zero-height areas; that means "clear to end of window." */
8592 if (end < inside_height)
c5e6e06b
GM
8593 x_clear_area (FRAME_X_DISPLAY (f), w,
8594 /* x, y, width, height, and exposures. */
8595 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8596 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
8597 inside_width, inside_height - end,
8598 False);
f451eb13 8599
f451eb13
JB
8600 }
8601
f451eb13
JB
8602 UNBLOCK_INPUT;
8603}
8604
5c187dee 8605#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 8606
06a2c219
GM
8607/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
8608 nil. */
58769bee 8609
12ba150f 8610static void
ab648270
JB
8611x_scroll_bar_remove (bar)
8612 struct scroll_bar *bar;
12ba150f 8613{
e83dc917 8614 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
8615 BLOCK_INPUT;
8616
eccc05db 8617#ifdef USE_TOOLKIT_SCROLL_BARS
e83dc917
GM
8618 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
8619#else
8620 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
8621#endif
06a2c219 8622
ab648270
JB
8623 /* Disassociate this scroll bar from its window. */
8624 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
8625
8626 UNBLOCK_INPUT;
8627}
8628
06a2c219 8629
12ba150f
JB
8630/* Set the handle of the vertical scroll bar for WINDOW to indicate
8631 that we are displaying PORTION characters out of a total of WHOLE
ab648270 8632 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 8633 create one. */
06a2c219 8634
12ba150f 8635static void
06a2c219
GM
8636XTset_vertical_scroll_bar (w, portion, whole, position)
8637 struct window *w;
f451eb13
JB
8638 int portion, whole, position;
8639{
06a2c219 8640 struct frame *f = XFRAME (w->frame);
ab648270 8641 struct scroll_bar *bar;
3c6ede7b 8642 int top, height, left, sb_left, width, sb_width;
06a2c219 8643 int window_x, window_y, window_width, window_height;
06a2c219 8644
3c6ede7b 8645 /* Get window dimensions. */
06a2c219 8646 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
8647 top = window_y;
8648 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
8649 height = window_height;
06a2c219 8650
3c6ede7b 8651 /* Compute the left edge of the scroll bar area. */
06a2c219 8652 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
8653 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
8654 else
8655 left = XFASTINT (w->left);
8656 left *= CANON_X_UNIT (f);
8657 left += FRAME_INTERNAL_BORDER_WIDTH (f);
8658
8659 /* Compute the width of the scroll bar which might be less than
8660 the width of the area reserved for the scroll bar. */
8661 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
8662 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 8663 else
3c6ede7b 8664 sb_width = width;
12ba150f 8665
3c6ede7b
GM
8666 /* Compute the left edge of the scroll bar. */
8667#ifdef USE_TOOLKIT_SCROLL_BARS
8668 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8669 sb_left = left + width - sb_width - (width - sb_width) / 2;
8670 else
8671 sb_left = left + (width - sb_width) / 2;
8672#else
8673 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
8674 sb_left = left + width - sb_width;
8675 else
8676 sb_left = left;
8677#endif
8678
ab648270 8679 /* Does the scroll bar exist yet? */
06a2c219 8680 if (NILP (w->vertical_scroll_bar))
3c6ede7b 8681 {
80c32bcc 8682 BLOCK_INPUT;
f964b4d7
GM
8683 if (width && height)
8684 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8685 left, top, width, height, False);
80c32bcc 8686 UNBLOCK_INPUT;
3c6ede7b
GM
8687 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
8688 }
f451eb13 8689 else
12ba150f
JB
8690 {
8691 /* It may just need to be moved and resized. */
06a2c219
GM
8692 unsigned int mask = 0;
8693
8694 bar = XSCROLL_BAR (w->vertical_scroll_bar);
8695
8696 BLOCK_INPUT;
8697
3c6ede7b 8698 if (sb_left != XINT (bar->left))
06a2c219 8699 mask |= CWX;
3c6ede7b 8700 if (top != XINT (bar->top))
06a2c219 8701 mask |= CWY;
3c6ede7b 8702 if (sb_width != XINT (bar->width))
06a2c219 8703 mask |= CWWidth;
3c6ede7b 8704 if (height != XINT (bar->height))
06a2c219
GM
8705 mask |= CWHeight;
8706
8707#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
8708
8709 /* Since toolkit scroll bars are smaller than the space reserved
8710 for them on the frame, we have to clear "under" them. */
f964b4d7
GM
8711 if (width && height)
8712 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8713 left, top, width, height, False);
06a2c219
GM
8714
8715 /* Move/size the scroll bar widget. */
8716 if (mask)
e83dc917 8717 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
3c6ede7b
GM
8718 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8719 top,
8720 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
f964b4d7 8721 max (height, 1), 0);
06a2c219
GM
8722
8723#else /* not USE_TOOLKIT_SCROLL_BARS */
8724
e1f6572f
RS
8725 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
8726 {
8727 /* Clear areas not covered by the scroll bar. This makes sure a
8728 previous mode line display is cleared after C-x 2 C-x 1, for
8729 example. Non-toolkit scroll bars are as wide as the area
8730 reserved for scroll bars - trim at both sides. */
c5e6e06b
GM
8731 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8732 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8733 height, False);
8734 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8735 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8736 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8737 height, False);
e1f6572f 8738 }
06a2c219
GM
8739
8740 /* Move/size the scroll bar window. */
8741 if (mask)
8742 {
8743 XWindowChanges wc;
8744
3c6ede7b
GM
8745 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
8746 wc.y = top;
8747 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
8748 wc.height = height;
06a2c219
GM
8749 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
8750 mask, &wc);
8751 }
8752
8753#endif /* not USE_TOOLKIT_SCROLL_BARS */
8754
8755 /* Remember new settings. */
3c6ede7b
GM
8756 XSETINT (bar->left, sb_left);
8757 XSETINT (bar->top, top);
8758 XSETINT (bar->width, sb_width);
8759 XSETINT (bar->height, height);
06a2c219
GM
8760
8761 UNBLOCK_INPUT;
12ba150f 8762 }
f451eb13 8763
eccc05db 8764#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8765 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
8766#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 8767 /* Set the scroll bar's current state, unless we're currently being
f451eb13 8768 dragged. */
12ba150f 8769 if (NILP (bar->dragging))
f451eb13 8770 {
92857db0 8771 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 8772
12ba150f 8773 if (whole == 0)
ab648270 8774 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
8775 else
8776 {
43f868f5
JB
8777 int start = ((double) position * top_range) / whole;
8778 int end = ((double) (position + portion) * top_range) / whole;
ab648270 8779 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 8780 }
f451eb13 8781 }
06a2c219 8782#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8783
06a2c219 8784 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
8785}
8786
12ba150f 8787
f451eb13 8788/* The following three hooks are used when we're doing a thorough
ab648270 8789 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 8790 are going to be deleted, because keeping track of when windows go
12ba150f
JB
8791 away is a real pain - "Can you say set-window-configuration, boys
8792 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 8793 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 8794 from the fiery pit when we actually redisplay its window. */
f451eb13 8795
ab648270
JB
8796/* Arrange for all scroll bars on FRAME to be removed at the next call
8797 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
8798 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
8799
58769bee 8800static void
ab648270 8801XTcondemn_scroll_bars (frame)
f451eb13
JB
8802 FRAME_PTR frame;
8803{
f9e24cb9
RS
8804 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
8805 while (! NILP (FRAME_SCROLL_BARS (frame)))
8806 {
8807 Lisp_Object bar;
8808 bar = FRAME_SCROLL_BARS (frame);
8809 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
8810 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
8811 XSCROLL_BAR (bar)->prev = Qnil;
8812 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
8813 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
8814 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
8815 }
f451eb13
JB
8816}
8817
fa2dfc30 8818
06a2c219 8819/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 8820 Note that WINDOW isn't necessarily condemned at all. */
fa2dfc30 8821
f451eb13 8822static void
ab648270 8823XTredeem_scroll_bar (window)
12ba150f 8824 struct window *window;
f451eb13 8825{
ab648270 8826 struct scroll_bar *bar;
fa2dfc30 8827 struct frame *f;
12ba150f 8828
ab648270
JB
8829 /* We can't redeem this window's scroll bar if it doesn't have one. */
8830 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
8831 abort ();
8832
ab648270 8833 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
8834
8835 /* Unlink it from the condemned list. */
fa2dfc30
GM
8836 f = XFRAME (WINDOW_FRAME (window));
8837 if (NILP (bar->prev))
8838 {
8839 /* If the prev pointer is nil, it must be the first in one of
8840 the lists. */
8841 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
8842 /* It's not condemned. Everything's fine. */
8843 return;
8844 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
8845 window->vertical_scroll_bar))
8846 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
8847 else
8848 /* If its prev pointer is nil, it must be at the front of
8849 one or the other! */
8850 abort ();
8851 }
8852 else
8853 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f 8854
fa2dfc30
GM
8855 if (! NILP (bar->next))
8856 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 8857
fa2dfc30
GM
8858 bar->next = FRAME_SCROLL_BARS (f);
8859 bar->prev = Qnil;
8860 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
8861 if (! NILP (bar->next))
8862 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13
JB
8863}
8864
ab648270
JB
8865/* Remove all scroll bars on FRAME that haven't been saved since the
8866 last call to `*condemn_scroll_bars_hook'. */
06a2c219 8867
f451eb13 8868static void
ab648270 8869XTjudge_scroll_bars (f)
12ba150f 8870 FRAME_PTR f;
f451eb13 8871{
12ba150f 8872 Lisp_Object bar, next;
f451eb13 8873
ab648270 8874 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
8875
8876 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
8877 more events on the hapless scroll bars. */
8878 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
8879
8880 for (; ! NILP (bar); bar = next)
f451eb13 8881 {
ab648270 8882 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 8883
ab648270 8884 x_scroll_bar_remove (b);
12ba150f
JB
8885
8886 next = b->next;
8887 b->next = b->prev = Qnil;
f451eb13 8888 }
12ba150f 8889
ab648270 8890 /* Now there should be no references to the condemned scroll bars,
12ba150f 8891 and they should get garbage-collected. */
f451eb13
JB
8892}
8893
8894
06a2c219
GM
8895/* Handle an Expose or GraphicsExpose event on a scroll bar. This
8896 is a no-op when using toolkit scroll bars.
ab648270
JB
8897
8898 This may be called from a signal handler, so we have to ignore GC
8899 mark bits. */
06a2c219 8900
f451eb13 8901static void
ab648270
JB
8902x_scroll_bar_expose (bar, event)
8903 struct scroll_bar *bar;
f451eb13
JB
8904 XEvent *event;
8905{
06a2c219
GM
8906#ifndef USE_TOOLKIT_SCROLL_BARS
8907
ab648270 8908 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8909 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8910 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 8911 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 8912
f451eb13
JB
8913 BLOCK_INPUT;
8914
ab648270 8915 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 8916
06a2c219 8917 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 8918 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
8919
8920 /* x, y, width, height */
d9cdbb3d 8921 0, 0,
3cbd2e0b 8922 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
8923 XINT (bar->height) - 1);
8924
f451eb13 8925 UNBLOCK_INPUT;
06a2c219
GM
8926
8927#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8928}
8929
ab648270
JB
8930/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
8931 is set to something other than no_event, it is enqueued.
8932
8933 This may be called from a signal handler, so we have to ignore GC
8934 mark bits. */
06a2c219 8935
5c187dee
GM
8936#ifndef USE_TOOLKIT_SCROLL_BARS
8937
f451eb13 8938static void
ab648270
JB
8939x_scroll_bar_handle_click (bar, event, emacs_event)
8940 struct scroll_bar *bar;
f451eb13
JB
8941 XEvent *event;
8942 struct input_event *emacs_event;
8943{
0299d313 8944 if (! GC_WINDOWP (bar->window))
12ba150f
JB
8945 abort ();
8946
ab648270 8947 emacs_event->kind = scroll_bar_click;
69388238 8948 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
8949 emacs_event->modifiers
8950 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
8951 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
8952 event->xbutton.state)
8953 | (event->type == ButtonRelease
8954 ? up_modifier
8955 : down_modifier));
12ba150f 8956 emacs_event->frame_or_window = bar->window;
0f8aabe9 8957 emacs_event->arg = Qnil;
f451eb13 8958 emacs_event->timestamp = event->xbutton.time;
12ba150f 8959 {
06a2c219 8960#if 0
d9cdbb3d 8961 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 8962 int internal_height
d9cdbb3d 8963 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 8964#endif
0299d313 8965 int top_range
d9cdbb3d 8966 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 8967 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
8968
8969 if (y < 0) y = 0;
8970 if (y > top_range) y = top_range;
8971
8972 if (y < XINT (bar->start))
ab648270
JB
8973 emacs_event->part = scroll_bar_above_handle;
8974 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
8975 emacs_event->part = scroll_bar_handle;
12ba150f 8976 else
ab648270 8977 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
8978
8979 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
8980 they want to drag it. Lisp code needs to be able to decide
8981 whether or not we're dragging. */
929787e1 8982#if 0
12ba150f
JB
8983 /* If the user has just clicked on the handle, record where they're
8984 holding it. */
8985 if (event->type == ButtonPress
ab648270 8986 && emacs_event->part == scroll_bar_handle)
e0c1aef2 8987 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 8988#endif
12ba150f
JB
8989
8990 /* If the user has released the handle, set it to its final position. */
8991 if (event->type == ButtonRelease
8992 && ! NILP (bar->dragging))
8993 {
8994 int new_start = y - XINT (bar->dragging);
8995 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 8996
ab648270 8997 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
8998 bar->dragging = Qnil;
8999 }
f451eb13 9000
5116f055
JB
9001 /* Same deal here as the other #if 0. */
9002#if 0
58769bee 9003 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 9004 the handle. */
ab648270 9005 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
9006 emacs_event->x = bar->start;
9007 else
e0c1aef2 9008 XSETINT (emacs_event->x, y);
5116f055 9009#else
e0c1aef2 9010 XSETINT (emacs_event->x, y);
5116f055 9011#endif
f451eb13 9012
e0c1aef2 9013 XSETINT (emacs_event->y, top_range);
12ba150f
JB
9014 }
9015}
f451eb13 9016
ab648270
JB
9017/* Handle some mouse motion while someone is dragging the scroll bar.
9018
9019 This may be called from a signal handler, so we have to ignore GC
9020 mark bits. */
06a2c219 9021
f451eb13 9022static void
ab648270
JB
9023x_scroll_bar_note_movement (bar, event)
9024 struct scroll_bar *bar;
f451eb13
JB
9025 XEvent *event;
9026{
39d8bb4d
KH
9027 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
9028
f451eb13
JB
9029 last_mouse_movement_time = event->xmotion.time;
9030
39d8bb4d 9031 f->mouse_moved = 1;
e0c1aef2 9032 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
9033
9034 /* If we're dragging the bar, display it. */
ab648270 9035 if (! GC_NILP (bar->dragging))
f451eb13
JB
9036 {
9037 /* Where should the handle be now? */
12ba150f 9038 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 9039
12ba150f 9040 if (new_start != XINT (bar->start))
f451eb13 9041 {
12ba150f 9042 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 9043
ab648270 9044 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
9045 }
9046 }
f451eb13
JB
9047}
9048
5c187dee
GM
9049#endif /* !USE_TOOLKIT_SCROLL_BARS */
9050
12ba150f 9051/* Return information to the user about the current position of the mouse
ab648270 9052 on the scroll bar. */
06a2c219 9053
12ba150f 9054static void
334208b7
RS
9055x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
9056 FRAME_PTR *fp;
12ba150f 9057 Lisp_Object *bar_window;
ab648270 9058 enum scroll_bar_part *part;
12ba150f
JB
9059 Lisp_Object *x, *y;
9060 unsigned long *time;
9061{
ab648270 9062 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
9063 Window w = SCROLL_BAR_X_WINDOW (bar);
9064 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 9065 int win_x, win_y;
559cb2fb
JB
9066 Window dummy_window;
9067 int dummy_coord;
9068 unsigned int dummy_mask;
12ba150f 9069
cf7cb199
JB
9070 BLOCK_INPUT;
9071
ab648270 9072 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 9073 report that. */
334208b7 9074 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 9075
559cb2fb
JB
9076 /* Root, child, root x and root y. */
9077 &dummy_window, &dummy_window,
9078 &dummy_coord, &dummy_coord,
12ba150f 9079
559cb2fb
JB
9080 /* Position relative to scroll bar. */
9081 &win_x, &win_y,
12ba150f 9082
559cb2fb
JB
9083 /* Mouse buttons and modifier keys. */
9084 &dummy_mask))
7a13e894 9085 ;
559cb2fb
JB
9086 else
9087 {
06a2c219 9088#if 0
559cb2fb 9089 int inside_height
d9cdbb3d 9090 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9091#endif
559cb2fb 9092 int top_range
d9cdbb3d 9093 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
9094
9095 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
9096
9097 if (! NILP (bar->dragging))
9098 win_y -= XINT (bar->dragging);
9099
9100 if (win_y < 0)
9101 win_y = 0;
9102 if (win_y > top_range)
9103 win_y = top_range;
9104
334208b7 9105 *fp = f;
7a13e894 9106 *bar_window = bar->window;
559cb2fb
JB
9107
9108 if (! NILP (bar->dragging))
9109 *part = scroll_bar_handle;
9110 else if (win_y < XINT (bar->start))
9111 *part = scroll_bar_above_handle;
9112 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9113 *part = scroll_bar_handle;
9114 else
9115 *part = scroll_bar_below_handle;
12ba150f 9116
e0c1aef2
KH
9117 XSETINT (*x, win_y);
9118 XSETINT (*y, top_range);
12ba150f 9119
39d8bb4d 9120 f->mouse_moved = 0;
559cb2fb
JB
9121 last_mouse_scroll_bar = Qnil;
9122 }
12ba150f 9123
559cb2fb 9124 *time = last_mouse_movement_time;
cf7cb199 9125
cf7cb199 9126 UNBLOCK_INPUT;
12ba150f
JB
9127}
9128
f451eb13 9129
dbc4e1c1 9130/* The screen has been cleared so we may have changed foreground or
ab648270
JB
9131 background colors, and the scroll bars may need to be redrawn.
9132 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
9133 redraw them. */
9134
dfcf069d 9135void
ab648270 9136x_scroll_bar_clear (f)
dbc4e1c1
JB
9137 FRAME_PTR f;
9138{
06a2c219 9139#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
9140 Lisp_Object bar;
9141
b80c363e
RS
9142 /* We can have scroll bars even if this is 0,
9143 if we just turned off scroll bar mode.
9144 But in that case we should not clear them. */
9145 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
9146 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
9147 bar = XSCROLL_BAR (bar)->next)
c5e6e06b
GM
9148 XClearArea (FRAME_X_DISPLAY (f),
9149 SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
b80c363e 9150 0, 0, 0, 0, True);
06a2c219 9151#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
9152}
9153
06a2c219 9154/* This processes Expose events from the menu-bar specific X event
19126e11 9155 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 9156 when handling menu-bar or pop-up items. */
3afe33e7 9157
06a2c219 9158int
3afe33e7
RS
9159process_expose_from_menu (event)
9160 XEvent event;
9161{
9162 FRAME_PTR f;
19126e11 9163 struct x_display_info *dpyinfo;
06a2c219 9164 int frame_exposed_p = 0;
3afe33e7 9165
f94397b5
KH
9166 BLOCK_INPUT;
9167
19126e11
KH
9168 dpyinfo = x_display_info_for_display (event.xexpose.display);
9169 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
9170 if (f)
9171 {
9172 if (f->async_visible == 0)
9173 {
9174 f->async_visible = 1;
9175 f->async_iconified = 0;
06c488fd 9176 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
9177 SET_FRAME_GARBAGED (f);
9178 }
9179 else
9180 {
06a2c219
GM
9181 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
9182 event.xexpose.x, event.xexpose.y,
9183 event.xexpose.width, event.xexpose.height);
9184 frame_exposed_p = 1;
3afe33e7
RS
9185 }
9186 }
9187 else
9188 {
9189 struct scroll_bar *bar
9190 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9191
3afe33e7
RS
9192 if (bar)
9193 x_scroll_bar_expose (bar, &event);
9194 }
f94397b5
KH
9195
9196 UNBLOCK_INPUT;
06a2c219 9197 return frame_exposed_p;
3afe33e7 9198}
09756a85
RS
9199\f
9200/* Define a queue to save up SelectionRequest events for later handling. */
9201
9202struct selection_event_queue
9203 {
9204 XEvent event;
9205 struct selection_event_queue *next;
9206 };
9207
9208static struct selection_event_queue *queue;
9209
9210/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 9211
09756a85
RS
9212static int x_queue_selection_requests;
9213
9214/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 9215
09756a85 9216static void
334208b7
RS
9217x_queue_event (f, event)
9218 FRAME_PTR f;
09756a85
RS
9219 XEvent *event;
9220{
9221 struct selection_event_queue *queue_tmp
06a2c219 9222 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 9223
58769bee 9224 if (queue_tmp != NULL)
09756a85
RS
9225 {
9226 queue_tmp->event = *event;
9227 queue_tmp->next = queue;
9228 queue = queue_tmp;
9229 }
9230}
9231
9232/* Take all the queued events and put them back
9233 so that they get processed afresh. */
9234
9235static void
db3906fd
RS
9236x_unqueue_events (display)
9237 Display *display;
09756a85 9238{
58769bee 9239 while (queue != NULL)
09756a85
RS
9240 {
9241 struct selection_event_queue *queue_tmp = queue;
db3906fd 9242 XPutBackEvent (display, &queue_tmp->event);
09756a85 9243 queue = queue_tmp->next;
06a2c219 9244 xfree ((char *)queue_tmp);
09756a85
RS
9245 }
9246}
9247
9248/* Start queuing SelectionRequest events. */
9249
9250void
db3906fd
RS
9251x_start_queuing_selection_requests (display)
9252 Display *display;
09756a85
RS
9253{
9254 x_queue_selection_requests++;
9255}
9256
9257/* Stop queuing SelectionRequest events. */
9258
9259void
db3906fd
RS
9260x_stop_queuing_selection_requests (display)
9261 Display *display;
09756a85
RS
9262{
9263 x_queue_selection_requests--;
db3906fd 9264 x_unqueue_events (display);
09756a85 9265}
f451eb13
JB
9266\f
9267/* The main X event-reading loop - XTread_socket. */
dc6f92b8 9268
06a2c219 9269/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
9270 but we have to put it out here, since static variables within functions
9271 sometimes don't work. */
06a2c219 9272
dc6f92b8
JB
9273static Time enter_timestamp;
9274
11edeb03 9275/* This holds the state XLookupString needs to implement dead keys
58769bee 9276 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
9277 says that a portable program can't use this, but Stephen Gildea assures
9278 me that letting the compiler initialize it to zeros will work okay.
9279
9280 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
9281 given for enter_time stamp, above. */
9282
11edeb03
JB
9283static XComposeStatus compose_status;
9284
10e6549c
RS
9285/* Record the last 100 characters stored
9286 to help debug the loss-of-chars-during-GC problem. */
06a2c219 9287
2224b905
RS
9288static int temp_index;
9289static short temp_buffer[100];
10e6549c 9290
7a13e894
RS
9291/* Set this to nonzero to fake an "X I/O error"
9292 on a particular display. */
06a2c219 9293
7a13e894
RS
9294struct x_display_info *XTread_socket_fake_io_error;
9295
2224b905
RS
9296/* When we find no input here, we occasionally do a no-op command
9297 to verify that the X server is still running and we can still talk with it.
9298 We try all the open displays, one by one.
9299 This variable is used for cycling thru the displays. */
06a2c219 9300
2224b905
RS
9301static struct x_display_info *next_noop_dpyinfo;
9302
06a2c219
GM
9303#define SET_SAVED_MENU_EVENT(size) \
9304 do \
9305 { \
9306 if (f->output_data.x->saved_menu_event == 0) \
9307 f->output_data.x->saved_menu_event \
9308 = (XEvent *) xmalloc (sizeof (XEvent)); \
9309 bcopy (&event, f->output_data.x->saved_menu_event, size); \
9310 if (numchars >= 1) \
9311 { \
9312 bufp->kind = menu_bar_activate_event; \
9313 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 9314 bufp->arg = Qnil; \
06a2c219
GM
9315 bufp++; \
9316 count++; \
9317 numchars--; \
9318 } \
9319 } \
9320 while (0)
9321
8805890a 9322#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 9323#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 9324
dc6f92b8
JB
9325/* Read events coming from the X server.
9326 This routine is called by the SIGIO handler.
9327 We return as soon as there are no more events to be read.
9328
9329 Events representing keys are stored in buffer BUFP,
9330 which can hold up to NUMCHARS characters.
9331 We return the number of characters stored into the buffer,
9332 thus pretending to be `read'.
9333
dc6f92b8
JB
9334 EXPECTED is nonzero if the caller knows input is available. */
9335
7c5283e4 9336int
f66868ba 9337XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 9338 register int sd;
8805890a
KH
9339 /* register */ struct input_event *bufp;
9340 /* register */ int numchars;
dc6f92b8
JB
9341 int expected;
9342{
9343 int count = 0;
9344 int nbytes = 0;
dc6f92b8 9345 XEvent event;
f676886a 9346 struct frame *f;
66f55a9d 9347 int event_found = 0;
334208b7 9348 struct x_display_info *dpyinfo;
379b5ac0 9349 struct coding_system coding;
dc6f92b8 9350
9ac0d9e0 9351 if (interrupt_input_blocked)
dc6f92b8 9352 {
9ac0d9e0 9353 interrupt_input_pending = 1;
dc6f92b8
JB
9354 return -1;
9355 }
9356
9ac0d9e0 9357 interrupt_input_pending = 0;
dc6f92b8 9358 BLOCK_INPUT;
c0a04927
RS
9359
9360 /* So people can tell when we have read the available input. */
9361 input_signal_count++;
9362
dc6f92b8 9363 if (numchars <= 0)
06a2c219 9364 abort (); /* Don't think this happens. */
dc6f92b8 9365
bde5503b
GM
9366 ++handling_signal;
9367
379b5ac0
KH
9368 /* The input should be decoded if it is from XIM. Currently the
9369 locale of XIM is the same as that of the system. So, we can use
9370 Vlocale_coding_system which is initialized properly at Emacs
9371 startup time. */
9372 setup_coding_system (Vlocale_coding_system, &coding);
9373 coding.src_multibyte = 0;
9374 coding.dst_multibyte = 1;
9375 /* The input is converted to events, thus we can't handle
9376 composition. Anyway, there's no XIM that gives us composition
9377 information. */
9378 coding.composing = COMPOSITION_DISABLED;
9379
7a13e894
RS
9380 /* Find the display we are supposed to read input for.
9381 It's the one communicating on descriptor SD. */
9382 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9383 {
9384#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9385#ifdef FIOSNBIO
7a13e894
RS
9386 /* If available, Xlib uses FIOSNBIO to make the socket
9387 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9388 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9389 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9390 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9391#endif /* ! defined (FIOSNBIO) */
7a13e894 9392#endif
dc6f92b8 9393
7a13e894
RS
9394#if 0 /* This code can't be made to work, with multiple displays,
9395 and appears not to be used on any system any more.
9396 Also keyboard.c doesn't turn O_NDELAY on and off
9397 for X connections. */
dc6f92b8
JB
9398#ifndef SIGIO
9399#ifndef HAVE_SELECT
7a13e894
RS
9400 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9401 {
9402 extern int read_alarm_should_throw;
9403 read_alarm_should_throw = 1;
9404 XPeekEvent (dpyinfo->display, &event);
9405 read_alarm_should_throw = 0;
9406 }
c118dd06
JB
9407#endif /* HAVE_SELECT */
9408#endif /* SIGIO */
7a13e894 9409#endif
dc6f92b8 9410
7a13e894
RS
9411 /* For debugging, this gives a way to fake an I/O error. */
9412 if (dpyinfo == XTread_socket_fake_io_error)
9413 {
9414 XTread_socket_fake_io_error = 0;
9415 x_io_error_quitter (dpyinfo->display);
9416 }
dc6f92b8 9417
06a2c219 9418 while (XPending (dpyinfo->display))
dc6f92b8 9419 {
7a13e894 9420 XNextEvent (dpyinfo->display, &event);
06a2c219 9421
531483fb 9422#ifdef HAVE_X_I18N
d1bc4182 9423 {
f2be1146
GM
9424 /* Filter events for the current X input method.
9425 XFilterEvent returns non-zero if the input method has
9426 consumed the event. We pass the frame's X window to
9427 XFilterEvent because that's the one for which the IC
9428 was created. */
f5d11644
GM
9429 struct frame *f1 = x_any_window_to_frame (dpyinfo,
9430 event.xclient.window);
9431 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
9432 break;
9433 }
0cd6403b 9434#endif
7a13e894
RS
9435 event_found = 1;
9436
9437 switch (event.type)
9438 {
9439 case ClientMessage:
c047688c 9440 {
7a13e894
RS
9441 if (event.xclient.message_type
9442 == dpyinfo->Xatom_wm_protocols
9443 && event.xclient.format == 32)
c047688c 9444 {
7a13e894
RS
9445 if (event.xclient.data.l[0]
9446 == dpyinfo->Xatom_wm_take_focus)
c047688c 9447 {
8c1a6a84
RS
9448 /* Use x_any_window_to_frame because this
9449 could be the shell widget window
9450 if the frame has no title bar. */
9451 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
9452#ifdef HAVE_X_I18N
9453 /* Not quite sure this is needed -pd */
8c1a6a84 9454 if (f && FRAME_XIC (f))
6c183ba5
RS
9455 XSetICFocus (FRAME_XIC (f));
9456#endif
f1da8f06
GM
9457#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
9458 instructs the WM to set the input focus automatically for
9459 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
9460 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
9461 it has set the focus. So, XSetInputFocus below is not
9462 needed.
9463
9464 The call to XSetInputFocus below has also caused trouble. In
9465 cases where the XSetInputFocus done by the WM and the one
9466 below are temporally close (on a fast machine), the call
9467 below can generate additional FocusIn events which confuse
9468 Emacs. */
9469
bf7253f4
RS
9470 /* Since we set WM_TAKE_FOCUS, we must call
9471 XSetInputFocus explicitly. But not if f is null,
9472 since that might be an event for a deleted frame. */
7a13e894 9473 if (f)
bf7253f4
RS
9474 {
9475 Display *d = event.xclient.display;
9476 /* Catch and ignore errors, in case window has been
9477 iconified by a window manager such as GWM. */
9478 int count = x_catch_errors (d);
9479 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
9480 /* The ICCCM says this is
9481 the only valid choice. */
9482 RevertToParent,
bf7253f4
RS
9483 event.xclient.data.l[1]);
9484 /* This is needed to detect the error
9485 if there is an error. */
9486 XSync (d, False);
9487 x_uncatch_errors (d, count);
9488 }
7a13e894 9489 /* Not certain about handling scroll bars here */
f1da8f06 9490#endif /* 0 */
c047688c 9491 }
7a13e894
RS
9492 else if (event.xclient.data.l[0]
9493 == dpyinfo->Xatom_wm_save_yourself)
9494 {
9495 /* Save state modify the WM_COMMAND property to
06a2c219 9496 something which can reinstate us. This notifies
7a13e894
RS
9497 the session manager, who's looking for such a
9498 PropertyNotify. Can restart processing when
06a2c219 9499 a keyboard or mouse event arrives. */
7a13e894
RS
9500 if (numchars > 0)
9501 {
19126e11
KH
9502 f = x_top_window_to_frame (dpyinfo,
9503 event.xclient.window);
7a13e894
RS
9504
9505 /* This is just so we only give real data once
9506 for a single Emacs process. */
b86bd3dd 9507 if (f == SELECTED_FRAME ())
7a13e894
RS
9508 XSetCommand (FRAME_X_DISPLAY (f),
9509 event.xclient.window,
9510 initial_argv, initial_argc);
f000f5c5 9511 else if (f)
7a13e894
RS
9512 XSetCommand (FRAME_X_DISPLAY (f),
9513 event.xclient.window,
9514 0, 0);
9515 }
9516 }
9517 else if (event.xclient.data.l[0]
9518 == dpyinfo->Xatom_wm_delete_window)
1fb20991 9519 {
19126e11
KH
9520 struct frame *f
9521 = x_any_window_to_frame (dpyinfo,
9522 event.xclient.window);
1fb20991 9523
7a13e894
RS
9524 if (f)
9525 {
9526 if (numchars == 0)
9527 abort ();
1fb20991 9528
7a13e894
RS
9529 bufp->kind = delete_window_event;
9530 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9531 bufp->arg = Qnil;
7a13e894
RS
9532 bufp++;
9533
9534 count += 1;
9535 numchars -= 1;
9536 }
1fb20991 9537 }
c047688c 9538 }
7a13e894
RS
9539 else if (event.xclient.message_type
9540 == dpyinfo->Xatom_wm_configure_denied)
9541 {
9542 }
9543 else if (event.xclient.message_type
9544 == dpyinfo->Xatom_wm_window_moved)
9545 {
9546 int new_x, new_y;
19126e11
KH
9547 struct frame *f
9548 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 9549
7a13e894
RS
9550 new_x = event.xclient.data.s[0];
9551 new_y = event.xclient.data.s[1];
1fb20991 9552
7a13e894
RS
9553 if (f)
9554 {
7556890b
RS
9555 f->output_data.x->left_pos = new_x;
9556 f->output_data.x->top_pos = new_y;
7a13e894 9557 }
1fb20991 9558 }
0fdff6bb 9559#ifdef HACK_EDITRES
7a13e894
RS
9560 else if (event.xclient.message_type
9561 == dpyinfo->Xatom_editres)
9562 {
19126e11
KH
9563 struct frame *f
9564 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 9565 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 9566 &event, NULL);
7a13e894 9567 }
0fdff6bb 9568#endif /* HACK_EDITRES */
06a2c219
GM
9569 else if ((event.xclient.message_type
9570 == dpyinfo->Xatom_DONE)
9571 || (event.xclient.message_type
9572 == dpyinfo->Xatom_PAGE))
9573 {
9574 /* Ghostview job completed. Kill it. We could
9575 reply with "Next" if we received "Page", but we
9576 currently never do because we are interested in
9577 images, only, which should have 1 page. */
06a2c219
GM
9578 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
9579 struct frame *f
9580 = x_window_to_frame (dpyinfo, event.xclient.window);
9581 x_kill_gs_process (pixmap, f);
9582 expose_frame (f, 0, 0, 0, 0);
9583 }
9584#ifdef USE_TOOLKIT_SCROLL_BARS
9585 /* Scroll bar callbacks send a ClientMessage from which
9586 we construct an input_event. */
9587 else if (event.xclient.message_type
9588 == dpyinfo->Xatom_Scrollbar)
9589 {
9590 x_scroll_bar_to_input_event (&event, bufp);
9591 ++bufp, ++count, --numchars;
9592 goto out;
9593 }
9594#endif /* USE_TOOLKIT_SCROLL_BARS */
9595 else
9596 goto OTHER;
7a13e894
RS
9597 }
9598 break;
dc6f92b8 9599
7a13e894 9600 case SelectionNotify:
3afe33e7 9601#ifdef USE_X_TOOLKIT
19126e11 9602 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 9603 goto OTHER;
3afe33e7 9604#endif /* not USE_X_TOOLKIT */
dfcf069d 9605 x_handle_selection_notify (&event.xselection);
7a13e894 9606 break;
d56a553a 9607
06a2c219 9608 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 9609#ifdef USE_X_TOOLKIT
19126e11 9610 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 9611 goto OTHER;
3afe33e7 9612#endif /* USE_X_TOOLKIT */
7a13e894
RS
9613 {
9614 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 9615
7a13e894
RS
9616 if (numchars == 0)
9617 abort ();
d56a553a 9618
7a13e894
RS
9619 bufp->kind = selection_clear_event;
9620 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9621 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9622 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9623 bufp->frame_or_window = Qnil;
0f8aabe9 9624 bufp->arg = Qnil;
7a13e894 9625 bufp++;
d56a553a 9626
7a13e894
RS
9627 count += 1;
9628 numchars -= 1;
9629 }
9630 break;
dc6f92b8 9631
06a2c219 9632 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 9633#ifdef USE_X_TOOLKIT
19126e11 9634 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 9635 goto OTHER;
3afe33e7 9636#endif /* USE_X_TOOLKIT */
7a13e894 9637 if (x_queue_selection_requests)
19126e11 9638 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
9639 &event);
9640 else
9641 {
9642 XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
dc6f92b8 9643
7a13e894
RS
9644 if (numchars == 0)
9645 abort ();
9646
9647 bufp->kind = selection_request_event;
9648 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9649 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
9650 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9651 SELECTION_EVENT_TARGET (bufp) = eventp->target;
9652 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
9653 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9654 bufp->frame_or_window = Qnil;
0f8aabe9 9655 bufp->arg = Qnil;
7a13e894
RS
9656 bufp++;
9657
9658 count += 1;
9659 numchars -= 1;
9660 }
9661 break;
9662
9663 case PropertyNotify:
3afe33e7 9664#ifdef USE_X_TOOLKIT
19126e11 9665 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 9666 goto OTHER;
3afe33e7 9667#endif /* not USE_X_TOOLKIT */
dfcf069d 9668 x_handle_property_notify (&event.xproperty);
7a13e894 9669 break;
dc6f92b8 9670
7a13e894 9671 case ReparentNotify:
19126e11 9672 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
9673 if (f)
9674 {
9675 int x, y;
7556890b 9676 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 9677 x_real_positions (f, &x, &y);
7556890b
RS
9678 f->output_data.x->left_pos = x;
9679 f->output_data.x->top_pos = y;
7a13e894
RS
9680 }
9681 break;
3bd330d4 9682
7a13e894 9683 case Expose:
19126e11 9684 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 9685 if (f)
dc6f92b8 9686 {
7a13e894
RS
9687 if (f->async_visible == 0)
9688 {
9689 f->async_visible = 1;
9690 f->async_iconified = 0;
06c488fd 9691 f->output_data.x->has_been_visible = 1;
7a13e894
RS
9692 SET_FRAME_GARBAGED (f);
9693 }
9694 else
06a2c219
GM
9695 expose_frame (x_window_to_frame (dpyinfo,
9696 event.xexpose.window),
9697 event.xexpose.x, event.xexpose.y,
9698 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
9699 }
9700 else
7a13e894 9701 {
06a2c219
GM
9702#ifdef USE_TOOLKIT_SCROLL_BARS
9703 /* Dispatch event to the widget. */
9704 goto OTHER;
9705#else /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9706 struct scroll_bar *bar
9707 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9708
7a13e894
RS
9709 if (bar)
9710 x_scroll_bar_expose (bar, &event);
3afe33e7 9711#ifdef USE_X_TOOLKIT
7a13e894
RS
9712 else
9713 goto OTHER;
3afe33e7 9714#endif /* USE_X_TOOLKIT */
06a2c219 9715#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
9716 }
9717 break;
dc6f92b8 9718
7a13e894
RS
9719 case GraphicsExpose: /* This occurs when an XCopyArea's
9720 source area was obscured or not
9721 available.*/
19126e11 9722 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
9723 if (f)
9724 {
06a2c219
GM
9725 expose_frame (f,
9726 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
9727 event.xgraphicsexpose.width,
9728 event.xgraphicsexpose.height);
7a13e894 9729 }
3afe33e7 9730#ifdef USE_X_TOOLKIT
7a13e894
RS
9731 else
9732 goto OTHER;
3afe33e7 9733#endif /* USE_X_TOOLKIT */
7a13e894 9734 break;
dc6f92b8 9735
7a13e894 9736 case NoExpose: /* This occurs when an XCopyArea's
06a2c219
GM
9737 source area was completely
9738 available */
7a13e894 9739 break;
dc6f92b8 9740
7a13e894 9741 case UnmapNotify:
06a2c219
GM
9742 /* Redo the mouse-highlight after the tooltip has gone. */
9743 if (event.xmap.window == tip_window)
9744 {
9745 tip_window = 0;
9746 redo_mouse_highlight ();
9747 }
9748
91ea2a7a 9749 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894
RS
9750 if (f) /* F may no longer exist if
9751 the frame was deleted. */
9752 {
9753 /* While a frame is unmapped, display generation is
9754 disabled; you don't want to spend time updating a
9755 display that won't ever be seen. */
9756 f->async_visible = 0;
9757 /* We can't distinguish, from the event, whether the window
9758 has become iconified or invisible. So assume, if it
9759 was previously visible, than now it is iconified.
1aa6072f
RS
9760 But x_make_frame_invisible clears both
9761 the visible flag and the iconified flag;
9762 and that way, we know the window is not iconified now. */
7a13e894 9763 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
9764 {
9765 f->async_iconified = 1;
bddd097c 9766
1aa6072f
RS
9767 bufp->kind = iconify_event;
9768 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9769 bufp->arg = Qnil;
1aa6072f
RS
9770 bufp++;
9771 count++;
9772 numchars--;
9773 }
7a13e894 9774 }
7a13e894 9775 goto OTHER;
dc6f92b8 9776
7a13e894 9777 case MapNotify:
06a2c219
GM
9778 if (event.xmap.window == tip_window)
9779 /* The tooltip has been drawn already. Avoid
9780 the SET_FRAME_GARBAGED below. */
9781 goto OTHER;
9782
9783 /* We use x_top_window_to_frame because map events can
9784 come for sub-windows and they don't mean that the
9785 frame is visible. */
19126e11 9786 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
9787 if (f)
9788 {
9789 f->async_visible = 1;
9790 f->async_iconified = 0;
06c488fd 9791 f->output_data.x->has_been_visible = 1;
dc6f92b8 9792
7a13e894
RS
9793 /* wait_reading_process_input will notice this and update
9794 the frame's display structures. */
9795 SET_FRAME_GARBAGED (f);
bddd097c 9796
d806e720
RS
9797 if (f->iconified)
9798 {
9799 bufp->kind = deiconify_event;
9800 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9801 bufp->arg = Qnil;
d806e720
RS
9802 bufp++;
9803 count++;
9804 numchars--;
9805 }
e73ec6fa 9806 else if (! NILP (Vframe_list)
8e713be6 9807 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
9808 /* Force a redisplay sooner or later
9809 to update the frame titles
9810 in case this is the second frame. */
9811 record_asynch_buffer_change ();
7a13e894 9812 }
7a13e894 9813 goto OTHER;
dc6f92b8 9814
7a13e894 9815 case KeyPress:
19126e11 9816 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 9817
eccc05db 9818#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
9819 /* I couldn't find a way to prevent LessTif scroll bars
9820 from consuming key events. */
9821 if (f == 0)
9822 {
9823 Widget widget = XtWindowToWidget (dpyinfo->display,
9824 event.xkey.window);
9825 if (widget && XmIsScrollBar (widget))
9826 {
9827 widget = XtParent (widget);
9828 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
9829 }
9830 }
eccc05db 9831#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
06a2c219 9832
7a13e894
RS
9833 if (f != 0)
9834 {
9835 KeySym keysym, orig_keysym;
379b5ac0
KH
9836 /* al%imercury@uunet.uu.net says that making this 81
9837 instead of 80 fixed a bug whereby meta chars made
9838 his Emacs hang.
9839
9840 It seems that some version of XmbLookupString has
9841 a bug of not returning XBufferOverflow in
9842 status_return even if the input is too long to
9843 fit in 81 bytes. So, we must prepare sufficient
9844 bytes for copy_buffer. 513 bytes (256 chars for
9845 two-byte character set) seems to be a faily good
9846 approximation. -- 2000.8.10 handa@etl.go.jp */
9847 unsigned char copy_buffer[513];
9848 unsigned char *copy_bufptr = copy_buffer;
9849 int copy_bufsiz = sizeof (copy_buffer);
7a13e894 9850 int modifiers;
64bb1782 9851
7a13e894
RS
9852 event.xkey.state
9853 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
9854 extra_keyboard_modifiers);
9855 modifiers = event.xkey.state;
3a2712f9 9856
7a13e894 9857 /* This will have to go some day... */
752a043f 9858
7a13e894
RS
9859 /* make_lispy_event turns chars into control chars.
9860 Don't do it here because XLookupString is too eager. */
9861 event.xkey.state &= ~ControlMask;
5d46f928
RS
9862 event.xkey.state &= ~(dpyinfo->meta_mod_mask
9863 | dpyinfo->super_mod_mask
9864 | dpyinfo->hyper_mod_mask
9865 | dpyinfo->alt_mod_mask);
9866
1cf4a0d1
RS
9867 /* In case Meta is ComposeCharacter,
9868 clear its status. According to Markus Ehrnsperger
9869 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
9870 this enables ComposeCharacter to work whether or
9871 not it is combined with Meta. */
9872 if (modifiers & dpyinfo->meta_mod_mask)
9873 bzero (&compose_status, sizeof (compose_status));
9874
6c183ba5
RS
9875#ifdef HAVE_X_I18N
9876 if (FRAME_XIC (f))
9877 {
f5d11644
GM
9878 Status status_return;
9879
6c183ba5 9880 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
9881 &event.xkey, copy_bufptr,
9882 copy_bufsiz, &keysym,
6c183ba5 9883 &status_return);
f5d11644
GM
9884 if (status_return == XBufferOverflow)
9885 {
9886 copy_bufsiz = nbytes + 1;
9887 copy_bufptr = (char *) alloca (copy_bufsiz);
9888 nbytes = XmbLookupString (FRAME_XIC (f),
9889 &event.xkey, copy_bufptr,
9890 copy_bufsiz, &keysym,
9891 &status_return);
9892 }
9893
1decb680
PE
9894 if (status_return == XLookupNone)
9895 break;
9896 else if (status_return == XLookupChars)
fdd9d55e
GM
9897 {
9898 keysym = NoSymbol;
9899 modifiers = 0;
9900 }
1decb680
PE
9901 else if (status_return != XLookupKeySym
9902 && status_return != XLookupBoth)
9903 abort ();
6c183ba5
RS
9904 }
9905 else
379b5ac0
KH
9906 nbytes = XLookupString (&event.xkey, copy_bufptr,
9907 copy_bufsiz, &keysym,
9908 &compose_status);
6c183ba5 9909#else
379b5ac0
KH
9910 nbytes = XLookupString (&event.xkey, copy_bufptr,
9911 copy_bufsiz, &keysym,
9912 &compose_status);
6c183ba5 9913#endif
dc6f92b8 9914
7a13e894 9915 orig_keysym = keysym;
55123275 9916
7a13e894
RS
9917 if (numchars > 1)
9918 {
9919 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
9920 || keysym == XK_Delete
1097aea0 9921#ifdef XK_ISO_Left_Tab
441affdb 9922 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 9923#endif
852bff8f 9924 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
9925 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
9926 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 9927#ifdef HPUX
7a13e894
RS
9928 /* This recognizes the "extended function keys".
9929 It seems there's no cleaner way.
9930 Test IsModifierKey to avoid handling mode_switch
9931 incorrectly. */
9932 || ((unsigned) (keysym) >= XK_Select
9933 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
9934#endif
9935#ifdef XK_dead_circumflex
7a13e894 9936 || orig_keysym == XK_dead_circumflex
69388238
RS
9937#endif
9938#ifdef XK_dead_grave
7a13e894 9939 || orig_keysym == XK_dead_grave
69388238
RS
9940#endif
9941#ifdef XK_dead_tilde
7a13e894 9942 || orig_keysym == XK_dead_tilde
69388238
RS
9943#endif
9944#ifdef XK_dead_diaeresis
7a13e894 9945 || orig_keysym == XK_dead_diaeresis
69388238
RS
9946#endif
9947#ifdef XK_dead_macron
7a13e894 9948 || orig_keysym == XK_dead_macron
69388238
RS
9949#endif
9950#ifdef XK_dead_degree
7a13e894 9951 || orig_keysym == XK_dead_degree
69388238
RS
9952#endif
9953#ifdef XK_dead_acute
7a13e894 9954 || orig_keysym == XK_dead_acute
69388238
RS
9955#endif
9956#ifdef XK_dead_cedilla
7a13e894 9957 || orig_keysym == XK_dead_cedilla
69388238
RS
9958#endif
9959#ifdef XK_dead_breve
7a13e894 9960 || orig_keysym == XK_dead_breve
69388238
RS
9961#endif
9962#ifdef XK_dead_ogonek
7a13e894 9963 || orig_keysym == XK_dead_ogonek
69388238
RS
9964#endif
9965#ifdef XK_dead_caron
7a13e894 9966 || orig_keysym == XK_dead_caron
69388238
RS
9967#endif
9968#ifdef XK_dead_doubleacute
7a13e894 9969 || orig_keysym == XK_dead_doubleacute
69388238
RS
9970#endif
9971#ifdef XK_dead_abovedot
7a13e894 9972 || orig_keysym == XK_dead_abovedot
c34790e0 9973#endif
7a13e894
RS
9974 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
9975 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
9976 /* Any "vendor-specific" key is ok. */
9977 || (orig_keysym & (1 << 28)))
9978 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
9979#ifndef HAVE_X11R5
9980#ifdef XK_Mode_switch
7a13e894 9981 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
9982#endif
9983#ifdef XK_Num_Lock
7a13e894 9984 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
9985#endif
9986#endif /* not HAVE_X11R5 */
7a13e894 9987 ))
dc6f92b8 9988 {
10e6549c
RS
9989 if (temp_index == sizeof temp_buffer / sizeof (short))
9990 temp_index = 0;
7a13e894
RS
9991 temp_buffer[temp_index++] = keysym;
9992 bufp->kind = non_ascii_keystroke;
9993 bufp->code = keysym;
e0c1aef2 9994 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9995 bufp->arg = Qnil;
334208b7
RS
9996 bufp->modifiers
9997 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
9998 modifiers);
1113d9db 9999 bufp->timestamp = event.xkey.time;
dc6f92b8 10000 bufp++;
7a13e894
RS
10001 count++;
10002 numchars--;
dc6f92b8 10003 }
7a13e894
RS
10004 else if (numchars > nbytes)
10005 {
10006 register int i;
379b5ac0 10007 register int c;
379b5ac0 10008 int nchars, len;
7a13e894
RS
10009
10010 for (i = 0; i < nbytes; i++)
10011 {
379b5ac0
KH
10012 if (temp_index == (sizeof temp_buffer
10013 / sizeof (short)))
7a13e894 10014 temp_index = 0;
379b5ac0
KH
10015 temp_buffer[temp_index++] = copy_bufptr[i];
10016 }
10017
10018 if (/* If the event is not from XIM, */
10019 event.xkey.keycode != 0
10020 /* or the current locale doesn't request
10021 decoding of the intup data, ... */
10022 || coding.type == coding_type_raw_text
10023 || coding.type == coding_type_no_conversion)
10024 {
10025 /* ... we can use the input data as is. */
10026 nchars = nbytes;
10027 }
10028 else
10029 {
10030 /* We have to decode the input data. */
10031 int require;
10032 unsigned char *p;
10033
10034 require = decoding_buffer_size (&coding, nbytes);
10035 p = (unsigned char *) alloca (require);
10036 coding.mode |= CODING_MODE_LAST_BLOCK;
10037 decode_coding (&coding, copy_bufptr, p,
10038 nbytes, require);
10039 nbytes = coding.produced;
10040 nchars = coding.produced_char;
10041 copy_bufptr = p;
10042 }
10043
10044 /* Convert the input data to a sequence of
10045 character events. */
10046 for (i = 0; i < nbytes; i += len)
10047 {
10048 c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
10049 nbytes - i, len);
10050 bufp->kind = (SINGLE_BYTE_CHAR_P (c)
10051 ? ascii_keystroke
10052 : multibyte_char_keystroke);
10053 bufp->code = c;
7a13e894 10054 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10055 bufp->arg = Qnil;
7a13e894
RS
10056 bufp->modifiers
10057 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10058 modifiers);
10059 bufp->timestamp = event.xkey.time;
10060 bufp++;
10061 }
10062
379b5ac0
KH
10063 count += nchars;
10064 numchars -= nchars;
1decb680
PE
10065
10066 if (keysym == NoSymbol)
10067 break;
7a13e894
RS
10068 }
10069 else
10070 abort ();
dc6f92b8 10071 }
10e6549c
RS
10072 else
10073 abort ();
dc6f92b8 10074 }
59ddecde
GM
10075#ifdef HAVE_X_I18N
10076 /* Don't dispatch this event since XtDispatchEvent calls
10077 XFilterEvent, and two calls in a row may freeze the
10078 client. */
10079 break;
10080#else
717ca130 10081 goto OTHER;
59ddecde 10082#endif
f451eb13 10083
f5d11644 10084 case KeyRelease:
59ddecde
GM
10085#ifdef HAVE_X_I18N
10086 /* Don't dispatch this event since XtDispatchEvent calls
10087 XFilterEvent, and two calls in a row may freeze the
10088 client. */
10089 break;
10090#else
f5d11644 10091 goto OTHER;
59ddecde 10092#endif
f5d11644 10093
7a13e894 10094 /* Here's a possible interpretation of the whole
06a2c219
GM
10095 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
10096 you get a FocusIn event, you have to get a FocusOut
10097 event before you relinquish the focus. If you
10098 haven't received a FocusIn event, then a mere
10099 LeaveNotify is enough to free you. */
f451eb13 10100
7a13e894 10101 case EnterNotify:
06a2c219
GM
10102 {
10103 int from_menu_bar_p = 0;
10104
10105 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
10106
10107#ifdef LESSTIF_VERSION
10108 /* When clicking outside of a menu bar popup to close
10109 it, we get a FocusIn/ EnterNotify sequence of
10110 events. The flag event.xcrossing.focus is not set
10111 in the EnterNotify event of that sequence because
10112 the focus is in the menu bar,
10113 event.xcrossing.window is the frame's X window.
10114 Unconditionally setting the focus frame to null in
10115 this case is not the right thing, because no event
10116 follows that could set the focus frame to the right
10117 value.
10118
10119 This could be a LessTif bug, but I wasn't able to
10120 reproduce the behavior in a simple test program.
3be7e417
GM
10121 On the other hand, Motif seems to not have this
10122 problem.
06a2c219 10123
3be7e417 10124 (gerd, LessTif 0.92). */
06a2c219
GM
10125
10126 if (!event.xcrossing.focus
10127 && f
10128 && f->output_data.x->menubar_widget)
10129 {
10130 Window focus;
10131 int revert;
10132
10133 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
10134 if (focus == XtWindow (f->output_data.x->menubar_widget))
10135 from_menu_bar_p = 1;
10136 }
10137#endif /* LESSTIF_VERSION */
6d4238f3 10138
06a2c219
GM
10139 if (event.xcrossing.focus || from_menu_bar_p)
10140 {
10141 /* Avoid nasty pop/raise loops. */
10142 if (f && (!(f->auto_raise)
10143 || !(f->auto_lower)
10144 || (event.xcrossing.time - enter_timestamp) > 500))
10145 {
10146 x_new_focus_frame (dpyinfo, f);
10147 enter_timestamp = event.xcrossing.time;
10148 }
10149 }
10150 else if (f == dpyinfo->x_focus_frame)
10151 x_new_focus_frame (dpyinfo, 0);
10152
10153 /* EnterNotify counts as mouse movement,
10154 so update things that depend on mouse position. */
2533c408 10155 if (f && !f->output_data.x->hourglass_p)
06a2c219
GM
10156 note_mouse_movement (f, &event.xmotion);
10157 goto OTHER;
10158 }
dc6f92b8 10159
7a13e894 10160 case FocusIn:
19126e11 10161 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10162 if (event.xfocus.detail != NotifyPointer)
0f941935 10163 dpyinfo->x_focus_event_frame = f;
7a13e894 10164 if (f)
eb72635f
GM
10165 {
10166 x_new_focus_frame (dpyinfo, f);
10167
10168 /* Don't stop displaying the initial startup message
10169 for a switch-frame event we don't need. */
10170 if (GC_NILP (Vterminal_frame)
10171 && GC_CONSP (Vframe_list)
10172 && !GC_NILP (XCDR (Vframe_list)))
10173 {
10174 bufp->kind = FOCUS_IN_EVENT;
10175 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10176 bufp->arg = Qnil;
eb72635f
GM
10177 ++bufp, ++count, --numchars;
10178 }
10179 }
f9e24cb9 10180
6c183ba5
RS
10181#ifdef HAVE_X_I18N
10182 if (f && FRAME_XIC (f))
10183 XSetICFocus (FRAME_XIC (f));
10184#endif
10185
7a13e894 10186 goto OTHER;
10c5e63d 10187
7a13e894 10188 case LeaveNotify:
19126e11 10189 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 10190 if (f)
10c5e63d 10191 {
06a2c219
GM
10192 int from_menu_bar_p = 0;
10193
7a13e894 10194 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
10195 {
10196 /* If we move outside the frame, then we're
10197 certainly no longer on any text in the frame. */
10198 clear_mouse_face (dpyinfo);
10199 dpyinfo->mouse_face_mouse_frame = 0;
10200 }
10201
10202 /* Generate a nil HELP_EVENT to cancel a help-echo.
10203 Do it only if there's something to cancel.
10204 Otherwise, the startup message is cleared when
10205 the mouse leaves the frame. */
10206 if (any_help_event_p)
10207 {
be010514
GM
10208 Lisp_Object frame;
10209 int n;
10210
06a2c219 10211 XSETFRAME (frame, f);
82c5d67a 10212 help_echo = Qnil;
5ab2570d
GM
10213 n = gen_help_event (bufp, numchars,
10214 Qnil, frame, Qnil, Qnil, 0);
be010514 10215 bufp += n, count += n, numchars -= n;
06a2c219 10216 }
7a13e894 10217
06a2c219
GM
10218#ifdef LESSTIF_VERSION
10219 /* Please see the comment at the start of the
10220 EnterNotify case. */
10221 if (!event.xcrossing.focus
10222 && f->output_data.x->menubar_widget)
10223 {
10224 Window focus;
10225 int revert;
10226 XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
10227 if (focus == XtWindow (f->output_data.x->menubar_widget))
10228 from_menu_bar_p = 1;
10229 }
10230#endif /* LESSTIF_VERSION */
10231
10232 if (event.xcrossing.focus || from_menu_bar_p)
0f941935 10233 x_mouse_leave (dpyinfo);
10c5e63d 10234 else
7a13e894 10235 {
0f941935
KH
10236 if (f == dpyinfo->x_focus_event_frame)
10237 dpyinfo->x_focus_event_frame = 0;
10238 if (f == dpyinfo->x_focus_frame)
10239 x_new_focus_frame (dpyinfo, 0);
7a13e894 10240 }
10c5e63d 10241 }
7a13e894 10242 goto OTHER;
dc6f92b8 10243
7a13e894 10244 case FocusOut:
19126e11 10245 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10246 if (event.xfocus.detail != NotifyPointer
0f941935
KH
10247 && f == dpyinfo->x_focus_event_frame)
10248 dpyinfo->x_focus_event_frame = 0;
10249 if (f && f == dpyinfo->x_focus_frame)
10250 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 10251
6c183ba5
RS
10252#ifdef HAVE_X_I18N
10253 if (f && FRAME_XIC (f))
10254 XUnsetICFocus (FRAME_XIC (f));
10255#endif
10256
7a13e894 10257 goto OTHER;
dc6f92b8 10258
7a13e894 10259 case MotionNotify:
dc6f92b8 10260 {
06a2c219 10261 previous_help_echo = help_echo;
7cea38bc 10262 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 10263 help_echo_pos = -1;
06a2c219 10264
7a13e894
RS
10265 if (dpyinfo->grabbed && last_mouse_frame
10266 && FRAME_LIVE_P (last_mouse_frame))
10267 f = last_mouse_frame;
10268 else
19126e11 10269 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 10270
7a13e894
RS
10271 if (f)
10272 note_mouse_movement (f, &event.xmotion);
10273 else
10274 {
e88b3c50 10275#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10276 struct scroll_bar *bar
10277 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 10278
7a13e894
RS
10279 if (bar)
10280 x_scroll_bar_note_movement (bar, &event);
e88b3c50 10281#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 10282
06a2c219
GM
10283 /* If we move outside the frame, then we're
10284 certainly no longer on any text in the frame. */
7a13e894
RS
10285 clear_mouse_face (dpyinfo);
10286 }
06a2c219
GM
10287
10288 /* If the contents of the global variable help_echo
10289 has changed, generate a HELP_EVENT. */
b7e80413
SM
10290 if (!NILP (help_echo)
10291 || !NILP (previous_help_echo))
06a2c219
GM
10292 {
10293 Lisp_Object frame;
be010514 10294 int n;
06a2c219
GM
10295
10296 if (f)
10297 XSETFRAME (frame, f);
10298 else
10299 frame = Qnil;
10300
10301 any_help_event_p = 1;
5ab2570d 10302 n = gen_help_event (bufp, numchars, help_echo, frame,
7cea38bc
GM
10303 help_echo_window, help_echo_object,
10304 help_echo_pos);
be010514 10305 bufp += n, count += n, numchars -= n;
06a2c219
GM
10306 }
10307
10308 goto OTHER;
dc6f92b8 10309 }
dc6f92b8 10310
7a13e894 10311 case ConfigureNotify:
9829ddba
RS
10312 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
10313 if (f)
af395ec1 10314 {
5c187dee 10315#ifndef USE_X_TOOLKIT
bf1b7b30
KH
10316 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
10317 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 10318
2d7fc7e8
RS
10319 /* In the toolkit version, change_frame_size
10320 is called by the code that handles resizing
10321 of the EmacsFrame widget. */
7a13e894 10322
7a13e894
RS
10323 /* Even if the number of character rows and columns has
10324 not changed, the font size may have changed, so we need
10325 to check the pixel dimensions as well. */
10326 if (columns != f->width
10327 || rows != f->height
7556890b
RS
10328 || event.xconfigure.width != f->output_data.x->pixel_width
10329 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 10330 {
7d1e984f 10331 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 10332 SET_FRAME_GARBAGED (f);
e687d06e 10333 cancel_mouse_face (f);
7a13e894 10334 }
2d7fc7e8 10335#endif
af395ec1 10336
7556890b
RS
10337 f->output_data.x->pixel_width = event.xconfigure.width;
10338 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
10339
10340 /* What we have now is the position of Emacs's own window.
10341 Convert that to the position of the window manager window. */
dcb07ae9
RS
10342 x_real_positions (f, &f->output_data.x->left_pos,
10343 &f->output_data.x->top_pos);
10344
f5d11644
GM
10345#ifdef HAVE_X_I18N
10346 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
10347 xic_set_statusarea (f);
10348#endif
10349
dcb07ae9
RS
10350 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
10351 {
10352 /* Since the WM decorations come below top_pos now,
10353 we must put them below top_pos in the future. */
10354 f->output_data.x->win_gravity = NorthWestGravity;
10355 x_wm_set_size_hint (f, (long) 0, 0);
10356 }
8f08dc93
KH
10357#ifdef USE_MOTIF
10358 /* Some window managers pass (0,0) as the location of
10359 the window, and the Motif event handler stores it
10360 in the emacs widget, which messes up Motif menus. */
10361 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
10362 {
10363 event.xconfigure.x = f->output_data.x->widget->core.x;
10364 event.xconfigure.y = f->output_data.x->widget->core.y;
10365 }
06a2c219 10366#endif /* USE_MOTIF */
7a13e894 10367 }
2d7fc7e8 10368 goto OTHER;
dc6f92b8 10369
7a13e894
RS
10370 case ButtonPress:
10371 case ButtonRelease:
10372 {
10373 /* If we decide we want to generate an event to be seen
10374 by the rest of Emacs, we put it here. */
10375 struct input_event emacs_event;
9ea173e8 10376 int tool_bar_p = 0;
06a2c219 10377
7a13e894 10378 emacs_event.kind = no_event;
7a13e894 10379 bzero (&compose_status, sizeof (compose_status));
9b07615b 10380
06a2c219
GM
10381 if (dpyinfo->grabbed
10382 && last_mouse_frame
9f67f20b
RS
10383 && FRAME_LIVE_P (last_mouse_frame))
10384 f = last_mouse_frame;
10385 else
2224b905 10386 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 10387
06a2c219
GM
10388 if (f)
10389 {
9ea173e8
GM
10390 /* Is this in the tool-bar? */
10391 if (WINDOWP (f->tool_bar_window)
10392 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
10393 {
10394 Lisp_Object window;
10395 int p, x, y;
10396
10397 x = event.xbutton.x;
10398 y = event.xbutton.y;
10399
10400 /* Set x and y. */
10401 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 10402 if (EQ (window, f->tool_bar_window))
06a2c219 10403 {
9ea173e8
GM
10404 x_handle_tool_bar_click (f, &event.xbutton);
10405 tool_bar_p = 1;
06a2c219
GM
10406 }
10407 }
10408
9ea173e8 10409 if (!tool_bar_p)
06a2c219
GM
10410 if (!dpyinfo->x_focus_frame
10411 || f == dpyinfo->x_focus_frame)
10412 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
10413 }
10414 else
10415 {
06a2c219 10416#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10417 struct scroll_bar *bar
10418 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 10419
7a13e894
RS
10420 if (bar)
10421 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 10422#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10423 }
10424
10425 if (event.type == ButtonPress)
10426 {
10427 dpyinfo->grabbed |= (1 << event.xbutton.button);
10428 last_mouse_frame = f;
edad46f6
KH
10429 /* Ignore any mouse motion that happened
10430 before this event; any subsequent mouse-movement
10431 Emacs events should reflect only motion after
10432 the ButtonPress. */
a00e91cd
KH
10433 if (f != 0)
10434 f->mouse_moved = 0;
06a2c219 10435
9ea173e8
GM
10436 if (!tool_bar_p)
10437 last_tool_bar_item = -1;
7a13e894 10438 }
3afe33e7
RS
10439 else
10440 {
7a13e894 10441 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10442 }
23faf38f 10443
7a13e894
RS
10444 if (numchars >= 1 && emacs_event.kind != no_event)
10445 {
10446 bcopy (&emacs_event, bufp, sizeof (struct input_event));
10447 bufp++;
10448 count++;
10449 numchars--;
10450 }
3afe33e7
RS
10451
10452#ifdef USE_X_TOOLKIT
2224b905
RS
10453 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
10454 /* For a down-event in the menu bar,
10455 don't pass it to Xt right now.
10456 Instead, save it away
10457 and we will pass it to Xt from kbd_buffer_get_event.
10458 That way, we can run some Lisp code first. */
91375f8f
RS
10459 if (f && event.type == ButtonPress
10460 /* Verify the event is really within the menu bar
10461 and not just sent to it due to grabbing. */
10462 && event.xbutton.x >= 0
10463 && event.xbutton.x < f->output_data.x->pixel_width
10464 && event.xbutton.y >= 0
10465 && event.xbutton.y < f->output_data.x->menubar_height
10466 && event.xbutton.same_screen)
2224b905 10467 {
8805890a 10468 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
10469 XSETFRAME (last_mouse_press_frame, f);
10470 }
10471 else if (event.type == ButtonPress)
10472 {
10473 last_mouse_press_frame = Qnil;
30e671c3 10474 goto OTHER;
ce89ef46 10475 }
06a2c219 10476
2237cac9
RS
10477#ifdef USE_MOTIF /* This should do not harm for Lucid,
10478 but I am trying to be cautious. */
ce89ef46
RS
10479 else if (event.type == ButtonRelease)
10480 {
2237cac9 10481 if (!NILP (last_mouse_press_frame))
f10ded1c 10482 {
2237cac9
RS
10483 f = XFRAME (last_mouse_press_frame);
10484 if (f->output_data.x)
06a2c219 10485 SET_SAVED_BUTTON_EVENT;
f10ded1c 10486 }
06a2c219 10487 else
30e671c3 10488 goto OTHER;
2224b905 10489 }
2237cac9 10490#endif /* USE_MOTIF */
2224b905
RS
10491 else
10492 goto OTHER;
3afe33e7 10493#endif /* USE_X_TOOLKIT */
7a13e894
RS
10494 }
10495 break;
dc6f92b8 10496
7a13e894 10497 case CirculateNotify:
06a2c219
GM
10498 goto OTHER;
10499
7a13e894 10500 case CirculateRequest:
06a2c219
GM
10501 goto OTHER;
10502
10503 case VisibilityNotify:
10504 goto OTHER;
dc6f92b8 10505
7a13e894
RS
10506 case MappingNotify:
10507 /* Someone has changed the keyboard mapping - update the
10508 local cache. */
10509 switch (event.xmapping.request)
10510 {
10511 case MappingModifier:
10512 x_find_modifier_meanings (dpyinfo);
10513 /* This is meant to fall through. */
10514 case MappingKeyboard:
10515 XRefreshKeyboardMapping (&event.xmapping);
10516 }
7a13e894 10517 goto OTHER;
dc6f92b8 10518
7a13e894 10519 default:
7a13e894 10520 OTHER:
717ca130 10521#ifdef USE_X_TOOLKIT
7a13e894
RS
10522 BLOCK_INPUT;
10523 XtDispatchEvent (&event);
10524 UNBLOCK_INPUT;
3afe33e7 10525#endif /* USE_X_TOOLKIT */
7a13e894
RS
10526 break;
10527 }
dc6f92b8
JB
10528 }
10529 }
10530
06a2c219
GM
10531 out:;
10532
9a5196d0
RS
10533 /* On some systems, an X bug causes Emacs to get no more events
10534 when the window is destroyed. Detect that. (1994.) */
58769bee 10535 if (! event_found)
ef2a22d0 10536 {
ef2a22d0
RS
10537 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
10538 One XNOOP in 100 loops will make Emacs terminate.
10539 B. Bretthauer, 1994 */
10540 x_noop_count++;
58769bee 10541 if (x_noop_count >= 100)
ef2a22d0
RS
10542 {
10543 x_noop_count=0;
2224b905
RS
10544
10545 if (next_noop_dpyinfo == 0)
10546 next_noop_dpyinfo = x_display_list;
10547
10548 XNoOp (next_noop_dpyinfo->display);
10549
10550 /* Each time we get here, cycle through the displays now open. */
10551 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
10552 }
10553 }
502add23 10554
06a2c219 10555 /* If the focus was just given to an auto-raising frame,
0134a210 10556 raise it now. */
7a13e894 10557 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
10558 if (pending_autoraise_frame)
10559 {
10560 x_raise_frame (pending_autoraise_frame);
10561 pending_autoraise_frame = 0;
10562 }
0134a210 10563
dc6f92b8 10564 UNBLOCK_INPUT;
bde5503b 10565 --handling_signal;
dc6f92b8
JB
10566 return count;
10567}
06a2c219
GM
10568
10569
10570
dc6f92b8 10571\f
06a2c219
GM
10572/***********************************************************************
10573 Text Cursor
10574 ***********************************************************************/
10575
10576/* Note if the text cursor of window W has been overwritten by a
10577 drawing operation that outputs N glyphs starting at HPOS in the
10578 line given by output_cursor.vpos. N < 0 means all the rest of the
10579 line after HPOS has been written. */
10580
10581static void
10582note_overwritten_text_cursor (w, hpos, n)
10583 struct window *w;
10584 int hpos, n;
10585{
10586 if (updated_area == TEXT_AREA
10587 && output_cursor.vpos == w->phys_cursor.vpos
10588 && hpos <= w->phys_cursor.hpos
10589 && (n < 0
10590 || hpos + n > w->phys_cursor.hpos))
10591 w->phys_cursor_on_p = 0;
10592}
f451eb13
JB
10593
10594
06a2c219
GM
10595/* Set clipping for output in glyph row ROW. W is the window in which
10596 we operate. GC is the graphics context to set clipping in.
10597 WHOLE_LINE_P non-zero means include the areas used for truncation
10598 mark display and alike in the clipping rectangle.
10599
10600 ROW may be a text row or, e.g., a mode line. Text rows must be
10601 clipped to the interior of the window dedicated to text display,
10602 mode lines must be clipped to the whole window. */
dc6f92b8
JB
10603
10604static void
06a2c219
GM
10605x_clip_to_row (w, row, gc, whole_line_p)
10606 struct window *w;
10607 struct glyph_row *row;
10608 GC gc;
10609 int whole_line_p;
dc6f92b8 10610{
06a2c219
GM
10611 struct frame *f = XFRAME (WINDOW_FRAME (w));
10612 XRectangle clip_rect;
10613 int window_x, window_y, window_width, window_height;
dc6f92b8 10614
06a2c219 10615 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 10616
06a2c219
GM
10617 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
10618 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
10619 clip_rect.y = max (clip_rect.y, window_y);
10620 clip_rect.width = window_width;
10621 clip_rect.height = row->visible_height;
5c1aae96 10622
06a2c219
GM
10623 /* If clipping to the whole line, including trunc marks, extend
10624 the rectangle to the left and increase its width. */
10625 if (whole_line_p)
10626 {
110859fc
GM
10627 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
10628 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 10629 }
5c1aae96 10630
06a2c219 10631 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
10632}
10633
06a2c219
GM
10634
10635/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
10636
10637static void
06a2c219
GM
10638x_draw_hollow_cursor (w, row)
10639 struct window *w;
10640 struct glyph_row *row;
dc6f92b8 10641{
06a2c219
GM
10642 struct frame *f = XFRAME (WINDOW_FRAME (w));
10643 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10644 Display *dpy = FRAME_X_DISPLAY (f);
10645 int x, y, wd, h;
10646 XGCValues xgcv;
10647 struct glyph *cursor_glyph;
10648 GC gc;
10649
10650 /* Compute frame-relative coordinates from window-relative
10651 coordinates. */
10652 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10653 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
10654 + row->ascent - w->phys_cursor_ascent);
10655 h = row->height - 1;
10656
10657 /* Get the glyph the cursor is on. If we can't tell because
10658 the current matrix is invalid or such, give up. */
10659 cursor_glyph = get_phys_cursor_glyph (w);
10660 if (cursor_glyph == NULL)
dc6f92b8
JB
10661 return;
10662
06a2c219
GM
10663 /* Compute the width of the rectangle to draw. If on a stretch
10664 glyph, and `x-stretch-block-cursor' is nil, don't draw a
10665 rectangle as wide as the glyph, but use a canonical character
10666 width instead. */
10667 wd = cursor_glyph->pixel_width - 1;
10668 if (cursor_glyph->type == STRETCH_GLYPH
10669 && !x_stretch_cursor_p)
10670 wd = min (CANON_X_UNIT (f), wd);
10671
10672 /* The foreground of cursor_gc is typically the same as the normal
10673 background color, which can cause the cursor box to be invisible. */
10674 xgcv.foreground = f->output_data.x->cursor_pixel;
10675 if (dpyinfo->scratch_cursor_gc)
10676 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
10677 else
10678 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
10679 GCForeground, &xgcv);
10680 gc = dpyinfo->scratch_cursor_gc;
10681
10682 /* Set clipping, draw the rectangle, and reset clipping again. */
10683 x_clip_to_row (w, row, gc, 0);
10684 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
10685 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
10686}
10687
06a2c219
GM
10688
10689/* Draw a bar cursor on window W in glyph row ROW.
10690
10691 Implementation note: One would like to draw a bar cursor with an
10692 angle equal to the one given by the font property XA_ITALIC_ANGLE.
10693 Unfortunately, I didn't find a font yet that has this property set.
10694 --gerd. */
dc6f92b8
JB
10695
10696static void
f02d8aa0 10697x_draw_bar_cursor (w, row, width)
06a2c219
GM
10698 struct window *w;
10699 struct glyph_row *row;
f02d8aa0 10700 int width;
dc6f92b8 10701{
92f424df
GM
10702 struct frame *f = XFRAME (w->frame);
10703 struct glyph *cursor_glyph;
10704 GC gc;
10705 int x;
10706 unsigned long mask;
10707 XGCValues xgcv;
10708 Display *dpy;
10709 Window window;
06a2c219 10710
92f424df
GM
10711 /* If cursor is out of bounds, don't draw garbage. This can happen
10712 in mini-buffer windows when switching between echo area glyphs
10713 and mini-buffer. */
10714 cursor_glyph = get_phys_cursor_glyph (w);
10715 if (cursor_glyph == NULL)
10716 return;
06a2c219 10717
92f424df
GM
10718 /* If on an image, draw like a normal cursor. That's usually better
10719 visible than drawing a bar, esp. if the image is large so that
10720 the bar might not be in the window. */
10721 if (cursor_glyph->type == IMAGE_GLYPH)
10722 {
10723 struct glyph_row *row;
10724 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
10725 x_draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
10726 }
10727 else
10728 {
06a2c219
GM
10729 xgcv.background = f->output_data.x->cursor_pixel;
10730 xgcv.foreground = f->output_data.x->cursor_pixel;
10731 xgcv.graphics_exposures = 0;
10732 mask = GCForeground | GCBackground | GCGraphicsExposures;
10733 dpy = FRAME_X_DISPLAY (f);
10734 window = FRAME_X_WINDOW (f);
10735 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
92f424df 10736
06a2c219
GM
10737 if (gc)
10738 XChangeGC (dpy, gc, mask, &xgcv);
10739 else
10740 {
10741 gc = XCreateGC (dpy, window, mask, &xgcv);
10742 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
10743 }
92f424df 10744
f02d8aa0
GM
10745 if (width < 0)
10746 width = f->output_data.x->cursor_width;
92f424df 10747
06a2c219
GM
10748 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10749 x_clip_to_row (w, row, gc, 0);
10750 XFillRectangle (dpy, window, gc,
10751 x,
10752 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
f02d8aa0 10753 min (cursor_glyph->pixel_width, width),
06a2c219
GM
10754 row->height);
10755 XSetClipMask (dpy, gc, None);
10756 }
dc6f92b8
JB
10757}
10758
06a2c219
GM
10759
10760/* Clear the cursor of window W to background color, and mark the
10761 cursor as not shown. This is used when the text where the cursor
10762 is is about to be rewritten. */
10763
dc6f92b8 10764static void
06a2c219
GM
10765x_clear_cursor (w)
10766 struct window *w;
dc6f92b8 10767{
06a2c219
GM
10768 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
10769 x_update_window_cursor (w, 0);
10770}
90e65f07 10771
dbc4e1c1 10772
06a2c219
GM
10773/* Draw the cursor glyph of window W in glyph row ROW. See the
10774 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 10775
06a2c219
GM
10776static void
10777x_draw_phys_cursor_glyph (w, row, hl)
10778 struct window *w;
10779 struct glyph_row *row;
10780 enum draw_glyphs_face hl;
10781{
10782 /* If cursor hpos is out of bounds, don't draw garbage. This can
10783 happen in mini-buffer windows when switching between echo area
10784 glyphs and mini-buffer. */
10785 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e
GM
10786 {
10787 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
10788 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
10789 hl, 0, 0, 0);
10790
10791 /* When we erase the cursor, and ROW is overlapped by other
10792 rows, make sure that these overlapping parts of other rows
10793 are redrawn. */
10794 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
10795 {
10796 if (row > w->current_matrix->rows
10797 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
10798 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
10799
10800 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
10801 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
10802 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
10803 }
10804 }
06a2c219 10805}
dbc4e1c1 10806
eea6af04 10807
06a2c219 10808/* Erase the image of a cursor of window W from the screen. */
eea6af04 10809
06a2c219
GM
10810static void
10811x_erase_phys_cursor (w)
10812 struct window *w;
10813{
10814 struct frame *f = XFRAME (w->frame);
10815 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10816 int hpos = w->phys_cursor.hpos;
10817 int vpos = w->phys_cursor.vpos;
10818 int mouse_face_here_p = 0;
10819 struct glyph_matrix *active_glyphs = w->current_matrix;
10820 struct glyph_row *cursor_row;
10821 struct glyph *cursor_glyph;
10822 enum draw_glyphs_face hl;
10823
10824 /* No cursor displayed or row invalidated => nothing to do on the
10825 screen. */
10826 if (w->phys_cursor_type == NO_CURSOR)
10827 goto mark_cursor_off;
10828
10829 /* VPOS >= active_glyphs->nrows means that window has been resized.
10830 Don't bother to erase the cursor. */
10831 if (vpos >= active_glyphs->nrows)
10832 goto mark_cursor_off;
10833
10834 /* If row containing cursor is marked invalid, there is nothing we
10835 can do. */
10836 cursor_row = MATRIX_ROW (active_glyphs, vpos);
10837 if (!cursor_row->enabled_p)
10838 goto mark_cursor_off;
10839
10840 /* This can happen when the new row is shorter than the old one.
10841 In this case, either x_draw_glyphs or clear_end_of_line
10842 should have cleared the cursor. Note that we wouldn't be
10843 able to erase the cursor in this case because we don't have a
10844 cursor glyph at hand. */
10845 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
10846 goto mark_cursor_off;
10847
10848 /* If the cursor is in the mouse face area, redisplay that when
10849 we clear the cursor. */
8801a864
KR
10850 if (! NILP (dpyinfo->mouse_face_window)
10851 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
10852 && (vpos > dpyinfo->mouse_face_beg_row
10853 || (vpos == dpyinfo->mouse_face_beg_row
10854 && hpos >= dpyinfo->mouse_face_beg_col))
10855 && (vpos < dpyinfo->mouse_face_end_row
10856 || (vpos == dpyinfo->mouse_face_end_row
10857 && hpos < dpyinfo->mouse_face_end_col))
10858 /* Don't redraw the cursor's spot in mouse face if it is at the
10859 end of a line (on a newline). The cursor appears there, but
10860 mouse highlighting does not. */
10861 && cursor_row->used[TEXT_AREA] > hpos)
10862 mouse_face_here_p = 1;
10863
10864 /* Maybe clear the display under the cursor. */
10865 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
10866 {
10867 int x;
045dee35 10868 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 10869
06a2c219
GM
10870 cursor_glyph = get_phys_cursor_glyph (w);
10871 if (cursor_glyph == NULL)
10872 goto mark_cursor_off;
dbc4e1c1 10873
06a2c219
GM
10874 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
10875
c5e6e06b
GM
10876 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
10877 x,
10878 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
10879 cursor_row->y)),
10880 cursor_glyph->pixel_width,
10881 cursor_row->visible_height,
10882 False);
dbc4e1c1 10883 }
06a2c219
GM
10884
10885 /* Erase the cursor by redrawing the character underneath it. */
10886 if (mouse_face_here_p)
10887 hl = DRAW_MOUSE_FACE;
10888 else if (cursor_row->inverse_p)
10889 hl = DRAW_INVERSE_VIDEO;
10890 else
10891 hl = DRAW_NORMAL_TEXT;
10892 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 10893
06a2c219
GM
10894 mark_cursor_off:
10895 w->phys_cursor_on_p = 0;
10896 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
10897}
10898
10899
06a2c219
GM
10900/* Display or clear cursor of window W. If ON is zero, clear the
10901 cursor. If it is non-zero, display the cursor. If ON is nonzero,
10902 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 10903
06a2c219
GM
10904void
10905x_display_and_set_cursor (w, on, hpos, vpos, x, y)
10906 struct window *w;
10907 int on, hpos, vpos, x, y;
dbc4e1c1 10908{
06a2c219
GM
10909 struct frame *f = XFRAME (w->frame);
10910 int new_cursor_type;
f02d8aa0 10911 int new_cursor_width;
06a2c219
GM
10912 struct glyph_matrix *current_glyphs;
10913 struct glyph_row *glyph_row;
10914 struct glyph *glyph;
dbc4e1c1 10915
49d838ea 10916 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
10917 windows and frames; in the latter case, the frame or window may
10918 be in the midst of changing its size, and x and y may be off the
10919 window. */
10920 if (! FRAME_VISIBLE_P (f)
10921 || FRAME_GARBAGED_P (f)
10922 || vpos >= w->current_matrix->nrows
10923 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
10924 return;
10925
10926 /* If cursor is off and we want it off, return quickly. */
06a2c219 10927 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
10928 return;
10929
06a2c219
GM
10930 current_glyphs = w->current_matrix;
10931 glyph_row = MATRIX_ROW (current_glyphs, vpos);
10932 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
10933
10934 /* If cursor row is not enabled, we don't really know where to
10935 display the cursor. */
10936 if (!glyph_row->enabled_p)
10937 {
10938 w->phys_cursor_on_p = 0;
10939 return;
10940 }
10941
10942 xassert (interrupt_input_blocked);
10943
10944 /* Set new_cursor_type to the cursor we want to be displayed. In a
10945 mini-buffer window, we want the cursor only to appear if we are
10946 reading input from this window. For the selected window, we want
10947 the cursor type given by the frame parameter. If explicitly
10948 marked off, draw no cursor. In all other cases, we want a hollow
10949 box cursor. */
f02d8aa0 10950 new_cursor_width = -1;
9b4a7047
GM
10951 if (cursor_in_echo_area
10952 && FRAME_HAS_MINIBUF_P (f)
10953 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 10954 {
9b4a7047
GM
10955 if (w == XWINDOW (echo_area_window))
10956 new_cursor_type = FRAME_DESIRED_CURSOR (f);
06a2c219
GM
10957 else
10958 new_cursor_type = HOLLOW_BOX_CURSOR;
10959 }
06a2c219 10960 else
9b4a7047 10961 {
7a58ab59
GM
10962 if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
10963 || w != XWINDOW (f->selected_window))
9b4a7047 10964 {
e55a0b79
GM
10965 extern int cursor_in_non_selected_windows;
10966
5cefa566
GM
10967 if (MINI_WINDOW_P (w)
10968 || !cursor_in_non_selected_windows
10969 || NILP (XBUFFER (w->buffer)->cursor_type))
9b4a7047
GM
10970 new_cursor_type = NO_CURSOR;
10971 else
10972 new_cursor_type = HOLLOW_BOX_CURSOR;
10973 }
10974 else if (w->cursor_off_p)
10975 new_cursor_type = NO_CURSOR;
10976 else
f02d8aa0
GM
10977 {
10978 struct buffer *b = XBUFFER (w->buffer);
10979
10980 if (EQ (b->cursor_type, Qt))
10981 new_cursor_type = FRAME_DESIRED_CURSOR (f);
10982 else
10983 new_cursor_type = x_specified_cursor_type (b->cursor_type,
10984 &new_cursor_width);
10985 }
9b4a7047 10986 }
06a2c219
GM
10987
10988 /* If cursor is currently being shown and we don't want it to be or
10989 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 10990 erase it. */
06a2c219 10991 if (w->phys_cursor_on_p
dc6f92b8 10992 && (!on
06a2c219
GM
10993 || w->phys_cursor.x != x
10994 || w->phys_cursor.y != y
10995 || new_cursor_type != w->phys_cursor_type))
10996 x_erase_phys_cursor (w);
10997
10998 /* If the cursor is now invisible and we want it to be visible,
10999 display it. */
11000 if (on && !w->phys_cursor_on_p)
11001 {
11002 w->phys_cursor_ascent = glyph_row->ascent;
11003 w->phys_cursor_height = glyph_row->height;
11004
11005 /* Set phys_cursor_.* before x_draw_.* is called because some
11006 of them may need the information. */
11007 w->phys_cursor.x = x;
11008 w->phys_cursor.y = glyph_row->y;
11009 w->phys_cursor.hpos = hpos;
11010 w->phys_cursor.vpos = vpos;
11011 w->phys_cursor_type = new_cursor_type;
11012 w->phys_cursor_on_p = 1;
11013
11014 switch (new_cursor_type)
dc6f92b8 11015 {
06a2c219
GM
11016 case HOLLOW_BOX_CURSOR:
11017 x_draw_hollow_cursor (w, glyph_row);
11018 break;
11019
11020 case FILLED_BOX_CURSOR:
11021 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
11022 break;
11023
11024 case BAR_CURSOR:
f02d8aa0 11025 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
11026 break;
11027
11028 case NO_CURSOR:
11029 break;
dc6f92b8 11030
06a2c219
GM
11031 default:
11032 abort ();
11033 }
59ddecde
GM
11034
11035#ifdef HAVE_X_I18N
11036 if (w == XWINDOW (f->selected_window))
11037 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
11038 xic_set_preeditarea (w, x, y);
11039#endif
dc6f92b8
JB
11040 }
11041
06a2c219 11042#ifndef XFlush
f676886a 11043 if (updating_frame != f)
334208b7 11044 XFlush (FRAME_X_DISPLAY (f));
06a2c219 11045#endif
dc6f92b8
JB
11046}
11047
06a2c219
GM
11048
11049/* Display the cursor on window W, or clear it. X and Y are window
11050 relative pixel coordinates. HPOS and VPOS are glyph matrix
11051 positions. If W is not the selected window, display a hollow
11052 cursor. ON non-zero means display the cursor at X, Y which
11053 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 11054
dfcf069d 11055void
06a2c219
GM
11056x_display_cursor (w, on, hpos, vpos, x, y)
11057 struct window *w;
11058 int on, hpos, vpos, x, y;
dc6f92b8 11059{
f94397b5 11060 BLOCK_INPUT;
06a2c219 11061 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
11062 UNBLOCK_INPUT;
11063}
11064
06a2c219
GM
11065
11066/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
11067 Don't change the cursor's position. */
11068
dfcf069d 11069void
06a2c219 11070x_update_cursor (f, on_p)
5d46f928 11071 struct frame *f;
5d46f928 11072{
06a2c219
GM
11073 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
11074}
11075
11076
11077/* Call x_update_window_cursor with parameter ON_P on all leaf windows
11078 in the window tree rooted at W. */
11079
11080static void
11081x_update_cursor_in_window_tree (w, on_p)
11082 struct window *w;
11083 int on_p;
11084{
11085 while (w)
11086 {
11087 if (!NILP (w->hchild))
11088 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
11089 else if (!NILP (w->vchild))
11090 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
11091 else
11092 x_update_window_cursor (w, on_p);
11093
11094 w = NILP (w->next) ? 0 : XWINDOW (w->next);
11095 }
11096}
5d46f928 11097
f94397b5 11098
06a2c219
GM
11099/* Switch the display of W's cursor on or off, according to the value
11100 of ON. */
11101
11102static void
11103x_update_window_cursor (w, on)
11104 struct window *w;
11105 int on;
11106{
16b5d424
GM
11107 /* Don't update cursor in windows whose frame is in the process
11108 of being deleted. */
11109 if (w->current_matrix)
11110 {
11111 BLOCK_INPUT;
11112 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
11113 w->phys_cursor.x, w->phys_cursor.y);
11114 UNBLOCK_INPUT;
11115 }
dc6f92b8 11116}
06a2c219
GM
11117
11118
11119
dc6f92b8
JB
11120\f
11121/* Icons. */
11122
f676886a 11123/* Refresh bitmap kitchen sink icon for frame F
06a2c219 11124 when we get an expose event for it. */
dc6f92b8 11125
dfcf069d 11126void
f676886a
JB
11127refreshicon (f)
11128 struct frame *f;
dc6f92b8 11129{
06a2c219 11130 /* Normally, the window manager handles this function. */
dc6f92b8
JB
11131}
11132
dbc4e1c1 11133/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
11134
11135int
990ba854 11136x_bitmap_icon (f, file)
f676886a 11137 struct frame *f;
990ba854 11138 Lisp_Object file;
dc6f92b8 11139{
06a2c219 11140 int bitmap_id;
dc6f92b8 11141
c118dd06 11142 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11143 return 1;
11144
990ba854 11145 /* Free up our existing icon bitmap if any. */
7556890b
RS
11146 if (f->output_data.x->icon_bitmap > 0)
11147 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11148 f->output_data.x->icon_bitmap = 0;
990ba854
RS
11149
11150 if (STRINGP (file))
7f2ae036
RS
11151 bitmap_id = x_create_bitmap_from_file (f, file);
11152 else
11153 {
990ba854 11154 /* Create the GNU bitmap if necessary. */
5bf01b68 11155 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
11156 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
11157 = x_create_bitmap_from_data (f, gnu_bits,
11158 gnu_width, gnu_height);
990ba854
RS
11159
11160 /* The first time we create the GNU bitmap,
06a2c219 11161 this increments the ref-count one extra time.
990ba854
RS
11162 As a result, the GNU bitmap is never freed.
11163 That way, we don't have to worry about allocating it again. */
334208b7 11164 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 11165
334208b7 11166 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
11167 }
11168
11169 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 11170 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
11171
11172 return 0;
11173}
11174
11175
1be2d067
KH
11176/* Make the x-window of frame F use a rectangle with text.
11177 Use ICON_NAME as the text. */
dc6f92b8
JB
11178
11179int
f676886a
JB
11180x_text_icon (f, icon_name)
11181 struct frame *f;
dc6f92b8
JB
11182 char *icon_name;
11183{
c118dd06 11184 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11185 return 1;
11186
1be2d067
KH
11187#ifdef HAVE_X11R4
11188 {
11189 XTextProperty text;
11190 text.value = (unsigned char *) icon_name;
11191 text.encoding = XA_STRING;
11192 text.format = 8;
11193 text.nitems = strlen (icon_name);
11194#ifdef USE_X_TOOLKIT
7556890b 11195 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
11196 &text);
11197#else /* not USE_X_TOOLKIT */
11198 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
11199#endif /* not USE_X_TOOLKIT */
11200 }
11201#else /* not HAVE_X11R4 */
11202 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
11203#endif /* not HAVE_X11R4 */
58769bee 11204
7556890b
RS
11205 if (f->output_data.x->icon_bitmap > 0)
11206 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11207 f->output_data.x->icon_bitmap = 0;
b1c884c3 11208 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
11209
11210 return 0;
11211}
11212\f
e99db5a1
RS
11213#define X_ERROR_MESSAGE_SIZE 200
11214
11215/* If non-nil, this should be a string.
11216 It means catch X errors and store the error message in this string. */
11217
11218static Lisp_Object x_error_message_string;
11219
11220/* An X error handler which stores the error message in
11221 x_error_message_string. This is called from x_error_handler if
11222 x_catch_errors is in effect. */
11223
06a2c219 11224static void
e99db5a1
RS
11225x_error_catcher (display, error)
11226 Display *display;
11227 XErrorEvent *error;
11228{
11229 XGetErrorText (display, error->error_code,
11230 XSTRING (x_error_message_string)->data,
11231 X_ERROR_MESSAGE_SIZE);
11232}
11233
11234/* Begin trapping X errors for display DPY. Actually we trap X errors
11235 for all displays, but DPY should be the display you are actually
11236 operating on.
11237
11238 After calling this function, X protocol errors no longer cause
11239 Emacs to exit; instead, they are recorded in the string
11240 stored in x_error_message_string.
11241
11242 Calling x_check_errors signals an Emacs error if an X error has
11243 occurred since the last call to x_catch_errors or x_check_errors.
11244
11245 Calling x_uncatch_errors resumes the normal error handling. */
11246
11247void x_check_errors ();
11248static Lisp_Object x_catch_errors_unwind ();
11249
11250int
11251x_catch_errors (dpy)
11252 Display *dpy;
11253{
11254 int count = specpdl_ptr - specpdl;
11255
11256 /* Make sure any errors from previous requests have been dealt with. */
11257 XSync (dpy, False);
11258
11259 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
11260
11261 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
11262 XSTRING (x_error_message_string)->data[0] = 0;
11263
11264 return count;
11265}
11266
11267/* Unbind the binding that we made to check for X errors. */
11268
11269static Lisp_Object
11270x_catch_errors_unwind (old_val)
11271 Lisp_Object old_val;
11272{
11273 x_error_message_string = old_val;
11274 return Qnil;
11275}
11276
11277/* If any X protocol errors have arrived since the last call to
11278 x_catch_errors or x_check_errors, signal an Emacs error using
11279 sprintf (a buffer, FORMAT, the x error message text) as the text. */
11280
11281void
11282x_check_errors (dpy, format)
11283 Display *dpy;
11284 char *format;
11285{
11286 /* Make sure to catch any errors incurred so far. */
11287 XSync (dpy, False);
11288
11289 if (XSTRING (x_error_message_string)->data[0])
11290 error (format, XSTRING (x_error_message_string)->data);
11291}
11292
9829ddba
RS
11293/* Nonzero if we had any X protocol errors
11294 since we did x_catch_errors on DPY. */
e99db5a1
RS
11295
11296int
11297x_had_errors_p (dpy)
11298 Display *dpy;
11299{
11300 /* Make sure to catch any errors incurred so far. */
11301 XSync (dpy, False);
11302
11303 return XSTRING (x_error_message_string)->data[0] != 0;
11304}
11305
9829ddba
RS
11306/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
11307
06a2c219 11308void
9829ddba
RS
11309x_clear_errors (dpy)
11310 Display *dpy;
11311{
11312 XSTRING (x_error_message_string)->data[0] = 0;
11313}
11314
e99db5a1
RS
11315/* Stop catching X protocol errors and let them make Emacs die.
11316 DPY should be the display that was passed to x_catch_errors.
11317 COUNT should be the value that was returned by
11318 the corresponding call to x_catch_errors. */
11319
11320void
11321x_uncatch_errors (dpy, count)
11322 Display *dpy;
11323 int count;
11324{
11325 unbind_to (count, Qnil);
11326}
11327
11328#if 0
11329static unsigned int x_wire_count;
11330x_trace_wire ()
11331{
11332 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
11333}
11334#endif /* ! 0 */
11335
11336\f
11337/* Handle SIGPIPE, which can happen when the connection to a server
11338 simply goes away. SIGPIPE is handled by x_connection_signal.
11339 Don't need to do anything, because the write which caused the
11340 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 11341 which will do the appropriate cleanup for us. */
e99db5a1
RS
11342
11343static SIGTYPE
11344x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 11345 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
11346{
11347#ifdef USG
11348 /* USG systems forget handlers when they are used;
11349 must reestablish each time */
11350 signal (signalnum, x_connection_signal);
11351#endif /* USG */
11352}
0da1ab50 11353
e99db5a1 11354\f
0da1ab50
GM
11355/************************************************************************
11356 Handling X errors
11357 ************************************************************************/
4746118a 11358
0da1ab50
GM
11359/* Handle the loss of connection to display DPY. ERROR_MESSAGE is
11360 the text of an error message that lead to the connection loss. */
16bd92ea 11361
4746118a 11362static SIGTYPE
5978125e
GM
11363x_connection_closed (dpy, error_message)
11364 Display *dpy;
7a13e894 11365 char *error_message;
4746118a 11366{
5978125e 11367 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
7a13e894 11368 Lisp_Object frame, tail;
0da1ab50
GM
11369 int count;
11370 char *msg;
11371
11372 msg = (char *) alloca (strlen (error_message) + 1);
11373 strcpy (msg, error_message);
1a532e54
GM
11374 handling_signal = 0;
11375
0da1ab50
GM
11376 /* Prevent being called recursively because of an error condition
11377 below. Otherwise, we might end up with printing ``can't find per
11378 display information'' in the recursive call instead of printing
11379 the original message here. */
11380 count = x_catch_errors (dpy);
11381
8a4f36cc
GM
11382 /* We have to close the display to inform Xt that it doesn't
11383 exist anymore. If we don't, Xt will continue to wait for
11384 events from the display. As a consequence, a sequence of
11385
11386 M-x make-frame-on-display RET :1 RET
11387 ...kill the new frame, so that we get an IO error...
11388 M-x make-frame-on-display RET :1 RET
11389
11390 will indefinitely wait in Xt for events for display `:1', opened
11391 in the first class to make-frame-on-display.
6186a4a0 11392
8a4f36cc
GM
11393 Closing the display is reported to lead to a bus error on
11394 OpenWindows in certain situations. I suspect that is a bug
11395 in OpenWindows. I don't know how to cicumvent it here. */
11396
f613a4c8 11397#ifdef USE_X_TOOLKIT
ae24cb3b
GM
11398 /* If DPYINFO is null, this means we didn't open the display
11399 in the first place, so don't try to close it. */
11400 if (dpyinfo)
11401 XtCloseDisplay (dpy);
f613a4c8 11402#endif
adabc3a9 11403
8a4f36cc 11404 /* Indicate that this display is dead. */
9e80b57d
KR
11405 if (dpyinfo)
11406 dpyinfo->display = 0;
6186a4a0 11407
06a2c219 11408 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
11409 that are on the dead display. */
11410 FOR_EACH_FRAME (tail, frame)
11411 {
11412 Lisp_Object minibuf_frame;
11413 minibuf_frame
11414 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
11415 if (FRAME_X_P (XFRAME (frame))
11416 && FRAME_X_P (XFRAME (minibuf_frame))
11417 && ! EQ (frame, minibuf_frame)
11418 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
11419 Fdelete_frame (frame, Qt);
11420 }
11421
11422 /* Now delete all remaining frames on the dead display.
06a2c219 11423 We are now sure none of these is used as the mini-buffer
7a13e894
RS
11424 for another frame that we need to delete. */
11425 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
11426 if (FRAME_X_P (XFRAME (frame))
11427 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
11428 {
11429 /* Set this to t so that Fdelete_frame won't get confused
11430 trying to find a replacement. */
11431 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
11432 Fdelete_frame (frame, Qt);
11433 }
7a13e894 11434
482a1bd2
KH
11435 if (dpyinfo)
11436 x_delete_display (dpyinfo);
7a13e894 11437
0da1ab50
GM
11438 x_uncatch_errors (dpy, count);
11439
7a13e894
RS
11440 if (x_display_list == 0)
11441 {
0da1ab50 11442 fprintf (stderr, "%s\n", msg);
7a13e894
RS
11443 shut_down_emacs (0, 0, Qnil);
11444 exit (70);
11445 }
12ba150f 11446
7a13e894
RS
11447 /* Ordinary stack unwind doesn't deal with these. */
11448#ifdef SIGIO
11449 sigunblock (sigmask (SIGIO));
11450#endif
11451 sigunblock (sigmask (SIGALRM));
11452 TOTALLY_UNBLOCK_INPUT;
11453
aa4d9a9e 11454 clear_waiting_for_input ();
0da1ab50 11455 error ("%s", msg);
4746118a
JB
11456}
11457
0da1ab50 11458
7a13e894
RS
11459/* This is the usual handler for X protocol errors.
11460 It kills all frames on the display that we got the error for.
11461 If that was the only one, it prints an error message and kills Emacs. */
11462
06a2c219 11463static void
c118dd06
JB
11464x_error_quitter (display, error)
11465 Display *display;
11466 XErrorEvent *error;
11467{
7a13e894 11468 char buf[256], buf1[356];
dc6f92b8 11469
58769bee 11470 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 11471 original error handler. */
dc6f92b8 11472
c118dd06 11473 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 11474 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 11475 buf, error->request_code);
7a13e894 11476 x_connection_closed (display, buf1);
dc6f92b8
JB
11477}
11478
0da1ab50 11479
e99db5a1
RS
11480/* This is the first-level handler for X protocol errors.
11481 It calls x_error_quitter or x_error_catcher. */
7a13e894 11482
8922af5f 11483static int
e99db5a1 11484x_error_handler (display, error)
8922af5f 11485 Display *display;
e99db5a1 11486 XErrorEvent *error;
8922af5f 11487{
e99db5a1
RS
11488 if (! NILP (x_error_message_string))
11489 x_error_catcher (display, error);
11490 else
11491 x_error_quitter (display, error);
06a2c219 11492 return 0;
f9e24cb9 11493}
c118dd06 11494
e99db5a1
RS
11495/* This is the handler for X IO errors, always.
11496 It kills all frames on the display that we lost touch with.
11497 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 11498
c118dd06 11499static int
e99db5a1 11500x_io_error_quitter (display)
c118dd06 11501 Display *display;
c118dd06 11502{
e99db5a1 11503 char buf[256];
dc6f92b8 11504
e99db5a1
RS
11505 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
11506 x_connection_closed (display, buf);
06a2c219 11507 return 0;
dc6f92b8 11508}
dc6f92b8 11509\f
f451eb13
JB
11510/* Changing the font of the frame. */
11511
76bcdf39
RS
11512/* Give frame F the font named FONTNAME as its default font, and
11513 return the full name of that font. FONTNAME may be a wildcard
11514 pattern; in that case, we choose some font that fits the pattern.
11515 The return value shows which font we chose. */
11516
b5cf7a0e 11517Lisp_Object
f676886a
JB
11518x_new_font (f, fontname)
11519 struct frame *f;
dc6f92b8
JB
11520 register char *fontname;
11521{
dc43ef94 11522 struct font_info *fontp
ee569018 11523 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 11524
dc43ef94
KH
11525 if (!fontp)
11526 return Qnil;
2224a5fc 11527
dc43ef94 11528 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 11529 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
11530 f->output_data.x->fontset = -1;
11531
b2cad826
KH
11532 /* Compute the scroll bar width in character columns. */
11533 if (f->scroll_bar_pixel_width > 0)
11534 {
7556890b 11535 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
11536 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
11537 }
11538 else
4e61bddf
RS
11539 {
11540 int wid = FONT_WIDTH (f->output_data.x->font);
11541 f->scroll_bar_cols = (14 + wid - 1) / wid;
11542 }
b2cad826 11543
f676886a 11544 /* Now make the frame display the given font. */
c118dd06 11545 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 11546 {
7556890b
RS
11547 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
11548 f->output_data.x->font->fid);
11549 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
11550 f->output_data.x->font->fid);
11551 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
11552 f->output_data.x->font->fid);
f676886a 11553
a27f9f86 11554 frame_update_line_height (f);
3497f73e
GM
11555
11556 /* Don't change the size of a tip frame; there's no point in
11557 doing it because it's done in Fx_show_tip, and it leads to
11558 problems because the tip frame has no widget. */
11559 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
11560 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 11561 }
a27f9f86
RS
11562 else
11563 /* If we are setting a new frame's font for the first time,
11564 there are no faces yet, so this font's height is the line height. */
7556890b 11565 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 11566
dc43ef94
KH
11567 return build_string (fontp->full_name);
11568}
11569
11570/* Give frame F the fontset named FONTSETNAME as its default font, and
11571 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
11572 pattern; in that case, we choose some fontset that fits the pattern.
11573 The return value shows which fontset we chose. */
b5cf7a0e 11574
dc43ef94
KH
11575Lisp_Object
11576x_new_fontset (f, fontsetname)
11577 struct frame *f;
11578 char *fontsetname;
11579{
ee569018 11580 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 11581 Lisp_Object result;
b5cf7a0e 11582
dc43ef94
KH
11583 if (fontset < 0)
11584 return Qnil;
b5cf7a0e 11585
2da424f1
KH
11586 if (f->output_data.x->fontset == fontset)
11587 /* This fontset is already set in frame F. There's nothing more
11588 to do. */
ee569018 11589 return fontset_name (fontset);
dc43ef94 11590
ee569018 11591 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
11592
11593 if (!STRINGP (result))
11594 /* Can't load ASCII font. */
11595 return Qnil;
11596
11597 /* Since x_new_font doesn't update any fontset information, do it now. */
11598 f->output_data.x->fontset = fontset;
dc43ef94 11599
f5d11644
GM
11600#ifdef HAVE_X_I18N
11601 if (FRAME_XIC (f)
11602 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 11603 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
11604#endif
11605
dc43ef94 11606 return build_string (fontsetname);
dc6f92b8 11607}
f5d11644
GM
11608
11609\f
11610/***********************************************************************
11611 X Input Methods
11612 ***********************************************************************/
11613
11614#ifdef HAVE_X_I18N
11615
11616#ifdef HAVE_X11R6
11617
11618/* XIM destroy callback function, which is called whenever the
11619 connection to input method XIM dies. CLIENT_DATA contains a
11620 pointer to the x_display_info structure corresponding to XIM. */
11621
11622static void
11623xim_destroy_callback (xim, client_data, call_data)
11624 XIM xim;
11625 XPointer client_data;
11626 XPointer call_data;
11627{
11628 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
11629 Lisp_Object frame, tail;
11630
11631 BLOCK_INPUT;
11632
11633 /* No need to call XDestroyIC.. */
11634 FOR_EACH_FRAME (tail, frame)
11635 {
11636 struct frame *f = XFRAME (frame);
11637 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
11638 {
11639 FRAME_XIC (f) = NULL;
11640 if (FRAME_XIC_FONTSET (f))
11641 {
11642 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
11643 FRAME_XIC_FONTSET (f) = NULL;
11644 }
11645 }
11646 }
11647
11648 /* No need to call XCloseIM. */
11649 dpyinfo->xim = NULL;
11650 XFree (dpyinfo->xim_styles);
11651 UNBLOCK_INPUT;
11652}
11653
11654#endif /* HAVE_X11R6 */
11655
11656/* Open the connection to the XIM server on display DPYINFO.
11657 RESOURCE_NAME is the resource name Emacs uses. */
11658
11659static void
11660xim_open_dpy (dpyinfo, resource_name)
11661 struct x_display_info *dpyinfo;
11662 char *resource_name;
11663{
287f7dd6 11664#ifdef USE_XIM
f5d11644
GM
11665 XIM xim;
11666
11667 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
11668 dpyinfo->xim = xim;
11669
11670 if (xim)
11671 {
f5d11644
GM
11672#ifdef HAVE_X11R6
11673 XIMCallback destroy;
11674#endif
11675
11676 /* Get supported styles and XIM values. */
11677 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
11678
11679#ifdef HAVE_X11R6
11680 destroy.callback = xim_destroy_callback;
11681 destroy.client_data = (XPointer)dpyinfo;
68642df6 11682 /* This isn't prptotyped in OSF 5.0. */
f5d11644
GM
11683 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
11684#endif
11685 }
287f7dd6
GM
11686
11687#else /* not USE_XIM */
11688 dpyinfo->xim = NULL;
11689#endif /* not USE_XIM */
f5d11644
GM
11690}
11691
11692
b9de836c 11693#ifdef HAVE_X11R6_XIM
f5d11644
GM
11694
11695struct xim_inst_t
11696{
11697 struct x_display_info *dpyinfo;
11698 char *resource_name;
11699};
11700
11701/* XIM instantiate callback function, which is called whenever an XIM
11702 server is available. DISPLAY is teh display of the XIM.
11703 CLIENT_DATA contains a pointer to an xim_inst_t structure created
11704 when the callback was registered. */
11705
11706static void
11707xim_instantiate_callback (display, client_data, call_data)
11708 Display *display;
11709 XPointer client_data;
11710 XPointer call_data;
11711{
11712 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
11713 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
11714
11715 /* We don't support multiple XIM connections. */
11716 if (dpyinfo->xim)
11717 return;
11718
11719 xim_open_dpy (dpyinfo, xim_inst->resource_name);
11720
11721 /* Create XIC for the existing frames on the same display, as long
11722 as they have no XIC. */
11723 if (dpyinfo->xim && dpyinfo->reference_count > 0)
11724 {
11725 Lisp_Object tail, frame;
11726
11727 BLOCK_INPUT;
11728 FOR_EACH_FRAME (tail, frame)
11729 {
11730 struct frame *f = XFRAME (frame);
11731
11732 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
11733 if (FRAME_XIC (f) == NULL)
11734 {
11735 create_frame_xic (f);
11736 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
11737 xic_set_statusarea (f);
11738 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
11739 {
11740 struct window *w = XWINDOW (f->selected_window);
11741 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
11742 }
11743 }
11744 }
11745
11746 UNBLOCK_INPUT;
11747 }
11748}
11749
b9de836c 11750#endif /* HAVE_X11R6_XIM */
f5d11644
GM
11751
11752
11753/* Open a connection to the XIM server on display DPYINFO.
11754 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
11755 connection only at the first time. On X11R6, open the connection
11756 in the XIM instantiate callback function. */
11757
11758static void
11759xim_initialize (dpyinfo, resource_name)
11760 struct x_display_info *dpyinfo;
11761 char *resource_name;
11762{
287f7dd6 11763#ifdef USE_XIM
b9de836c 11764#ifdef HAVE_X11R6_XIM
f5d11644
GM
11765 struct xim_inst_t *xim_inst;
11766 int len;
11767
11768 dpyinfo->xim = NULL;
11769 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
11770 xim_inst->dpyinfo = dpyinfo;
11771 len = strlen (resource_name);
11772 xim_inst->resource_name = (char *) xmalloc (len + 1);
11773 bcopy (resource_name, xim_inst->resource_name, len + 1);
11774 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11775 resource_name, EMACS_CLASS,
11776 xim_instantiate_callback,
2ebb2f8b
DL
11777 /* Fixme: This is XPointer in
11778 XFree86 but (XPointer *) on
11779 Tru64, at least. */
11780 (XPointer) xim_inst);
b9de836c 11781#else /* not HAVE_X11R6_XIM */
f5d11644
GM
11782 dpyinfo->xim = NULL;
11783 xim_open_dpy (dpyinfo, resource_name);
b9de836c 11784#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
11785
11786#else /* not USE_XIM */
11787 dpyinfo->xim = NULL;
11788#endif /* not USE_XIM */
f5d11644
GM
11789}
11790
11791
11792/* Close the connection to the XIM server on display DPYINFO. */
11793
11794static void
11795xim_close_dpy (dpyinfo)
11796 struct x_display_info *dpyinfo;
11797{
287f7dd6 11798#ifdef USE_XIM
b9de836c 11799#ifdef HAVE_X11R6_XIM
8a4f36cc
GM
11800 if (dpyinfo->display)
11801 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
11802 NULL, EMACS_CLASS,
11803 xim_instantiate_callback, NULL);
b9de836c 11804#endif /* not HAVE_X11R6_XIM */
8a4f36cc
GM
11805 if (dpyinfo->display)
11806 XCloseIM (dpyinfo->xim);
f5d11644
GM
11807 dpyinfo->xim = NULL;
11808 XFree (dpyinfo->xim_styles);
287f7dd6 11809#endif /* USE_XIM */
f5d11644
GM
11810}
11811
b9de836c 11812#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
11813
11814
dc6f92b8 11815\f
2e365682
RS
11816/* Calculate the absolute position in frame F
11817 from its current recorded position values and gravity. */
11818
dfcf069d 11819void
43bca5d5 11820x_calc_absolute_position (f)
f676886a 11821 struct frame *f;
dc6f92b8 11822{
06a2c219 11823 Window child;
6dba1858 11824 int win_x = 0, win_y = 0;
7556890b 11825 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
11826 int this_window;
11827
9829ddba
RS
11828 /* We have nothing to do if the current position
11829 is already for the top-left corner. */
11830 if (! ((flags & XNegative) || (flags & YNegative)))
11831 return;
11832
c81412a0 11833#ifdef USE_X_TOOLKIT
7556890b 11834 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
11835#else
11836 this_window = FRAME_X_WINDOW (f);
11837#endif
6dba1858
RS
11838
11839 /* Find the position of the outside upper-left corner of
9829ddba
RS
11840 the inner window, with respect to the outer window.
11841 But do this only if we will need the results. */
7556890b 11842 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 11843 {
9829ddba
RS
11844 int count;
11845
6dba1858 11846 BLOCK_INPUT;
9829ddba
RS
11847 count = x_catch_errors (FRAME_X_DISPLAY (f));
11848 while (1)
11849 {
11850 x_clear_errors (FRAME_X_DISPLAY (f));
11851 XTranslateCoordinates (FRAME_X_DISPLAY (f),
11852
11853 /* From-window, to-window. */
11854 this_window,
11855 f->output_data.x->parent_desc,
11856
11857 /* From-position, to-position. */
11858 0, 0, &win_x, &win_y,
11859
11860 /* Child of win. */
11861 &child);
11862 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
11863 {
11864 Window newroot, newparent = 0xdeadbeef;
11865 Window *newchildren;
2ebb2f8b 11866 unsigned int nchildren;
9829ddba
RS
11867
11868 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
11869 &newparent, &newchildren, &nchildren))
11870 break;
58769bee 11871
7c3c78a3 11872 XFree ((char *) newchildren);
6dba1858 11873
9829ddba
RS
11874 f->output_data.x->parent_desc = newparent;
11875 }
11876 else
11877 break;
11878 }
6dba1858 11879
9829ddba 11880 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
11881 UNBLOCK_INPUT;
11882 }
11883
11884 /* Treat negative positions as relative to the leftmost bottommost
11885 position that fits on the screen. */
20f55f9a 11886 if (flags & XNegative)
7556890b 11887 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
11888 - 2 * f->output_data.x->border_width - win_x
11889 - PIXEL_WIDTH (f)
11890 + f->output_data.x->left_pos);
dc6f92b8 11891
7708ced0
GM
11892 {
11893 int height = PIXEL_HEIGHT (f);
06a2c219 11894
7708ced0
GM
11895#if defined USE_X_TOOLKIT && defined USE_MOTIF
11896 /* Something is fishy here. When using Motif, starting Emacs with
11897 `-g -0-0', the frame appears too low by a few pixels.
11898
11899 This seems to be so because initially, while Emacs is starting,
11900 the column widget's height and the frame's pixel height are
11901 different. The column widget's height is the right one. In
11902 later invocations, when Emacs is up, the frame's pixel height
11903 is right, though.
11904
11905 It's not obvious where the initial small difference comes from.
11906 2000-12-01, gerd. */
11907
11908 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
06a2c219 11909#endif
2e365682 11910
7708ced0
GM
11911 if (flags & YNegative)
11912 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
11913 - 2 * f->output_data.x->border_width
11914 - win_y
11915 - height
11916 + f->output_data.x->top_pos);
11917 }
11918
3a35ab44
RS
11919 /* The left_pos and top_pos
11920 are now relative to the top and left screen edges,
11921 so the flags should correspond. */
7556890b 11922 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
11923}
11924
3a35ab44
RS
11925/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
11926 to really change the position, and 0 when calling from
11927 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
11928 position values). It is -1 when calling from x_set_frame_parameters,
11929 which means, do adjust for borders but don't change the gravity. */
3a35ab44 11930
dfcf069d 11931void
dc05a16b 11932x_set_offset (f, xoff, yoff, change_gravity)
f676886a 11933 struct frame *f;
dc6f92b8 11934 register int xoff, yoff;
dc05a16b 11935 int change_gravity;
dc6f92b8 11936{
4a4cbdd5
KH
11937 int modified_top, modified_left;
11938
aa3ff7c9 11939 if (change_gravity > 0)
3a35ab44 11940 {
7556890b
RS
11941 f->output_data.x->top_pos = yoff;
11942 f->output_data.x->left_pos = xoff;
11943 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 11944 if (xoff < 0)
7556890b 11945 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 11946 if (yoff < 0)
7556890b
RS
11947 f->output_data.x->size_hint_flags |= YNegative;
11948 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 11949 }
43bca5d5 11950 x_calc_absolute_position (f);
dc6f92b8
JB
11951
11952 BLOCK_INPUT;
c32cdd9a 11953 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 11954
7556890b
RS
11955 modified_left = f->output_data.x->left_pos;
11956 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
11957#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
11958 this seems to be unnecessary and incorrect. rms, 4/17/97. */
11959 /* It is a mystery why we need to add the border_width here
11960 when the frame is already visible, but experiment says we do. */
aa3ff7c9 11961 if (change_gravity != 0)
4a4cbdd5 11962 {
7556890b
RS
11963 modified_left += f->output_data.x->border_width;
11964 modified_top += f->output_data.x->border_width;
4a4cbdd5 11965 }
e73ec6fa 11966#endif
4a4cbdd5 11967
3afe33e7 11968#ifdef USE_X_TOOLKIT
7556890b 11969 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 11970 modified_left, modified_top);
3afe33e7 11971#else /* not USE_X_TOOLKIT */
334208b7 11972 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 11973 modified_left, modified_top);
3afe33e7 11974#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
11975 UNBLOCK_INPUT;
11976}
11977
dc6f92b8 11978
499b1844
GM
11979/* Change the size of frame F's X window to COLS/ROWS in the case F
11980 doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
11981 top-left-corner window gravity for this size change and subsequent
11982 size changes. Otherwise we leave the window gravity unchanged. */
11983
11984static void
11985x_set_window_size_1 (f, change_gravity, cols, rows)
f676886a 11986 struct frame *f;
bc20ebbf 11987 int change_gravity;
b1c884c3 11988 int cols, rows;
dc6f92b8
JB
11989{
11990 int pixelwidth, pixelheight;
80fd1fe2 11991
b1c884c3 11992 check_frame_size (f, &rows, &cols);
7556890b 11993 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
11994 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
11995 ? 0
11996 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 11997 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 11998 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 11999 f->output_data.x->flags_areas_extra
110859fc 12000 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
12001 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
12002 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 12003
7556890b 12004 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 12005 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 12006
334208b7
RS
12007 XSync (FRAME_X_DISPLAY (f), False);
12008 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12009 pixelwidth, pixelheight);
b1c884c3
JB
12010
12011 /* Now, strictly speaking, we can't be sure that this is accurate,
12012 but the window manager will get around to dealing with the size
12013 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
12014 ConfigureNotify event gets here.
12015
12016 We could just not bother storing any of this information here,
12017 and let the ConfigureNotify event set everything up, but that
fddd5ceb 12018 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 12019 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
12020 point in the future when the ConfigureNotify event arrives.
12021
12022 We pass 1 for DELAY since we can't run Lisp code inside of
12023 a BLOCK_INPUT. */
7d1e984f 12024 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
12025 PIXEL_WIDTH (f) = pixelwidth;
12026 PIXEL_HEIGHT (f) = pixelheight;
12027
aee9a898
RS
12028 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
12029 receive in the ConfigureNotify event; if we get what we asked
12030 for, then the event won't cause the screen to become garbaged, so
12031 we have to make sure to do it here. */
12032 SET_FRAME_GARBAGED (f);
12033
12034 XFlush (FRAME_X_DISPLAY (f));
499b1844
GM
12035}
12036
12037
12038/* Call this to change the size of frame F's x-window.
12039 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
12040 for this size change and subsequent size changes.
12041 Otherwise we leave the window gravity unchanged. */
aee9a898 12042
499b1844
GM
12043void
12044x_set_window_size (f, change_gravity, cols, rows)
12045 struct frame *f;
12046 int change_gravity;
12047 int cols, rows;
12048{
12049 BLOCK_INPUT;
12050
12051#ifdef USE_X_TOOLKIT
12052
f1f4d345 12053 if (f->output_data.x->widget != NULL)
499b1844
GM
12054 {
12055 /* The x and y position of the widget is clobbered by the
12056 call to XtSetValues within EmacsFrameSetCharSize.
12057 This is a real kludge, but I don't understand Xt so I can't
12058 figure out a correct fix. Can anyone else tell me? -- rms. */
12059 int xpos = f->output_data.x->widget->core.x;
12060 int ypos = f->output_data.x->widget->core.y;
12061 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
12062 f->output_data.x->widget->core.x = xpos;
12063 f->output_data.x->widget->core.y = ypos;
12064 }
12065 else
12066 x_set_window_size_1 (f, change_gravity, cols, rows);
12067
12068#else /* not USE_X_TOOLKIT */
12069
12070 x_set_window_size_1 (f, change_gravity, cols, rows);
12071
aee9a898
RS
12072#endif /* not USE_X_TOOLKIT */
12073
4d73d038 12074 /* If cursor was outside the new size, mark it as off. */
06a2c219 12075 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 12076
aee9a898
RS
12077 /* Clear out any recollection of where the mouse highlighting was,
12078 since it might be in a place that's outside the new frame size.
12079 Actually checking whether it is outside is a pain in the neck,
12080 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 12081 cancel_mouse_face (f);
dbc4e1c1 12082
dc6f92b8
JB
12083 UNBLOCK_INPUT;
12084}
dc6f92b8 12085\f
d047c4eb 12086/* Mouse warping. */
dc6f92b8 12087
9b378208 12088void
f676886a
JB
12089x_set_mouse_position (f, x, y)
12090 struct frame *f;
dc6f92b8
JB
12091 int x, y;
12092{
12093 int pix_x, pix_y;
12094
7556890b
RS
12095 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
12096 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
12097
12098 if (pix_x < 0) pix_x = 0;
12099 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
12100
12101 if (pix_y < 0) pix_y = 0;
12102 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
12103
12104 BLOCK_INPUT;
dc6f92b8 12105
334208b7
RS
12106 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12107 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
12108 UNBLOCK_INPUT;
12109}
12110
9b378208
RS
12111/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
12112
12113void
12114x_set_mouse_pixel_position (f, pix_x, pix_y)
12115 struct frame *f;
12116 int pix_x, pix_y;
12117{
12118 BLOCK_INPUT;
12119
334208b7
RS
12120 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12121 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
12122 UNBLOCK_INPUT;
12123}
d047c4eb
KH
12124\f
12125/* focus shifting, raising and lowering. */
9b378208 12126
dfcf069d 12127void
f676886a
JB
12128x_focus_on_frame (f)
12129 struct frame *f;
dc6f92b8 12130{
1fb20991 12131#if 0 /* This proves to be unpleasant. */
f676886a 12132 x_raise_frame (f);
1fb20991 12133#endif
6d4238f3
JB
12134#if 0
12135 /* I don't think that the ICCCM allows programs to do things like this
12136 without the interaction of the window manager. Whatever you end up
f676886a 12137 doing with this code, do it to x_unfocus_frame too. */
334208b7 12138 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 12139 RevertToPointerRoot, CurrentTime);
c118dd06 12140#endif /* ! 0 */
dc6f92b8
JB
12141}
12142
dfcf069d 12143void
f676886a
JB
12144x_unfocus_frame (f)
12145 struct frame *f;
dc6f92b8 12146{
6d4238f3 12147#if 0
f676886a 12148 /* Look at the remarks in x_focus_on_frame. */
0f941935 12149 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 12150 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 12151 RevertToPointerRoot, CurrentTime);
c118dd06 12152#endif /* ! 0 */
dc6f92b8
JB
12153}
12154
f676886a 12155/* Raise frame F. */
dc6f92b8 12156
dfcf069d 12157void
f676886a
JB
12158x_raise_frame (f)
12159 struct frame *f;
dc6f92b8 12160{
3a88c238 12161 if (f->async_visible)
dc6f92b8
JB
12162 {
12163 BLOCK_INPUT;
3afe33e7 12164#ifdef USE_X_TOOLKIT
7556890b 12165 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12166#else /* not USE_X_TOOLKIT */
334208b7 12167 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12168#endif /* not USE_X_TOOLKIT */
334208b7 12169 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12170 UNBLOCK_INPUT;
12171 }
12172}
12173
f676886a 12174/* Lower frame F. */
dc6f92b8 12175
dfcf069d 12176void
f676886a
JB
12177x_lower_frame (f)
12178 struct frame *f;
dc6f92b8 12179{
3a88c238 12180 if (f->async_visible)
dc6f92b8
JB
12181 {
12182 BLOCK_INPUT;
3afe33e7 12183#ifdef USE_X_TOOLKIT
7556890b 12184 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12185#else /* not USE_X_TOOLKIT */
334208b7 12186 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12187#endif /* not USE_X_TOOLKIT */
334208b7 12188 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12189 UNBLOCK_INPUT;
12190 }
12191}
12192
dbc4e1c1 12193static void
6b0442dc 12194XTframe_raise_lower (f, raise_flag)
dbc4e1c1 12195 FRAME_PTR f;
6b0442dc 12196 int raise_flag;
dbc4e1c1 12197{
6b0442dc 12198 if (raise_flag)
dbc4e1c1
JB
12199 x_raise_frame (f);
12200 else
12201 x_lower_frame (f);
12202}
d047c4eb
KH
12203\f
12204/* Change of visibility. */
dc6f92b8 12205
9382638d
KH
12206/* This tries to wait until the frame is really visible.
12207 However, if the window manager asks the user where to position
12208 the frame, this will return before the user finishes doing that.
12209 The frame will not actually be visible at that time,
12210 but it will become visible later when the window manager
12211 finishes with it. */
12212
dfcf069d 12213void
f676886a
JB
12214x_make_frame_visible (f)
12215 struct frame *f;
dc6f92b8 12216{
990ba854 12217 Lisp_Object type;
1aa6072f 12218 int original_top, original_left;
31be9251
GM
12219 int retry_count = 2;
12220
12221 retry:
dc6f92b8 12222
dc6f92b8 12223 BLOCK_INPUT;
dc6f92b8 12224
990ba854
RS
12225 type = x_icon_type (f);
12226 if (!NILP (type))
12227 x_bitmap_icon (f, type);
bdcd49ba 12228
f676886a 12229 if (! FRAME_VISIBLE_P (f))
90e65f07 12230 {
1aa6072f
RS
12231 /* We test FRAME_GARBAGED_P here to make sure we don't
12232 call x_set_offset a second time
12233 if we get to x_make_frame_visible a second time
12234 before the window gets really visible. */
12235 if (! FRAME_ICONIFIED_P (f)
12236 && ! f->output_data.x->asked_for_visible)
12237 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
12238
12239 f->output_data.x->asked_for_visible = 1;
12240
90e65f07 12241 if (! EQ (Vx_no_window_manager, Qt))
f676886a 12242 x_wm_set_window_state (f, NormalState);
3afe33e7 12243#ifdef USE_X_TOOLKIT
d7a38a2e 12244 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 12245 XtMapWidget (f->output_data.x->widget);
3afe33e7 12246#else /* not USE_X_TOOLKIT */
7f9c7f94 12247 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12248#endif /* not USE_X_TOOLKIT */
0134a210
RS
12249#if 0 /* This seems to bring back scroll bars in the wrong places
12250 if the window configuration has changed. They seem
12251 to come back ok without this. */
ab648270 12252 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 12253 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 12254#endif
90e65f07 12255 }
dc6f92b8 12256
334208b7 12257 XFlush (FRAME_X_DISPLAY (f));
90e65f07 12258
0dacf791
RS
12259 /* Synchronize to ensure Emacs knows the frame is visible
12260 before we do anything else. We do this loop with input not blocked
12261 so that incoming events are handled. */
12262 {
12263 Lisp_Object frame;
12ce2351 12264 int count;
28c01ffe
RS
12265 /* This must be before UNBLOCK_INPUT
12266 since events that arrive in response to the actions above
12267 will set it when they are handled. */
12268 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
12269
12270 original_left = f->output_data.x->left_pos;
12271 original_top = f->output_data.x->top_pos;
c0a04927
RS
12272
12273 /* This must come after we set COUNT. */
12274 UNBLOCK_INPUT;
12275
2745e6c4 12276 /* We unblock here so that arriving X events are processed. */
1aa6072f 12277
dcb07ae9
RS
12278 /* Now move the window back to where it was "supposed to be".
12279 But don't do it if the gravity is negative.
12280 When the gravity is negative, this uses a position
28c01ffe
RS
12281 that is 3 pixels too low. Perhaps that's really the border width.
12282
12283 Don't do this if the window has never been visible before,
12284 because the window manager may choose the position
12285 and we don't want to override it. */
1aa6072f 12286
4d3f5d9a 12287 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 12288 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 12289 && previously_visible)
1aa6072f 12290 {
2745e6c4
RS
12291 Drawable rootw;
12292 int x, y;
12293 unsigned int width, height, border, depth;
06a2c219 12294
1aa6072f 12295 BLOCK_INPUT;
9829ddba 12296
06a2c219
GM
12297 /* On some window managers (such as FVWM) moving an existing
12298 window, even to the same place, causes the window manager
12299 to introduce an offset. This can cause the window to move
12300 to an unexpected location. Check the geometry (a little
12301 slow here) and then verify that the window is in the right
12302 place. If the window is not in the right place, move it
12303 there, and take the potential window manager hit. */
2745e6c4
RS
12304 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12305 &rootw, &x, &y, &width, &height, &border, &depth);
12306
12307 if (original_left != x || original_top != y)
12308 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12309 original_left, original_top);
12310
1aa6072f
RS
12311 UNBLOCK_INPUT;
12312 }
9829ddba 12313
e0c1aef2 12314 XSETFRAME (frame, f);
c0a04927 12315
12ce2351
GM
12316 /* Wait until the frame is visible. Process X events until a
12317 MapNotify event has been seen, or until we think we won't get a
12318 MapNotify at all.. */
12319 for (count = input_signal_count + 10;
12320 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 12321 {
12ce2351 12322 /* Force processing of queued events. */
334208b7 12323 x_sync (f);
12ce2351
GM
12324
12325 /* Machines that do polling rather than SIGIO have been
12326 observed to go into a busy-wait here. So we'll fake an
12327 alarm signal to let the handler know that there's something
12328 to be read. We used to raise a real alarm, but it seems
12329 that the handler isn't always enabled here. This is
12330 probably a bug. */
8b2f8d4e 12331 if (input_polling_used ())
3b2fa4e6 12332 {
12ce2351
GM
12333 /* It could be confusing if a real alarm arrives while
12334 processing the fake one. Turn it off and let the
12335 handler reset it. */
3e71d8f2 12336 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
12337 int old_poll_suppress_count = poll_suppress_count;
12338 poll_suppress_count = 1;
12339 poll_for_input_1 ();
12340 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 12341 }
12ce2351
GM
12342
12343 /* See if a MapNotify event has been processed. */
12344 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 12345 }
31be9251
GM
12346
12347 /* 2000-09-28: In
12348
12349 (let ((f (selected-frame)))
12350 (iconify-frame f)
12351 (raise-frame f))
12352
12353 the frame is not raised with various window managers on
12354 FreeBSD, Linux and Solaris. It turns out that, for some
12355 unknown reason, the call to XtMapWidget is completely ignored.
12356 Mapping the widget a second time works. */
12357
12358 if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
12359 goto retry;
0dacf791 12360 }
dc6f92b8
JB
12361}
12362
06a2c219 12363/* Change from mapped state to withdrawn state. */
dc6f92b8 12364
d047c4eb
KH
12365/* Make the frame visible (mapped and not iconified). */
12366
dfcf069d 12367void
f676886a
JB
12368x_make_frame_invisible (f)
12369 struct frame *f;
dc6f92b8 12370{
546e6d5b
RS
12371 Window window;
12372
12373#ifdef USE_X_TOOLKIT
12374 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 12375 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
12376#else /* not USE_X_TOOLKIT */
12377 window = FRAME_X_WINDOW (f);
12378#endif /* not USE_X_TOOLKIT */
dc6f92b8 12379
9319ae23 12380 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
12381 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
12382 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 12383
5627c40e 12384#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 12385 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 12386 return;
5627c40e 12387#endif
dc6f92b8
JB
12388
12389 BLOCK_INPUT;
c118dd06 12390
af31d76f
RS
12391 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
12392 that the current position of the window is user-specified, rather than
12393 program-specified, so that when the window is mapped again, it will be
12394 placed at the same location, without forcing the user to position it
12395 by hand again (they have already done that once for this window.) */
c32cdd9a 12396 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 12397
c118dd06
JB
12398#ifdef HAVE_X11R4
12399
334208b7
RS
12400 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
12401 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
12402 {
12403 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12404 error ("Can't notify window manager of window withdrawal");
c118dd06 12405 }
c118dd06 12406#else /* ! defined (HAVE_X11R4) */
16bd92ea 12407
c118dd06 12408 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
12409 if (! EQ (Vx_no_window_manager, Qt))
12410 {
16bd92ea 12411 XEvent unmap;
dc6f92b8 12412
16bd92ea 12413 unmap.xunmap.type = UnmapNotify;
546e6d5b 12414 unmap.xunmap.window = window;
334208b7 12415 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 12416 unmap.xunmap.from_configure = False;
334208b7
RS
12417 if (! XSendEvent (FRAME_X_DISPLAY (f),
12418 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 12419 False,
06a2c219 12420 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
12421 &unmap))
12422 {
12423 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12424 error ("Can't notify window manager of withdrawal");
16bd92ea 12425 }
dc6f92b8
JB
12426 }
12427
16bd92ea 12428 /* Unmap the window ourselves. Cheeky! */
334208b7 12429 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 12430#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 12431
5627c40e
RS
12432 /* We can't distinguish this from iconification
12433 just by the event that we get from the server.
12434 So we can't win using the usual strategy of letting
12435 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
12436 and synchronize with the server to make sure we agree. */
12437 f->visible = 0;
12438 FRAME_ICONIFIED_P (f) = 0;
12439 f->async_visible = 0;
12440 f->async_iconified = 0;
12441
334208b7 12442 x_sync (f);
5627c40e 12443
dc6f92b8
JB
12444 UNBLOCK_INPUT;
12445}
12446
06a2c219 12447/* Change window state from mapped to iconified. */
dc6f92b8 12448
dfcf069d 12449void
f676886a
JB
12450x_iconify_frame (f)
12451 struct frame *f;
dc6f92b8 12452{
3afe33e7 12453 int result;
990ba854 12454 Lisp_Object type;
dc6f92b8 12455
9319ae23 12456 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
12457 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
12458 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 12459
3a88c238 12460 if (f->async_iconified)
dc6f92b8
JB
12461 return;
12462
3afe33e7 12463 BLOCK_INPUT;
546e6d5b 12464
9af3143a
RS
12465 FRAME_SAMPLE_VISIBILITY (f);
12466
990ba854
RS
12467 type = x_icon_type (f);
12468 if (!NILP (type))
12469 x_bitmap_icon (f, type);
bdcd49ba
RS
12470
12471#ifdef USE_X_TOOLKIT
12472
546e6d5b
RS
12473 if (! FRAME_VISIBLE_P (f))
12474 {
12475 if (! EQ (Vx_no_window_manager, Qt))
12476 x_wm_set_window_state (f, IconicState);
12477 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 12478 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
12479 /* The server won't give us any event to indicate
12480 that an invisible frame was changed to an icon,
12481 so we have to record it here. */
12482 f->iconified = 1;
1e6bc770 12483 f->visible = 1;
9cf30a30 12484 f->async_iconified = 1;
1e6bc770 12485 f->async_visible = 0;
546e6d5b
RS
12486 UNBLOCK_INPUT;
12487 return;
12488 }
12489
334208b7 12490 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 12491 XtWindow (f->output_data.x->widget),
334208b7 12492 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
12493 UNBLOCK_INPUT;
12494
12495 if (!result)
546e6d5b 12496 error ("Can't notify window manager of iconification");
3afe33e7
RS
12497
12498 f->async_iconified = 1;
1e6bc770
RS
12499 f->async_visible = 0;
12500
8c002a25
KH
12501
12502 BLOCK_INPUT;
334208b7 12503 XFlush (FRAME_X_DISPLAY (f));
8c002a25 12504 UNBLOCK_INPUT;
3afe33e7
RS
12505#else /* not USE_X_TOOLKIT */
12506
fd13dbb2
RS
12507 /* Make sure the X server knows where the window should be positioned,
12508 in case the user deiconifies with the window manager. */
12509 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 12510 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 12511
16bd92ea
JB
12512 /* Since we don't know which revision of X we're running, we'll use both
12513 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
12514
12515 /* X11R4: send a ClientMessage to the window manager using the
12516 WM_CHANGE_STATE type. */
12517 {
12518 XEvent message;
58769bee 12519
c118dd06 12520 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 12521 message.xclient.type = ClientMessage;
334208b7 12522 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
12523 message.xclient.format = 32;
12524 message.xclient.data.l[0] = IconicState;
12525
334208b7
RS
12526 if (! XSendEvent (FRAME_X_DISPLAY (f),
12527 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
12528 False,
12529 SubstructureRedirectMask | SubstructureNotifyMask,
12530 &message))
dc6f92b8
JB
12531 {
12532 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12533 error ("Can't notify window manager of iconification");
dc6f92b8 12534 }
16bd92ea 12535 }
dc6f92b8 12536
58769bee 12537 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
12538 IconicState. */
12539 x_wm_set_window_state (f, IconicState);
dc6f92b8 12540
a9c00105
RS
12541 if (!FRAME_VISIBLE_P (f))
12542 {
12543 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 12544 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
12545 }
12546
3a88c238 12547 f->async_iconified = 1;
1e6bc770 12548 f->async_visible = 0;
dc6f92b8 12549
334208b7 12550 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 12551 UNBLOCK_INPUT;
8c002a25 12552#endif /* not USE_X_TOOLKIT */
dc6f92b8 12553}
19f71add 12554
d047c4eb 12555\f
19f71add 12556/* Free X resources of frame F. */
dc6f92b8 12557
dfcf069d 12558void
19f71add 12559x_free_frame_resources (f)
f676886a 12560 struct frame *f;
dc6f92b8 12561{
7f9c7f94
RS
12562 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12563
dc6f92b8 12564 BLOCK_INPUT;
c0ff3fab 12565
6186a4a0
RS
12566 /* If a display connection is dead, don't try sending more
12567 commands to the X server. */
19f71add 12568 if (dpyinfo->display)
6186a4a0 12569 {
19f71add 12570 if (f->output_data.x->icon_desc)
6186a4a0 12571 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
19f71add 12572
31f41daf 12573#ifdef HAVE_X_I18N
f5d11644
GM
12574 if (FRAME_XIC (f))
12575 free_frame_xic (f);
31f41daf 12576#endif
19f71add 12577
2662734b 12578 if (FRAME_X_WINDOW (f))
19f71add
GM
12579 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
12580
3afe33e7 12581#ifdef USE_X_TOOLKIT
06a2c219
GM
12582 if (f->output_data.x->widget)
12583 XtDestroyWidget (f->output_data.x->widget);
6186a4a0 12584 free_frame_menubar (f);
3afe33e7
RS
12585#endif /* USE_X_TOOLKIT */
12586
3e71d8f2
GM
12587 unload_color (f, f->output_data.x->foreground_pixel);
12588 unload_color (f, f->output_data.x->background_pixel);
12589 unload_color (f, f->output_data.x->cursor_pixel);
12590 unload_color (f, f->output_data.x->cursor_foreground_pixel);
12591 unload_color (f, f->output_data.x->border_pixel);
12592 unload_color (f, f->output_data.x->mouse_pixel);
19f71add 12593
3e71d8f2
GM
12594 if (f->output_data.x->scroll_bar_background_pixel != -1)
12595 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
12596 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
12597 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
12598 if (f->output_data.x->white_relief.allocated_p)
12599 unload_color (f, f->output_data.x->white_relief.pixel);
12600 if (f->output_data.x->black_relief.allocated_p)
12601 unload_color (f, f->output_data.x->black_relief.pixel);
4ca78676 12602
19f71add
GM
12603 if (FRAME_FACE_CACHE (f))
12604 free_frame_faces (f);
12605
4ca78676 12606 x_free_gcs (f);
6186a4a0
RS
12607 XFlush (FRAME_X_DISPLAY (f));
12608 }
dc6f92b8 12609
df89d8a4 12610 if (f->output_data.x->saved_menu_event)
06a2c219 12611 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 12612
7556890b 12613 xfree (f->output_data.x);
19f71add
GM
12614 f->output_data.x = NULL;
12615
0f941935
KH
12616 if (f == dpyinfo->x_focus_frame)
12617 dpyinfo->x_focus_frame = 0;
12618 if (f == dpyinfo->x_focus_event_frame)
12619 dpyinfo->x_focus_event_frame = 0;
12620 if (f == dpyinfo->x_highlight_frame)
12621 dpyinfo->x_highlight_frame = 0;
c0ff3fab 12622
7f9c7f94 12623 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 12624 {
7f9c7f94
RS
12625 dpyinfo->mouse_face_beg_row
12626 = dpyinfo->mouse_face_beg_col = -1;
12627 dpyinfo->mouse_face_end_row
12628 = dpyinfo->mouse_face_end_col = -1;
12629 dpyinfo->mouse_face_window = Qnil;
21323706
RS
12630 dpyinfo->mouse_face_deferred_gc = 0;
12631 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 12632 }
0134a210 12633
c0ff3fab 12634 UNBLOCK_INPUT;
dc6f92b8 12635}
19f71add
GM
12636
12637
12638/* Destroy the X window of frame F. */
12639
12640void
12641x_destroy_window (f)
12642 struct frame *f;
12643{
12644 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12645
12646 /* If a display connection is dead, don't try sending more
12647 commands to the X server. */
12648 if (dpyinfo->display != 0)
12649 x_free_frame_resources (f);
12650
12651 dpyinfo->reference_count--;
12652}
12653
dc6f92b8 12654\f
f451eb13
JB
12655/* Setting window manager hints. */
12656
af31d76f
RS
12657/* Set the normal size hints for the window manager, for frame F.
12658 FLAGS is the flags word to use--or 0 meaning preserve the flags
12659 that the window now has.
12660 If USER_POSITION is nonzero, we set the USPosition
12661 flag (this is useful when FLAGS is 0). */
6dba1858 12662
dfcf069d 12663void
af31d76f 12664x_wm_set_size_hint (f, flags, user_position)
f676886a 12665 struct frame *f;
af31d76f
RS
12666 long flags;
12667 int user_position;
dc6f92b8
JB
12668{
12669 XSizeHints size_hints;
3afe33e7
RS
12670
12671#ifdef USE_X_TOOLKIT
7e4f2521
FP
12672 Arg al[2];
12673 int ac = 0;
12674 Dimension widget_width, widget_height;
7556890b 12675 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 12676#else /* not USE_X_TOOLKIT */
c118dd06 12677 Window window = FRAME_X_WINDOW (f);
3afe33e7 12678#endif /* not USE_X_TOOLKIT */
dc6f92b8 12679
b72a58fd
RS
12680 /* Setting PMaxSize caused various problems. */
12681 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 12682
7556890b
RS
12683 size_hints.x = f->output_data.x->left_pos;
12684 size_hints.y = f->output_data.x->top_pos;
7553a6b7 12685
7e4f2521
FP
12686#ifdef USE_X_TOOLKIT
12687 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
12688 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 12689 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
12690 size_hints.height = widget_height;
12691 size_hints.width = widget_width;
12692#else /* not USE_X_TOOLKIT */
f676886a
JB
12693 size_hints.height = PIXEL_HEIGHT (f);
12694 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 12695#endif /* not USE_X_TOOLKIT */
7553a6b7 12696
7556890b
RS
12697 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
12698 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
12699 size_hints.max_width
12700 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
12701 size_hints.max_height
12702 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 12703
d067ea8b
KH
12704 /* Calculate the base and minimum sizes.
12705
12706 (When we use the X toolkit, we don't do it here.
12707 Instead we copy the values that the widgets are using, below.) */
12708#ifndef USE_X_TOOLKIT
b1c884c3 12709 {
b0342f17 12710 int base_width, base_height;
0134a210 12711 int min_rows = 0, min_cols = 0;
b0342f17 12712
f451eb13
JB
12713 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
12714 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 12715
0134a210 12716 check_frame_size (f, &min_rows, &min_cols);
b0342f17 12717
0134a210
RS
12718 /* The window manager uses the base width hints to calculate the
12719 current number of rows and columns in the frame while
12720 resizing; min_width and min_height aren't useful for this
12721 purpose, since they might not give the dimensions for a
12722 zero-row, zero-column frame.
58769bee 12723
0134a210
RS
12724 We use the base_width and base_height members if we have
12725 them; otherwise, we set the min_width and min_height members
12726 to the size for a zero x zero frame. */
b0342f17
JB
12727
12728#ifdef HAVE_X11R4
0134a210
RS
12729 size_hints.flags |= PBaseSize;
12730 size_hints.base_width = base_width;
12731 size_hints.base_height = base_height;
12732 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
12733 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 12734#else
0134a210
RS
12735 size_hints.min_width = base_width;
12736 size_hints.min_height = base_height;
b0342f17 12737#endif
b1c884c3 12738 }
dc6f92b8 12739
d067ea8b 12740 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 12741 if (flags)
dc6f92b8 12742 {
d067ea8b
KH
12743 size_hints.flags |= flags;
12744 goto no_read;
12745 }
12746#endif /* not USE_X_TOOLKIT */
12747
12748 {
12749 XSizeHints hints; /* Sometimes I hate X Windows... */
12750 long supplied_return;
12751 int value;
af31d76f
RS
12752
12753#ifdef HAVE_X11R4
d067ea8b
KH
12754 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
12755 &supplied_return);
af31d76f 12756#else
d067ea8b 12757 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 12758#endif
58769bee 12759
d067ea8b
KH
12760#ifdef USE_X_TOOLKIT
12761 size_hints.base_height = hints.base_height;
12762 size_hints.base_width = hints.base_width;
12763 size_hints.min_height = hints.min_height;
12764 size_hints.min_width = hints.min_width;
12765#endif
12766
12767 if (flags)
12768 size_hints.flags |= flags;
12769 else
12770 {
12771 if (value == 0)
12772 hints.flags = 0;
12773 if (hints.flags & PSize)
12774 size_hints.flags |= PSize;
12775 if (hints.flags & PPosition)
12776 size_hints.flags |= PPosition;
12777 if (hints.flags & USPosition)
12778 size_hints.flags |= USPosition;
12779 if (hints.flags & USSize)
12780 size_hints.flags |= USSize;
12781 }
12782 }
12783
06a2c219 12784#ifndef USE_X_TOOLKIT
d067ea8b 12785 no_read:
06a2c219 12786#endif
0134a210 12787
af31d76f 12788#ifdef PWinGravity
7556890b 12789 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 12790 size_hints.flags |= PWinGravity;
dc05a16b 12791
af31d76f 12792 if (user_position)
6dba1858 12793 {
af31d76f
RS
12794 size_hints.flags &= ~ PPosition;
12795 size_hints.flags |= USPosition;
6dba1858 12796 }
2554751d 12797#endif /* PWinGravity */
6dba1858 12798
b0342f17 12799#ifdef HAVE_X11R4
334208b7 12800 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12801#else
334208b7 12802 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 12803#endif
dc6f92b8
JB
12804}
12805
12806/* Used for IconicState or NormalState */
06a2c219 12807
dfcf069d 12808void
f676886a
JB
12809x_wm_set_window_state (f, state)
12810 struct frame *f;
dc6f92b8
JB
12811 int state;
12812{
3afe33e7 12813#ifdef USE_X_TOOLKIT
546e6d5b
RS
12814 Arg al[1];
12815
12816 XtSetArg (al[0], XtNinitialState, state);
7556890b 12817 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 12818#else /* not USE_X_TOOLKIT */
c118dd06 12819 Window window = FRAME_X_WINDOW (f);
dc6f92b8 12820
7556890b
RS
12821 f->output_data.x->wm_hints.flags |= StateHint;
12822 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 12823
7556890b 12824 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 12825#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12826}
12827
dfcf069d 12828void
7f2ae036 12829x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 12830 struct frame *f;
7f2ae036 12831 int pixmap_id;
dc6f92b8 12832{
d2bd6bc4
RS
12833 Pixmap icon_pixmap;
12834
06a2c219 12835#ifndef USE_X_TOOLKIT
c118dd06 12836 Window window = FRAME_X_WINDOW (f);
75231bad 12837#endif
dc6f92b8 12838
7f2ae036 12839 if (pixmap_id > 0)
dbc4e1c1 12840 {
d2bd6bc4 12841 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 12842 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
12843 }
12844 else
68568555
RS
12845 {
12846 /* It seems there is no way to turn off use of an icon pixmap.
12847 The following line does it, only if no icon has yet been created,
12848 for some window managers. But with mwm it crashes.
12849 Some people say it should clear the IconPixmapHint bit in this case,
12850 but that doesn't work, and the X consortium said it isn't the
12851 right thing at all. Since there is no way to win,
12852 best to explicitly give up. */
12853#if 0
12854 f->output_data.x->wm_hints.icon_pixmap = None;
12855#else
12856 return;
12857#endif
12858 }
b1c884c3 12859
d2bd6bc4
RS
12860#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
12861
12862 {
12863 Arg al[1];
12864 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
12865 XtSetValues (f->output_data.x->widget, al, 1);
12866 }
12867
12868#else /* not USE_X_TOOLKIT */
12869
7556890b
RS
12870 f->output_data.x->wm_hints.flags |= IconPixmapHint;
12871 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
12872
12873#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12874}
12875
dfcf069d 12876void
f676886a
JB
12877x_wm_set_icon_position (f, icon_x, icon_y)
12878 struct frame *f;
dc6f92b8
JB
12879 int icon_x, icon_y;
12880{
75231bad 12881#ifdef USE_X_TOOLKIT
7556890b 12882 Window window = XtWindow (f->output_data.x->widget);
75231bad 12883#else
c118dd06 12884 Window window = FRAME_X_WINDOW (f);
75231bad 12885#endif
dc6f92b8 12886
7556890b
RS
12887 f->output_data.x->wm_hints.flags |= IconPositionHint;
12888 f->output_data.x->wm_hints.icon_x = icon_x;
12889 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 12890
7556890b 12891 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
12892}
12893
12894\f
06a2c219
GM
12895/***********************************************************************
12896 Fonts
12897 ***********************************************************************/
dc43ef94
KH
12898
12899/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 12900
dc43ef94
KH
12901struct font_info *
12902x_get_font_info (f, font_idx)
12903 FRAME_PTR f;
12904 int font_idx;
12905{
12906 return (FRAME_X_FONT_TABLE (f) + font_idx);
12907}
12908
12909
9c11f79e
GM
12910/* Return a list of names of available fonts matching PATTERN on frame F.
12911
12912 If SIZE is > 0, it is the size (maximum bounds width) of fonts
12913 to be listed.
12914
12915 SIZE < 0 means include scalable fonts.
12916
12917 Frame F null means we have not yet created any frame on X, and
12918 consult the first display in x_display_list. MAXNAMES sets a limit
12919 on how many fonts to match. */
dc43ef94
KH
12920
12921Lisp_Object
12922x_list_fonts (f, pattern, size, maxnames)
9c11f79e 12923 struct frame *f;
dc43ef94
KH
12924 Lisp_Object pattern;
12925 int size;
12926 int maxnames;
12927{
06a2c219
GM
12928 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
12929 Lisp_Object tem, second_best;
9c11f79e
GM
12930 struct x_display_info *dpyinfo
12931 = f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
12932 Display *dpy = dpyinfo->display;
09c6077f 12933 int try_XLoadQueryFont = 0;
53ca4657 12934 int count;
9c11f79e
GM
12935 int allow_scalable_fonts_p = 0;
12936
12937 if (size < 0)
12938 {
12939 allow_scalable_fonts_p = 1;
12940 size = 0;
12941 }
dc43ef94 12942
6b0efe73 12943 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
12944 if (NILP (patterns))
12945 patterns = Fcons (pattern, Qnil);
81ba44e5 12946
09c6077f
KH
12947 if (maxnames == 1 && !size)
12948 /* We can return any single font matching PATTERN. */
12949 try_XLoadQueryFont = 1;
9a32686f 12950
8e713be6 12951 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 12952 {
dc43ef94 12953 int num_fonts;
3e71d8f2 12954 char **names = NULL;
dc43ef94 12955
8e713be6 12956 pattern = XCAR (patterns);
536f4067
RS
12957 /* See if we cached the result for this particular query.
12958 The cache is an alist of the form:
9c11f79e
GM
12959 ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */
12960 tem = XCDR (dpyinfo->name_list_element);
12961 key = Fcons (Fcons (pattern, make_number (maxnames)),
12962 allow_scalable_fonts_p ? Qt : Qnil);
12963 list = Fassoc (key, tem);
12964 if (!NILP (list))
b5210ea7
KH
12965 {
12966 list = Fcdr_safe (list);
12967 /* We have a cashed list. Don't have to get the list again. */
12968 goto label_cached;
12969 }
12970
12971 /* At first, put PATTERN in the cache. */
09c6077f 12972
dc43ef94 12973 BLOCK_INPUT;
17d85edc
KH
12974 count = x_catch_errors (dpy);
12975
09c6077f
KH
12976 if (try_XLoadQueryFont)
12977 {
12978 XFontStruct *font;
12979 unsigned long value;
12980
12981 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
12982 if (x_had_errors_p (dpy))
12983 {
12984 /* This error is perhaps due to insufficient memory on X
12985 server. Let's just ignore it. */
12986 font = NULL;
12987 x_clear_errors (dpy);
12988 }
12989
09c6077f
KH
12990 if (font
12991 && XGetFontProperty (font, XA_FONT, &value))
12992 {
12993 char *name = (char *) XGetAtomName (dpy, (Atom) value);
12994 int len = strlen (name);
01c752b5 12995 char *tmp;
09c6077f 12996
6f6512e8
KH
12997 /* If DXPC (a Differential X Protocol Compressor)
12998 Ver.3.7 is running, XGetAtomName will return null
12999 string. We must avoid such a name. */
13000 if (len == 0)
13001 try_XLoadQueryFont = 0;
13002 else
13003 {
13004 num_fonts = 1;
13005 names = (char **) alloca (sizeof (char *));
13006 /* Some systems only allow alloca assigned to a
13007 simple var. */
13008 tmp = (char *) alloca (len + 1); names[0] = tmp;
13009 bcopy (name, names[0], len + 1);
13010 XFree (name);
13011 }
09c6077f
KH
13012 }
13013 else
13014 try_XLoadQueryFont = 0;
a083fd23
RS
13015
13016 if (font)
13017 XFreeFont (dpy, font);
09c6077f
KH
13018 }
13019
13020 if (!try_XLoadQueryFont)
17d85edc
KH
13021 {
13022 /* We try at least 10 fonts because XListFonts will return
13023 auto-scaled fonts at the head. */
13024 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
13025 &num_fonts);
13026 if (x_had_errors_p (dpy))
13027 {
13028 /* This error is perhaps due to insufficient memory on X
13029 server. Let's just ignore it. */
13030 names = NULL;
13031 x_clear_errors (dpy);
13032 }
13033 }
13034
13035 x_uncatch_errors (dpy, count);
dc43ef94
KH
13036 UNBLOCK_INPUT;
13037
13038 if (names)
13039 {
13040 int i;
dc43ef94
KH
13041
13042 /* Make a list of all the fonts we got back.
13043 Store that in the font cache for the display. */
13044 for (i = 0; i < num_fonts; i++)
13045 {
06a2c219 13046 int width = 0;
dc43ef94 13047 char *p = names[i];
06a2c219
GM
13048 int average_width = -1, dashes = 0;
13049
dc43ef94 13050 /* Count the number of dashes in NAMES[I]. If there are
9c11f79e
GM
13051 14 dashes, and the field value following 12th dash
13052 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
13053 is usually too ugly to be used for editing. Let's
13054 ignore it. */
dc43ef94
KH
13055 while (*p)
13056 if (*p++ == '-')
13057 {
13058 dashes++;
13059 if (dashes == 7) /* PIXEL_SIZE field */
13060 width = atoi (p);
13061 else if (dashes == 12) /* AVERAGE_WIDTH field */
13062 average_width = atoi (p);
13063 }
9c11f79e
GM
13064
13065 if (allow_scalable_fonts_p
13066 || dashes < 14 || average_width != 0)
dc43ef94
KH
13067 {
13068 tem = build_string (names[i]);
13069 if (NILP (Fassoc (tem, list)))
13070 {
13071 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
13072 && ((fast_c_string_match_ignore_case
13073 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
13074 >= 0))
13075 /* We can set the value of PIXEL_SIZE to the
b5210ea7 13076 width of this font. */
dc43ef94
KH
13077 list = Fcons (Fcons (tem, make_number (width)), list);
13078 else
13079 /* For the moment, width is not known. */
13080 list = Fcons (Fcons (tem, Qnil), list);
13081 }
13082 }
13083 }
09c6077f
KH
13084 if (!try_XLoadQueryFont)
13085 XFreeFontNames (names);
dc43ef94
KH
13086 }
13087
b5210ea7 13088 /* Now store the result in the cache. */
9c11f79e
GM
13089 XCDR (dpyinfo->name_list_element)
13090 = Fcons (Fcons (key, list), XCDR (dpyinfo->name_list_element));
dc43ef94 13091
b5210ea7
KH
13092 label_cached:
13093 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 13094
b5210ea7
KH
13095 newlist = second_best = Qnil;
13096 /* Make a list of the fonts that have the right width. */
8e713be6 13097 for (; CONSP (list); list = XCDR (list))
b5210ea7 13098 {
536f4067
RS
13099 int found_size;
13100
8e713be6 13101 tem = XCAR (list);
dc43ef94 13102
8e713be6 13103 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
13104 continue;
13105 if (!size)
13106 {
8e713be6 13107 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
13108 continue;
13109 }
dc43ef94 13110
8e713be6 13111 if (!INTEGERP (XCDR (tem)))
dc43ef94 13112 {
b5210ea7 13113 /* Since we have not yet known the size of this font, we
9c11f79e 13114 must try slow function call XLoadQueryFont. */
dc43ef94
KH
13115 XFontStruct *thisinfo;
13116
13117 BLOCK_INPUT;
17d85edc 13118 count = x_catch_errors (dpy);
dc43ef94 13119 thisinfo = XLoadQueryFont (dpy,
8e713be6 13120 XSTRING (XCAR (tem))->data);
17d85edc
KH
13121 if (x_had_errors_p (dpy))
13122 {
13123 /* This error is perhaps due to insufficient memory on X
13124 server. Let's just ignore it. */
13125 thisinfo = NULL;
13126 x_clear_errors (dpy);
13127 }
13128 x_uncatch_errors (dpy, count);
dc43ef94
KH
13129 UNBLOCK_INPUT;
13130
13131 if (thisinfo)
13132 {
8e713be6 13133 XCDR (tem)
536f4067
RS
13134 = (thisinfo->min_bounds.width == 0
13135 ? make_number (0)
13136 : make_number (thisinfo->max_bounds.width));
dc43ef94
KH
13137 XFreeFont (dpy, thisinfo);
13138 }
13139 else
b5210ea7 13140 /* For unknown reason, the previous call of XListFont had
06a2c219 13141 returned a font which can't be opened. Record the size
b5210ea7 13142 as 0 not to try to open it again. */
8e713be6 13143 XCDR (tem) = make_number (0);
dc43ef94 13144 }
536f4067 13145
8e713be6 13146 found_size = XINT (XCDR (tem));
536f4067 13147 if (found_size == size)
8e713be6 13148 newlist = Fcons (XCAR (tem), newlist);
536f4067 13149 else if (found_size > 0)
b5210ea7 13150 {
536f4067 13151 if (NILP (second_best))
b5210ea7 13152 second_best = tem;
536f4067
RS
13153 else if (found_size < size)
13154 {
8e713be6
KR
13155 if (XINT (XCDR (second_best)) > size
13156 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
13157 second_best = tem;
13158 }
13159 else
13160 {
8e713be6
KR
13161 if (XINT (XCDR (second_best)) > size
13162 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
13163 second_best = tem;
13164 }
b5210ea7
KH
13165 }
13166 }
13167 if (!NILP (newlist))
13168 break;
13169 else if (!NILP (second_best))
13170 {
8e713be6 13171 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 13172 break;
dc43ef94 13173 }
dc43ef94
KH
13174 }
13175
13176 return newlist;
13177}
13178
06a2c219
GM
13179
13180#if GLYPH_DEBUG
13181
13182/* Check that FONT is valid on frame F. It is if it can be found in F's
13183 font table. */
13184
13185static void
13186x_check_font (f, font)
13187 struct frame *f;
13188 XFontStruct *font;
13189{
13190 int i;
13191 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13192
13193 xassert (font != NULL);
13194
13195 for (i = 0; i < dpyinfo->n_fonts; i++)
13196 if (dpyinfo->font_table[i].name
13197 && font == dpyinfo->font_table[i].font)
13198 break;
13199
13200 xassert (i < dpyinfo->n_fonts);
13201}
13202
13203#endif /* GLYPH_DEBUG != 0 */
13204
13205/* Set *W to the minimum width, *H to the minimum font height of FONT.
13206 Note: There are (broken) X fonts out there with invalid XFontStruct
13207 min_bounds contents. For example, handa@etl.go.jp reports that
13208 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
13209 have font->min_bounds.width == 0. */
13210
13211static INLINE void
13212x_font_min_bounds (font, w, h)
13213 XFontStruct *font;
13214 int *w, *h;
13215{
13216 *h = FONT_HEIGHT (font);
13217 *w = font->min_bounds.width;
13218
13219 /* Try to handle the case where FONT->min_bounds has invalid
13220 contents. Since the only font known to have invalid min_bounds
13221 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
13222 if (*w <= 0)
13223 *w = font->max_bounds.width;
13224}
13225
13226
13227/* Compute the smallest character width and smallest font height over
13228 all fonts available on frame F. Set the members smallest_char_width
13229 and smallest_font_height in F's x_display_info structure to
13230 the values computed. Value is non-zero if smallest_font_height or
13231 smallest_char_width become smaller than they were before. */
13232
13233static int
13234x_compute_min_glyph_bounds (f)
13235 struct frame *f;
13236{
13237 int i;
13238 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13239 XFontStruct *font;
13240 int old_width = dpyinfo->smallest_char_width;
13241 int old_height = dpyinfo->smallest_font_height;
13242
13243 dpyinfo->smallest_font_height = 100000;
13244 dpyinfo->smallest_char_width = 100000;
13245
13246 for (i = 0; i < dpyinfo->n_fonts; ++i)
13247 if (dpyinfo->font_table[i].name)
13248 {
13249 struct font_info *fontp = dpyinfo->font_table + i;
13250 int w, h;
13251
13252 font = (XFontStruct *) fontp->font;
13253 xassert (font != (XFontStruct *) ~0);
13254 x_font_min_bounds (font, &w, &h);
13255
13256 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
13257 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
13258 }
13259
13260 xassert (dpyinfo->smallest_char_width > 0
13261 && dpyinfo->smallest_font_height > 0);
13262
13263 return (dpyinfo->n_fonts == 1
13264 || dpyinfo->smallest_char_width < old_width
13265 || dpyinfo->smallest_font_height < old_height);
13266}
13267
13268
dc43ef94
KH
13269/* Load font named FONTNAME of the size SIZE for frame F, and return a
13270 pointer to the structure font_info while allocating it dynamically.
13271 If SIZE is 0, load any size of font.
13272 If loading is failed, return NULL. */
13273
13274struct font_info *
13275x_load_font (f, fontname, size)
13276 struct frame *f;
13277 register char *fontname;
13278 int size;
13279{
13280 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13281 Lisp_Object font_names;
d645aaa4 13282 int count;
dc43ef94
KH
13283
13284 /* Get a list of all the fonts that match this name. Once we
13285 have a list of matching fonts, we compare them against the fonts
13286 we already have by comparing names. */
09c6077f 13287 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
13288
13289 if (!NILP (font_names))
13290 {
13291 Lisp_Object tail;
13292 int i;
13293
13294 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 13295 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
13296 if (dpyinfo->font_table[i].name
13297 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 13298 XSTRING (XCAR (tail))->data)
06a2c219 13299 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 13300 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
13301 return (dpyinfo->font_table + i);
13302 }
13303
13304 /* Load the font and add it to the table. */
13305 {
13306 char *full_name;
13307 XFontStruct *font;
13308 struct font_info *fontp;
13309 unsigned long value;
06a2c219 13310 int i;
dc43ef94 13311
2da424f1
KH
13312 /* If we have found fonts by x_list_font, load one of them. If
13313 not, we still try to load a font by the name given as FONTNAME
13314 because XListFonts (called in x_list_font) of some X server has
13315 a bug of not finding a font even if the font surely exists and
13316 is loadable by XLoadQueryFont. */
e1d6d5b9 13317 if (size > 0 && !NILP (font_names))
8e713be6 13318 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
13319
13320 BLOCK_INPUT;
d645aaa4 13321 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 13322 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
13323 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
13324 {
13325 /* This error is perhaps due to insufficient memory on X
13326 server. Let's just ignore it. */
13327 font = NULL;
13328 x_clear_errors (FRAME_X_DISPLAY (f));
13329 }
13330 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 13331 UNBLOCK_INPUT;
b5210ea7 13332 if (!font)
dc43ef94
KH
13333 return NULL;
13334
06a2c219
GM
13335 /* Find a free slot in the font table. */
13336 for (i = 0; i < dpyinfo->n_fonts; ++i)
13337 if (dpyinfo->font_table[i].name == NULL)
13338 break;
13339
13340 /* If no free slot found, maybe enlarge the font table. */
13341 if (i == dpyinfo->n_fonts
13342 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 13343 {
06a2c219
GM
13344 int sz;
13345 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
13346 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 13347 dpyinfo->font_table
06a2c219 13348 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
13349 }
13350
06a2c219
GM
13351 fontp = dpyinfo->font_table + i;
13352 if (i == dpyinfo->n_fonts)
13353 ++dpyinfo->n_fonts;
dc43ef94
KH
13354
13355 /* Now fill in the slots of *FONTP. */
13356 BLOCK_INPUT;
13357 fontp->font = font;
06a2c219 13358 fontp->font_idx = i;
dc43ef94
KH
13359 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
13360 bcopy (fontname, fontp->name, strlen (fontname) + 1);
13361
13362 /* Try to get the full name of FONT. Put it in FULL_NAME. */
13363 full_name = 0;
13364 if (XGetFontProperty (font, XA_FONT, &value))
13365 {
13366 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
13367 char *p = name;
13368 int dashes = 0;
13369
13370 /* Count the number of dashes in the "full name".
13371 If it is too few, this isn't really the font's full name,
13372 so don't use it.
13373 In X11R4, the fonts did not come with their canonical names
13374 stored in them. */
13375 while (*p)
13376 {
13377 if (*p == '-')
13378 dashes++;
13379 p++;
13380 }
13381
13382 if (dashes >= 13)
13383 {
13384 full_name = (char *) xmalloc (p - name + 1);
13385 bcopy (name, full_name, p - name + 1);
13386 }
13387
13388 XFree (name);
13389 }
13390
13391 if (full_name != 0)
13392 fontp->full_name = full_name;
13393 else
13394 fontp->full_name = fontp->name;
13395
13396 fontp->size = font->max_bounds.width;
d5749adb 13397 fontp->height = FONT_HEIGHT (font);
dc43ef94 13398
2da424f1
KH
13399 if (NILP (font_names))
13400 {
13401 /* We come here because of a bug of XListFonts mentioned at
13402 the head of this block. Let's store this information in
13403 the cache for x_list_fonts. */
13404 Lisp_Object lispy_name = build_string (fontname);
13405 Lisp_Object lispy_full_name = build_string (fontp->full_name);
9c11f79e
GM
13406 Lisp_Object key = Fcons (Fcons (lispy_name, make_number (256)),
13407 Qnil);
2da424f1 13408
8e713be6 13409 XCDR (dpyinfo->name_list_element)
9c11f79e 13410 = Fcons (Fcons (key,
2da424f1
KH
13411 Fcons (Fcons (lispy_full_name,
13412 make_number (fontp->size)),
13413 Qnil)),
8e713be6 13414 XCDR (dpyinfo->name_list_element));
2da424f1 13415 if (full_name)
9c11f79e
GM
13416 {
13417 key = Fcons (Fcons (lispy_full_name, make_number (256)),
13418 Qnil);
13419 XCDR (dpyinfo->name_list_element)
13420 = Fcons (Fcons (key,
13421 Fcons (Fcons (lispy_full_name,
13422 make_number (fontp->size)),
13423 Qnil)),
13424 XCDR (dpyinfo->name_list_element));
13425 }
2da424f1
KH
13426 }
13427
dc43ef94
KH
13428 /* The slot `encoding' specifies how to map a character
13429 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
13430 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
13431 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 13432 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 13433 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
13434 which is never used by any charset. If mapping can't be
13435 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
13436 fontp->encoding[1]
13437 = (font->max_byte1 == 0
13438 /* 1-byte font */
13439 ? (font->min_char_or_byte2 < 0x80
13440 ? (font->max_char_or_byte2 < 0x80
13441 ? 0 /* 0x20..0x7F */
8ff102bd 13442 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
13443 : 1) /* 0xA0..0xFF */
13444 /* 2-byte font */
13445 : (font->min_byte1 < 0x80
13446 ? (font->max_byte1 < 0x80
13447 ? (font->min_char_or_byte2 < 0x80
13448 ? (font->max_char_or_byte2 < 0x80
13449 ? 0 /* 0x2020..0x7F7F */
8ff102bd 13450 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 13451 : 3) /* 0x20A0..0x7FFF */
8ff102bd 13452 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
13453 : (font->min_char_or_byte2 < 0x80
13454 ? (font->max_char_or_byte2 < 0x80
13455 ? 2 /* 0xA020..0xFF7F */
8ff102bd 13456 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
13457 : 1))); /* 0xA0A0..0xFFFF */
13458
13459 fontp->baseline_offset
13460 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
13461 ? (long) value : 0);
13462 fontp->relative_compose
13463 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
13464 ? (long) value : 0);
f78798df
KH
13465 fontp->default_ascent
13466 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
13467 ? (long) value : 0);
dc43ef94 13468
06a2c219
GM
13469 /* Set global flag fonts_changed_p to non-zero if the font loaded
13470 has a character with a smaller width than any other character
13471 before, or if the font loaded has a smalle>r height than any
13472 other font loaded before. If this happens, it will make a
13473 glyph matrix reallocation necessary. */
13474 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 13475 UNBLOCK_INPUT;
dc43ef94
KH
13476 return fontp;
13477 }
13478}
13479
06a2c219
GM
13480
13481/* Return a pointer to struct font_info of a font named FONTNAME for
13482 frame F. If no such font is loaded, return NULL. */
13483
dc43ef94
KH
13484struct font_info *
13485x_query_font (f, fontname)
13486 struct frame *f;
13487 register char *fontname;
13488{
13489 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13490 int i;
13491
13492 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
13493 if (dpyinfo->font_table[i].name
13494 && (!strcmp (dpyinfo->font_table[i].name, fontname)
13495 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
13496 return (dpyinfo->font_table + i);
13497 return NULL;
13498}
13499
06a2c219
GM
13500
13501/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
13502 `encoder' of the structure. */
13503
13504void
13505x_find_ccl_program (fontp)
13506 struct font_info *fontp;
13507{
a42f54e6 13508 Lisp_Object list, elt;
a6582676 13509
f9b5db02 13510 elt = Qnil;
8e713be6 13511 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 13512 {
8e713be6 13513 elt = XCAR (list);
a6582676 13514 if (CONSP (elt)
8e713be6 13515 && STRINGP (XCAR (elt))
9f2feff6
KH
13516 && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
13517 >= 0)
13518 || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
13519 >= 0)))
a42f54e6
KH
13520 break;
13521 }
f9b5db02 13522
a42f54e6
KH
13523 if (! NILP (list))
13524 {
d27f8ca7
KH
13525 struct ccl_program *ccl
13526 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 13527
8e713be6 13528 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
13529 xfree (ccl);
13530 else
13531 fontp->font_encoder = ccl;
a6582676
KH
13532 }
13533}
13534
06a2c219 13535
dc43ef94 13536\f
06a2c219
GM
13537/***********************************************************************
13538 Initialization
13539 ***********************************************************************/
f451eb13 13540
3afe33e7
RS
13541#ifdef USE_X_TOOLKIT
13542static XrmOptionDescRec emacs_options[] = {
13543 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
13544 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
13545
13546 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
13547 XrmoptionSepArg, NULL},
13548 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
13549
13550 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13551 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13552 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13553 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
13554 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
13555 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
13556 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
13557};
13558#endif /* USE_X_TOOLKIT */
13559
7a13e894
RS
13560static int x_initialized;
13561
29b38361
KH
13562#ifdef MULTI_KBOARD
13563/* Test whether two display-name strings agree up to the dot that separates
13564 the screen number from the server number. */
13565static int
13566same_x_server (name1, name2)
13567 char *name1, *name2;
13568{
13569 int seen_colon = 0;
cf591cc1
RS
13570 unsigned char *system_name = XSTRING (Vsystem_name)->data;
13571 int system_name_length = strlen (system_name);
13572 int length_until_period = 0;
13573
13574 while (system_name[length_until_period] != 0
13575 && system_name[length_until_period] != '.')
13576 length_until_period++;
13577
13578 /* Treat `unix' like an empty host name. */
13579 if (! strncmp (name1, "unix:", 5))
13580 name1 += 4;
13581 if (! strncmp (name2, "unix:", 5))
13582 name2 += 4;
13583 /* Treat this host's name like an empty host name. */
13584 if (! strncmp (name1, system_name, system_name_length)
13585 && name1[system_name_length] == ':')
13586 name1 += system_name_length;
13587 if (! strncmp (name2, system_name, system_name_length)
13588 && name2[system_name_length] == ':')
13589 name2 += system_name_length;
13590 /* Treat this host's domainless name like an empty host name. */
13591 if (! strncmp (name1, system_name, length_until_period)
13592 && name1[length_until_period] == ':')
13593 name1 += length_until_period;
13594 if (! strncmp (name2, system_name, length_until_period)
13595 && name2[length_until_period] == ':')
13596 name2 += length_until_period;
13597
29b38361
KH
13598 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
13599 {
13600 if (*name1 == ':')
13601 seen_colon++;
13602 if (seen_colon && *name1 == '.')
13603 return 1;
13604 }
13605 return (seen_colon
13606 && (*name1 == '.' || *name1 == '\0')
13607 && (*name2 == '.' || *name2 == '\0'));
13608}
13609#endif
13610
334208b7 13611struct x_display_info *
1f8255f2 13612x_term_init (display_name, xrm_option, resource_name)
334208b7 13613 Lisp_Object display_name;
1f8255f2
RS
13614 char *xrm_option;
13615 char *resource_name;
dc6f92b8 13616{
334208b7 13617 int connection;
7a13e894 13618 Display *dpy;
334208b7
RS
13619 struct x_display_info *dpyinfo;
13620 XrmDatabase xrdb;
13621
60439948
KH
13622 BLOCK_INPUT;
13623
7a13e894
RS
13624 if (!x_initialized)
13625 {
13626 x_initialize ();
13627 x_initialized = 1;
13628 }
dc6f92b8 13629
3afe33e7 13630#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
13631 /* weiner@footloose.sps.mot.com reports that this causes
13632 errors with X11R5:
13633 X protocol error: BadAtom (invalid Atom parameter)
13634 on protocol request 18skiloaf.
13635 So let's not use it until R6. */
13636#ifdef HAVE_X11XTR6
bdcd49ba
RS
13637 XtSetLanguageProc (NULL, NULL, NULL);
13638#endif
13639
7f9c7f94
RS
13640 {
13641 int argc = 0;
13642 char *argv[3];
13643
13644 argv[0] = "";
13645 argc = 1;
13646 if (xrm_option)
13647 {
13648 argv[argc++] = "-xrm";
13649 argv[argc++] = xrm_option;
13650 }
13651 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
13652 resource_name, EMACS_CLASS,
13653 emacs_options, XtNumber (emacs_options),
13654 &argc, argv);
39d8bb4d
KH
13655
13656#ifdef HAVE_X11XTR6
10537cb1 13657 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 13658 fixup_locale ();
39d8bb4d 13659#endif
7f9c7f94 13660 }
3afe33e7
RS
13661
13662#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
13663#ifdef HAVE_X11R5
13664 XSetLocaleModifiers ("");
13665#endif
7a13e894 13666 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 13667#endif /* not USE_X_TOOLKIT */
334208b7 13668
7a13e894
RS
13669 /* Detect failure. */
13670 if (dpy == 0)
60439948
KH
13671 {
13672 UNBLOCK_INPUT;
13673 return 0;
13674 }
7a13e894
RS
13675
13676 /* We have definitely succeeded. Record the new connection. */
13677
13678 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
f04e1297 13679 bzero (dpyinfo, sizeof *dpyinfo);
7a13e894 13680
29b38361
KH
13681#ifdef MULTI_KBOARD
13682 {
13683 struct x_display_info *share;
13684 Lisp_Object tail;
13685
13686 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
13687 share = share->next, tail = XCDR (tail))
13688 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
13689 XSTRING (display_name)->data))
13690 break;
13691 if (share)
13692 dpyinfo->kboard = share->kboard;
13693 else
13694 {
13695 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
13696 init_kboard (dpyinfo->kboard);
59e755be
KH
13697 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
13698 {
13699 char *vendor = ServerVendor (dpy);
9b6ed9f3 13700 UNBLOCK_INPUT;
59e755be
KH
13701 dpyinfo->kboard->Vsystem_key_alist
13702 = call1 (Qvendor_specific_keysyms,
13703 build_string (vendor ? vendor : ""));
9b6ed9f3 13704 BLOCK_INPUT;
59e755be
KH
13705 }
13706
29b38361
KH
13707 dpyinfo->kboard->next_kboard = all_kboards;
13708 all_kboards = dpyinfo->kboard;
0ad5446c
KH
13709 /* Don't let the initial kboard remain current longer than necessary.
13710 That would cause problems if a file loaded on startup tries to
06a2c219 13711 prompt in the mini-buffer. */
0ad5446c
KH
13712 if (current_kboard == initial_kboard)
13713 current_kboard = dpyinfo->kboard;
29b38361
KH
13714 }
13715 dpyinfo->kboard->reference_count++;
13716 }
b9737ad3
KH
13717#endif
13718
7a13e894
RS
13719 /* Put this display on the chain. */
13720 dpyinfo->next = x_display_list;
13721 x_display_list = dpyinfo;
13722
13723 /* Put it on x_display_name_list as well, to keep them parallel. */
13724 x_display_name_list = Fcons (Fcons (display_name, Qnil),
13725 x_display_name_list);
8e713be6 13726 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
13727
13728 dpyinfo->display = dpy;
dc6f92b8 13729
dc6f92b8 13730#if 0
7a13e894 13731 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 13732#endif /* ! 0 */
7a13e894
RS
13733
13734 dpyinfo->x_id_name
fc932ac6
RS
13735 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
13736 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
13737 + 2);
13738 sprintf (dpyinfo->x_id_name, "%s@%s",
13739 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
13740
13741 /* Figure out which modifier bits mean what. */
334208b7 13742 x_find_modifier_meanings (dpyinfo);
f451eb13 13743
ab648270 13744 /* Get the scroll bar cursor. */
7a13e894 13745 dpyinfo->vertical_scroll_bar_cursor
334208b7 13746 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 13747
334208b7
RS
13748 xrdb = x_load_resources (dpyinfo->display, xrm_option,
13749 resource_name, EMACS_CLASS);
13750#ifdef HAVE_XRMSETDATABASE
13751 XrmSetDatabase (dpyinfo->display, xrdb);
13752#else
13753 dpyinfo->display->db = xrdb;
13754#endif
547d9db8 13755 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
13756 all versions. */
13757 dpyinfo->xrdb = xrdb;
334208b7
RS
13758
13759 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
13760 DefaultScreen (dpyinfo->display));
5ff67d81 13761 select_visual (dpyinfo);
43bd1b2b 13762 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
13763 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
13764 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
13765 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
13766 dpyinfo->grabbed = 0;
13767 dpyinfo->reference_count = 0;
13768 dpyinfo->icon_bitmap_id = -1;
06a2c219 13769 dpyinfo->font_table = NULL;
7a13e894
RS
13770 dpyinfo->n_fonts = 0;
13771 dpyinfo->font_table_size = 0;
13772 dpyinfo->bitmaps = 0;
13773 dpyinfo->bitmaps_size = 0;
13774 dpyinfo->bitmaps_last = 0;
13775 dpyinfo->scratch_cursor_gc = 0;
13776 dpyinfo->mouse_face_mouse_frame = 0;
13777 dpyinfo->mouse_face_deferred_gc = 0;
13778 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
13779 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 13780 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894
RS
13781 dpyinfo->mouse_face_window = Qnil;
13782 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
13783 dpyinfo->mouse_face_defer = 0;
0f941935
KH
13784 dpyinfo->x_focus_frame = 0;
13785 dpyinfo->x_focus_event_frame = 0;
13786 dpyinfo->x_highlight_frame = 0;
06a2c219 13787 dpyinfo->image_cache = make_image_cache ();
334208b7 13788
43bd1b2b 13789 /* See if a private colormap is requested. */
5ff67d81
GM
13790 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
13791 {
13792 if (dpyinfo->visual->class == PseudoColor)
13793 {
13794 Lisp_Object value;
13795 value = display_x_get_resource (dpyinfo,
13796 build_string ("privateColormap"),
13797 build_string ("PrivateColormap"),
13798 Qnil, Qnil);
13799 if (STRINGP (value)
13800 && (!strcmp (XSTRING (value)->data, "true")
13801 || !strcmp (XSTRING (value)->data, "on")))
13802 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
13803 }
43bd1b2b 13804 }
5ff67d81
GM
13805 else
13806 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
13807 dpyinfo->visual, AllocNone);
43bd1b2b 13808
06a2c219
GM
13809 {
13810 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
13811 double pixels = DisplayHeight (dpyinfo->display, screen_number);
13812 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
13813 dpyinfo->resy = pixels * 25.4 / mm;
13814 pixels = DisplayWidth (dpyinfo->display, screen_number);
13815 mm = DisplayWidthMM (dpyinfo->display, screen_number);
13816 dpyinfo->resx = pixels * 25.4 / mm;
13817 }
13818
334208b7
RS
13819 dpyinfo->Xatom_wm_protocols
13820 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
13821 dpyinfo->Xatom_wm_take_focus
13822 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
13823 dpyinfo->Xatom_wm_save_yourself
13824 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
13825 dpyinfo->Xatom_wm_delete_window
13826 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
13827 dpyinfo->Xatom_wm_change_state
13828 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
13829 dpyinfo->Xatom_wm_configure_denied
13830 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
13831 dpyinfo->Xatom_wm_window_moved
13832 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
13833 dpyinfo->Xatom_editres
13834 = XInternAtom (dpyinfo->display, "Editres", False);
13835 dpyinfo->Xatom_CLIPBOARD
13836 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
13837 dpyinfo->Xatom_TIMESTAMP
13838 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
13839 dpyinfo->Xatom_TEXT
13840 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
13841 dpyinfo->Xatom_COMPOUND_TEXT
13842 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
13843 dpyinfo->Xatom_DELETE
13844 = XInternAtom (dpyinfo->display, "DELETE", False);
13845 dpyinfo->Xatom_MULTIPLE
13846 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
13847 dpyinfo->Xatom_INCR
13848 = XInternAtom (dpyinfo->display, "INCR", False);
13849 dpyinfo->Xatom_EMACS_TMP
13850 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
13851 dpyinfo->Xatom_TARGETS
13852 = XInternAtom (dpyinfo->display, "TARGETS", False);
13853 dpyinfo->Xatom_NULL
13854 = XInternAtom (dpyinfo->display, "NULL", False);
13855 dpyinfo->Xatom_ATOM_PAIR
13856 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
13857 /* For properties of font. */
13858 dpyinfo->Xatom_PIXEL_SIZE
13859 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
13860 dpyinfo->Xatom_MULE_BASELINE_OFFSET
13861 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
13862 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
13863 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
13864 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
13865 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 13866
06a2c219
GM
13867 /* Ghostscript support. */
13868 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
13869 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
13870
13871 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
13872 False);
13873
547d9db8
KH
13874 dpyinfo->cut_buffers_initialized = 0;
13875
334208b7
RS
13876 connection = ConnectionNumber (dpyinfo->display);
13877 dpyinfo->connection = connection;
13878
dc43ef94 13879 {
5d7cc324
RS
13880 char null_bits[1];
13881
13882 null_bits[0] = 0x00;
dc43ef94
KH
13883
13884 dpyinfo->null_pixel
13885 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13886 null_bits, 1, 1, (long) 0, (long) 0,
13887 1);
13888 }
13889
06a2c219
GM
13890 {
13891 extern int gray_bitmap_width, gray_bitmap_height;
10659c77 13892 extern char *gray_bitmap_bits;
06a2c219
GM
13893 dpyinfo->gray
13894 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
13895 gray_bitmap_bits,
13896 gray_bitmap_width, gray_bitmap_height,
13897 (unsigned long) 1, (unsigned long) 0, 1);
13898 }
13899
f5d11644
GM
13900#ifdef HAVE_X_I18N
13901 xim_initialize (dpyinfo, resource_name);
13902#endif
13903
87485d6f
MW
13904#ifdef subprocesses
13905 /* This is only needed for distinguishing keyboard and process input. */
334208b7 13906 if (connection != 0)
7a13e894 13907 add_keyboard_wait_descriptor (connection);
87485d6f 13908#endif
6d4238f3 13909
041b69ac 13910#ifndef F_SETOWN_BUG
dc6f92b8 13911#ifdef F_SETOWN
dc6f92b8 13912#ifdef F_SETOWN_SOCK_NEG
61c3ce62 13913 /* stdin is a socket here */
334208b7 13914 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 13915#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 13916 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
13917#endif /* ! defined (F_SETOWN_SOCK_NEG) */
13918#endif /* ! defined (F_SETOWN) */
041b69ac 13919#endif /* F_SETOWN_BUG */
dc6f92b8
JB
13920
13921#ifdef SIGIO
eee20f6a
KH
13922 if (interrupt_input)
13923 init_sigio (connection);
c118dd06 13924#endif /* ! defined (SIGIO) */
dc6f92b8 13925
51b592fb 13926#ifdef USE_LUCID
f8c39f51 13927#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
13928 /* Make sure that we have a valid font for dialog boxes
13929 so that Xt does not crash. */
13930 {
13931 Display *dpy = dpyinfo->display;
13932 XrmValue d, fr, to;
13933 Font font;
e99db5a1 13934 int count;
51b592fb
RS
13935
13936 d.addr = (XPointer)&dpy;
13937 d.size = sizeof (Display *);
13938 fr.addr = XtDefaultFont;
13939 fr.size = sizeof (XtDefaultFont);
13940 to.size = sizeof (Font *);
13941 to.addr = (XPointer)&font;
e99db5a1 13942 count = x_catch_errors (dpy);
51b592fb
RS
13943 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
13944 abort ();
13945 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
13946 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 13947 x_uncatch_errors (dpy, count);
51b592fb
RS
13948 }
13949#endif
f8c39f51 13950#endif
51b592fb 13951
34e23e5a
GM
13952 /* See if we should run in synchronous mode. This is useful
13953 for debugging X code. */
13954 {
13955 Lisp_Object value;
13956 value = display_x_get_resource (dpyinfo,
13957 build_string ("synchronous"),
13958 build_string ("Synchronous"),
13959 Qnil, Qnil);
13960 if (STRINGP (value)
13961 && (!strcmp (XSTRING (value)->data, "true")
13962 || !strcmp (XSTRING (value)->data, "on")))
13963 XSynchronize (dpyinfo->display, True);
13964 }
13965
60439948
KH
13966 UNBLOCK_INPUT;
13967
7a13e894
RS
13968 return dpyinfo;
13969}
13970\f
13971/* Get rid of display DPYINFO, assuming all frames are already gone,
13972 and without sending any more commands to the X server. */
dc6f92b8 13973
7a13e894
RS
13974void
13975x_delete_display (dpyinfo)
13976 struct x_display_info *dpyinfo;
13977{
13978 delete_keyboard_wait_descriptor (dpyinfo->connection);
13979
13980 /* Discard this display from x_display_name_list and x_display_list.
13981 We can't use Fdelq because that can quit. */
13982 if (! NILP (x_display_name_list)
8e713be6
KR
13983 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
13984 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
13985 else
13986 {
13987 Lisp_Object tail;
13988
13989 tail = x_display_name_list;
8e713be6 13990 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 13991 {
bffcfca9 13992 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 13993 {
8e713be6 13994 XCDR (tail) = XCDR (XCDR (tail));
7a13e894
RS
13995 break;
13996 }
8e713be6 13997 tail = XCDR (tail);
7a13e894
RS
13998 }
13999 }
14000
9bda743f
GM
14001 if (next_noop_dpyinfo == dpyinfo)
14002 next_noop_dpyinfo = dpyinfo->next;
14003
7a13e894
RS
14004 if (x_display_list == dpyinfo)
14005 x_display_list = dpyinfo->next;
7f9c7f94
RS
14006 else
14007 {
14008 struct x_display_info *tail;
7a13e894 14009
7f9c7f94
RS
14010 for (tail = x_display_list; tail; tail = tail->next)
14011 if (tail->next == dpyinfo)
14012 tail->next = tail->next->next;
14013 }
7a13e894 14014
0d777288
RS
14015#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
14016#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
14017 XrmDestroyDatabase (dpyinfo->xrdb);
14018#endif
0d777288 14019#endif
29b38361
KH
14020#ifdef MULTI_KBOARD
14021 if (--dpyinfo->kboard->reference_count == 0)
39f79001 14022 delete_kboard (dpyinfo->kboard);
b9737ad3 14023#endif
f5d11644
GM
14024#ifdef HAVE_X_I18N
14025 if (dpyinfo->xim)
14026 xim_close_dpy (dpyinfo);
14027#endif
14028
b9737ad3
KH
14029 xfree (dpyinfo->font_table);
14030 xfree (dpyinfo->x_id_name);
f04e1297 14031 xfree (dpyinfo->color_cells);
b9737ad3 14032 xfree (dpyinfo);
7a13e894 14033}
f04e1297 14034
7a13e894
RS
14035\f
14036/* Set up use of X before we make the first connection. */
14037
06a2c219
GM
14038static struct redisplay_interface x_redisplay_interface =
14039{
14040 x_produce_glyphs,
14041 x_write_glyphs,
14042 x_insert_glyphs,
14043 x_clear_end_of_line,
14044 x_scroll_run,
14045 x_after_update_window_line,
14046 x_update_window_begin,
14047 x_update_window_end,
14048 XTcursor_to,
14049 x_flush,
71b8321e 14050 x_clear_mouse_face,
66ac4b0e
GM
14051 x_get_glyph_overhangs,
14052 x_fix_overlapping_area
06a2c219
GM
14053};
14054
dfcf069d 14055void
7a13e894
RS
14056x_initialize ()
14057{
06a2c219
GM
14058 rif = &x_redisplay_interface;
14059
14060 clear_frame_hook = x_clear_frame;
14061 ins_del_lines_hook = x_ins_del_lines;
14062 change_line_highlight_hook = x_change_line_highlight;
14063 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
14064 ring_bell_hook = XTring_bell;
14065 reset_terminal_modes_hook = XTreset_terminal_modes;
14066 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
14067 update_begin_hook = x_update_begin;
14068 update_end_hook = x_update_end;
dc6f92b8
JB
14069 set_terminal_window_hook = XTset_terminal_window;
14070 read_socket_hook = XTread_socket;
b8009dd1 14071 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8 14072 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 14073 mouse_position_hook = XTmouse_position;
f451eb13 14074 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 14075 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
14076 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
14077 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
14078 redeem_scroll_bar_hook = XTredeem_scroll_bar;
14079 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 14080 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 14081
f676886a 14082 scroll_region_ok = 1; /* we'll scroll partial frames */
9017309f 14083 char_ins_del_ok = 1;
dc6f92b8
JB
14084 line_ins_del_ok = 1; /* we'll just blt 'em */
14085 fast_clear_end_of_line = 1; /* X does this well */
58769bee 14086 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
14087 off the bottom */
14088 baud_rate = 19200;
14089
7a13e894 14090 x_noop_count = 0;
9ea173e8 14091 last_tool_bar_item = -1;
06a2c219
GM
14092 any_help_event_p = 0;
14093
b30b24cb
RS
14094 /* Try to use interrupt input; if we can't, then start polling. */
14095 Fset_input_mode (Qt, Qnil, Qt, Qnil);
14096
7f9c7f94
RS
14097#ifdef USE_X_TOOLKIT
14098 XtToolkitInitialize ();
14099 Xt_app_con = XtCreateApplicationContext ();
665881ad 14100 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
14101
14102 /* Install an asynchronous timer that processes Xt timeout events
14103 every 0.1s. This is necessary because some widget sets use
14104 timeouts internally, for example the LessTif menu bar, or the
14105 Xaw3d scroll bar. When Xt timouts aren't processed, these
14106 widgets don't behave normally. */
14107 {
14108 EMACS_TIME interval;
14109 EMACS_SET_SECS_USECS (interval, 0, 100000);
14110 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
14111 }
db74249b 14112#endif
bffcfca9 14113
eccc05db 14114#ifdef USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
14115 xaw3d_arrow_scroll = False;
14116 xaw3d_pick_top = True;
7f9c7f94
RS
14117#endif
14118
58769bee 14119 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 14120 original error handler. */
e99db5a1 14121 XSetErrorHandler (x_error_handler);
334208b7 14122 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 14123
06a2c219 14124 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
14125#ifdef SIGWINCH
14126 signal (SIGWINCH, SIG_DFL);
c118dd06 14127#endif /* ! defined (SIGWINCH) */
dc6f92b8 14128
92e2441b 14129 signal (SIGPIPE, x_connection_signal);
dc6f92b8 14130}
55123275 14131
06a2c219 14132
55123275
JB
14133void
14134syms_of_xterm ()
14135{
e99db5a1
RS
14136 staticpro (&x_error_message_string);
14137 x_error_message_string = Qnil;
14138
7a13e894
RS
14139 staticpro (&x_display_name_list);
14140 x_display_name_list = Qnil;
334208b7 14141
ab648270 14142 staticpro (&last_mouse_scroll_bar);
e53cb100 14143 last_mouse_scroll_bar = Qnil;
59e755be
KH
14144
14145 staticpro (&Qvendor_specific_keysyms);
14146 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
14147
14148 staticpro (&last_mouse_press_frame);
14149 last_mouse_press_frame = Qnil;
06a2c219 14150
06a2c219 14151 help_echo = Qnil;
be010514
GM
14152 staticpro (&help_echo);
14153 help_echo_object = Qnil;
14154 staticpro (&help_echo_object);
7cea38bc
GM
14155 help_echo_window = Qnil;
14156 staticpro (&help_echo_window);
06a2c219 14157 previous_help_echo = Qnil;
be010514
GM
14158 staticpro (&previous_help_echo);
14159 help_echo_pos = -1;
06a2c219
GM
14160
14161 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
14162 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
14163For example, if a block cursor is over a tab, it will be drawn as\n\
14164wide as that tab on the display.");
14165 x_stretch_cursor_p = 0;
14166
5bf04520
GM
14167 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
14168 "What X toolkit scroll bars Emacs uses.\n\
14169A value of nil means Emacs doesn't use X toolkit scroll bars.\n\
14170Otherwise, value is a symbol describing the X toolkit.");
eccc05db 14171#ifdef USE_TOOLKIT_SCROLL_BARS
5bf04520
GM
14172#ifdef USE_MOTIF
14173 Vx_toolkit_scroll_bars = intern ("motif");
14174#elif defined HAVE_XAW3D
14175 Vx_toolkit_scroll_bars = intern ("xaw3d");
14176#else
14177 Vx_toolkit_scroll_bars = intern ("xaw");
14178#endif
06a2c219 14179#else
5bf04520 14180 Vx_toolkit_scroll_bars = Qnil;
06a2c219
GM
14181#endif
14182
06a2c219
GM
14183 staticpro (&last_mouse_motion_frame);
14184 last_mouse_motion_frame = Qnil;
55123275 14185}
6cf0ae86
RS
14186
14187#endif /* not HAVE_X_WINDOWS */