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