(apropos-next-label-button): Update arguments to `next-button'.
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
edf36fe6 2 Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001
06a2c219 3 Free Software Foundation, Inc.
dc6f92b8
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
4746118a 9the Free Software Foundation; either version 2, or (at your option)
dc6f92b8
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
dc6f92b8 21
06a2c219 22/* New display code by Gerd Moellmann <gerd@gnu.org>. */
3afe33e7
RS
23/* Xt features made by Fred Pierresteguy. */
24
68c45bf0
PE
25#include <config.h>
26
039440c4 27/* On 4.3 these lose if they come after xterm.h. */
039440c4 28/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
29#include <signal.h>
30
4846819e
RS
31#include <stdio.h>
32
dc6f92b8
JB
33#ifdef HAVE_X_WINDOWS
34
35#include "lisp.h"
9ac0d9e0 36#include "blockinput.h"
dc6f92b8 37
ae79c227
AS
38/* Need syssignal.h for various externs and definitions that may be required
39 by some configurations for calls to signal later in this source file. */
40#include "syssignal.h"
41
dc6f92b8
JB
42/* This may include sys/types.h, and that somehow loses
43 if this is not done before the other system files. */
44#include "xterm.h"
f451eb13 45#include <X11/cursorfont.h>
dc6f92b8
JB
46
47/* Load sys/types.h if not already loaded.
48 In some systems loading it twice is suicidal. */
49#ifndef makedev
50#include <sys/types.h>
c118dd06 51#endif /* makedev */
dc6f92b8 52
6df54671 53#ifdef BSD_SYSTEM
dc6f92b8 54#include <sys/ioctl.h>
6df54671 55#endif /* ! defined (BSD_SYSTEM) */
dc6f92b8 56
2d368234 57#include "systty.h"
3a2712f9 58#include "systime.h"
dc6f92b8 59
b8009dd1 60#ifndef INCLUDED_FCNTL
dc6f92b8 61#include <fcntl.h>
b8009dd1 62#endif
dc6f92b8
JB
63#include <ctype.h>
64#include <errno.h>
65#include <setjmp.h>
66#include <sys/stat.h>
a0a7635f
RS
67/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
68/* #include <sys/param.h> */
dc6f92b8 69
dc43ef94 70#include "charset.h"
379b5ac0 71#include "coding.h"
dc43ef94 72#include "ccl.h"
7a13e894 73#include "frame.h"
dc6f92b8 74#include "dispextern.h"
ee569018 75#include "fontset.h"
dc6f92b8
JB
76#include "termhooks.h"
77#include "termopts.h"
78#include "termchar.h"
dc6f92b8 79#include "gnu.h"
dc6f92b8 80#include "disptab.h"
dc6f92b8 81#include "buffer.h"
f451eb13 82#include "window.h"
3b2fa4e6 83#include "keyboard.h"
bde7c500 84#include "intervals.h"
dfcf069d 85#include "process.h"
bffcfca9 86#include "atimer.h"
dc6f92b8 87
d2bd6bc4
RS
88#ifdef USE_X_TOOLKIT
89#include <X11/Shell.h>
90#endif
91
06a2c219
GM
92#ifdef HAVE_SYS_TIME_H
93#include <sys/time.h>
94#endif
95#ifdef HAVE_UNISTD_H
96#include <unistd.h>
97#endif
98
3afe33e7 99#ifdef USE_X_TOOLKIT
06a2c219 100
952291d9
GM
101extern void free_frame_menubar P_ ((struct frame *));
102extern struct frame *x_menubar_window_to_frame P_ ((struct x_display_info *,
103 int));
06a2c219 104
0fdff6bb
RS
105#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
106#define HACK_EDITRES
107extern void _XEditResCheckMessages ();
108#endif /* not NO_EDITRES */
06a2c219
GM
109
110/* Include toolkit specific headers for the scroll bar widget. */
111
112#ifdef USE_TOOLKIT_SCROLL_BARS
113#if defined USE_MOTIF
114#include <Xm/Xm.h> /* for LESSTIF_VERSION */
115#include <Xm/ScrollBar.h>
ec18280f
SM
116#else /* !USE_MOTIF i.e. use Xaw */
117
118#ifdef HAVE_XAW3D
06a2c219 119#include <X11/Xaw3d/Simple.h>
06a2c219
GM
120#include <X11/Xaw3d/Scrollbar.h>
121#define ARROW_SCROLLBAR
122#include <X11/Xaw3d/ScrollbarP.h>
ec18280f
SM
123#else /* !HAVE_XAW3D */
124#include <X11/Xaw/Simple.h>
125#include <X11/Xaw/Scrollbar.h>
126#endif /* !HAVE_XAW3D */
127#ifndef XtNpickTop
128#define XtNpickTop "pickTop"
129#endif /* !XtNpickTop */
130#endif /* !USE_MOTIF */
06a2c219
GM
131#endif /* USE_TOOLKIT_SCROLL_BARS */
132
3afe33e7
RS
133#endif /* USE_X_TOOLKIT */
134
b849c413
RS
135#ifndef USE_X_TOOLKIT
136#define x_any_window_to_frame x_window_to_frame
5627c40e 137#define x_top_window_to_frame x_window_to_frame
b849c413
RS
138#endif
139
546e6d5b 140#ifdef USE_X_TOOLKIT
d067ea8b 141#include "widget.h"
546e6d5b
RS
142#ifndef XtNinitialState
143#define XtNinitialState "initialState"
144#endif
145#endif
146
e4b68333 147#ifndef min
06a2c219 148#define min(a,b) ((a) < (b) ? (a) : (b))
e4b68333
RS
149#endif
150#ifndef max
06a2c219
GM
151#define max(a,b) ((a) > (b) ? (a) : (b))
152#endif
153
154#define abs(x) ((x) < 0 ? -(x) : (x))
155
156#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
157
158\f
159/* Bitmaps for truncated lines. */
160
161enum bitmap_type
162{
163 NO_BITMAP,
164 LEFT_TRUNCATION_BITMAP,
165 RIGHT_TRUNCATION_BITMAP,
166 OVERLAY_ARROW_BITMAP,
167 CONTINUED_LINE_BITMAP,
168 CONTINUATION_LINE_BITMAP,
169 ZV_LINE_BITMAP
170};
171
172/* Bitmap drawn to indicate lines not displaying text if
173 `indicate-empty-lines' is non-nil. */
174
175#define zv_width 8
176#define zv_height 8
177static unsigned char zv_bits[] = {
178 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00};
179
180/* An arrow like this: `<-'. */
181
182#define left_width 8
183#define left_height 8
184static unsigned char left_bits[] = {
185 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
186
110859fc
GM
187/* Right truncation arrow bitmap `->'. */
188
189#define right_width 8
190#define right_height 8
191static unsigned char right_bits[] = {
192 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
193
06a2c219
GM
194/* Marker for continued lines. */
195
196#define continued_width 8
197#define continued_height 8
198static unsigned char continued_bits[] = {
110859fc
GM
199 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
200
201/* Marker for continuation lines. */
06a2c219
GM
202
203#define continuation_width 8
204#define continuation_height 8
205static unsigned char continuation_bits[] = {
110859fc 206 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
06a2c219 207
110859fc 208/* Overlay arrow bitmap. */
06a2c219 209
110859fc
GM
210#if 0
211/* A bomb. */
06a2c219
GM
212#define ov_width 8
213#define ov_height 8
214static unsigned char ov_bits[] = {
215 0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
06a2c219 216#else
110859fc 217/* A triangular arrow. */
06a2c219
GM
218#define ov_width 8
219#define ov_height 8
220static unsigned char ov_bits[] = {
110859fc
GM
221 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
222
e4b68333 223#endif
06a2c219
GM
224
225extern Lisp_Object Qhelp_echo;
226
69388238 227\f
5bf04520 228/* Non-nil means Emacs uses toolkit scroll bars. */
06a2c219 229
5bf04520 230Lisp_Object Vx_toolkit_scroll_bars;
06a2c219
GM
231
232/* If a string, XTread_socket generates an event to display that string.
233 (The display is done in read_char.) */
234
235static Lisp_Object help_echo;
7cea38bc 236static Lisp_Object help_echo_window;
be010514
GM
237static Lisp_Object help_echo_object;
238static int help_echo_pos;
06a2c219
GM
239
240/* Temporary variable for XTread_socket. */
241
242static Lisp_Object previous_help_echo;
243
244/* Non-zero means that a HELP_EVENT has been generated since Emacs
245 start. */
246
247static int any_help_event_p;
248
249/* Non-zero means draw block and hollow cursor as wide as the glyph
250 under it. For example, if a block cursor is over a tab, it will be
251 drawn as wide as that tab on the display. */
252
253int x_stretch_cursor_p;
254
a72d5ce5
GM
255/* Non-zero means make use of UNDERLINE_POSITION font properties. */
256
257int x_use_underline_position_properties;
258
06a2c219
GM
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
b7f83f9e 398static int cursor_in_mouse_face_p P_ ((struct window *));
fa262c07 399static int clear_mouse_face P_ ((struct x_display_info *));
651f03b6 400static int x_alloc_nearest_color_1 P_ ((Display *, Colormap, XColor *));
499b1844 401static void x_set_window_size_1 P_ ((struct frame *, int, int, int));
651f03b6 402static const XColor *x_color_cells P_ ((Display *, int *));
71b8321e 403static void x_update_window_end P_ ((struct window *, int, int));
06a2c219
GM
404static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
405void x_delete_display P_ ((struct x_display_info *));
406static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
407 unsigned));
408static int fast_find_position P_ ((struct window *, int, int *, int *,
7e376260 409 int *, int *, Lisp_Object));
f9db2310
GM
410static int fast_find_string_pos P_ ((struct window *, int, Lisp_Object,
411 int *, int *, int *, int *, int));
06a2c219
GM
412static void set_output_cursor P_ ((struct cursor_pos *));
413static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
f9db2310 414 int *, int *, int *, int));
06a2c219 415static void note_mode_line_highlight P_ ((struct window *, int, int));
06a2c219 416static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
417static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
418static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
419static void show_mouse_face P_ ((struct x_display_info *,
420 enum draw_glyphs_face));
421static int x_io_error_quitter P_ ((Display *));
422int x_catch_errors P_ ((Display *));
423void x_uncatch_errors P_ ((Display *, int));
424void x_lower_frame P_ ((struct frame *));
425void x_scroll_bar_clear P_ ((struct frame *));
426int x_had_errors_p P_ ((Display *));
427void x_wm_set_size_hint P_ ((struct frame *, long, int));
428void x_raise_frame P_ ((struct frame *));
429void x_set_window_size P_ ((struct frame *, int, int, int));
430void x_wm_set_window_state P_ ((struct frame *, int));
431void x_wm_set_icon_pixmap P_ ((struct frame *, int));
432void x_initialize P_ ((void));
433static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
434static int x_compute_min_glyph_bounds P_ ((struct frame *));
435static void x_draw_phys_cursor_glyph P_ ((struct window *,
436 struct glyph_row *,
437 enum draw_glyphs_face));
438static void x_update_end P_ ((struct frame *));
439static void XTframe_up_to_date P_ ((struct frame *));
440static void XTreassert_line_highlight P_ ((int, int));
441static void x_change_line_highlight P_ ((int, int, int, int));
442static void XTset_terminal_modes P_ ((void));
443static void XTreset_terminal_modes P_ ((void));
444static void XTcursor_to P_ ((int, int, int, int));
445static void x_write_glyphs P_ ((struct glyph *, int));
446static void x_clear_end_of_line P_ ((int));
447static void x_clear_frame P_ ((void));
448static void x_clear_cursor P_ ((struct window *));
449static void frame_highlight P_ ((struct frame *));
450static void frame_unhighlight P_ ((struct frame *));
451static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
452static void XTframe_rehighlight P_ ((struct frame *));
453static void x_frame_rehighlight P_ ((struct x_display_info *));
454static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
f02d8aa0 455static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
06a2c219
GM
456static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
457 XRectangle *));
458static void expose_frame P_ ((struct frame *, int, int, int, int));
82f053ab 459static int expose_window_tree P_ ((struct window *, XRectangle *));
a39202f6 460static int expose_window P_ ((struct window *, XRectangle *));
06a2c219
GM
461static void expose_area P_ ((struct window *, struct glyph_row *,
462 XRectangle *, enum glyph_row_area));
82f053ab 463static int expose_line P_ ((struct window *, struct glyph_row *,
06a2c219
GM
464 XRectangle *));
465static void x_update_cursor_in_window_tree P_ ((struct window *, int));
466static void x_update_window_cursor P_ ((struct window *, int));
467static void x_erase_phys_cursor P_ ((struct window *));
468void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
469static void x_draw_bitmap P_ ((struct window *, struct glyph_row *,
470 enum bitmap_type));
471
472static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
473 GC, int));
474static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
475static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
476static void note_overwritten_text_cursor P_ ((struct window *, int, int));
477static void x_flush P_ ((struct frame *f));
952291d9
GM
478static void x_update_begin P_ ((struct frame *));
479static void x_update_window_begin P_ ((struct window *));
480static void x_draw_vertical_border P_ ((struct window *));
481static void x_after_update_window_line P_ ((struct glyph_row *));
482static INLINE void take_vertical_position_into_account P_ ((struct it *));
483static void x_produce_stretch_glyph P_ ((struct it *));
b52b65bd
GM
484static struct scroll_bar *x_window_to_scroll_bar P_ ((Window));
485static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
486 enum scroll_bar_part *,
487 Lisp_Object *, Lisp_Object *,
488 unsigned long *));
06a2c219
GM
489
490/* Flush display of frame F, or of all frames if F is null. */
491
492static void
493x_flush (f)
494 struct frame *f;
495{
496 BLOCK_INPUT;
497 if (f == NULL)
498 {
499 Lisp_Object rest, frame;
500 FOR_EACH_FRAME (rest, frame)
501 x_flush (XFRAME (frame));
502 }
503 else if (FRAME_X_P (f))
504 XFlush (FRAME_X_DISPLAY (f));
505 UNBLOCK_INPUT;
506}
507
dc6f92b8 508
06a2c219
GM
509/* Remove calls to XFlush by defining XFlush to an empty replacement.
510 Calls to XFlush should be unnecessary because the X output buffer
511 is flushed automatically as needed by calls to XPending,
512 XNextEvent, or XWindowEvent according to the XFlush man page.
513 XTread_socket calls XPending. Removing XFlush improves
514 performance. */
515
516#define XFlush(DISPLAY) (void) 0
b8009dd1 517
334208b7 518\f
06a2c219
GM
519/***********************************************************************
520 Debugging
521 ***********************************************************************/
522
9382638d 523#if 0
06a2c219
GM
524
525/* This is a function useful for recording debugging information about
526 the sequence of occurrences in this file. */
9382638d
KH
527
528struct record
529{
530 char *locus;
531 int type;
532};
533
534struct record event_record[100];
535
536int event_record_index;
537
538record_event (locus, type)
539 char *locus;
540 int type;
541{
542 if (event_record_index == sizeof (event_record) / sizeof (struct record))
543 event_record_index = 0;
544
545 event_record[event_record_index].locus = locus;
546 event_record[event_record_index].type = type;
547 event_record_index++;
548}
549
550#endif /* 0 */
06a2c219
GM
551
552
9382638d 553\f
334208b7
RS
554/* Return the struct x_display_info corresponding to DPY. */
555
556struct x_display_info *
557x_display_info_for_display (dpy)
558 Display *dpy;
559{
560 struct x_display_info *dpyinfo;
561
562 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
563 if (dpyinfo->display == dpy)
564 return dpyinfo;
16bd92ea 565
334208b7
RS
566 return 0;
567}
f451eb13 568
06a2c219
GM
569
570\f
571/***********************************************************************
572 Starting and ending an update
573 ***********************************************************************/
574
575/* Start an update of frame F. This function is installed as a hook
576 for update_begin, i.e. it is called when update_begin is called.
577 This function is called prior to calls to x_update_window_begin for
578 each window being updated. Currently, there is nothing to do here
579 because all interesting stuff is done on a window basis. */
dc6f92b8 580
dfcf069d 581static void
06a2c219 582x_update_begin (f)
f676886a 583 struct frame *f;
58769bee 584{
06a2c219
GM
585 /* Nothing to do. */
586}
dc6f92b8 587
dc6f92b8 588
06a2c219
GM
589/* Start update of window W. Set the global variable updated_window
590 to the window being updated and set output_cursor to the cursor
591 position of W. */
dc6f92b8 592
06a2c219
GM
593static void
594x_update_window_begin (w)
595 struct window *w;
596{
597 struct frame *f = XFRAME (WINDOW_FRAME (w));
598 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
599
600 updated_window = w;
601 set_output_cursor (&w->cursor);
b8009dd1 602
06a2c219 603 BLOCK_INPUT;
d1bc4182 604
06a2c219 605 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 606 {
514e4681 607 /* Don't do highlighting for mouse motion during the update. */
06a2c219 608 display_info->mouse_face_defer = 1;
37c2c98b 609
06a2c219
GM
610 /* If F needs to be redrawn, simply forget about any prior mouse
611 highlighting. */
9f67f20b 612 if (FRAME_GARBAGED_P (f))
06a2c219
GM
613 display_info->mouse_face_window = Qnil;
614
64f26cf5
GM
615#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
616 their mouse_face_p flag set, which means that they are always
617 unequal to rows in a desired matrix which never have that
618 flag set. So, rows containing mouse-face glyphs are never
619 scrolled, and we don't have to switch the mouse highlight off
620 here to prevent it from being scrolled. */
621
06a2c219
GM
622 /* Can we tell that this update does not affect the window
623 where the mouse highlight is? If so, no need to turn off.
624 Likewise, don't do anything if the frame is garbaged;
625 in that case, the frame's current matrix that we would use
626 is all wrong, and we will redisplay that line anyway. */
627 if (!NILP (display_info->mouse_face_window)
628 && w == XWINDOW (display_info->mouse_face_window))
514e4681 629 {
06a2c219 630 int i;
514e4681 631
06a2c219
GM
632 for (i = 0; i < w->desired_matrix->nrows; ++i)
633 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
634 break;
635
06a2c219
GM
636 if (i < w->desired_matrix->nrows)
637 clear_mouse_face (display_info);
514e4681 638 }
64f26cf5 639#endif /* 0 */
b8009dd1 640 }
6ccf47d1 641
dc6f92b8
JB
642 UNBLOCK_INPUT;
643}
644
06a2c219
GM
645
646/* Draw a vertical window border to the right of window W if W doesn't
647 have vertical scroll bars. */
648
dfcf069d 649static void
06a2c219
GM
650x_draw_vertical_border (w)
651 struct window *w;
58769bee 652{
06a2c219
GM
653 struct frame *f = XFRAME (WINDOW_FRAME (w));
654
655 /* Redraw borders between horizontally adjacent windows. Don't
656 do it for frames with vertical scroll bars because either the
657 right scroll bar of a window, or the left scroll bar of its
658 neighbor will suffice as a border. */
659 if (!WINDOW_RIGHTMOST_P (w)
660 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
661 {
662 int x0, x1, y0, y1;
dc6f92b8 663
06a2c219 664 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
110859fc 665 x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
666 y1 -= 1;
667
668 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
669 f->output_data.x->normal_gc, x1, y0, x1, y1);
670 }
671}
672
673
71b8321e
GM
674/* End update of window W (which is equal to updated_window).
675
676 Draw vertical borders between horizontally adjacent windows, and
677 display W's cursor if CURSOR_ON_P is non-zero.
678
679 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
680 glyphs in mouse-face were overwritten. In that case we have to
681 make sure that the mouse-highlight is properly redrawn.
682
683 W may be a menu bar pseudo-window in case we don't have X toolkit
684 support. Such windows don't have a cursor, so don't display it
685 here. */
06a2c219
GM
686
687static void
71b8321e 688x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 689 struct window *w;
71b8321e 690 int cursor_on_p, mouse_face_overwritten_p;
06a2c219 691{
140330de
GM
692 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
693
06a2c219
GM
694 if (!w->pseudo_window_p)
695 {
696 BLOCK_INPUT;
71b8321e 697
06a2c219
GM
698 if (cursor_on_p)
699 x_display_and_set_cursor (w, 1, output_cursor.hpos,
700 output_cursor.vpos,
701 output_cursor.x, output_cursor.y);
71b8321e 702
06a2c219
GM
703 x_draw_vertical_border (w);
704 UNBLOCK_INPUT;
705 }
706
140330de
GM
707 /* If a row with mouse-face was overwritten, arrange for
708 XTframe_up_to_date to redisplay the mouse highlight. */
709 if (mouse_face_overwritten_p)
710 {
711 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
712 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
713 dpyinfo->mouse_face_window = Qnil;
714 }
715
06a2c219
GM
716 updated_window = NULL;
717}
dc6f92b8 718
dc6f92b8 719
06a2c219
GM
720/* End update of frame F. This function is installed as a hook in
721 update_end. */
722
723static void
724x_update_end (f)
725 struct frame *f;
726{
727 /* Mouse highlight may be displayed again. */
aa8bff2e 728 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 729
06a2c219 730 BLOCK_INPUT;
334208b7 731 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
732 UNBLOCK_INPUT;
733}
b8009dd1 734
06a2c219
GM
735
736/* This function is called from various places in xdisp.c whenever a
737 complete update has been performed. The global variable
738 updated_window is not available here. */
b8009dd1 739
dfcf069d 740static void
b8009dd1 741XTframe_up_to_date (f)
06a2c219 742 struct frame *f;
b8009dd1 743{
06a2c219 744 if (FRAME_X_P (f))
514e4681 745 {
06a2c219 746 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 747
06a2c219
GM
748 if (dpyinfo->mouse_face_deferred_gc
749 || f == dpyinfo->mouse_face_mouse_frame)
750 {
751 BLOCK_INPUT;
752 if (dpyinfo->mouse_face_mouse_frame)
753 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
754 dpyinfo->mouse_face_mouse_x,
755 dpyinfo->mouse_face_mouse_y);
756 dpyinfo->mouse_face_deferred_gc = 0;
757 UNBLOCK_INPUT;
758 }
514e4681 759 }
b8009dd1 760}
06a2c219
GM
761
762
763/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
764 arrow bitmaps, or clear the areas where they would be displayed
765 before DESIRED_ROW is made current. The window being updated is
766 found in updated_window. This function It is called from
767 update_window_line only if it is known that there are differences
768 between bitmaps to be drawn between current row and DESIRED_ROW. */
769
770static void
771x_after_update_window_line (desired_row)
772 struct glyph_row *desired_row;
773{
774 struct window *w = updated_window;
775
776 xassert (w);
777
778 if (!desired_row->mode_line_p && !w->pseudo_window_p)
779 {
c5e6e06b
GM
780 struct frame *f;
781 int width;
782
06a2c219
GM
783 BLOCK_INPUT;
784 x_draw_row_bitmaps (w, desired_row);
785
786 /* When a window has disappeared, make sure that no rest of
787 full-width rows stays visible in the internal border. */
c5e6e06b
GM
788 if (windows_or_buffers_changed
789 && (f = XFRAME (w->frame),
790 width = FRAME_INTERNAL_BORDER_WIDTH (f),
791 width != 0))
06a2c219 792 {
06a2c219 793 int height = desired_row->visible_height;
110859fc
GM
794 int x = (window_box_right (w, -1)
795 + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
796 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
797
c5e6e06b
GM
798 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
799 x, y, width, height, False);
06a2c219
GM
800 }
801
802 UNBLOCK_INPUT;
803 }
804}
805
806
807/* Draw the bitmap WHICH in one of the areas to the left or right of
808 window W. ROW is the glyph row for which to display the bitmap; it
809 determines the vertical position at which the bitmap has to be
810 drawn. */
811
812static void
813x_draw_bitmap (w, row, which)
814 struct window *w;
815 struct glyph_row *row;
816 enum bitmap_type which;
817{
818 struct frame *f = XFRAME (WINDOW_FRAME (w));
819 Display *display = FRAME_X_DISPLAY (f);
820 Window window = FRAME_X_WINDOW (f);
821 int x, y, wd, h, dy;
822 unsigned char *bits;
823 Pixmap pixmap;
824 GC gc = f->output_data.x->normal_gc;
825 struct face *face;
826 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
827
828 /* Must clip because of partially visible lines. */
829 x_clip_to_row (w, row, gc, 1);
830
831 switch (which)
832 {
833 case LEFT_TRUNCATION_BITMAP:
834 wd = left_width;
835 h = left_height;
836 bits = left_bits;
837 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
838 - wd
110859fc 839 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
840 break;
841
842 case OVERLAY_ARROW_BITMAP:
843 wd = left_width;
844 h = left_height;
845 bits = ov_bits;
846 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
847 - wd
110859fc 848 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
849 break;
850
851 case RIGHT_TRUNCATION_BITMAP:
852 wd = right_width;
853 h = right_height;
854 bits = right_bits;
855 x = window_box_right (w, -1);
110859fc 856 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
857 break;
858
859 case CONTINUED_LINE_BITMAP:
860 wd = right_width;
861 h = right_height;
862 bits = continued_bits;
863 x = window_box_right (w, -1);
110859fc 864 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
865 break;
866
867 case CONTINUATION_LINE_BITMAP:
868 wd = continuation_width;
869 h = continuation_height;
870 bits = continuation_bits;
871 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
872 - wd
110859fc 873 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
874 break;
875
876 case ZV_LINE_BITMAP:
877 wd = zv_width;
878 h = zv_height;
879 bits = zv_bits;
880 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
881 - wd
110859fc 882 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
883 break;
884
885 default:
886 abort ();
887 }
888
889 /* Convert to frame coordinates. Set dy to the offset in the row to
890 start drawing the bitmap. */
891 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
892 dy = (row->height - h) / 2;
893
894 /* Draw the bitmap. I believe these small pixmaps can be cached
895 by the server. */
896 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
897 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
898 face->foreground,
899 face->background, depth);
900 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
901 XFreePixmap (display, pixmap);
902 XSetClipMask (display, gc, None);
903}
904
905
906/* Draw flags bitmaps for glyph row ROW on window W. Call this
907 function with input blocked. */
908
909static void
910x_draw_row_bitmaps (w, row)
911 struct window *w;
912 struct glyph_row *row;
913{
914 struct frame *f = XFRAME (w->frame);
915 enum bitmap_type bitmap;
916 struct face *face;
045dee35 917 int header_line_height = -1;
06a2c219
GM
918
919 xassert (interrupt_input_blocked);
920
921 /* If row is completely invisible, because of vscrolling, we
922 don't have to draw anything. */
923 if (row->visible_height <= 0)
924 return;
925
926 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
927 PREPARE_FACE_FOR_DISPLAY (f, face);
928
929 /* Decide which bitmap to draw at the left side. */
930 if (row->overlay_arrow_p)
931 bitmap = OVERLAY_ARROW_BITMAP;
932 else if (row->truncated_on_left_p)
933 bitmap = LEFT_TRUNCATION_BITMAP;
934 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
935 bitmap = CONTINUATION_LINE_BITMAP;
936 else if (row->indicate_empty_line_p)
937 bitmap = ZV_LINE_BITMAP;
938 else
939 bitmap = NO_BITMAP;
940
941 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
942 the flags area. */
943 if (bitmap == NO_BITMAP
110859fc 944 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
945 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
946 {
947 /* If W has a vertical border to its left, don't draw over it. */
948 int border = ((XFASTINT (w->left) > 0
949 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
950 ? 1 : 0);
951 int left = window_box_left (w, -1);
952
045dee35
GM
953 if (header_line_height < 0)
954 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
955
956 /* In case the same realized face is used for bitmap areas and
957 for something displayed in the text (e.g. face `region' on
958 mono-displays, the fill style may have been changed to
959 FillSolid in x_draw_glyph_string_background. */
960 if (face->stipple)
961 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
962 else
963 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
964
06a2c219
GM
965 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
966 face->gc,
967 (left
110859fc 968 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219 969 + border),
045dee35 970 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 971 row->y)),
110859fc 972 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
06a2c219 973 row->visible_height);
dcd08bfb
GM
974 if (!face->stipple)
975 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
976 }
977
978 /* Draw the left bitmap. */
979 if (bitmap != NO_BITMAP)
980 x_draw_bitmap (w, row, bitmap);
981
982 /* Decide which bitmap to draw at the right side. */
983 if (row->truncated_on_right_p)
984 bitmap = RIGHT_TRUNCATION_BITMAP;
985 else if (row->continued_p)
986 bitmap = CONTINUED_LINE_BITMAP;
987 else
988 bitmap = NO_BITMAP;
989
990 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
991 the flags area. */
992 if (bitmap == NO_BITMAP
110859fc 993 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
994 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
995 {
996 int right = window_box_right (w, -1);
997
045dee35
GM
998 if (header_line_height < 0)
999 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
1000
1001 /* In case the same realized face is used for bitmap areas and
1002 for something displayed in the text (e.g. face `region' on
1003 mono-displays, the fill style may have been changed to
1004 FillSolid in x_draw_glyph_string_background. */
1005 if (face->stipple)
1006 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
1007 else
1008 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
1009 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1010 face->gc,
1011 right,
045dee35 1012 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 1013 row->y)),
110859fc 1014 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
06a2c219 1015 row->visible_height);
dcd08bfb
GM
1016 if (!face->stipple)
1017 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
1018 }
1019
1020 /* Draw the right bitmap. */
1021 if (bitmap != NO_BITMAP)
1022 x_draw_bitmap (w, row, bitmap);
1023}
1024
dc6f92b8 1025\f
06a2c219
GM
1026/***********************************************************************
1027 Line Highlighting
1028 ***********************************************************************/
dc6f92b8 1029
06a2c219
GM
1030/* External interface to control of standout mode. Not used for X
1031 frames. Aborts when called. */
1032
1033static void
dc6f92b8
JB
1034XTreassert_line_highlight (new, vpos)
1035 int new, vpos;
1036{
06a2c219 1037 abort ();
dc6f92b8
JB
1038}
1039
06a2c219
GM
1040
1041/* Call this when about to modify line at position VPOS and change
1042 whether it is highlighted. Not used for X frames. Aborts when
1043 called. */
dc6f92b8 1044
dfcf069d 1045static void
06a2c219
GM
1046x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1047 int new_highlight, vpos, y, first_unused_hpos;
dc6f92b8 1048{
06a2c219 1049 abort ();
dc6f92b8
JB
1050}
1051
06a2c219
GM
1052
1053/* This is called when starting Emacs and when restarting after
1054 suspend. When starting Emacs, no X window is mapped. And nothing
1055 must be done to Emacs's own window if it is suspended (though that
1056 rarely happens). */
dc6f92b8 1057
dfcf069d 1058static void
dc6f92b8
JB
1059XTset_terminal_modes ()
1060{
1061}
1062
06a2c219
GM
1063/* This is called when exiting or suspending Emacs. Exiting will make
1064 the X-windows go away, and suspending requires no action. */
dc6f92b8 1065
dfcf069d 1066static void
dc6f92b8
JB
1067XTreset_terminal_modes ()
1068{
dc6f92b8 1069}
06a2c219
GM
1070
1071
dc6f92b8 1072\f
06a2c219
GM
1073/***********************************************************************
1074 Output Cursor
1075 ***********************************************************************/
1076
1077/* Set the global variable output_cursor to CURSOR. All cursor
1078 positions are relative to updated_window. */
dc6f92b8 1079
dfcf069d 1080static void
06a2c219
GM
1081set_output_cursor (cursor)
1082 struct cursor_pos *cursor;
dc6f92b8 1083{
06a2c219
GM
1084 output_cursor.hpos = cursor->hpos;
1085 output_cursor.vpos = cursor->vpos;
1086 output_cursor.x = cursor->x;
1087 output_cursor.y = cursor->y;
1088}
1089
1090
1091/* Set a nominal cursor position.
dc6f92b8 1092
06a2c219
GM
1093 HPOS and VPOS are column/row positions in a window glyph matrix. X
1094 and Y are window text area relative pixel positions.
1095
1096 If this is done during an update, updated_window will contain the
1097 window that is being updated and the position is the future output
1098 cursor position for that window. If updated_window is null, use
1099 selected_window and display the cursor at the given position. */
1100
1101static void
1102XTcursor_to (vpos, hpos, y, x)
1103 int vpos, hpos, y, x;
1104{
1105 struct window *w;
1106
1107 /* If updated_window is not set, work on selected_window. */
1108 if (updated_window)
1109 w = updated_window;
1110 else
1111 w = XWINDOW (selected_window);
dbcb258a 1112
06a2c219
GM
1113 /* Set the output cursor. */
1114 output_cursor.hpos = hpos;
1115 output_cursor.vpos = vpos;
1116 output_cursor.x = x;
1117 output_cursor.y = y;
dc6f92b8 1118
06a2c219
GM
1119 /* If not called as part of an update, really display the cursor.
1120 This will also set the cursor position of W. */
1121 if (updated_window == NULL)
dc6f92b8
JB
1122 {
1123 BLOCK_INPUT;
06a2c219 1124 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1125 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1126 UNBLOCK_INPUT;
1127 }
1128}
dc43ef94 1129
06a2c219
GM
1130
1131\f
1132/***********************************************************************
1133 Display Iterator
1134 ***********************************************************************/
1135
1136/* Function prototypes of this page. */
1137
1138static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1139 struct glyph *,
ee569018
KH
1140 XChar2b *,
1141 int *));
06a2c219
GM
1142static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1143 int, XChar2b *, int));
1144static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1145static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1146static void x_append_glyph P_ ((struct it *));
b4192550 1147static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1148static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1149 int, int, double));
1150static void x_produce_glyphs P_ ((struct it *));
06a2c219 1151static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1152
1153
e2ef8ee6
GM
1154/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1155 is not contained in the font. */
dc43ef94 1156
06a2c219 1157static INLINE XCharStruct *
ee569018 1158x_per_char_metric (font, char2b)
06a2c219
GM
1159 XFontStruct *font;
1160 XChar2b *char2b;
1161{
1162 /* The result metric information. */
1163 XCharStruct *pcm = NULL;
dc6f92b8 1164
06a2c219 1165 xassert (font && char2b);
dc6f92b8 1166
06a2c219 1167 if (font->per_char != NULL)
dc6f92b8 1168 {
06a2c219 1169 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1170 {
06a2c219
GM
1171 /* min_char_or_byte2 specifies the linear character index
1172 corresponding to the first element of the per_char array,
1173 max_char_or_byte2 is the index of the last character. A
1174 character with non-zero CHAR2B->byte1 is not in the font.
1175 A character with byte2 less than min_char_or_byte2 or
1176 greater max_char_or_byte2 is not in the font. */
1177 if (char2b->byte1 == 0
1178 && char2b->byte2 >= font->min_char_or_byte2
1179 && char2b->byte2 <= font->max_char_or_byte2)
1180 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1181 }
06a2c219 1182 else
dc6f92b8 1183 {
06a2c219
GM
1184 /* If either min_byte1 or max_byte1 are nonzero, both
1185 min_char_or_byte2 and max_char_or_byte2 are less than
1186 256, and the 2-byte character index values corresponding
1187 to the per_char array element N (counting from 0) are:
1188
1189 byte1 = N/D + min_byte1
1190 byte2 = N\D + min_char_or_byte2
1191
1192 where:
1193
1194 D = max_char_or_byte2 - min_char_or_byte2 + 1
1195 / = integer division
1196 \ = integer modulus */
1197 if (char2b->byte1 >= font->min_byte1
1198 && char2b->byte1 <= font->max_byte1
1199 && char2b->byte2 >= font->min_char_or_byte2
1200 && char2b->byte2 <= font->max_char_or_byte2)
1201 {
1202 pcm = (font->per_char
1203 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1204 * (char2b->byte1 - font->min_byte1))
1205 + (char2b->byte2 - font->min_char_or_byte2));
1206 }
dc6f92b8 1207 }
06a2c219
GM
1208 }
1209 else
1210 {
1211 /* If the per_char pointer is null, all glyphs between the first
1212 and last character indexes inclusive have the same
1213 information, as given by both min_bounds and max_bounds. */
1214 if (char2b->byte2 >= font->min_char_or_byte2
1215 && char2b->byte2 <= font->max_char_or_byte2)
1216 pcm = &font->max_bounds;
1217 }
dc6f92b8 1218
ee569018 1219 return ((pcm == NULL
3e71d8f2 1220 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1221 ? NULL : pcm);
06a2c219 1222}
b73b6aaf 1223
57b03282 1224
06a2c219
GM
1225/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1226 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1227
06a2c219
GM
1228static INLINE void
1229x_encode_char (c, char2b, font_info)
1230 int c;
1231 XChar2b *char2b;
1232 struct font_info *font_info;
1233{
1234 int charset = CHAR_CHARSET (c);
1235 XFontStruct *font = font_info->font;
1236
1237 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1238 This may be either a program in a special encoder language or a
1239 fixed encoding. */
1240 if (font_info->font_encoder)
1241 {
1242 /* It's a program. */
1243 struct ccl_program *ccl = font_info->font_encoder;
1244
1245 if (CHARSET_DIMENSION (charset) == 1)
1246 {
1247 ccl->reg[0] = charset;
1248 ccl->reg[1] = char2b->byte2;
1249 }
1250 else
1251 {
1252 ccl->reg[0] = charset;
1253 ccl->reg[1] = char2b->byte1;
1254 ccl->reg[2] = char2b->byte2;
1255 }
1256
1257 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1258
1259 /* We assume that MSBs are appropriately set/reset by CCL
1260 program. */
1261 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1262 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1263 else
1264 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1265 }
1266 else if (font_info->encoding[charset])
1267 {
1268 /* Fixed encoding scheme. See fontset.h for the meaning of the
1269 encoding numbers. */
1270 int enc = font_info->encoding[charset];
1271
1272 if ((enc == 1 || enc == 2)
1273 && CHARSET_DIMENSION (charset) == 2)
1274 char2b->byte1 |= 0x80;
1275
1276 if (enc == 1 || enc == 3)
1277 char2b->byte2 |= 0x80;
1278 }
1279}
1280
1281
1282/* Get face and two-byte form of character C in face FACE_ID on frame
1283 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1284 means we want to display multibyte text. Value is a pointer to a
1285 realized face that is ready for display. */
1286
1287static INLINE struct face *
1288x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1289 struct frame *f;
1290 int c, face_id;
1291 XChar2b *char2b;
1292 int multibyte_p;
1293{
1294 struct face *face = FACE_FROM_ID (f, face_id);
1295
1296 if (!multibyte_p)
1297 {
1298 /* Unibyte case. We don't have to encode, but we have to make
1299 sure to use a face suitable for unibyte. */
1300 char2b->byte1 = 0;
1301 char2b->byte2 = c;
ee569018
KH
1302 face_id = FACE_FOR_CHAR (f, face, c);
1303 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1304 }
1305 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1306 {
1307 /* Case of ASCII in a face known to fit ASCII. */
1308 char2b->byte1 = 0;
1309 char2b->byte2 = c;
1310 }
1311 else
1312 {
1313 int c1, c2, charset;
1314
1315 /* Split characters into bytes. If c2 is -1 afterwards, C is
1316 really a one-byte character so that byte1 is zero. */
1317 SPLIT_CHAR (c, charset, c1, c2);
1318 if (c2 > 0)
1319 char2b->byte1 = c1, char2b->byte2 = c2;
1320 else
1321 char2b->byte1 = 0, char2b->byte2 = c1;
1322
06a2c219 1323 /* Maybe encode the character in *CHAR2B. */
ee569018 1324 if (face->font != NULL)
06a2c219
GM
1325 {
1326 struct font_info *font_info
1327 = FONT_INFO_FROM_ID (f, face->font_info_id);
1328 if (font_info)
ee569018 1329 x_encode_char (c, char2b, font_info);
06a2c219
GM
1330 }
1331 }
1332
1333 /* Make sure X resources of the face are allocated. */
1334 xassert (face != NULL);
1335 PREPARE_FACE_FOR_DISPLAY (f, face);
1336
1337 return face;
1338}
1339
1340
1341/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1342 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1343 a pointer to a realized face that is ready for display. */
1344
1345static INLINE struct face *
ee569018 1346x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1347 struct frame *f;
1348 struct glyph *glyph;
1349 XChar2b *char2b;
ee569018 1350 int *two_byte_p;
06a2c219
GM
1351{
1352 struct face *face;
1353
1354 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1355 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1356
ee569018
KH
1357 if (two_byte_p)
1358 *two_byte_p = 0;
1359
06a2c219
GM
1360 if (!glyph->multibyte_p)
1361 {
1362 /* Unibyte case. We don't have to encode, but we have to make
1363 sure to use a face suitable for unibyte. */
1364 char2b->byte1 = 0;
43d120d8 1365 char2b->byte2 = glyph->u.ch;
06a2c219 1366 }
43d120d8
KH
1367 else if (glyph->u.ch < 128
1368 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1369 {
1370 /* Case of ASCII in a face known to fit ASCII. */
1371 char2b->byte1 = 0;
43d120d8 1372 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1373 }
1374 else
1375 {
1376 int c1, c2, charset;
1377
1378 /* Split characters into bytes. If c2 is -1 afterwards, C is
1379 really a one-byte character so that byte1 is zero. */
43d120d8 1380 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1381 if (c2 > 0)
1382 char2b->byte1 = c1, char2b->byte2 = c2;
1383 else
1384 char2b->byte1 = 0, char2b->byte2 = c1;
1385
1386 /* Maybe encode the character in *CHAR2B. */
1387 if (charset != CHARSET_ASCII)
1388 {
1389 struct font_info *font_info
1390 = FONT_INFO_FROM_ID (f, face->font_info_id);
1391 if (font_info)
1392 {
43d120d8 1393 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1394 if (two_byte_p)
1395 *two_byte_p
1396 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1397 }
1398 }
1399 }
1400
1401 /* Make sure X resources of the face are allocated. */
1402 xassert (face != NULL);
1403 PREPARE_FACE_FOR_DISPLAY (f, face);
1404 return face;
1405}
1406
1407
1408/* Store one glyph for IT->char_to_display in IT->glyph_row.
1409 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1410
1411static INLINE void
1412x_append_glyph (it)
1413 struct it *it;
1414{
1415 struct glyph *glyph;
1416 enum glyph_row_area area = it->area;
1417
1418 xassert (it->glyph_row);
1419 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1420
1421 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1422 if (glyph < it->glyph_row->glyphs[area + 1])
1423 {
06a2c219
GM
1424 glyph->charpos = CHARPOS (it->position);
1425 glyph->object = it->object;
88d75730 1426 glyph->pixel_width = it->pixel_width;
06a2c219 1427 glyph->voffset = it->voffset;
88d75730 1428 glyph->type = CHAR_GLYPH;
06a2c219 1429 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1430 glyph->left_box_line_p = it->start_of_box_run_p;
1431 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1432 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1433 || it->phys_descent > it->descent);
88d75730 1434 glyph->padding_p = 0;
ee569018 1435 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1436 glyph->face_id = it->face_id;
1437 glyph->u.ch = it->char_to_display;
06a2c219
GM
1438 ++it->glyph_row->used[area];
1439 }
1440}
1441
b4192550
KH
1442/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1443 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1444
1445static INLINE void
1446x_append_composite_glyph (it)
1447 struct it *it;
1448{
1449 struct glyph *glyph;
1450 enum glyph_row_area area = it->area;
1451
1452 xassert (it->glyph_row);
1453
1454 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1455 if (glyph < it->glyph_row->glyphs[area + 1])
1456 {
b4192550
KH
1457 glyph->charpos = CHARPOS (it->position);
1458 glyph->object = it->object;
88d75730 1459 glyph->pixel_width = it->pixel_width;
b4192550 1460 glyph->voffset = it->voffset;
88d75730 1461 glyph->type = COMPOSITE_GLYPH;
b4192550 1462 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1463 glyph->left_box_line_p = it->start_of_box_run_p;
1464 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1465 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1466 || it->phys_descent > it->descent);
88d75730
GM
1467 glyph->padding_p = 0;
1468 glyph->glyph_not_available_p = 0;
1469 glyph->face_id = it->face_id;
1470 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1471 ++it->glyph_row->used[area];
1472 }
1473}
1474
06a2c219
GM
1475
1476/* Change IT->ascent and IT->height according to the setting of
1477 IT->voffset. */
1478
1479static INLINE void
1480take_vertical_position_into_account (it)
1481 struct it *it;
1482{
1483 if (it->voffset)
1484 {
1485 if (it->voffset < 0)
1486 /* Increase the ascent so that we can display the text higher
1487 in the line. */
1488 it->ascent += abs (it->voffset);
1489 else
1490 /* Increase the descent so that we can display the text lower
1491 in the line. */
1492 it->descent += it->voffset;
1493 }
1494}
1495
1496
1497/* Produce glyphs/get display metrics for the image IT is loaded with.
1498 See the description of struct display_iterator in dispextern.h for
1499 an overview of struct display_iterator. */
1500
1501static void
1502x_produce_image_glyph (it)
1503 struct it *it;
1504{
1505 struct image *img;
1506 struct face *face;
1507
1508 xassert (it->what == IT_IMAGE);
1509
1510 face = FACE_FROM_ID (it->f, it->face_id);
1511 img = IMAGE_FROM_ID (it->f, it->image_id);
1512 xassert (img);
1513
1514 /* Make sure X resources of the face and image are loaded. */
1515 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1516 prepare_image_for_display (it->f, img);
1517
95af8492 1518 it->ascent = it->phys_ascent = image_ascent (img, face);
22d650b8
GM
1519 it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
1520 it->pixel_width = img->width + 2 * img->hmargin;
06a2c219
GM
1521
1522 it->nglyphs = 1;
1523
1524 if (face->box != FACE_NO_BOX)
1525 {
ea2ba0d4
KH
1526 if (face->box_line_width > 0)
1527 {
1528 it->ascent += face->box_line_width;
1529 it->descent += face->box_line_width;
1530 }
06a2c219
GM
1531
1532 if (it->start_of_box_run_p)
ea2ba0d4 1533 it->pixel_width += abs (face->box_line_width);
06a2c219 1534 if (it->end_of_box_run_p)
ea2ba0d4 1535 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1536 }
1537
1538 take_vertical_position_into_account (it);
1539
1540 if (it->glyph_row)
1541 {
1542 struct glyph *glyph;
1543 enum glyph_row_area area = it->area;
1544
1545 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1546 if (glyph < it->glyph_row->glyphs[area + 1])
1547 {
06a2c219
GM
1548 glyph->charpos = CHARPOS (it->position);
1549 glyph->object = it->object;
88d75730 1550 glyph->pixel_width = it->pixel_width;
06a2c219 1551 glyph->voffset = it->voffset;
88d75730 1552 glyph->type = IMAGE_GLYPH;
06a2c219 1553 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1554 glyph->left_box_line_p = it->start_of_box_run_p;
1555 glyph->right_box_line_p = it->end_of_box_run_p;
1556 glyph->overlaps_vertically_p = 0;
1557 glyph->padding_p = 0;
1558 glyph->glyph_not_available_p = 0;
1559 glyph->face_id = it->face_id;
1560 glyph->u.img_id = img->id;
06a2c219
GM
1561 ++it->glyph_row->used[area];
1562 }
1563 }
1564}
1565
1566
1567/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1568 of the glyph, WIDTH and HEIGHT are the width and height of the
1569 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1570 ascent of the glyph (0 <= ASCENT <= 1). */
1571
1572static void
1573x_append_stretch_glyph (it, object, width, height, ascent)
1574 struct it *it;
1575 Lisp_Object object;
1576 int width, height;
1577 double ascent;
1578{
1579 struct glyph *glyph;
1580 enum glyph_row_area area = it->area;
1581
1582 xassert (ascent >= 0 && ascent <= 1);
1583
1584 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1585 if (glyph < it->glyph_row->glyphs[area + 1])
1586 {
06a2c219
GM
1587 glyph->charpos = CHARPOS (it->position);
1588 glyph->object = object;
88d75730 1589 glyph->pixel_width = width;
06a2c219 1590 glyph->voffset = it->voffset;
88d75730 1591 glyph->type = STRETCH_GLYPH;
06a2c219 1592 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1593 glyph->left_box_line_p = it->start_of_box_run_p;
1594 glyph->right_box_line_p = it->end_of_box_run_p;
1595 glyph->overlaps_vertically_p = 0;
1596 glyph->padding_p = 0;
1597 glyph->glyph_not_available_p = 0;
1598 glyph->face_id = it->face_id;
1599 glyph->u.stretch.ascent = height * ascent;
1600 glyph->u.stretch.height = height;
06a2c219
GM
1601 ++it->glyph_row->used[area];
1602 }
1603}
1604
1605
1606/* Produce a stretch glyph for iterator IT. IT->object is the value
1607 of the glyph property displayed. The value must be a list
1608 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1609 being recognized:
1610
1611 1. `:width WIDTH' specifies that the space should be WIDTH *
1612 canonical char width wide. WIDTH may be an integer or floating
1613 point number.
1614
1615 2. `:relative-width FACTOR' specifies that the width of the stretch
1616 should be computed from the width of the first character having the
1617 `glyph' property, and should be FACTOR times that width.
1618
1619 3. `:align-to HPOS' specifies that the space should be wide enough
1620 to reach HPOS, a value in canonical character units.
1621
1622 Exactly one of the above pairs must be present.
1623
1624 4. `:height HEIGHT' specifies that the height of the stretch produced
1625 should be HEIGHT, measured in canonical character units.
1626
1627 5. `:relative-height FACTOR' specifies that the height of the the
1628 stretch should be FACTOR times the height of the characters having
1629 the glyph property.
1630
1631 Either none or exactly one of 4 or 5 must be present.
1632
1633 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1634 of the stretch should be used for the ascent of the stretch.
1635 ASCENT must be in the range 0 <= ASCENT <= 100. */
1636
1637#define NUMVAL(X) \
1638 ((INTEGERP (X) || FLOATP (X)) \
1639 ? XFLOATINT (X) \
1640 : - 1)
1641
1642
1643static void
1644x_produce_stretch_glyph (it)
1645 struct it *it;
1646{
1647 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1648#if GLYPH_DEBUG
1649 extern Lisp_Object Qspace;
1650#endif
1651 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1652 extern Lisp_Object QCrelative_width, QCrelative_height;
1653 extern Lisp_Object QCalign_to;
1654 Lisp_Object prop, plist;
1655 double width = 0, height = 0, ascent = 0;
1656 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1657 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1658
1659 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1660
1661 /* List should start with `space'. */
1662 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1663 plist = XCDR (it->object);
1664
1665 /* Compute the width of the stretch. */
1666 if (prop = Fplist_get (plist, QCwidth),
1667 NUMVAL (prop) > 0)
1668 /* Absolute width `:width WIDTH' specified and valid. */
1669 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1670 else if (prop = Fplist_get (plist, QCrelative_width),
1671 NUMVAL (prop) > 0)
1672 {
1673 /* Relative width `:relative-width FACTOR' specified and valid.
1674 Compute the width of the characters having the `glyph'
1675 property. */
1676 struct it it2;
1677 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1678
1679 it2 = *it;
1680 if (it->multibyte_p)
1681 {
1682 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1683 - IT_BYTEPOS (*it));
1684 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1685 }
1686 else
1687 it2.c = *p, it2.len = 1;
1688
1689 it2.glyph_row = NULL;
1690 it2.what = IT_CHARACTER;
1691 x_produce_glyphs (&it2);
1692 width = NUMVAL (prop) * it2.pixel_width;
1693 }
1694 else if (prop = Fplist_get (plist, QCalign_to),
1695 NUMVAL (prop) > 0)
1696 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1697 else
1698 /* Nothing specified -> width defaults to canonical char width. */
1699 width = CANON_X_UNIT (it->f);
1700
1701 /* Compute height. */
1702 if (prop = Fplist_get (plist, QCheight),
1703 NUMVAL (prop) > 0)
1704 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1705 else if (prop = Fplist_get (plist, QCrelative_height),
1706 NUMVAL (prop) > 0)
1707 height = FONT_HEIGHT (font) * NUMVAL (prop);
1708 else
1709 height = FONT_HEIGHT (font);
1710
1711 /* Compute percentage of height used for ascent. If
1712 `:ascent ASCENT' is present and valid, use that. Otherwise,
1713 derive the ascent from the font in use. */
1714 if (prop = Fplist_get (plist, QCascent),
1715 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1716 ascent = NUMVAL (prop) / 100.0;
1717 else
1718 ascent = (double) font->ascent / FONT_HEIGHT (font);
1719
1720 if (width <= 0)
1721 width = 1;
1722 if (height <= 0)
1723 height = 1;
1724
1725 if (it->glyph_row)
1726 {
1727 Lisp_Object object = it->stack[it->sp - 1].string;
1728 if (!STRINGP (object))
1729 object = it->w->buffer;
1730 x_append_stretch_glyph (it, object, width, height, ascent);
1731 }
1732
1733 it->pixel_width = width;
66ac4b0e
GM
1734 it->ascent = it->phys_ascent = height * ascent;
1735 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1736 it->nglyphs = 1;
1737
1738 if (face->box != FACE_NO_BOX)
1739 {
ea2ba0d4
KH
1740 if (face->box_line_width > 0)
1741 {
1742 it->ascent += face->box_line_width;
1743 it->descent += face->box_line_width;
1744 }
06a2c219
GM
1745
1746 if (it->start_of_box_run_p)
ea2ba0d4 1747 it->pixel_width += abs (face->box_line_width);
06a2c219 1748 if (it->end_of_box_run_p)
ea2ba0d4 1749 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1750 }
1751
1752 take_vertical_position_into_account (it);
1753}
1754
b4192550
KH
1755/* Return proper value to be used as baseline offset of font that has
1756 ASCENT and DESCENT to draw characters by the font at the vertical
1757 center of the line of frame F.
1758
1759 Here, out task is to find the value of BOFF in the following figure;
1760
1761 -------------------------+-----------+-
1762 -+-+---------+-+ | |
1763 | | | | | |
1764 | | | | F_ASCENT F_HEIGHT
1765 | | | ASCENT | |
1766 HEIGHT | | | | |
1767 | | |-|-+------+-----------|------- baseline
1768 | | | | BOFF | |
1769 | |---------|-+-+ | |
1770 | | | DESCENT | |
1771 -+-+---------+-+ F_DESCENT |
1772 -------------------------+-----------+-
1773
1774 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1775 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1776 DESCENT = FONT->descent
1777 HEIGHT = FONT_HEIGHT (FONT)
1778 F_DESCENT = (F->output_data.x->font->descent
1779 - F->output_data.x->baseline_offset)
1780 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1781*/
1782
458f45fa
KH
1783#define VCENTER_BASELINE_OFFSET(FONT, F) \
1784 ((FONT)->descent \
1785 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT)) \
1786 + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \
1787 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1788
1789/* Produce glyphs/get display metrics for the display element IT is
1790 loaded with. See the description of struct display_iterator in
1791 dispextern.h for an overview of struct display_iterator. */
1792
1793static void
1794x_produce_glyphs (it)
1795 struct it *it;
1796{
ee569018
KH
1797 it->glyph_not_available_p = 0;
1798
06a2c219
GM
1799 if (it->what == IT_CHARACTER)
1800 {
1801 XChar2b char2b;
1802 XFontStruct *font;
ee569018 1803 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1804 XCharStruct *pcm;
06a2c219 1805 int font_not_found_p;
b4192550
KH
1806 struct font_info *font_info;
1807 int boff; /* baseline offset */
a4249304
KH
1808 /* We may change it->multibyte_p upon unibyte<->multibyte
1809 conversion. So, save the current value now and restore it
1810 later.
1811
1812 Note: It seems that we don't have to record multibyte_p in
1813 struct glyph because the character code itself tells if or
1814 not the character is multibyte. Thus, in the future, we must
1815 consider eliminating the field `multibyte_p' in the struct
c347a1c3 1816 glyph. */
a4249304 1817 int saved_multibyte_p = it->multibyte_p;
06a2c219 1818
ee569018
KH
1819 /* Maybe translate single-byte characters to multibyte, or the
1820 other way. */
06a2c219 1821 it->char_to_display = it->c;
ee569018 1822 if (!ASCII_BYTE_P (it->c))
06a2c219 1823 {
ee569018
KH
1824 if (unibyte_display_via_language_environment
1825 && SINGLE_BYTE_CHAR_P (it->c)
1826 && (it->c >= 0240
1827 || !NILP (Vnonascii_translation_table)))
1828 {
1829 it->char_to_display = unibyte_char_to_multibyte (it->c);
a4249304 1830 it->multibyte_p = 1;
ee569018
KH
1831 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1832 face = FACE_FROM_ID (it->f, it->face_id);
1833 }
1834 else if (!SINGLE_BYTE_CHAR_P (it->c)
1835 && !it->multibyte_p)
1836 {
c347a1c3 1837 it->multibyte_p = 1;
ee569018
KH
1838 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1839 face = FACE_FROM_ID (it->f, it->face_id);
1840 }
06a2c219
GM
1841 }
1842
ee569018
KH
1843 /* Get font to use. Encode IT->char_to_display. */
1844 x_get_char_face_and_encoding (it->f, it->char_to_display,
1845 it->face_id, &char2b,
1846 it->multibyte_p);
06a2c219
GM
1847 font = face->font;
1848
1849 /* When no suitable font found, use the default font. */
1850 font_not_found_p = font == NULL;
1851 if (font_not_found_p)
b4192550
KH
1852 {
1853 font = FRAME_FONT (it->f);
1854 boff = it->f->output_data.x->baseline_offset;
1855 font_info = NULL;
1856 }
1857 else
1858 {
1859 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1860 boff = font_info->baseline_offset;
1861 if (font_info->vertical_centering)
1862 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1863 }
06a2c219
GM
1864
1865 if (it->char_to_display >= ' '
1866 && (!it->multibyte_p || it->char_to_display < 128))
1867 {
1868 /* Either unibyte or ASCII. */
1869 int stretched_p;
1870
1871 it->nglyphs = 1;
06a2c219
GM
1872
1873 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1874 it->ascent = font->ascent + boff;
1875 it->descent = font->descent - boff;
474848ac
GM
1876
1877 if (pcm)
1878 {
1879 it->phys_ascent = pcm->ascent + boff;
1880 it->phys_descent = pcm->descent - boff;
1881 it->pixel_width = pcm->width;
1882 }
1883 else
1884 {
1885 it->glyph_not_available_p = 1;
1886 it->phys_ascent = font->ascent + boff;
1887 it->phys_descent = font->descent - boff;
1888 it->pixel_width = FONT_WIDTH (font);
1889 }
06a2c219
GM
1890
1891 /* If this is a space inside a region of text with
1892 `space-width' property, change its width. */
1893 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1894 if (stretched_p)
1895 it->pixel_width *= XFLOATINT (it->space_width);
1896
1897 /* If face has a box, add the box thickness to the character
1898 height. If character has a box line to the left and/or
1899 right, add the box line width to the character's width. */
1900 if (face->box != FACE_NO_BOX)
1901 {
1902 int thick = face->box_line_width;
1903
ea2ba0d4
KH
1904 if (thick > 0)
1905 {
1906 it->ascent += thick;
1907 it->descent += thick;
1908 }
1909 else
1910 thick = -thick;
1911
06a2c219
GM
1912 if (it->start_of_box_run_p)
1913 it->pixel_width += thick;
1914 if (it->end_of_box_run_p)
1915 it->pixel_width += thick;
1916 }
1917
1918 /* If face has an overline, add the height of the overline
1919 (1 pixel) and a 1 pixel margin to the character height. */
1920 if (face->overline_p)
1921 it->ascent += 2;
1922
1923 take_vertical_position_into_account (it);
1924
1925 /* If we have to actually produce glyphs, do it. */
1926 if (it->glyph_row)
1927 {
1928 if (stretched_p)
1929 {
1930 /* Translate a space with a `space-width' property
1931 into a stretch glyph. */
1932 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1933 x_append_stretch_glyph (it, it->object, it->pixel_width,
1934 it->ascent + it->descent, ascent);
1935 }
1936 else
1937 x_append_glyph (it);
1938
1939 /* If characters with lbearing or rbearing are displayed
1940 in this line, record that fact in a flag of the
1941 glyph row. This is used to optimize X output code. */
1c7e22fd 1942 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1943 it->glyph_row->contains_overlapping_glyphs_p = 1;
1944 }
1945 }
1946 else if (it->char_to_display == '\n')
1947 {
1948 /* A newline has no width but we need the height of the line. */
1949 it->pixel_width = 0;
1950 it->nglyphs = 0;
b4192550
KH
1951 it->ascent = it->phys_ascent = font->ascent + boff;
1952 it->descent = it->phys_descent = font->descent - boff;
06a2c219 1953
ea2ba0d4
KH
1954 if (face->box != FACE_NO_BOX
1955 && face->box_line_width > 0)
06a2c219 1956 {
ea2ba0d4
KH
1957 it->ascent += face->box_line_width;
1958 it->descent += face->box_line_width;
06a2c219
GM
1959 }
1960 }
1961 else if (it->char_to_display == '\t')
1962 {
1963 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1964 int x = it->current_x + it->continuation_lines_width;
06a2c219 1965 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
2a32b5ea
GM
1966
1967 /* If the distance from the current position to the next tab
1968 stop is less than a canonical character width, use the
1969 tab stop after that. */
1970 if (next_tab_x - x < CANON_X_UNIT (it->f))
1971 next_tab_x += tab_width;
06a2c219
GM
1972
1973 it->pixel_width = next_tab_x - x;
1974 it->nglyphs = 1;
b4192550
KH
1975 it->ascent = it->phys_ascent = font->ascent + boff;
1976 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1977
1978 if (it->glyph_row)
1979 {
1980 double ascent = (double) it->ascent / (it->ascent + it->descent);
1981 x_append_stretch_glyph (it, it->object, it->pixel_width,
1982 it->ascent + it->descent, ascent);
1983 }
1984 }
1985 else
1986 {
1987 /* A multi-byte character. Assume that the display width of the
1988 character is the width of the character multiplied by the
b4192550 1989 width of the font. */
06a2c219 1990
b4192550
KH
1991 /* If we found a font, this font should give us the right
1992 metrics. If we didn't find a font, use the frame's
1993 default font and calculate the width of the character
1994 from the charset width; this is what old redisplay code
1995 did. */
1996 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
1997 if (font_not_found_p || !pcm)
1998 {
1999 int charset = CHAR_CHARSET (it->char_to_display);
2000
2001 it->glyph_not_available_p = 1;
2002 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
2003 * CHARSET_WIDTH (charset));
2004 it->phys_ascent = font->ascent + boff;
2005 it->phys_descent = font->descent - boff;
2006 }
2007 else
2008 {
2009 it->pixel_width = pcm->width;
2010 it->phys_ascent = pcm->ascent + boff;
2011 it->phys_descent = pcm->descent - boff;
2012 if (it->glyph_row
2013 && (pcm->lbearing < 0
2014 || pcm->rbearing > pcm->width))
2015 it->glyph_row->contains_overlapping_glyphs_p = 1;
2016 }
b4192550
KH
2017 it->nglyphs = 1;
2018 it->ascent = font->ascent + boff;
2019 it->descent = font->descent - boff;
06a2c219
GM
2020 if (face->box != FACE_NO_BOX)
2021 {
2022 int thick = face->box_line_width;
ea2ba0d4
KH
2023
2024 if (thick > 0)
2025 {
2026 it->ascent += thick;
2027 it->descent += thick;
2028 }
2029 else
2030 thick = - thick;
06a2c219
GM
2031
2032 if (it->start_of_box_run_p)
2033 it->pixel_width += thick;
2034 if (it->end_of_box_run_p)
2035 it->pixel_width += thick;
2036 }
2037
2038 /* If face has an overline, add the height of the overline
2039 (1 pixel) and a 1 pixel margin to the character height. */
2040 if (face->overline_p)
2041 it->ascent += 2;
2042
2043 take_vertical_position_into_account (it);
2044
2045 if (it->glyph_row)
2046 x_append_glyph (it);
2047 }
a4249304 2048 it->multibyte_p = saved_multibyte_p;
06a2c219 2049 }
b4192550
KH
2050 else if (it->what == IT_COMPOSITION)
2051 {
2052 /* Note: A composition is represented as one glyph in the
2053 glyph matrix. There are no padding glyphs. */
2054 XChar2b char2b;
2055 XFontStruct *font;
ee569018 2056 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2057 XCharStruct *pcm;
2058 int font_not_found_p;
2059 struct font_info *font_info;
2060 int boff; /* baseline offset */
2061 struct composition *cmp = composition_table[it->cmp_id];
2062
2063 /* Maybe translate single-byte characters to multibyte. */
2064 it->char_to_display = it->c;
2065 if (unibyte_display_via_language_environment
2066 && SINGLE_BYTE_CHAR_P (it->c)
2067 && (it->c >= 0240
2068 || (it->c >= 0200
2069 && !NILP (Vnonascii_translation_table))))
2070 {
2071 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2072 }
2073
2074 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2075 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2076 face = FACE_FROM_ID (it->f, it->face_id);
2077 x_get_char_face_and_encoding (it->f, it->char_to_display,
2078 it->face_id, &char2b, it->multibyte_p);
b4192550
KH
2079 font = face->font;
2080
2081 /* When no suitable font found, use the default font. */
2082 font_not_found_p = font == NULL;
2083 if (font_not_found_p)
2084 {
2085 font = FRAME_FONT (it->f);
2086 boff = it->f->output_data.x->baseline_offset;
2087 font_info = NULL;
2088 }
2089 else
2090 {
2091 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2092 boff = font_info->baseline_offset;
2093 if (font_info->vertical_centering)
2094 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2095 }
2096
2097 /* There are no padding glyphs, so there is only one glyph to
2098 produce for the composition. Important is that pixel_width,
2099 ascent and descent are the values of what is drawn by
2100 draw_glyphs (i.e. the values of the overall glyphs composed). */
2101 it->nglyphs = 1;
2102
2103 /* If we have not yet calculated pixel size data of glyphs of
2104 the composition for the current face font, calculate them
2105 now. Theoretically, we have to check all fonts for the
2106 glyphs, but that requires much time and memory space. So,
2107 here we check only the font of the first glyph. This leads
2108 to incorrect display very rarely, and C-l (recenter) can
2109 correct the display anyway. */
2110 if (cmp->font != (void *) font)
2111 {
2112 /* Ascent and descent of the font of the first character of
2113 this composition (adjusted by baseline offset). Ascent
2114 and descent of overall glyphs should not be less than
2115 them respectively. */
2116 int font_ascent = font->ascent + boff;
2117 int font_descent = font->descent - boff;
2118 /* Bounding box of the overall glyphs. */
2119 int leftmost, rightmost, lowest, highest;
329bed06 2120 int i, width, ascent, descent;
b4192550
KH
2121
2122 cmp->font = (void *) font;
2123
2124 /* Initialize the bounding box. */
1bdeec2e
KH
2125 if (font_info
2126 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2127 {
2128 width = pcm->width;
2129 ascent = pcm->ascent;
2130 descent = pcm->descent;
2131 }
2132 else
2133 {
2134 width = FONT_WIDTH (font);
2135 ascent = font->ascent;
2136 descent = font->descent;
2137 }
2138
2139 rightmost = width;
2140 lowest = - descent + boff;
2141 highest = ascent + boff;
b4192550 2142 leftmost = 0;
329bed06 2143
b4192550
KH
2144 if (font_info
2145 && font_info->default_ascent
2146 && CHAR_TABLE_P (Vuse_default_ascent)
2147 && !NILP (Faref (Vuse_default_ascent,
2148 make_number (it->char_to_display))))
2149 highest = font_info->default_ascent + boff;
2150
2151 /* Draw the first glyph at the normal position. It may be
2152 shifted to right later if some other glyphs are drawn at
2153 the left. */
2154 cmp->offsets[0] = 0;
2155 cmp->offsets[1] = boff;
2156
2157 /* Set cmp->offsets for the remaining glyphs. */
2158 for (i = 1; i < cmp->glyph_len; i++)
2159 {
2160 int left, right, btm, top;
2161 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2162 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2163
2164 face = FACE_FROM_ID (it->f, face_id);
2165 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2166 it->multibyte_p);
b4192550
KH
2167 font = face->font;
2168 if (font == NULL)
2169 {
2170 font = FRAME_FONT (it->f);
2171 boff = it->f->output_data.x->baseline_offset;
2172 font_info = NULL;
2173 }
2174 else
2175 {
2176 font_info
2177 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2178 boff = font_info->baseline_offset;
2179 if (font_info->vertical_centering)
2180 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2181 }
2182
1bdeec2e
KH
2183 if (font_info
2184 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2185 {
2186 width = pcm->width;
2187 ascent = pcm->ascent;
2188 descent = pcm->descent;
2189 }
2190 else
2191 {
2192 width = FONT_WIDTH (font);
1bdeec2e
KH
2193 ascent = 1;
2194 descent = 0;
329bed06 2195 }
b4192550
KH
2196
2197 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2198 {
2199 /* Relative composition with or without
2200 alternate chars. */
329bed06
GM
2201 left = (leftmost + rightmost - width) / 2;
2202 btm = - descent + boff;
b4192550
KH
2203 if (font_info && font_info->relative_compose
2204 && (! CHAR_TABLE_P (Vignore_relative_composition)
2205 || NILP (Faref (Vignore_relative_composition,
2206 make_number (ch)))))
2207 {
2208
329bed06 2209 if (- descent >= font_info->relative_compose)
b4192550
KH
2210 /* One extra pixel between two glyphs. */
2211 btm = highest + 1;
329bed06 2212 else if (ascent <= 0)
b4192550 2213 /* One extra pixel between two glyphs. */
329bed06 2214 btm = lowest - 1 - ascent - descent;
b4192550
KH
2215 }
2216 }
2217 else
2218 {
2219 /* A composition rule is specified by an integer
2220 value that encodes global and new reference
2221 points (GREF and NREF). GREF and NREF are
2222 specified by numbers as below:
2223
2224 0---1---2 -- ascent
2225 | |
2226 | |
2227 | |
2228 9--10--11 -- center
2229 | |
2230 ---3---4---5--- baseline
2231 | |
2232 6---7---8 -- descent
2233 */
2234 int rule = COMPOSITION_RULE (cmp, i);
2235 int gref, nref, grefx, grefy, nrefx, nrefy;
2236
2237 COMPOSITION_DECODE_RULE (rule, gref, nref);
2238 grefx = gref % 3, nrefx = nref % 3;
2239 grefy = gref / 3, nrefy = nref / 3;
2240
2241 left = (leftmost
2242 + grefx * (rightmost - leftmost) / 2
329bed06 2243 - nrefx * width / 2);
b4192550
KH
2244 btm = ((grefy == 0 ? highest
2245 : grefy == 1 ? 0
2246 : grefy == 2 ? lowest
2247 : (highest + lowest) / 2)
329bed06
GM
2248 - (nrefy == 0 ? ascent + descent
2249 : nrefy == 1 ? descent - boff
b4192550 2250 : nrefy == 2 ? 0
329bed06 2251 : (ascent + descent) / 2));
b4192550
KH
2252 }
2253
2254 cmp->offsets[i * 2] = left;
329bed06 2255 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2256
2257 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2258 right = left + width;
2259 top = btm + descent + ascent;
b4192550
KH
2260 if (left < leftmost)
2261 leftmost = left;
2262 if (right > rightmost)
2263 rightmost = right;
2264 if (top > highest)
2265 highest = top;
2266 if (btm < lowest)
2267 lowest = btm;
2268 }
2269
2270 /* If there are glyphs whose x-offsets are negative,
2271 shift all glyphs to the right and make all x-offsets
2272 non-negative. */
2273 if (leftmost < 0)
2274 {
2275 for (i = 0; i < cmp->glyph_len; i++)
2276 cmp->offsets[i * 2] -= leftmost;
2277 rightmost -= leftmost;
2278 }
2279
2280 cmp->pixel_width = rightmost;
2281 cmp->ascent = highest;
2282 cmp->descent = - lowest;
2283 if (cmp->ascent < font_ascent)
2284 cmp->ascent = font_ascent;
2285 if (cmp->descent < font_descent)
2286 cmp->descent = font_descent;
2287 }
2288
2289 it->pixel_width = cmp->pixel_width;
2290 it->ascent = it->phys_ascent = cmp->ascent;
2291 it->descent = it->phys_descent = cmp->descent;
2292
2293 if (face->box != FACE_NO_BOX)
2294 {
2295 int thick = face->box_line_width;
ea2ba0d4
KH
2296
2297 if (thick > 0)
2298 {
2299 it->ascent += thick;
2300 it->descent += thick;
2301 }
2302 else
2303 thick = - thick;
b4192550
KH
2304
2305 if (it->start_of_box_run_p)
2306 it->pixel_width += thick;
2307 if (it->end_of_box_run_p)
2308 it->pixel_width += thick;
2309 }
2310
2311 /* If face has an overline, add the height of the overline
2312 (1 pixel) and a 1 pixel margin to the character height. */
2313 if (face->overline_p)
2314 it->ascent += 2;
2315
2316 take_vertical_position_into_account (it);
2317
2318 if (it->glyph_row)
2319 x_append_composite_glyph (it);
2320 }
06a2c219
GM
2321 else if (it->what == IT_IMAGE)
2322 x_produce_image_glyph (it);
2323 else if (it->what == IT_STRETCH)
2324 x_produce_stretch_glyph (it);
2325
3017fdd1
GM
2326 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2327 because this isn't true for images with `:ascent 100'. */
2328 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2329 if (it->area == TEXT_AREA)
2330 it->current_x += it->pixel_width;
66ac4b0e 2331
d365f5bb
GM
2332 it->descent += it->extra_line_spacing;
2333
06a2c219
GM
2334 it->max_ascent = max (it->max_ascent, it->ascent);
2335 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2336 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2337 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2338}
2339
2340
2341/* Estimate the pixel height of the mode or top line on frame F.
2342 FACE_ID specifies what line's height to estimate. */
2343
2344int
2345x_estimate_mode_line_height (f, face_id)
2346 struct frame *f;
2347 enum face_id face_id;
2348{
43281ee3 2349 int height = FONT_HEIGHT (FRAME_FONT (f));
06a2c219
GM
2350
2351 /* This function is called so early when Emacs starts that the face
2352 cache and mode line face are not yet initialized. */
2353 if (FRAME_FACE_CACHE (f))
2354 {
2355 struct face *face = FACE_FROM_ID (f, face_id);
2356 if (face)
43281ee3
GM
2357 {
2358 if (face->font)
2359 height = FONT_HEIGHT (face->font);
ea2ba0d4
KH
2360 if (face->box_line_width > 0)
2361 height += 2 * face->box_line_width;
43281ee3 2362 }
06a2c219
GM
2363 }
2364
2365 return height;
2366}
2367
2368\f
2369/***********************************************************************
2370 Glyph display
2371 ***********************************************************************/
2372
2373/* A sequence of glyphs to be drawn in the same face.
2374
2375 This data structure is not really completely X specific, so it
2376 could possibly, at least partially, be useful for other systems. It
2377 is currently not part of the external redisplay interface because
2378 it's not clear what other systems will need. */
2379
2380struct glyph_string
2381{
2382 /* X-origin of the string. */
2383 int x;
2384
2385 /* Y-origin and y-position of the base line of this string. */
2386 int y, ybase;
2387
2388 /* The width of the string, not including a face extension. */
2389 int width;
2390
2391 /* The width of the string, including a face extension. */
2392 int background_width;
2393
2394 /* The height of this string. This is the height of the line this
2395 string is drawn in, and can be different from the height of the
2396 font the string is drawn in. */
2397 int height;
2398
2399 /* Number of pixels this string overwrites in front of its x-origin.
2400 This number is zero if the string has an lbearing >= 0; it is
2401 -lbearing, if the string has an lbearing < 0. */
2402 int left_overhang;
2403
2404 /* Number of pixels this string overwrites past its right-most
2405 nominal x-position, i.e. x + width. Zero if the string's
2406 rbearing is <= its nominal width, rbearing - width otherwise. */
2407 int right_overhang;
2408
2409 /* The frame on which the glyph string is drawn. */
2410 struct frame *f;
2411
2412 /* The window on which the glyph string is drawn. */
2413 struct window *w;
2414
2415 /* X display and window for convenience. */
2416 Display *display;
2417 Window window;
2418
2419 /* The glyph row for which this string was built. It determines the
2420 y-origin and height of the string. */
2421 struct glyph_row *row;
2422
2423 /* The area within row. */
2424 enum glyph_row_area area;
2425
2426 /* Characters to be drawn, and number of characters. */
2427 XChar2b *char2b;
2428 int nchars;
2429
06a2c219
GM
2430 /* A face-override for drawing cursors, mouse face and similar. */
2431 enum draw_glyphs_face hl;
2432
2433 /* Face in which this string is to be drawn. */
2434 struct face *face;
2435
2436 /* Font in which this string is to be drawn. */
2437 XFontStruct *font;
2438
2439 /* Font info for this string. */
2440 struct font_info *font_info;
2441
b4192550
KH
2442 /* Non-null means this string describes (part of) a composition.
2443 All characters from char2b are drawn composed. */
2444 struct composition *cmp;
06a2c219
GM
2445
2446 /* Index of this glyph string's first character in the glyph
b4192550
KH
2447 definition of CMP. If this is zero, this glyph string describes
2448 the first character of a composition. */
06a2c219
GM
2449 int gidx;
2450
2451 /* 1 means this glyph strings face has to be drawn to the right end
2452 of the window's drawing area. */
2453 unsigned extends_to_end_of_line_p : 1;
2454
2455 /* 1 means the background of this string has been drawn. */
2456 unsigned background_filled_p : 1;
2457
2458 /* 1 means glyph string must be drawn with 16-bit functions. */
2459 unsigned two_byte_p : 1;
2460
2461 /* 1 means that the original font determined for drawing this glyph
2462 string could not be loaded. The member `font' has been set to
2463 the frame's default font in this case. */
2464 unsigned font_not_found_p : 1;
2465
2466 /* 1 means that the face in which this glyph string is drawn has a
2467 stipple pattern. */
2468 unsigned stippled_p : 1;
2469
66ac4b0e
GM
2470 /* 1 means only the foreground of this glyph string must be drawn,
2471 and we should use the physical height of the line this glyph
2472 string appears in as clip rect. */
2473 unsigned for_overlaps_p : 1;
2474
06a2c219
GM
2475 /* The GC to use for drawing this glyph string. */
2476 GC gc;
2477
2478 /* A pointer to the first glyph in the string. This glyph
2479 corresponds to char2b[0]. Needed to draw rectangles if
2480 font_not_found_p is 1. */
2481 struct glyph *first_glyph;
2482
2483 /* Image, if any. */
2484 struct image *img;
2485
2486 struct glyph_string *next, *prev;
2487};
2488
2489
61869b99 2490#if GLYPH_DEBUG
06a2c219
GM
2491
2492static void
2493x_dump_glyph_string (s)
2494 struct glyph_string *s;
2495{
2496 fprintf (stderr, "glyph string\n");
2497 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2498 s->x, s->y, s->width, s->height);
2499 fprintf (stderr, " ybase = %d\n", s->ybase);
2500 fprintf (stderr, " hl = %d\n", s->hl);
2501 fprintf (stderr, " left overhang = %d, right = %d\n",
2502 s->left_overhang, s->right_overhang);
2503 fprintf (stderr, " nchars = %d\n", s->nchars);
2504 fprintf (stderr, " extends to end of line = %d\n",
2505 s->extends_to_end_of_line_p);
2506 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2507 fprintf (stderr, " bg width = %d\n", s->background_width);
2508}
2509
2510#endif /* GLYPH_DEBUG */
2511
2512
2513
2514static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2515 struct glyph_string **,
2516 struct glyph_string *,
2517 struct glyph_string *));
2518static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2519 struct glyph_string **,
2520 struct glyph_string *,
2521 struct glyph_string *));
2522static void x_append_glyph_string P_ ((struct glyph_string **,
2523 struct glyph_string **,
2524 struct glyph_string *));
2525static int x_left_overwritten P_ ((struct glyph_string *));
2526static int x_left_overwriting P_ ((struct glyph_string *));
2527static int x_right_overwritten P_ ((struct glyph_string *));
2528static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2529static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2530 int));
06a2c219
GM
2531static void x_init_glyph_string P_ ((struct glyph_string *,
2532 XChar2b *, struct window *,
2533 struct glyph_row *,
2534 enum glyph_row_area, int,
2535 enum draw_glyphs_face));
2536static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2537 enum glyph_row_area, int, int,
66ac4b0e 2538 enum draw_glyphs_face, int *, int *, int));
06a2c219
GM
2539static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2540static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2541static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2542 int));
2543static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2544static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2545static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2546static void x_draw_glyph_string P_ ((struct glyph_string *));
2547static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2548static void x_set_cursor_gc P_ ((struct glyph_string *));
2549static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2550static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2551static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2552 int *, int *));
2553static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2554static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2555 unsigned long *, double, int));
06a2c219 2556static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2557 double, int, unsigned long));
06a2c219
GM
2558static void x_setup_relief_colors P_ ((struct glyph_string *));
2559static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2560static void x_draw_image_relief P_ ((struct glyph_string *));
2561static void x_draw_image_foreground P_ ((struct glyph_string *));
2562static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2563static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2564static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2565 int, int, int));
2566static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2567 int, int, int, int, XRectangle *));
2568static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2569 int, int, int, XRectangle *));
66ac4b0e
GM
2570static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2571 enum glyph_row_area));
209f68d9
GM
2572static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2573 struct glyph_row *,
2574 enum glyph_row_area, int, int));
06a2c219 2575
163dcff3
GM
2576#if GLYPH_DEBUG
2577static void x_check_font P_ ((struct frame *, XFontStruct *));
2578#endif
2579
06a2c219 2580
06a2c219
GM
2581/* Append the list of glyph strings with head H and tail T to the list
2582 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2583
2584static INLINE void
2585x_append_glyph_string_lists (head, tail, h, t)
2586 struct glyph_string **head, **tail;
2587 struct glyph_string *h, *t;
2588{
2589 if (h)
2590 {
2591 if (*head)
2592 (*tail)->next = h;
2593 else
2594 *head = h;
2595 h->prev = *tail;
2596 *tail = t;
2597 }
2598}
2599
2600
2601/* Prepend the list of glyph strings with head H and tail T to the
2602 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2603 result. */
2604
2605static INLINE void
2606x_prepend_glyph_string_lists (head, tail, h, t)
2607 struct glyph_string **head, **tail;
2608 struct glyph_string *h, *t;
2609{
2610 if (h)
2611 {
2612 if (*head)
2613 (*head)->prev = t;
2614 else
2615 *tail = t;
2616 t->next = *head;
2617 *head = h;
2618 }
2619}
2620
2621
2622/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2623 Set *HEAD and *TAIL to the resulting list. */
2624
2625static INLINE void
2626x_append_glyph_string (head, tail, s)
2627 struct glyph_string **head, **tail;
2628 struct glyph_string *s;
2629{
2630 s->next = s->prev = NULL;
2631 x_append_glyph_string_lists (head, tail, s, s);
2632}
2633
2634
2635/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2636 face. */
2637
2638static void
2639x_set_cursor_gc (s)
2640 struct glyph_string *s;
2641{
2642 if (s->font == FRAME_FONT (s->f)
2643 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2644 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2645 && !s->cmp)
06a2c219
GM
2646 s->gc = s->f->output_data.x->cursor_gc;
2647 else
2648 {
2649 /* Cursor on non-default face: must merge. */
2650 XGCValues xgcv;
2651 unsigned long mask;
2652
2653 xgcv.background = s->f->output_data.x->cursor_pixel;
2654 xgcv.foreground = s->face->background;
2655
2656 /* If the glyph would be invisible, try a different foreground. */
2657 if (xgcv.foreground == xgcv.background)
2658 xgcv.foreground = s->face->foreground;
2659 if (xgcv.foreground == xgcv.background)
2660 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2661 if (xgcv.foreground == xgcv.background)
2662 xgcv.foreground = s->face->foreground;
2663
2664 /* Make sure the cursor is distinct from text in this face. */
2665 if (xgcv.background == s->face->background
2666 && xgcv.foreground == s->face->foreground)
2667 {
2668 xgcv.background = s->face->foreground;
2669 xgcv.foreground = s->face->background;
2670 }
2671
2672 IF_DEBUG (x_check_font (s->f, s->font));
2673 xgcv.font = s->font->fid;
2674 xgcv.graphics_exposures = False;
2675 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2676
2677 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2678 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2679 mask, &xgcv);
2680 else
2681 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2682 = XCreateGC (s->display, s->window, mask, &xgcv);
2683
2684 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2685 }
2686}
2687
2688
2689/* Set up S->gc of glyph string S for drawing text in mouse face. */
2690
2691static void
2692x_set_mouse_face_gc (s)
2693 struct glyph_string *s;
2694{
2695 int face_id;
ee569018 2696 struct face *face;
06a2c219 2697
e4ded23c 2698 /* What face has to be used last for the mouse face? */
06a2c219 2699 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2700 face = FACE_FROM_ID (s->f, face_id);
e4ded23c
GM
2701 if (face == NULL)
2702 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2703
033e3e18
GM
2704 if (s->first_glyph->type == CHAR_GLYPH)
2705 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2706 else
2707 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2708 s->face = FACE_FROM_ID (s->f, face_id);
2709 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2710
2711 /* If font in this face is same as S->font, use it. */
2712 if (s->font == s->face->font)
2713 s->gc = s->face->gc;
2714 else
2715 {
2716 /* Otherwise construct scratch_cursor_gc with values from FACE
2717 but font FONT. */
2718 XGCValues xgcv;
2719 unsigned long mask;
2720
2721 xgcv.background = s->face->background;
2722 xgcv.foreground = s->face->foreground;
2723 IF_DEBUG (x_check_font (s->f, s->font));
2724 xgcv.font = s->font->fid;
2725 xgcv.graphics_exposures = False;
2726 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2727
2728 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2729 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2730 mask, &xgcv);
2731 else
2732 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2733 = XCreateGC (s->display, s->window, mask, &xgcv);
2734
2735 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2736 }
2737
2738 xassert (s->gc != 0);
2739}
2740
2741
2742/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2743 Faces to use in the mode line have already been computed when the
2744 matrix was built, so there isn't much to do, here. */
2745
2746static INLINE void
2747x_set_mode_line_face_gc (s)
2748 struct glyph_string *s;
2749{
2750 s->gc = s->face->gc;
06a2c219
GM
2751}
2752
2753
2754/* Set S->gc of glyph string S for drawing that glyph string. Set
2755 S->stippled_p to a non-zero value if the face of S has a stipple
2756 pattern. */
2757
2758static INLINE void
2759x_set_glyph_string_gc (s)
2760 struct glyph_string *s;
2761{
209f68d9
GM
2762 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2763
06a2c219
GM
2764 if (s->hl == DRAW_NORMAL_TEXT)
2765 {
2766 s->gc = s->face->gc;
2767 s->stippled_p = s->face->stipple != 0;
2768 }
2769 else if (s->hl == DRAW_INVERSE_VIDEO)
2770 {
2771 x_set_mode_line_face_gc (s);
2772 s->stippled_p = s->face->stipple != 0;
2773 }
2774 else if (s->hl == DRAW_CURSOR)
2775 {
2776 x_set_cursor_gc (s);
2777 s->stippled_p = 0;
2778 }
2779 else if (s->hl == DRAW_MOUSE_FACE)
2780 {
2781 x_set_mouse_face_gc (s);
2782 s->stippled_p = s->face->stipple != 0;
2783 }
2784 else if (s->hl == DRAW_IMAGE_RAISED
2785 || s->hl == DRAW_IMAGE_SUNKEN)
2786 {
2787 s->gc = s->face->gc;
2788 s->stippled_p = s->face->stipple != 0;
2789 }
2790 else
2791 {
2792 s->gc = s->face->gc;
2793 s->stippled_p = s->face->stipple != 0;
2794 }
2795
2796 /* GC must have been set. */
2797 xassert (s->gc != 0);
2798}
2799
2800
2801/* Return in *R the clipping rectangle for glyph string S. */
2802
2803static void
2804x_get_glyph_string_clip_rect (s, r)
2805 struct glyph_string *s;
2806 XRectangle *r;
2807{
2808 if (s->row->full_width_p)
2809 {
2810 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2811 int canon_x = CANON_X_UNIT (s->f);
2812
2813 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2814 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2815
2816 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2817 {
1da3fd71 2818 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2819 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2820 r->x -= width;
2821 }
2822
b9432a85 2823 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2824
06a2c219
GM
2825 /* Unless displaying a mode or menu bar line, which are always
2826 fully visible, clip to the visible part of the row. */
2827 if (s->w->pseudo_window_p)
2828 r->height = s->row->visible_height;
2829 else
2830 r->height = s->height;
2831 }
2832 else
2833 {
2834 /* This is a text line that may be partially visible. */
2835 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2836 r->width = window_box_width (s->w, s->area);
2837 r->height = s->row->visible_height;
2838 }
2839
66ac4b0e
GM
2840 /* If S draws overlapping rows, it's sufficient to use the top and
2841 bottom of the window for clipping because this glyph string
2842 intentionally draws over other lines. */
2843 if (s->for_overlaps_p)
2844 {
045dee35 2845 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2846 r->height = window_text_bottom_y (s->w) - r->y;
2847 }
98b8a90f
GM
2848 else
2849 {
2850 /* Don't use S->y for clipping because it doesn't take partially
2851 visible lines into account. For example, it can be negative for
2852 partially visible lines at the top of a window. */
2853 if (!s->row->full_width_p
2854 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
2855 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
2856 else
2857 r->y = max (0, s->row->y);
2858
2859 /* If drawing a tool-bar window, draw it over the internal border
2860 at the top of the window. */
2861 if (s->w == XWINDOW (s->f->tool_bar_window))
2862 r->y -= s->f->output_data.x->internal_border_width;
2863 }
2864
66ac4b0e 2865 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2866}
2867
2868
2869/* Set clipping for output of glyph string S. S may be part of a mode
2870 line or menu if we don't have X toolkit support. */
2871
2872static INLINE void
2873x_set_glyph_string_clipping (s)
2874 struct glyph_string *s;
2875{
2876 XRectangle r;
2877 x_get_glyph_string_clip_rect (s, &r);
2878 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2879}
2880
2881
2882/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2883 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2884
2885static INLINE void
2886x_compute_glyph_string_overhangs (s)
2887 struct glyph_string *s;
2888{
b4192550 2889 if (s->cmp == NULL
06a2c219
GM
2890 && s->first_glyph->type == CHAR_GLYPH)
2891 {
2892 XCharStruct cs;
2893 int direction, font_ascent, font_descent;
2894 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2895 &font_ascent, &font_descent, &cs);
2896 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2897 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2898 }
2899}
2900
2901
2902/* Compute overhangs and x-positions for glyph string S and its
2903 predecessors, or successors. X is the starting x-position for S.
2904 BACKWARD_P non-zero means process predecessors. */
2905
2906static void
2907x_compute_overhangs_and_x (s, x, backward_p)
2908 struct glyph_string *s;
2909 int x;
2910 int backward_p;
2911{
2912 if (backward_p)
2913 {
2914 while (s)
2915 {
2916 x_compute_glyph_string_overhangs (s);
2917 x -= s->width;
2918 s->x = x;
2919 s = s->prev;
2920 }
2921 }
2922 else
2923 {
2924 while (s)
2925 {
2926 x_compute_glyph_string_overhangs (s);
2927 s->x = x;
2928 x += s->width;
2929 s = s->next;
2930 }
2931 }
2932}
2933
2934
2935/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2936 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2937 assumed to be zero. */
06a2c219
GM
2938
2939static void
2940x_get_glyph_overhangs (glyph, f, left, right)
2941 struct glyph *glyph;
2942 struct frame *f;
2943 int *left, *right;
2944{
06a2c219
GM
2945 *left = *right = 0;
2946
b4192550 2947 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2948 {
2949 XFontStruct *font;
2950 struct face *face;
2951 struct font_info *font_info;
2952 XChar2b char2b;
ee569018
KH
2953 XCharStruct *pcm;
2954
2955 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2956 font = face->font;
2957 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2958 if (font
2959 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2960 {
06a2c219
GM
2961 if (pcm->rbearing > pcm->width)
2962 *right = pcm->rbearing - pcm->width;
2963 if (pcm->lbearing < 0)
2964 *left = -pcm->lbearing;
2965 }
2966 }
2967}
2968
2969
2970/* Return the index of the first glyph preceding glyph string S that
2971 is overwritten by S because of S's left overhang. Value is -1
2972 if no glyphs are overwritten. */
2973
2974static int
2975x_left_overwritten (s)
2976 struct glyph_string *s;
2977{
2978 int k;
2979
2980 if (s->left_overhang)
2981 {
2982 int x = 0, i;
2983 struct glyph *glyphs = s->row->glyphs[s->area];
2984 int first = s->first_glyph - glyphs;
2985
2986 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2987 x -= glyphs[i].pixel_width;
2988
2989 k = i + 1;
2990 }
2991 else
2992 k = -1;
2993
2994 return k;
2995}
2996
2997
2998/* Return the index of the first glyph preceding glyph string S that
2999 is overwriting S because of its right overhang. Value is -1 if no
3000 glyph in front of S overwrites S. */
3001
3002static int
3003x_left_overwriting (s)
3004 struct glyph_string *s;
3005{
3006 int i, k, x;
3007 struct glyph *glyphs = s->row->glyphs[s->area];
3008 int first = s->first_glyph - glyphs;
3009
3010 k = -1;
3011 x = 0;
3012 for (i = first - 1; i >= 0; --i)
3013 {
3014 int left, right;
3015 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3016 if (x + right > 0)
3017 k = i;
3018 x -= glyphs[i].pixel_width;
3019 }
3020
3021 return k;
3022}
3023
3024
3025/* Return the index of the last glyph following glyph string S that is
3026 not overwritten by S because of S's right overhang. Value is -1 if
3027 no such glyph is found. */
3028
3029static int
3030x_right_overwritten (s)
3031 struct glyph_string *s;
3032{
3033 int k = -1;
3034
3035 if (s->right_overhang)
3036 {
3037 int x = 0, i;
3038 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3039 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3040 int end = s->row->used[s->area];
3041
3042 for (i = first; i < end && s->right_overhang > x; ++i)
3043 x += glyphs[i].pixel_width;
3044
3045 k = i;
3046 }
3047
3048 return k;
3049}
3050
3051
3052/* Return the index of the last glyph following glyph string S that
3053 overwrites S because of its left overhang. Value is negative
3054 if no such glyph is found. */
3055
3056static int
3057x_right_overwriting (s)
3058 struct glyph_string *s;
3059{
3060 int i, k, x;
3061 int end = s->row->used[s->area];
3062 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3063 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3064
3065 k = -1;
3066 x = 0;
3067 for (i = first; i < end; ++i)
3068 {
3069 int left, right;
3070 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3071 if (x - left < 0)
3072 k = i;
3073 x += glyphs[i].pixel_width;
3074 }
3075
3076 return k;
3077}
3078
3079
3080/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3081
3082static INLINE void
3083x_clear_glyph_string_rect (s, x, y, w, h)
3084 struct glyph_string *s;
3085 int x, y, w, h;
3086{
3087 XGCValues xgcv;
3088 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3089 XSetForeground (s->display, s->gc, xgcv.background);
3090 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3091 XSetForeground (s->display, s->gc, xgcv.foreground);
3092}
3093
3094
3095/* Draw the background of glyph_string S. If S->background_filled_p
3096 is non-zero don't draw it. FORCE_P non-zero means draw the
3097 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3098 when a string preceding S draws into the background of S, or S
3099 contains the first component of a composition. */
06a2c219
GM
3100
3101static void
3102x_draw_glyph_string_background (s, force_p)
3103 struct glyph_string *s;
3104 int force_p;
3105{
3106 /* Nothing to do if background has already been drawn or if it
3107 shouldn't be drawn in the first place. */
3108 if (!s->background_filled_p)
3109 {
ea2ba0d4
KH
3110 int box_line_width = max (s->face->box_line_width, 0);
3111
b4192550 3112 if (s->stippled_p)
06a2c219
GM
3113 {
3114 /* Fill background with a stipple pattern. */
3115 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3116 XFillRectangle (s->display, s->window, s->gc, s->x,
ea2ba0d4 3117 s->y + box_line_width,
06a2c219 3118 s->background_width,
ea2ba0d4 3119 s->height - 2 * box_line_width);
06a2c219
GM
3120 XSetFillStyle (s->display, s->gc, FillSolid);
3121 s->background_filled_p = 1;
3122 }
ea2ba0d4 3123 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
06a2c219
GM
3124 || s->font_not_found_p
3125 || s->extends_to_end_of_line_p
06a2c219
GM
3126 || force_p)
3127 {
ea2ba0d4 3128 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
06a2c219 3129 s->background_width,
ea2ba0d4 3130 s->height - 2 * box_line_width);
06a2c219
GM
3131 s->background_filled_p = 1;
3132 }
3133 }
3134}
3135
3136
3137/* Draw the foreground of glyph string S. */
3138
3139static void
3140x_draw_glyph_string_foreground (s)
3141 struct glyph_string *s;
3142{
3143 int i, x;
3144
3145 /* If first glyph of S has a left box line, start drawing the text
3146 of S to the right of that box line. */
3147 if (s->face->box != FACE_NO_BOX
3148 && s->first_glyph->left_box_line_p)
ea2ba0d4 3149 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
3150 else
3151 x = s->x;
3152
b4192550
KH
3153 /* Draw characters of S as rectangles if S's font could not be
3154 loaded. */
3155 if (s->font_not_found_p)
06a2c219 3156 {
b4192550 3157 for (i = 0; i < s->nchars; ++i)
06a2c219 3158 {
b4192550
KH
3159 struct glyph *g = s->first_glyph + i;
3160 XDrawRectangle (s->display, s->window,
3161 s->gc, x, s->y, g->pixel_width - 1,
3162 s->height - 1);
3163 x += g->pixel_width;
06a2c219
GM
3164 }
3165 }
3166 else
3167 {
b4192550
KH
3168 char *char1b = (char *) s->char2b;
3169 int boff = s->font_info->baseline_offset;
06a2c219 3170
b4192550
KH
3171 if (s->font_info->vertical_centering)
3172 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3173
3174 /* If we can use 8-bit functions, condense S->char2b. */
3175 if (!s->two_byte_p)
3176 for (i = 0; i < s->nchars; ++i)
3177 char1b[i] = s->char2b[i].byte2;
3178
3179 /* Draw text with XDrawString if background has already been
3180 filled. Otherwise, use XDrawImageString. (Note that
3181 XDrawImageString is usually faster than XDrawString.) Always
3182 use XDrawImageString when drawing the cursor so that there is
3183 no chance that characters under a box cursor are invisible. */
3184 if (s->for_overlaps_p
3185 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3186 {
3187 /* Draw characters with 16-bit or 8-bit functions. */
3188 if (s->two_byte_p)
3189 XDrawString16 (s->display, s->window, s->gc, x,
3190 s->ybase - boff, s->char2b, s->nchars);
3191 else
3192 XDrawString (s->display, s->window, s->gc, x,
3193 s->ybase - boff, char1b, s->nchars);
3194 }
06a2c219
GM
3195 else
3196 {
b4192550
KH
3197 if (s->two_byte_p)
3198 XDrawImageString16 (s->display, s->window, s->gc, x,
3199 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3200 else
b4192550
KH
3201 XDrawImageString (s->display, s->window, s->gc, x,
3202 s->ybase - boff, char1b, s->nchars);
3203 }
3204 }
3205}
06a2c219 3206
b4192550 3207/* Draw the foreground of composite glyph string S. */
06a2c219 3208
b4192550
KH
3209static void
3210x_draw_composite_glyph_string_foreground (s)
3211 struct glyph_string *s;
3212{
3213 int i, x;
06a2c219 3214
b4192550
KH
3215 /* If first glyph of S has a left box line, start drawing the text
3216 of S to the right of that box line. */
3217 if (s->face->box != FACE_NO_BOX
3218 && s->first_glyph->left_box_line_p)
ea2ba0d4 3219 x = s->x + abs (s->face->box_line_width);
b4192550
KH
3220 else
3221 x = s->x;
06a2c219 3222
b4192550
KH
3223 /* S is a glyph string for a composition. S->gidx is the index of
3224 the first character drawn for glyphs of this composition.
3225 S->gidx == 0 means we are drawing the very first character of
3226 this composition. */
06a2c219 3227
b4192550
KH
3228 /* Draw a rectangle for the composition if the font for the very
3229 first character of the composition could not be loaded. */
3230 if (s->font_not_found_p)
3231 {
3232 if (s->gidx == 0)
3233 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3234 s->width - 1, s->height - 1);
3235 }
3236 else
3237 {
3238 for (i = 0; i < s->nchars; i++, ++s->gidx)
3239 XDrawString16 (s->display, s->window, s->gc,
3240 x + s->cmp->offsets[s->gidx * 2],
3241 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3242 s->char2b + i, 1);
06a2c219
GM
3243 }
3244}
3245
3246
80c32bcc
GM
3247#ifdef USE_X_TOOLKIT
3248
3e71d8f2 3249static struct frame *x_frame_of_widget P_ ((Widget));
651f03b6
GM
3250static Boolean cvt_string_to_pixel P_ ((Display *, XrmValue *, Cardinal *,
3251 XrmValue *, XrmValue *, XtPointer *));
3252static void cvt_pixel_dtor P_ ((XtAppContext, XrmValue *, XtPointer,
3253 XrmValue *, Cardinal *));
80c32bcc 3254
3e71d8f2
GM
3255
3256/* Return the frame on which widget WIDGET is used.. Abort if frame
3257 cannot be determined. */
3258
e851c833 3259static struct frame *
3e71d8f2 3260x_frame_of_widget (widget)
80c32bcc 3261 Widget widget;
80c32bcc 3262{
80c32bcc 3263 struct x_display_info *dpyinfo;
5c187dee 3264 Lisp_Object tail;
3e71d8f2
GM
3265 struct frame *f;
3266
80c32bcc
GM
3267 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3268
3269 /* Find the top-level shell of the widget. Note that this function
3270 can be called when the widget is not yet realized, so XtWindow
3271 (widget) == 0. That's the reason we can't simply use
3272 x_any_window_to_frame. */
3273 while (!XtIsTopLevelShell (widget))
3274 widget = XtParent (widget);
3275
3276 /* Look for a frame with that top-level widget. Allocate the color
3277 on that frame to get the right gamma correction value. */
3278 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3279 if (GC_FRAMEP (XCAR (tail))
3280 && (f = XFRAME (XCAR (tail)),
3281 (f->output_data.nothing != 1
3282 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3283 && f->output_data.x->widget == widget)
3e71d8f2 3284 return f;
80c32bcc
GM
3285
3286 abort ();
3287}
3288
3e71d8f2
GM
3289
3290/* Allocate the color COLOR->pixel on the screen and display of
3291 widget WIDGET in colormap CMAP. If an exact match cannot be
3292 allocated, try the nearest color available. Value is non-zero
3293 if successful. This is called from lwlib. */
3294
3295int
3296x_alloc_nearest_color_for_widget (widget, cmap, color)
3297 Widget widget;
3298 Colormap cmap;
3299 XColor *color;
3300{
3301 struct frame *f = x_frame_of_widget (widget);
3302 return x_alloc_nearest_color (f, cmap, color);
3303}
3304
3305
46d516e5
MB
3306/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3307 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3308 If this produces the same color as PIXEL, try a color where all RGB
3309 values have DELTA added. Return the allocated color in *PIXEL.
3310 DISPLAY is the X display, CMAP is the colormap to operate on.
3311 Value is non-zero if successful. */
3312
3313int
3314x_alloc_lighter_color_for_widget (widget, display, cmap, pixel, factor, delta)
3315 Widget widget;
3316 Display *display;
3317 Colormap cmap;
3318 unsigned long *pixel;
3319 double factor;
3320 int delta;
3321{
3322 struct frame *f = x_frame_of_widget (widget);
3323 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
3324}
3325
3326
651f03b6
GM
3327/* Structure specifying which arguments should be passed by Xt to
3328 cvt_string_to_pixel. We want the widget's screen and colormap. */
3329
3330static XtConvertArgRec cvt_string_to_pixel_args[] =
3331 {
3332 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.screen),
3333 sizeof (Screen *)},
3334 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.colormap),
3335 sizeof (Colormap)}
3336 };
3337
3338
3339/* The address of this variable is returned by
3340 cvt_string_to_pixel. */
3341
3342static Pixel cvt_string_to_pixel_value;
3343
3344
3345/* Convert a color name to a pixel color.
3346
3347 DPY is the display we are working on.
3348
3349 ARGS is an array of *NARGS XrmValue structures holding additional
3350 information about the widget for which the conversion takes place.
3351 The contents of this array are determined by the specification
3352 in cvt_string_to_pixel_args.
3353
3354 FROM is a pointer to an XrmValue which points to the color name to
3355 convert. TO is an XrmValue in which to return the pixel color.
3356
3357 CLOSURE_RET is a pointer to user-data, in which we record if
3358 we allocated the color or not.
3359
3360 Value is True if successful, False otherwise. */
3361
3362static Boolean
3363cvt_string_to_pixel (dpy, args, nargs, from, to, closure_ret)
3364 Display *dpy;
3365 XrmValue *args;
3366 Cardinal *nargs;
3367 XrmValue *from, *to;
3368 XtPointer *closure_ret;
3369{
3370 Screen *screen;
3371 Colormap cmap;
3372 Pixel pixel;
3373 String color_name;
3374 XColor color;
3375
3376 if (*nargs != 2)
3377 {
3378 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3379 "wrongParameters", "cvt_string_to_pixel",
3380 "XtToolkitError",
3381 "Screen and colormap args required", NULL, NULL);
3382 return False;
3383 }
3384
3385 screen = *(Screen **) args[0].addr;
3386 cmap = *(Colormap *) args[1].addr;
3387 color_name = (String) from->addr;
3388
3389 if (strcmp (color_name, XtDefaultBackground) == 0)
3390 {
3391 *closure_ret = (XtPointer) False;
3392 pixel = WhitePixelOfScreen (screen);
3393 }
3394 else if (strcmp (color_name, XtDefaultForeground) == 0)
3395 {
3396 *closure_ret = (XtPointer) False;
3397 pixel = BlackPixelOfScreen (screen);
3398 }
3399 else if (XParseColor (dpy, cmap, color_name, &color)
3400 && x_alloc_nearest_color_1 (dpy, cmap, &color))
3401 {
3402 pixel = color.pixel;
3403 *closure_ret = (XtPointer) True;
3404 }
3405 else
3406 {
3407 String params[1];
3408 Cardinal nparams = 1;
3409
3410 params[0] = color_name;
3411 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3412 "badValue", "cvt_string_to_pixel",
3413 "XtToolkitError", "Invalid color `%s'",
3414 params, &nparams);
3415 return False;
3416 }
3417
3418 if (to->addr != NULL)
3419 {
3420 if (to->size < sizeof (Pixel))
3421 {
3422 to->size = sizeof (Pixel);
3423 return False;
3424 }
3425
3426 *(Pixel *) to->addr = pixel;
3427 }
3428 else
3429 {
3430 cvt_string_to_pixel_value = pixel;
3431 to->addr = (XtPointer) &cvt_string_to_pixel_value;
3432 }
3433
3434 to->size = sizeof (Pixel);
3435 return True;
3436}
3437
3438
3439/* Free a pixel color which was previously allocated via
3440 cvt_string_to_pixel. This is registered as the destructor
3441 for this type of resource via XtSetTypeConverter.
3442
3443 APP is the application context in which we work.
3444
3445 TO is a pointer to an XrmValue holding the color to free.
3446 CLOSURE is the value we stored in CLOSURE_RET for this color
3447 in cvt_string_to_pixel.
3448
3449 ARGS and NARGS are like for cvt_string_to_pixel. */
3450
3451static void
3452cvt_pixel_dtor (app, to, closure, args, nargs)
3453 XtAppContext app;
3454 XrmValuePtr to;
3455 XtPointer closure;
3456 XrmValuePtr args;
3457 Cardinal *nargs;
3458{
3459 if (*nargs != 2)
3460 {
3461 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
3462 "XtToolkitError",
3463 "Screen and colormap arguments required",
3464 NULL, NULL);
3465 }
3466 else if (closure != NULL)
3467 {
3468 /* We did allocate the pixel, so free it. */
3469 Screen *screen = *(Screen **) args[0].addr;
3470 Colormap cmap = *(Colormap *) args[1].addr;
3471 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
97762eb7 3472 (Pixel *) to->addr, 1);
651f03b6
GM
3473 }
3474}
3475
3476
80c32bcc
GM
3477#endif /* USE_X_TOOLKIT */
3478
3479
f04e1297 3480/* Value is an array of XColor structures for the contents of the
651f03b6 3481 color map of display DPY. Set *NCELLS to the size of the array.
f04e1297
GM
3482 Note that this probably shouldn't be called for large color maps,
3483 say a 24-bit TrueColor map. */
3484
3485static const XColor *
651f03b6
GM
3486x_color_cells (dpy, ncells)
3487 Display *dpy;
f04e1297
GM
3488 int *ncells;
3489{
651f03b6 3490 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
f04e1297
GM
3491
3492 if (dpyinfo->color_cells == NULL)
3493 {
651f03b6 3494 Screen *screen = dpyinfo->screen;
f04e1297
GM
3495 int i;
3496
3497 dpyinfo->ncolor_cells
651f03b6 3498 = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
f04e1297
GM
3499 dpyinfo->color_cells
3500 = (XColor *) xmalloc (dpyinfo->ncolor_cells
3501 * sizeof *dpyinfo->color_cells);
3502
3503 for (i = 0; i < dpyinfo->ncolor_cells; ++i)
3504 dpyinfo->color_cells[i].pixel = i;
3505
651f03b6 3506 XQueryColors (dpy, dpyinfo->cmap,
f04e1297
GM
3507 dpyinfo->color_cells, dpyinfo->ncolor_cells);
3508 }
3509
3510 *ncells = dpyinfo->ncolor_cells;
3511 return dpyinfo->color_cells;
3512}
3513
3514
3515/* On frame F, translate pixel colors to RGB values for the NCOLORS
3516 colors in COLORS. Use cached information, if available. */
3517
3518void
3519x_query_colors (f, colors, ncolors)
3520 struct frame *f;
3521 XColor *colors;
3522 int ncolors;
3523{
3524 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3525
3526 if (dpyinfo->color_cells)
3527 {
3528 int i;
3529 for (i = 0; i < ncolors; ++i)
3530 {
3531 unsigned long pixel = colors[i].pixel;
3532 xassert (pixel < dpyinfo->ncolor_cells);
3533 xassert (dpyinfo->color_cells[pixel].pixel == pixel);
3534 colors[i] = dpyinfo->color_cells[pixel];
3535 }
3536 }
3537 else
3538 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
3539}
3540
3541
3542/* On frame F, translate pixel color to RGB values for the color in
3543 COLOR. Use cached information, if available. */
3544
3545void
3546x_query_color (f, color)
3547 struct frame *f;
3548 XColor *color;
3549{
3550 x_query_colors (f, color, 1);
3551}
3552
3553
651f03b6
GM
3554/* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
3555 exact match can't be allocated, try the nearest color available.
3556 Value is non-zero if successful. Set *COLOR to the color
3557 allocated. */
06a2c219 3558
651f03b6
GM
3559static int
3560x_alloc_nearest_color_1 (dpy, cmap, color)
3561 Display *dpy;
06a2c219
GM
3562 Colormap cmap;
3563 XColor *color;
3564{
80c32bcc
GM
3565 int rc;
3566
651f03b6 3567 rc = XAllocColor (dpy, cmap, color);
06a2c219
GM
3568 if (rc == 0)
3569 {
3570 /* If we got to this point, the colormap is full, so we're going
3571 to try to get the next closest color. The algorithm used is
3572 a least-squares matching, which is what X uses for closest
3573 color matching with StaticColor visuals. */
3574 int nearest, i;
3575 unsigned long nearest_delta = ~0;
f04e1297 3576 int ncells;
651f03b6 3577 const XColor *cells = x_color_cells (dpy, &ncells);
06a2c219
GM
3578
3579 for (nearest = i = 0; i < ncells; ++i)
3580 {
3581 long dred = (color->red >> 8) - (cells[i].red >> 8);
3582 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3583 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3584 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3585
3586 if (delta < nearest_delta)
3587 {
3588 nearest = i;
3589 nearest_delta = delta;
3590 }
3591 }
3592
3593 color->red = cells[nearest].red;
3594 color->green = cells[nearest].green;
3595 color->blue = cells[nearest].blue;
651f03b6 3596 rc = XAllocColor (dpy, cmap, color);
06a2c219 3597 }
35efe0a1
GM
3598 else
3599 {
3600 /* If allocation succeeded, and the allocated pixel color is not
3601 equal to a cached pixel color recorded earlier, there was a
3602 change in the colormap, so clear the color cache. */
651f03b6 3603 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
35efe0a1
GM
3604 XColor *cached_color;
3605
3606 if (dpyinfo->color_cells
3607 && (cached_color = &dpyinfo->color_cells[color->pixel],
cae71efe
GM
3608 (cached_color->red != color->red
3609 || cached_color->blue != color->blue
3610 || cached_color->green != color->green)))
35efe0a1
GM
3611 {
3612 xfree (dpyinfo->color_cells);
3613 dpyinfo->color_cells = NULL;
3614 dpyinfo->ncolor_cells = 0;
3615 }
3616 }
06a2c219 3617
d9c545da
GM
3618#ifdef DEBUG_X_COLORS
3619 if (rc)
3620 register_color (color->pixel);
3621#endif /* DEBUG_X_COLORS */
3622
06a2c219
GM
3623 return rc;
3624}
3625
3626
651f03b6
GM
3627/* Allocate the color COLOR->pixel on frame F, colormap CMAP. If an
3628 exact match can't be allocated, try the nearest color available.
3629 Value is non-zero if successful. Set *COLOR to the color
3630 allocated. */
3631
3632int
3633x_alloc_nearest_color (f, cmap, color)
3634 struct frame *f;
3635 Colormap cmap;
3636 XColor *color;
3637{
3638 gamma_correct (f, color);
3639 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
3640}
3641
3642
d9c545da
GM
3643/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3644 It's necessary to do this instead of just using PIXEL directly to
3645 get color reference counts right. */
3646
3647unsigned long
3648x_copy_color (f, pixel)
3649 struct frame *f;
3650 unsigned long pixel;
3651{
3652 XColor color;
3653
3654 color.pixel = pixel;
3655 BLOCK_INPUT;
f04e1297 3656 x_query_color (f, &color);
d9c545da
GM
3657 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3658 UNBLOCK_INPUT;
3659#ifdef DEBUG_X_COLORS
3660 register_color (pixel);
3661#endif
3662 return color.pixel;
3663}
3664
3665
3e71d8f2
GM
3666/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3667 It's necessary to do this instead of just using PIXEL directly to
3668 get color reference counts right. */
3669
3670unsigned long
3671x_copy_dpy_color (dpy, cmap, pixel)
3672 Display *dpy;
3673 Colormap cmap;
3674 unsigned long pixel;
3675{
3676 XColor color;
3677
3678 color.pixel = pixel;
3679 BLOCK_INPUT;
3680 XQueryColor (dpy, cmap, &color);
3681 XAllocColor (dpy, cmap, &color);
3682 UNBLOCK_INPUT;
3683#ifdef DEBUG_X_COLORS
3684 register_color (pixel);
3685#endif
3686 return color.pixel;
3687}
3688
3689
6d8b0acd 3690/* Brightness beyond which a color won't have its highlight brightness
d7361edf 3691 boosted.
6d8b0acd 3692
d7361edf
MB
3693 Nominally, highlight colors for `3d' faces are calculated by
3694 brightening an object's color by a constant scale factor, but this
3695 doesn't yield good results for dark colors, so for colors who's
3696 brightness is less than this value (on a scale of 0-65535) have an
3697 use an additional additive factor.
6d8b0acd
MB
3698
3699 The value here is set so that the default menu-bar/mode-line color
3700 (grey75) will not have its highlights changed at all. */
3701#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
3702
3703
06a2c219
GM
3704/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3705 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3706 If this produces the same color as PIXEL, try a color where all RGB
3707 values have DELTA added. Return the allocated color in *PIXEL.
3708 DISPLAY is the X display, CMAP is the colormap to operate on.
3709 Value is non-zero if successful. */
3710
3711static int
3712x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3713 struct frame *f;
3714 Display *display;
3715 Colormap cmap;
3716 unsigned long *pixel;
68c45bf0 3717 double factor;
06a2c219
GM
3718 int delta;
3719{
3720 XColor color, new;
6d8b0acd 3721 long bright;
06a2c219
GM
3722 int success_p;
3723
3724 /* Get RGB color values. */
3725 color.pixel = *pixel;
f04e1297 3726 x_query_color (f, &color);
06a2c219
GM
3727
3728 /* Change RGB values by specified FACTOR. Avoid overflow! */
3729 xassert (factor >= 0);
3730 new.red = min (0xffff, factor * color.red);
3731 new.green = min (0xffff, factor * color.green);
3732 new.blue = min (0xffff, factor * color.blue);
3733
d7361edf
MB
3734 /* Calculate brightness of COLOR. */
3735 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
6d8b0acd
MB
3736
3737 /* We only boost colors that are darker than
3738 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3739 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3740 /* Make an additive adjustment to NEW, because it's dark enough so
3741 that scaling by FACTOR alone isn't enough. */
3742 {
3743 /* How far below the limit this color is (0 - 1, 1 being darker). */
3744 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3745 /* The additive adjustment. */
d7361edf 3746 int min_delta = delta * dimness * factor / 2;
6d8b0acd
MB
3747
3748 if (factor < 1)
3749 {
6d8b0acd
MB
3750 new.red = max (0, new.red - min_delta);
3751 new.green = max (0, new.green - min_delta);
3752 new.blue = max (0, new.blue - min_delta);
3753 }
3754 else
3755 {
3756 new.red = min (0xffff, min_delta + new.red);
3757 new.green = min (0xffff, min_delta + new.green);
3758 new.blue = min (0xffff, min_delta + new.blue);
3759 }
3760 }
3761
06a2c219 3762 /* Try to allocate the color. */
80c32bcc 3763 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3764 if (success_p)
3765 {
3766 if (new.pixel == *pixel)
3767 {
3768 /* If we end up with the same color as before, try adding
3769 delta to the RGB values. */
0d605c67 3770 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3771
3772 new.red = min (0xffff, delta + color.red);
3773 new.green = min (0xffff, delta + color.green);
3774 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3775 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3776 }
3777 else
3778 success_p = 1;
3779 *pixel = new.pixel;
3780 }
3781
3782 return success_p;
3783}
3784
3785
3786/* Set up the foreground color for drawing relief lines of glyph
3787 string S. RELIEF is a pointer to a struct relief containing the GC
3788 with which lines will be drawn. Use a color that is FACTOR or
3789 DELTA lighter or darker than the relief's background which is found
3790 in S->f->output_data.x->relief_background. If such a color cannot
3791 be allocated, use DEFAULT_PIXEL, instead. */
3792
3793static void
3794x_setup_relief_color (f, relief, factor, delta, default_pixel)
3795 struct frame *f;
3796 struct relief *relief;
68c45bf0 3797 double factor;
06a2c219
GM
3798 int delta;
3799 unsigned long default_pixel;
3800{
3801 XGCValues xgcv;
3802 struct x_output *di = f->output_data.x;
3803 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3804 unsigned long pixel;
3805 unsigned long background = di->relief_background;
43bd1b2b 3806 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3807 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3808 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3809
3810 xgcv.graphics_exposures = False;
3811 xgcv.line_width = 1;
3812
3813 /* Free previously allocated color. The color cell will be reused
3814 when it has been freed as many times as it was allocated, so this
3815 doesn't affect faces using the same colors. */
3816 if (relief->gc
3817 && relief->allocated_p)
3818 {
0d605c67 3819 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3820 relief->allocated_p = 0;
3821 }
3822
3823 /* Allocate new color. */
3824 xgcv.foreground = default_pixel;
3825 pixel = background;
dcd08bfb
GM
3826 if (dpyinfo->n_planes != 1
3827 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3828 {
3829 relief->allocated_p = 1;
3830 xgcv.foreground = relief->pixel = pixel;
3831 }
3832
3833 if (relief->gc == 0)
3834 {
dcd08bfb 3835 xgcv.stipple = dpyinfo->gray;
06a2c219 3836 mask |= GCStipple;
dcd08bfb 3837 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3838 }
3839 else
dcd08bfb 3840 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3841}
3842
3843
3844/* Set up colors for the relief lines around glyph string S. */
3845
3846static void
3847x_setup_relief_colors (s)
3848 struct glyph_string *s;
3849{
3850 struct x_output *di = s->f->output_data.x;
3851 unsigned long color;
3852
3853 if (s->face->use_box_color_for_shadows_p)
3854 color = s->face->box_color;
3855 else
3856 {
3857 XGCValues xgcv;
3858
3859 /* Get the background color of the face. */
3860 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3861 color = xgcv.background;
3862 }
3863
3864 if (di->white_relief.gc == 0
3865 || color != di->relief_background)
3866 {
3867 di->relief_background = color;
3868 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3869 WHITE_PIX_DEFAULT (s->f));
3870 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3871 BLACK_PIX_DEFAULT (s->f));
3872 }
3873}
3874
3875
3876/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3877 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3878 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3879 relief. LEFT_P non-zero means draw a relief on the left side of
3880 the rectangle. RIGHT_P non-zero means draw a relief on the right
3881 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3882 when drawing. */
3883
3884static void
3885x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3886 raised_p, left_p, right_p, clip_rect)
3887 struct frame *f;
3888 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3889 XRectangle *clip_rect;
3890{
de507556
GM
3891 Display *dpy = FRAME_X_DISPLAY (f);
3892 Window window = FRAME_X_WINDOW (f);
06a2c219
GM
3893 int i;
3894 GC gc;
3895
3896 if (raised_p)
3897 gc = f->output_data.x->white_relief.gc;
3898 else
3899 gc = f->output_data.x->black_relief.gc;
de507556 3900 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3901
3902 /* Top. */
3903 for (i = 0; i < width; ++i)
de507556 3904 XDrawLine (dpy, window, gc,
06a2c219
GM
3905 left_x + i * left_p, top_y + i,
3906 right_x + 1 - i * right_p, top_y + i);
3907
3908 /* Left. */
3909 if (left_p)
3910 for (i = 0; i < width; ++i)
de507556 3911 XDrawLine (dpy, window, gc,
44655e77 3912 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
06a2c219 3913
de507556 3914 XSetClipMask (dpy, gc, None);
06a2c219
GM
3915 if (raised_p)
3916 gc = f->output_data.x->black_relief.gc;
3917 else
3918 gc = f->output_data.x->white_relief.gc;
de507556 3919 XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
06a2c219
GM
3920
3921 /* Bottom. */
3922 for (i = 0; i < width; ++i)
de507556
GM
3923 XDrawLine (dpy, window, gc,
3924 left_x + i * left_p, bottom_y - i,
3925 right_x + 2 - i * right_p, bottom_y - i);
06a2c219
GM
3926
3927 /* Right. */
3928 if (right_p)
3929 for (i = 0; i < width; ++i)
de507556 3930 XDrawLine (dpy, window, gc,
06a2c219
GM
3931 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3932
de507556 3933 XSetClipMask (dpy, gc, None);
06a2c219
GM
3934}
3935
3936
3937/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3938 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3939 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3940 left side of the rectangle. RIGHT_P non-zero means draw a line
3941 on the right side of the rectangle. CLIP_RECT is the clipping
3942 rectangle to use when drawing. */
3943
3944static void
3945x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3946 left_p, right_p, clip_rect)
3947 struct glyph_string *s;
3948 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3949 XRectangle *clip_rect;
3950{
3951 XGCValues xgcv;
3952
3953 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3954 XSetForeground (s->display, s->gc, s->face->box_color);
3955 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3956
3957 /* Top. */
3958 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3959 left_x, top_y, right_x - left_x + 1, width);
06a2c219
GM
3960
3961 /* Left. */
3962 if (left_p)
3963 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3964 left_x, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3965
3966 /* Bottom. */
3967 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3968 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
06a2c219
GM
3969
3970 /* Right. */
3971 if (right_p)
3972 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3973 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3974
3975 XSetForeground (s->display, s->gc, xgcv.foreground);
3976 XSetClipMask (s->display, s->gc, None);
3977}
3978
3979
3980/* Draw a box around glyph string S. */
3981
3982static void
3983x_draw_glyph_string_box (s)
3984 struct glyph_string *s;
3985{
3986 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3987 int left_p, right_p;
3988 struct glyph *last_glyph;
3989 XRectangle clip_rect;
3990
3991 last_x = window_box_right (s->w, s->area);
3992 if (s->row->full_width_p
3993 && !s->w->pseudo_window_p)
3994 {
110859fc 3995 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
06a2c219
GM
3996 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3997 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3998 }
3999
4000 /* The glyph that may have a right box line. */
b4192550 4001 last_glyph = (s->cmp || s->img
06a2c219
GM
4002 ? s->first_glyph
4003 : s->first_glyph + s->nchars - 1);
4004
ea2ba0d4 4005 width = abs (s->face->box_line_width);
06a2c219
GM
4006 raised_p = s->face->box == FACE_RAISED_BOX;
4007 left_x = s->x;
57ac7c81
GM
4008 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
4009 ? last_x - 1
4010 : min (last_x, s->x + s->background_width) - 1);
06a2c219
GM
4011 top_y = s->y;
4012 bottom_y = top_y + s->height - 1;
4013
4014 left_p = (s->first_glyph->left_box_line_p
4015 || (s->hl == DRAW_MOUSE_FACE
4016 && (s->prev == NULL
4017 || s->prev->hl != s->hl)));
4018 right_p = (last_glyph->right_box_line_p
4019 || (s->hl == DRAW_MOUSE_FACE
4020 && (s->next == NULL
4021 || s->next->hl != s->hl)));
4022
4023 x_get_glyph_string_clip_rect (s, &clip_rect);
4024
4025 if (s->face->box == FACE_SIMPLE_BOX)
4026 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4027 left_p, right_p, &clip_rect);
4028 else
4029 {
4030 x_setup_relief_colors (s);
4031 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
4032 width, raised_p, left_p, right_p, &clip_rect);
4033 }
4034}
4035
4036
4037/* Draw foreground of image glyph string S. */
4038
4039static void
4040x_draw_image_foreground (s)
4041 struct glyph_string *s;
4042{
4043 int x;
95af8492 4044 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4045
4046 /* If first glyph of S has a left box line, start drawing it to the
4047 right of that line. */
4048 if (s->face->box != FACE_NO_BOX
4049 && s->first_glyph->left_box_line_p)
ea2ba0d4 4050 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4051 else
4052 x = s->x;
4053
4054 /* If there is a margin around the image, adjust x- and y-position
4055 by that margin. */
22d650b8
GM
4056 x += s->img->hmargin;
4057 y += s->img->vmargin;
06a2c219
GM
4058
4059 if (s->img->pixmap)
4060 {
4061 if (s->img->mask)
4062 {
4063 /* We can't set both a clip mask and use XSetClipRectangles
4064 because the latter also sets a clip mask. We also can't
4065 trust on the shape extension to be available
4066 (XShapeCombineRegion). So, compute the rectangle to draw
4067 manually. */
4068 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4069 | GCFunction);
4070 XGCValues xgcv;
4071 XRectangle clip_rect, image_rect, r;
4072
4073 xgcv.clip_mask = s->img->mask;
4074 xgcv.clip_x_origin = x;
4075 xgcv.clip_y_origin = y;
4076 xgcv.function = GXcopy;
4077 XChangeGC (s->display, s->gc, mask, &xgcv);
4078
4079 x_get_glyph_string_clip_rect (s, &clip_rect);
4080 image_rect.x = x;
4081 image_rect.y = y;
4082 image_rect.width = s->img->width;
4083 image_rect.height = s->img->height;
4084 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4085 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4086 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
4087 }
4088 else
4089 {
49ad1d99
GM
4090 unsigned long mask = GCClipXOrigin | GCClipYOrigin | GCFunction;
4091 XGCValues xgcv;
4092 XRectangle clip_rect, image_rect, r;
4093
4094 x_get_glyph_string_clip_rect (s, &clip_rect);
4095 image_rect.x = x;
4096 image_rect.y = y;
4097 image_rect.width = s->img->width;
4098 image_rect.height = s->img->height;
4099 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4100 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4101 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
06a2c219
GM
4102
4103 /* When the image has a mask, we can expect that at
4104 least part of a mouse highlight or a block cursor will
4105 be visible. If the image doesn't have a mask, make
4106 a block cursor visible by drawing a rectangle around
4107 the image. I believe it's looking better if we do
4108 nothing here for mouse-face. */
4109 if (s->hl == DRAW_CURSOR)
4110 XDrawRectangle (s->display, s->window, s->gc, x, y,
4111 s->img->width - 1, s->img->height - 1);
4112 }
4113 }
4114 else
4115 /* Draw a rectangle if image could not be loaded. */
4116 XDrawRectangle (s->display, s->window, s->gc, x, y,
4117 s->img->width - 1, s->img->height - 1);
4118}
4119
4120
4121/* Draw a relief around the image glyph string S. */
4122
4123static void
4124x_draw_image_relief (s)
4125 struct glyph_string *s;
4126{
4127 int x0, y0, x1, y1, thick, raised_p;
4128 XRectangle r;
4129 int x;
95af8492 4130 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4131
4132 /* If first glyph of S has a left box line, start drawing it to the
4133 right of that line. */
4134 if (s->face->box != FACE_NO_BOX
4135 && s->first_glyph->left_box_line_p)
ea2ba0d4 4136 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4137 else
4138 x = s->x;
4139
4140 /* If there is a margin around the image, adjust x- and y-position
4141 by that margin. */
22d650b8
GM
4142 x += s->img->hmargin;
4143 y += s->img->vmargin;
06a2c219
GM
4144
4145 if (s->hl == DRAW_IMAGE_SUNKEN
4146 || s->hl == DRAW_IMAGE_RAISED)
4147 {
9ea173e8 4148 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
06a2c219
GM
4149 raised_p = s->hl == DRAW_IMAGE_RAISED;
4150 }
4151 else
4152 {
4153 thick = abs (s->img->relief);
4154 raised_p = s->img->relief > 0;
4155 }
4156
4157 x0 = x - thick;
4158 y0 = y - thick;
4159 x1 = x + s->img->width + thick - 1;
4160 y1 = y + s->img->height + thick - 1;
4161
4162 x_setup_relief_colors (s);
4163 x_get_glyph_string_clip_rect (s, &r);
4164 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
4165}
4166
4167
4168/* Draw the foreground of image glyph string S to PIXMAP. */
4169
4170static void
4171x_draw_image_foreground_1 (s, pixmap)
4172 struct glyph_string *s;
4173 Pixmap pixmap;
4174{
4175 int x;
95af8492 4176 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
4177
4178 /* If first glyph of S has a left box line, start drawing it to the
4179 right of that line. */
4180 if (s->face->box != FACE_NO_BOX
4181 && s->first_glyph->left_box_line_p)
ea2ba0d4 4182 x = abs (s->face->box_line_width);
06a2c219
GM
4183 else
4184 x = 0;
4185
4186 /* If there is a margin around the image, adjust x- and y-position
4187 by that margin. */
22d650b8
GM
4188 x += s->img->hmargin;
4189 y += s->img->vmargin;
dc43ef94 4190
06a2c219
GM
4191 if (s->img->pixmap)
4192 {
4193 if (s->img->mask)
4194 {
4195 /* We can't set both a clip mask and use XSetClipRectangles
4196 because the latter also sets a clip mask. We also can't
4197 trust on the shape extension to be available
4198 (XShapeCombineRegion). So, compute the rectangle to draw
4199 manually. */
4200 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4201 | GCFunction);
4202 XGCValues xgcv;
4203
4204 xgcv.clip_mask = s->img->mask;
4205 xgcv.clip_x_origin = x;
4206 xgcv.clip_y_origin = y;
4207 xgcv.function = GXcopy;
4208 XChangeGC (s->display, s->gc, mask, &xgcv);
4209
4210 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4211 0, 0, s->img->width, s->img->height, x, y);
4212 XSetClipMask (s->display, s->gc, None);
4213 }
4214 else
4215 {
4216 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4217 0, 0, s->img->width, s->img->height, x, y);
4218
4219 /* When the image has a mask, we can expect that at
4220 least part of a mouse highlight or a block cursor will
4221 be visible. If the image doesn't have a mask, make
4222 a block cursor visible by drawing a rectangle around
4223 the image. I believe it's looking better if we do
4224 nothing here for mouse-face. */
4225 if (s->hl == DRAW_CURSOR)
4226 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4227 s->img->width - 1, s->img->height - 1);
4228 }
4229 }
4230 else
4231 /* Draw a rectangle if image could not be loaded. */
4232 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4233 s->img->width - 1, s->img->height - 1);
4234}
dc43ef94 4235
990ba854 4236
06a2c219
GM
4237/* Draw part of the background of glyph string S. X, Y, W, and H
4238 give the rectangle to draw. */
a9a5b0a5 4239
06a2c219
GM
4240static void
4241x_draw_glyph_string_bg_rect (s, x, y, w, h)
4242 struct glyph_string *s;
4243 int x, y, w, h;
4244{
4245 if (s->stippled_p)
4246 {
4247 /* Fill background with a stipple pattern. */
4248 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4249 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4250 XSetFillStyle (s->display, s->gc, FillSolid);
4251 }
4252 else
4253 x_clear_glyph_string_rect (s, x, y, w, h);
4254}
07e34cb0 4255
b5210ea7 4256
06a2c219 4257/* Draw image glyph string S.
dc43ef94 4258
06a2c219
GM
4259 s->y
4260 s->x +-------------------------
4261 | s->face->box
4262 |
4263 | +-------------------------
4264 | | s->img->margin
4265 | |
4266 | | +-------------------
4267 | | | the image
dc43ef94 4268
06a2c219 4269 */
dc43ef94 4270
06a2c219
GM
4271static void
4272x_draw_image_glyph_string (s)
4273 struct glyph_string *s;
4274{
4275 int x, y;
ea2ba0d4
KH
4276 int box_line_hwidth = abs (s->face->box_line_width);
4277 int box_line_vwidth = max (s->face->box_line_width, 0);
06a2c219
GM
4278 int height;
4279 Pixmap pixmap = None;
4280
ea2ba0d4 4281 height = s->height - 2 * box_line_vwidth;
06a2c219
GM
4282
4283 /* Fill background with face under the image. Do it only if row is
4284 taller than image or if image has a clip mask to reduce
4285 flickering. */
4286 s->stippled_p = s->face->stipple != 0;
4287 if (height > s->img->height
22d650b8
GM
4288 || s->img->hmargin
4289 || s->img->vmargin
06a2c219
GM
4290 || s->img->mask
4291 || s->img->pixmap == 0
4292 || s->width != s->background_width)
4293 {
ea2ba0d4
KH
4294 if (box_line_hwidth && s->first_glyph->left_box_line_p)
4295 x = s->x + box_line_hwidth;
06a2c219
GM
4296 else
4297 x = s->x;
4298
ea2ba0d4 4299 y = s->y + box_line_vwidth;
06a2c219
GM
4300
4301 if (s->img->mask)
4302 {
f9b5db02
GM
4303 /* Create a pixmap as large as the glyph string. Fill it
4304 with the background color. Copy the image to it, using
4305 its mask. Copy the temporary pixmap to the display. */
06a2c219
GM
4306 Screen *screen = FRAME_X_SCREEN (s->f);
4307 int depth = DefaultDepthOfScreen (screen);
4308
4309 /* Create a pixmap as large as the glyph string. */
4310 pixmap = XCreatePixmap (s->display, s->window,
4311 s->background_width,
4312 s->height, depth);
4313
4314 /* Don't clip in the following because we're working on the
4315 pixmap. */
4316 XSetClipMask (s->display, s->gc, None);
4317
4318 /* Fill the pixmap with the background color/stipple. */
4319 if (s->stippled_p)
4320 {
4321 /* Fill background with a stipple pattern. */
4322 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4323 XFillRectangle (s->display, pixmap, s->gc,
4324 0, 0, s->background_width, s->height);
4325 XSetFillStyle (s->display, s->gc, FillSolid);
4326 }
4327 else
4328 {
4329 XGCValues xgcv;
4330 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4331 &xgcv);
4332 XSetForeground (s->display, s->gc, xgcv.background);
4333 XFillRectangle (s->display, pixmap, s->gc,
4334 0, 0, s->background_width, s->height);
4335 XSetForeground (s->display, s->gc, xgcv.foreground);
4336 }
4337 }
4338 else
06a2c219
GM
4339 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
4340
4341 s->background_filled_p = 1;
4342 }
dc43ef94 4343
06a2c219
GM
4344 /* Draw the foreground. */
4345 if (pixmap != None)
4346 {
4347 x_draw_image_foreground_1 (s, pixmap);
4348 x_set_glyph_string_clipping (s);
4349 XCopyArea (s->display, pixmap, s->window, s->gc,
4350 0, 0, s->background_width, s->height, s->x, s->y);
4351 XFreePixmap (s->display, pixmap);
4352 }
4353 else
4354 x_draw_image_foreground (s);
b5210ea7 4355
06a2c219
GM
4356 /* If we must draw a relief around the image, do it. */
4357 if (s->img->relief
4358 || s->hl == DRAW_IMAGE_RAISED
4359 || s->hl == DRAW_IMAGE_SUNKEN)
4360 x_draw_image_relief (s);
4361}
8c1a6a84 4362
990ba854 4363
06a2c219 4364/* Draw stretch glyph string S. */
dc43ef94 4365
06a2c219
GM
4366static void
4367x_draw_stretch_glyph_string (s)
4368 struct glyph_string *s;
4369{
4370 xassert (s->first_glyph->type == STRETCH_GLYPH);
4371 s->stippled_p = s->face->stipple != 0;
990ba854 4372
06a2c219
GM
4373 if (s->hl == DRAW_CURSOR
4374 && !x_stretch_cursor_p)
4375 {
4376 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4377 as wide as the stretch glyph. */
4378 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4379
06a2c219
GM
4380 /* Draw cursor. */
4381 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4382
06a2c219
GM
4383 /* Clear rest using the GC of the original non-cursor face. */
4384 if (width < s->background_width)
4385 {
06a2c219
GM
4386 int x = s->x + width, y = s->y;
4387 int w = s->background_width - width, h = s->height;
4388 XRectangle r;
b7f83f9e 4389 GC gc;
dc43ef94 4390
b7f83f9e
GM
4391 if (s->row->mouse_face_p
4392 && cursor_in_mouse_face_p (s->w))
4393 {
4394 x_set_mouse_face_gc (s);
4395 gc = s->gc;
4396 }
4397 else
4398 gc = s->face->gc;
4399
06a2c219
GM
4400 x_get_glyph_string_clip_rect (s, &r);
4401 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
b7f83f9e 4402
06a2c219
GM
4403 if (s->face->stipple)
4404 {
4405 /* Fill background with a stipple pattern. */
4406 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4407 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4408 XSetFillStyle (s->display, gc, FillSolid);
4409 }
4410 else
4411 {
4412 XGCValues xgcv;
4413 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4414 XSetForeground (s->display, gc, xgcv.background);
4415 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4416 XSetForeground (s->display, gc, xgcv.foreground);
4417 }
4418 }
4419 }
61e9f9f3 4420 else if (!s->background_filled_p)
06a2c219
GM
4421 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4422 s->height);
4423
4424 s->background_filled_p = 1;
4425}
4426
4427
4428/* Draw glyph string S. */
4429
4430static void
4431x_draw_glyph_string (s)
4432 struct glyph_string *s;
4433{
4458cf11
KH
4434 int relief_drawn_p = 0;
4435
06a2c219
GM
4436 /* If S draws into the background of its successor, draw the
4437 background of the successor first so that S can draw into it.
4438 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4439 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4440 {
4441 xassert (s->next->img == NULL);
4442 x_set_glyph_string_gc (s->next);
4443 x_set_glyph_string_clipping (s->next);
4444 x_draw_glyph_string_background (s->next, 1);
4445 }
97210f4e 4446
06a2c219
GM
4447 /* Set up S->gc, set clipping and draw S. */
4448 x_set_glyph_string_gc (s);
4449 x_set_glyph_string_clipping (s);
4450
4458cf11
KH
4451 /* Draw relief (if any) in advance for char/composition so that the
4452 glyph string can be drawn over it. */
4453 if (!s->for_overlaps_p
4454 && s->face->box != FACE_NO_BOX
4455 && (s->first_glyph->type == CHAR_GLYPH
4456 || s->first_glyph->type == COMPOSITE_GLYPH))
4457
4458 {
4459 x_draw_glyph_string_background (s, 1);
4460 x_draw_glyph_string_box (s);
4461 relief_drawn_p = 1;
4462 }
4463
06a2c219
GM
4464 switch (s->first_glyph->type)
4465 {
4466 case IMAGE_GLYPH:
4467 x_draw_image_glyph_string (s);
4468 break;
4469
4470 case STRETCH_GLYPH:
4471 x_draw_stretch_glyph_string (s);
4472 break;
4473
4474 case CHAR_GLYPH:
66ac4b0e
GM
4475 if (s->for_overlaps_p)
4476 s->background_filled_p = 1;
4477 else
4478 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4479 x_draw_glyph_string_foreground (s);
4480 break;
4481
b4192550
KH
4482 case COMPOSITE_GLYPH:
4483 if (s->for_overlaps_p || s->gidx > 0)
4484 s->background_filled_p = 1;
4485 else
4486 x_draw_glyph_string_background (s, 1);
4487 x_draw_composite_glyph_string_foreground (s);
4488 break;
4489
06a2c219
GM
4490 default:
4491 abort ();
4492 }
4493
66ac4b0e 4494 if (!s->for_overlaps_p)
06a2c219 4495 {
66ac4b0e
GM
4496 /* Draw underline. */
4497 if (s->face->underline_p)
4498 {
e24e84cc
GM
4499 unsigned long tem, h;
4500 int y;
06a2c219 4501
e24e84cc 4502 /* Get the underline thickness. Default is 1 pixel. */
66ac4b0e
GM
4503 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4504 h = 1;
e24e84cc
GM
4505
4506 /* Get the underline position. This is the recommended
4507 vertical offset in pixels from the baseline to the top of
4508 the underline. This is a signed value according to the
4509 specs, and its default is
4510
4511 ROUND ((maximum descent) / 2), with
4512 ROUND(x) = floor (x + 0.5) */
4513
a72d5ce5
GM
4514 if (x_use_underline_position_properties
4515 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
e24e84cc
GM
4516 y = s->ybase + (long) tem;
4517 else if (s->face->font)
4518 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4519 else
a02f1be0 4520 y = s->y + s->height - h;
06a2c219 4521
66ac4b0e 4522 if (s->face->underline_defaulted_p)
e24e84cc
GM
4523 XFillRectangle (s->display, s->window, s->gc,
4524 s->x, y, s->width, h);
66ac4b0e
GM
4525 else
4526 {
4527 XGCValues xgcv;
4528 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4529 XSetForeground (s->display, s->gc, s->face->underline_color);
e24e84cc
GM
4530 XFillRectangle (s->display, s->window, s->gc,
4531 s->x, y, s->width, h);
66ac4b0e
GM
4532 XSetForeground (s->display, s->gc, xgcv.foreground);
4533 }
dc6f92b8 4534 }
07e34cb0 4535
66ac4b0e
GM
4536 /* Draw overline. */
4537 if (s->face->overline_p)
06a2c219 4538 {
66ac4b0e
GM
4539 unsigned long dy = 0, h = 1;
4540
4541 if (s->face->overline_color_defaulted_p)
4542 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4543 s->width, h);
4544 else
4545 {
4546 XGCValues xgcv;
4547 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4548 XSetForeground (s->display, s->gc, s->face->overline_color);
4549 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4550 s->width, h);
4551 XSetForeground (s->display, s->gc, xgcv.foreground);
4552 }
06a2c219 4553 }
06a2c219 4554
66ac4b0e
GM
4555 /* Draw strike-through. */
4556 if (s->face->strike_through_p)
06a2c219 4557 {
66ac4b0e
GM
4558 unsigned long h = 1;
4559 unsigned long dy = (s->height - h) / 2;
4560
4561 if (s->face->strike_through_color_defaulted_p)
4562 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4563 s->width, h);
4564 else
4565 {
4566 XGCValues xgcv;
4567 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4568 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4569 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4570 s->width, h);
4571 XSetForeground (s->display, s->gc, xgcv.foreground);
4572 }
06a2c219 4573 }
06a2c219 4574
4458cf11
KH
4575 /* Draw relief if not yet drawn. */
4576 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
66ac4b0e
GM
4577 x_draw_glyph_string_box (s);
4578 }
06a2c219
GM
4579
4580 /* Reset clipping. */
4581 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4582}
07e34cb0 4583
06a2c219 4584
b4192550
KH
4585static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4586 struct face **, int));
06a2c219 4587
06a2c219 4588
209f68d9
GM
4589/* Fill glyph string S with composition components specified by S->cmp.
4590
b4192550
KH
4591 FACES is an array of faces for all components of this composition.
4592 S->gidx is the index of the first component for S.
4593 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4594 use its physical height for clipping.
06a2c219 4595
b4192550 4596 Value is the index of a component not in S. */
07e34cb0 4597
b4192550
KH
4598static int
4599x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4600 struct glyph_string *s;
b4192550 4601 struct face **faces;
66ac4b0e 4602 int overlaps_p;
07e34cb0 4603{
b4192550 4604 int i;
06a2c219 4605
b4192550 4606 xassert (s);
06a2c219 4607
b4192550 4608 s->for_overlaps_p = overlaps_p;
06a2c219 4609
b4192550
KH
4610 s->face = faces[s->gidx];
4611 s->font = s->face->font;
4612 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4613
b4192550
KH
4614 /* For all glyphs of this composition, starting at the offset
4615 S->gidx, until we reach the end of the definition or encounter a
4616 glyph that requires the different face, add it to S. */
4617 ++s->nchars;
4618 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4619 ++s->nchars;
06a2c219 4620
b4192550
KH
4621 /* All glyph strings for the same composition has the same width,
4622 i.e. the width set for the first component of the composition. */
06a2c219 4623
06a2c219
GM
4624 s->width = s->first_glyph->pixel_width;
4625
4626 /* If the specified font could not be loaded, use the frame's
4627 default font, but record the fact that we couldn't load it in
4628 the glyph string so that we can draw rectangles for the
4629 characters of the glyph string. */
4630 if (s->font == NULL)
4631 {
4632 s->font_not_found_p = 1;
4633 s->font = FRAME_FONT (s->f);
4634 }
4635
4636 /* Adjust base line for subscript/superscript text. */
4637 s->ybase += s->first_glyph->voffset;
4638
4639 xassert (s->face && s->face->gc);
4640
4641 /* This glyph string must always be drawn with 16-bit functions. */
4642 s->two_byte_p = 1;
b4192550
KH
4643
4644 return s->gidx + s->nchars;
06a2c219
GM
4645}
4646
4647
209f68d9
GM
4648/* Fill glyph string S from a sequence of character glyphs.
4649
06a2c219 4650 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4651 first glyph to consider, END is the index of the last + 1.
4652 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4653 use its physical height for clipping.
66ac4b0e
GM
4654
4655 Value is the index of the first glyph not in S. */
06a2c219
GM
4656
4657static int
66ac4b0e 4658x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4659 struct glyph_string *s;
4660 int face_id;
66ac4b0e 4661 int start, end, overlaps_p;
06a2c219
GM
4662{
4663 struct glyph *glyph, *last;
4664 int voffset;
ee569018 4665 int glyph_not_available_p;
06a2c219 4666
06a2c219
GM
4667 xassert (s->f == XFRAME (s->w->frame));
4668 xassert (s->nchars == 0);
4669 xassert (start >= 0 && end > start);
4670
66ac4b0e 4671 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4672 glyph = s->row->glyphs[s->area] + start;
4673 last = s->row->glyphs[s->area] + end;
4674 voffset = glyph->voffset;
4675
ee569018
KH
4676 glyph_not_available_p = glyph->glyph_not_available_p;
4677
06a2c219
GM
4678 while (glyph < last
4679 && glyph->type == CHAR_GLYPH
4680 && glyph->voffset == voffset
ee569018
KH
4681 /* Same face id implies same font, nowadays. */
4682 && glyph->face_id == face_id
4683 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4684 {
ee569018
KH
4685 int two_byte_p;
4686
06a2c219 4687 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4688 s->char2b + s->nchars,
4689 &two_byte_p);
4690 s->two_byte_p = two_byte_p;
06a2c219
GM
4691 ++s->nchars;
4692 xassert (s->nchars <= end - start);
4693 s->width += glyph->pixel_width;
4694 ++glyph;
4695 }
4696
4697 s->font = s->face->font;
4698 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4699
4700 /* If the specified font could not be loaded, use the frame's font,
4701 but record the fact that we couldn't load it in
4702 S->font_not_found_p so that we can draw rectangles for the
4703 characters of the glyph string. */
ee569018 4704 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4705 {
4706 s->font_not_found_p = 1;
4707 s->font = FRAME_FONT (s->f);
4708 }
4709
4710 /* Adjust base line for subscript/superscript text. */
4711 s->ybase += voffset;
66ac4b0e 4712
06a2c219
GM
4713 xassert (s->face && s->face->gc);
4714 return glyph - s->row->glyphs[s->area];
07e34cb0 4715}
dc6f92b8 4716
06a2c219
GM
4717
4718/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4719
dfcf069d 4720static void
06a2c219
GM
4721x_fill_image_glyph_string (s)
4722 struct glyph_string *s;
4723{
4724 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4725 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4726 xassert (s->img);
43d120d8 4727 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4728 s->font = s->face->font;
4729 s->width = s->first_glyph->pixel_width;
4730
4731 /* Adjust base line for subscript/superscript text. */
4732 s->ybase += s->first_glyph->voffset;
4733}
4734
4735
209f68d9 4736/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4737
209f68d9
GM
4738 ROW is the glyph row in which the glyphs are found, AREA is the
4739 area within the row. START is the index of the first glyph to
4740 consider, END is the index of the last + 1.
4741
4742 Value is the index of the first glyph not in S. */
4743
4744static int
4745x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4746 struct glyph_string *s;
209f68d9
GM
4747 struct glyph_row *row;
4748 enum glyph_row_area area;
4749 int start, end;
06a2c219 4750{
209f68d9
GM
4751 struct glyph *glyph, *last;
4752 int voffset, face_id;
4753
06a2c219 4754 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4755
4756 glyph = s->row->glyphs[s->area] + start;
4757 last = s->row->glyphs[s->area] + end;
4758 face_id = glyph->face_id;
4759 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4760 s->font = s->face->font;
209f68d9
GM
4761 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4762 s->width = glyph->pixel_width;
4763 voffset = glyph->voffset;
4764
4765 for (++glyph;
4766 (glyph < last
4767 && glyph->type == STRETCH_GLYPH
4768 && glyph->voffset == voffset
4769 && glyph->face_id == face_id);
4770 ++glyph)
4771 s->width += glyph->pixel_width;
06a2c219
GM
4772
4773 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4774 s->ybase += voffset;
4775
c296fc01
GM
4776 /* The case that face->gc == 0 is handled when drawing the glyph
4777 string by calling PREPARE_FACE_FOR_DISPLAY. */
4778 xassert (s->face);
209f68d9 4779 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4780}
4781
4782
4783/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4784 of XChar2b structures for S; it can't be allocated in
4785 x_init_glyph_string because it must be allocated via `alloca'. W
4786 is the window on which S is drawn. ROW and AREA are the glyph row
4787 and area within the row from which S is constructed. START is the
4788 index of the first glyph structure covered by S. HL is a
4789 face-override for drawing S. */
4790
4791static void
4792x_init_glyph_string (s, char2b, w, row, area, start, hl)
4793 struct glyph_string *s;
4794 XChar2b *char2b;
4795 struct window *w;
4796 struct glyph_row *row;
4797 enum glyph_row_area area;
4798 int start;
4799 enum draw_glyphs_face hl;
4800{
4801 bzero (s, sizeof *s);
4802 s->w = w;
4803 s->f = XFRAME (w->frame);
4804 s->display = FRAME_X_DISPLAY (s->f);
4805 s->window = FRAME_X_WINDOW (s->f);
4806 s->char2b = char2b;
4807 s->hl = hl;
4808 s->row = row;
4809 s->area = area;
4810 s->first_glyph = row->glyphs[area] + start;
4811 s->height = row->height;
4812 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4813
9ea173e8
GM
4814 /* Display the internal border below the tool-bar window. */
4815 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4816 s->y -= s->f->output_data.x->internal_border_width;
4817
4818 s->ybase = s->y + row->ascent;
4819}
4820
4821
4822/* Set background width of glyph string S. START is the index of the
4823 first glyph following S. LAST_X is the right-most x-position + 1
4824 in the drawing area. */
4825
4826static INLINE void
4827x_set_glyph_string_background_width (s, start, last_x)
4828 struct glyph_string *s;
4829 int start;
4830 int last_x;
4831{
4832 /* If the face of this glyph string has to be drawn to the end of
4833 the drawing area, set S->extends_to_end_of_line_p. */
4834 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4835
4836 if (start == s->row->used[s->area]
eb79f5cc 4837 && s->area == TEXT_AREA
7b0870b2
GM
4838 && ((s->hl == DRAW_NORMAL_TEXT
4839 && (s->row->fill_line_p
4840 || s->face->background != default_face->background
4841 || s->face->stipple != default_face->stipple
4842 || s->row->mouse_face_p))
4843 || s->hl == DRAW_MOUSE_FACE))
4844 s->extends_to_end_of_line_p = 1;
06a2c219
GM
4845
4846 /* If S extends its face to the end of the line, set its
4847 background_width to the distance to the right edge of the drawing
4848 area. */
4849 if (s->extends_to_end_of_line_p)
1da3fd71 4850 s->background_width = last_x - s->x + 1;
06a2c219
GM
4851 else
4852 s->background_width = s->width;
4853}
4854
4855
4856/* Add a glyph string for a stretch glyph to the list of strings
4857 between HEAD and TAIL. START is the index of the stretch glyph in
4858 row area AREA of glyph row ROW. END is the index of the last glyph
4859 in that glyph row area. X is the current output position assigned
4860 to the new glyph string constructed. HL overrides that face of the
4861 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4862 is the right-most x-position of the drawing area. */
4863
8abee2e1
DL
4864/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
4865 and below -- keep them on one line. */
4866#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4867 do \
4868 { \
4869 s = (struct glyph_string *) alloca (sizeof *s); \
4870 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
209f68d9 4871 START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
06a2c219 4872 x_append_glyph_string (&HEAD, &TAIL, s); \
06a2c219
GM
4873 s->x = (X); \
4874 } \
4875 while (0)
4876
4877
4878/* Add a glyph string for an image glyph to the list of strings
4879 between HEAD and TAIL. START is the index of the image glyph in
4880 row area AREA of glyph row ROW. END is the index of the last glyph
4881 in that glyph row area. X is the current output position assigned
4882 to the new glyph string constructed. HL overrides that face of the
4883 glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
4884 is the right-most x-position of the drawing area. */
4885
8abee2e1 4886#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
06a2c219
GM
4887 do \
4888 { \
4889 s = (struct glyph_string *) alloca (sizeof *s); \
4890 x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
4891 x_fill_image_glyph_string (s); \
4892 x_append_glyph_string (&HEAD, &TAIL, s); \
4893 ++START; \
4894 s->x = (X); \
4895 } \
4896 while (0)
4897
4898
4899/* Add a glyph string for a sequence of character glyphs to the list
4900 of strings between HEAD and TAIL. START is the index of the first
4901 glyph in row area AREA of glyph row ROW that is part of the new
4902 glyph string. END is the index of the last glyph in that glyph row
4903 area. X is the current output position assigned to the new glyph
4904 string constructed. HL overrides that face of the glyph; e.g. it
4905 is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
4906 right-most x-position of the drawing area. */
4907
8abee2e1 4908#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4909 do \
4910 { \
3e71d8f2 4911 int c, face_id; \
06a2c219
GM
4912 XChar2b *char2b; \
4913 \
43d120d8 4914 c = (ROW)->glyphs[AREA][START].u.ch; \
43d120d8 4915 face_id = (ROW)->glyphs[AREA][START].face_id; \
06a2c219 4916 \
b4192550
KH
4917 s = (struct glyph_string *) alloca (sizeof *s); \
4918 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
4919 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
4920 x_append_glyph_string (&HEAD, &TAIL, s); \
b4192550
KH
4921 s->x = (X); \
4922 START = x_fill_glyph_string (s, face_id, START, END, \
66ac4b0e 4923 OVERLAPS_P); \
06a2c219
GM
4924 } \
4925 while (0)
4926
4927
b4192550
KH
4928/* Add a glyph string for a composite sequence to the list of strings
4929 between HEAD and TAIL. START is the index of the first glyph in
4930 row area AREA of glyph row ROW that is part of the new glyph
4931 string. END is the index of the last glyph in that glyph row area.
4932 X is the current output position assigned to the new glyph string
4933 constructed. HL overrides that face of the glyph; e.g. it is
4934 DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
4935 x-position of the drawing area. */
4936
6c27ec25 4937#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
b4192550 4938 do { \
43d120d8
KH
4939 int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
4940 int face_id = (ROW)->glyphs[AREA][START].face_id; \
ee569018 4941 struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
b4192550
KH
4942 struct composition *cmp = composition_table[cmp_id]; \
4943 int glyph_len = cmp->glyph_len; \
4944 XChar2b *char2b; \
4945 struct face **faces; \
4946 struct glyph_string *first_s = NULL; \
4947 int n; \
4948 \
ee569018 4949 base_face = base_face->ascii_face; \
b4192550
KH
4950 char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
4951 faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
4952 /* At first, fill in `char2b' and `faces'. */ \
4953 for (n = 0; n < glyph_len; n++) \
4954 { \
43d120d8 4955 int c = COMPOSITION_GLYPH (cmp, n); \
ee569018
KH
4956 int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
4957 faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
4958 x_get_char_face_and_encoding (XFRAME (w->frame), c, \
4959 this_face_id, char2b + n, 1); \
b4192550
KH
4960 } \
4961 \
4962 /* Make glyph_strings for each glyph sequence that is drawable by \
4963 the same face, and append them to HEAD/TAIL. */ \
4964 for (n = 0; n < cmp->glyph_len;) \
4965 { \
4966 s = (struct glyph_string *) alloca (sizeof *s); \
4967 x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
4968 x_append_glyph_string (&(HEAD), &(TAIL), s); \
4969 s->cmp = cmp; \
4970 s->gidx = n; \
b4192550
KH
4971 s->x = (X); \
4972 \
4973 if (n == 0) \
4974 first_s = s; \
4975 \
4976 n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
4977 } \
4978 \
4979 ++START; \
4980 s = first_s; \
4981 } while (0)
4982
4983
06a2c219
GM
4984/* Build a list of glyph strings between HEAD and TAIL for the glyphs
4985 of AREA of glyph row ROW on window W between indices START and END.
4986 HL overrides the face for drawing glyph strings, e.g. it is
4987 DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
4988 x-positions of the drawing area.
4989
4990 This is an ugly monster macro construct because we must use alloca
4991 to allocate glyph strings (because x_draw_glyphs can be called
4992 asynchronously). */
4993
8abee2e1 4994#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
06a2c219
GM
4995 do \
4996 { \
4997 HEAD = TAIL = NULL; \
4998 while (START < END) \
4999 { \
5000 struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
5001 switch (first_glyph->type) \
5002 { \
5003 case CHAR_GLYPH: \
5004 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
66ac4b0e
GM
5005 TAIL, HL, X, LAST_X, \
5006 OVERLAPS_P); \
06a2c219
GM
5007 break; \
5008 \
b4192550
KH
5009 case COMPOSITE_GLYPH: \
5010 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
5011 HEAD, TAIL, HL, X, LAST_X,\
5012 OVERLAPS_P); \
5013 break; \
5014 \
06a2c219
GM
5015 case STRETCH_GLYPH: \
5016 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
5017 HEAD, TAIL, HL, X, LAST_X); \
5018 break; \
5019 \
5020 case IMAGE_GLYPH: \
5021 BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
5022 TAIL, HL, X, LAST_X); \
5023 break; \
5024 \
5025 default: \
5026 abort (); \
5027 } \
5028 \
5029 x_set_glyph_string_background_width (s, START, LAST_X); \
5030 (X) += s->width; \
5031 } \
5032 } \
5033 while (0)
5034
5035
5036/* Draw glyphs between START and END in AREA of ROW on window W,
5037 starting at x-position X. X is relative to AREA in W. HL is a
5038 face-override with the following meaning:
5039
5040 DRAW_NORMAL_TEXT draw normally
5041 DRAW_CURSOR draw in cursor face
5042 DRAW_MOUSE_FACE draw in mouse face.
5043 DRAW_INVERSE_VIDEO draw in mode line face
5044 DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
5045 DRAW_IMAGE_RAISED draw an image with a raised relief around it
5046
5047 If REAL_START is non-null, return in *REAL_START the real starting
5048 position for display. This can be different from START in case
5049 overlapping glyphs must be displayed. If REAL_END is non-null,
5050 return in *REAL_END the real end position for display. This can be
5051 different from END in case overlapping glyphs must be displayed.
5052
66ac4b0e
GM
5053 If OVERLAPS_P is non-zero, draw only the foreground of characters
5054 and clip to the physical height of ROW.
5055
06a2c219
GM
5056 Value is the x-position reached, relative to AREA of W. */
5057
5058static int
66ac4b0e
GM
5059x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end,
5060 overlaps_p)
06a2c219
GM
5061 struct window *w;
5062 int x;
5063 struct glyph_row *row;
5064 enum glyph_row_area area;
5065 int start, end;
5066 enum draw_glyphs_face hl;
5067 int *real_start, *real_end;
66ac4b0e 5068 int overlaps_p;
dc6f92b8 5069{
06a2c219
GM
5070 struct glyph_string *head, *tail;
5071 struct glyph_string *s;
5072 int last_x, area_width;
5073 int x_reached;
5074 int i, j;
5075
5076 /* Let's rather be paranoid than getting a SEGV. */
06a2c219 5077 end = min (end, row->used[area]);
a8710abf
GM
5078 start = max (0, start);
5079 start = min (end, start);
06a2c219
GM
5080 if (real_start)
5081 *real_start = start;
5082 if (real_end)
5083 *real_end = end;
5084
5085 /* Translate X to frame coordinates. Set last_x to the right
5086 end of the drawing area. */
5087 if (row->full_width_p)
5088 {
5089 /* X is relative to the left edge of W, without scroll bars
5090 or flag areas. */
5091 struct frame *f = XFRAME (w->frame);
110859fc 5092 /* int width = FRAME_FLAGS_AREA_WIDTH (f); */
06a2c219 5093 int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
dc6f92b8 5094
06a2c219
GM
5095 x += window_left_x;
5096 area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
5097 last_x = window_left_x + area_width;
5098
5099 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
5100 {
110859fc 5101 int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
06a2c219
GM
5102 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
5103 last_x += width;
5104 else
5105 x -= width;
5106 }
dc6f92b8 5107
b9432a85 5108 x += FRAME_INTERNAL_BORDER_WIDTH (f);
98fedd97 5109 last_x += FRAME_INTERNAL_BORDER_WIDTH (f);
06a2c219
GM
5110 }
5111 else
dc6f92b8 5112 {
06a2c219
GM
5113 x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
5114 area_width = window_box_width (w, area);
5115 last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
dc6f92b8
JB
5116 }
5117
06a2c219
GM
5118 /* Build a doubly-linked list of glyph_string structures between
5119 head and tail from what we have to draw. Note that the macro
5120 BUILD_GLYPH_STRINGS will modify its start parameter. That's
5121 the reason we use a separate variable `i'. */
5122 i = start;
66ac4b0e
GM
5123 BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
5124 overlaps_p);
06a2c219
GM
5125 if (tail)
5126 x_reached = tail->x + tail->background_width;
5127 else
5128 x_reached = x;
90e65f07 5129
06a2c219
GM
5130 /* If there are any glyphs with lbearing < 0 or rbearing > width in
5131 the row, redraw some glyphs in front or following the glyph
5132 strings built above. */
a8710abf 5133 if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
06a2c219
GM
5134 {
5135 int dummy_x = 0;
5136 struct glyph_string *h, *t;
5137
5138 /* Compute overhangs for all glyph strings. */
5139 for (s = head; s; s = s->next)
5140 x_compute_glyph_string_overhangs (s);
5141
5142 /* Prepend glyph strings for glyphs in front of the first glyph
5143 string that are overwritten because of the first glyph
5144 string's left overhang. The background of all strings
5145 prepended must be drawn because the first glyph string
5146 draws over it. */
5147 i = x_left_overwritten (head);
5148 if (i >= 0)
5149 {
5150 j = i;
5151 BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
66ac4b0e
GM
5152 DRAW_NORMAL_TEXT, dummy_x, last_x,
5153 overlaps_p);
06a2c219
GM
5154 start = i;
5155 if (real_start)
5156 *real_start = start;
5157 x_compute_overhangs_and_x (t, head->x, 1);
5158 x_prepend_glyph_string_lists (&head, &tail, h, t);
5159 }
58769bee 5160
06a2c219
GM
5161 /* Prepend glyph strings for glyphs in front of the first glyph
5162 string that overwrite that glyph string because of their
5163 right overhang. For these strings, only the foreground must
5164 be drawn, because it draws over the glyph string at `head'.
5165 The background must not be drawn because this would overwrite
5166 right overhangs of preceding glyphs for which no glyph
5167 strings exist. */
5168 i = x_left_overwriting (head);
5169 if (i >= 0)
5170 {
5171 BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
66ac4b0e
GM
5172 DRAW_NORMAL_TEXT, dummy_x, last_x,
5173 overlaps_p);
06a2c219
GM
5174 for (s = h; s; s = s->next)
5175 s->background_filled_p = 1;
5176 if (real_start)
5177 *real_start = i;
5178 x_compute_overhangs_and_x (t, head->x, 1);
5179 x_prepend_glyph_string_lists (&head, &tail, h, t);
5180 }
dbcb258a 5181
06a2c219
GM
5182 /* Append glyphs strings for glyphs following the last glyph
5183 string tail that are overwritten by tail. The background of
5184 these strings has to be drawn because tail's foreground draws
5185 over it. */
5186 i = x_right_overwritten (tail);
5187 if (i >= 0)
5188 {
5189 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5190 DRAW_NORMAL_TEXT, x, last_x,
5191 overlaps_p);
06a2c219
GM
5192 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5193 x_append_glyph_string_lists (&head, &tail, h, t);
5194 if (real_end)
5195 *real_end = i;
5196 }
dc6f92b8 5197
06a2c219
GM
5198 /* Append glyph strings for glyphs following the last glyph
5199 string tail that overwrite tail. The foreground of such
5200 glyphs has to be drawn because it writes into the background
5201 of tail. The background must not be drawn because it could
5202 paint over the foreground of following glyphs. */
5203 i = x_right_overwriting (tail);
5204 if (i >= 0)
5205 {
5206 BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
66ac4b0e
GM
5207 DRAW_NORMAL_TEXT, x, last_x,
5208 overlaps_p);
06a2c219
GM
5209 for (s = h; s; s = s->next)
5210 s->background_filled_p = 1;
5211 x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
5212 x_append_glyph_string_lists (&head, &tail, h, t);
5213 if (real_end)
5214 *real_end = i;
5215 }
5216 }
58769bee 5217
06a2c219
GM
5218 /* Draw all strings. */
5219 for (s = head; s; s = s->next)
5220 x_draw_glyph_string (s);
dc6f92b8 5221
06a2c219
GM
5222 /* Value is the x-position up to which drawn, relative to AREA of W.
5223 This doesn't include parts drawn because of overhangs. */
5224 x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
5225 if (!row->full_width_p)
5226 {
5227 if (area > LEFT_MARGIN_AREA)
5228 x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
5229 if (area > TEXT_AREA)
5230 x_reached -= window_box_width (w, TEXT_AREA);
5231 }
a8710abf 5232
06a2c219
GM
5233 return x_reached;
5234}
dc6f92b8 5235
dc6f92b8 5236
66ac4b0e
GM
5237/* Fix the display of area AREA of overlapping row ROW in window W. */
5238
5239static void
5240x_fix_overlapping_area (w, row, area)
5241 struct window *w;
5242 struct glyph_row *row;
5243 enum glyph_row_area area;
5244{
5245 int i, x;
5246
5247 BLOCK_INPUT;
5248
5249 if (area == LEFT_MARGIN_AREA)
5250 x = 0;
5251 else if (area == TEXT_AREA)
5252 x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5253 else
5254 x = (window_box_width (w, LEFT_MARGIN_AREA)
5255 + window_box_width (w, TEXT_AREA));
5256
5257 for (i = 0; i < row->used[area];)
5258 {
5259 if (row->glyphs[area][i].overlaps_vertically_p)
5260 {
5261 int start = i, start_x = x;
5262
5263 do
5264 {
5265 x += row->glyphs[area][i].pixel_width;
5266 ++i;
5267 }
5268 while (i < row->used[area]
5269 && row->glyphs[area][i].overlaps_vertically_p);
5270
5271 x_draw_glyphs (w, start_x, row, area, start, i,
5272 (row->inverse_p
5273 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
5274 NULL, NULL, 1);
5275 }
5276 else
5277 {
5278 x += row->glyphs[area][i].pixel_width;
5279 ++i;
5280 }
5281 }
5282
5283 UNBLOCK_INPUT;
5284}
5285
5286
06a2c219
GM
5287/* Output LEN glyphs starting at START at the nominal cursor position.
5288 Advance the nominal cursor over the text. The global variable
5289 updated_window contains the window being updated, updated_row is
5290 the glyph row being updated, and updated_area is the area of that
5291 row being updated. */
dc6f92b8 5292
06a2c219
GM
5293static void
5294x_write_glyphs (start, len)
5295 struct glyph *start;
5296 int len;
5297{
5298 int x, hpos, real_start, real_end;
d9cdbb3d 5299
06a2c219 5300 xassert (updated_window && updated_row);
dc6f92b8 5301 BLOCK_INPUT;
06a2c219
GM
5302
5303 /* Write glyphs. */
dc6f92b8 5304
06a2c219
GM
5305 hpos = start - updated_row->glyphs[updated_area];
5306 x = x_draw_glyphs (updated_window, output_cursor.x,
5307 updated_row, updated_area,
5308 hpos, hpos + len,
5309 (updated_row->inverse_p
5310 ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
66ac4b0e 5311 &real_start, &real_end, 0);
b30ec466 5312
06a2c219
GM
5313 /* If we drew over the cursor, note that it is not visible any more. */
5314 note_overwritten_text_cursor (updated_window, real_start,
5315 real_end - real_start);
dc6f92b8
JB
5316
5317 UNBLOCK_INPUT;
06a2c219
GM
5318
5319 /* Advance the output cursor. */
5320 output_cursor.hpos += len;
5321 output_cursor.x = x;
dc6f92b8
JB
5322}
5323
0cdd0c9f 5324
06a2c219 5325/* Insert LEN glyphs from START at the nominal cursor position. */
0cdd0c9f 5326
06a2c219
GM
5327static void
5328x_insert_glyphs (start, len)
5329 struct glyph *start;
5330 register int len;
5331{
5332 struct frame *f;
5333 struct window *w;
5334 int line_height, shift_by_width, shifted_region_width;
5335 struct glyph_row *row;
5336 struct glyph *glyph;
5337 int frame_x, frame_y, hpos, real_start, real_end;
58769bee 5338
06a2c219 5339 xassert (updated_window && updated_row);
0cdd0c9f 5340 BLOCK_INPUT;
06a2c219
GM
5341 w = updated_window;
5342 f = XFRAME (WINDOW_FRAME (w));
5343
5344 /* Get the height of the line we are in. */
5345 row = updated_row;
5346 line_height = row->height;
5347
5348 /* Get the width of the glyphs to insert. */
5349 shift_by_width = 0;
5350 for (glyph = start; glyph < start + len; ++glyph)
5351 shift_by_width += glyph->pixel_width;
5352
5353 /* Get the width of the region to shift right. */
5354 shifted_region_width = (window_box_width (w, updated_area)
5355 - output_cursor.x
5356 - shift_by_width);
5357
5358 /* Shift right. */
bf0ab8a2 5359 frame_x = window_box_left (w, updated_area) + output_cursor.x;
06a2c219
GM
5360 frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
5361 XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5362 f->output_data.x->normal_gc,
5363 frame_x, frame_y,
5364 shifted_region_width, line_height,
5365 frame_x + shift_by_width, frame_y);
5366
5367 /* Write the glyphs. */
5368 hpos = start - row->glyphs[updated_area];
5369 x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
66ac4b0e 5370 DRAW_NORMAL_TEXT, &real_start, &real_end, 0);
06a2c219
GM
5371 note_overwritten_text_cursor (w, real_start, real_end - real_start);
5372
5373 /* Advance the output cursor. */
5374 output_cursor.hpos += len;
5375 output_cursor.x += shift_by_width;
0cdd0c9f
RS
5376 UNBLOCK_INPUT;
5377}
0cdd0c9f 5378
0cdd0c9f 5379
06a2c219
GM
5380/* Delete N glyphs at the nominal cursor position. Not implemented
5381 for X frames. */
c83febd7
RS
5382
5383static void
06a2c219
GM
5384x_delete_glyphs (n)
5385 register int n;
c83febd7 5386{
06a2c219 5387 abort ();
c83febd7
RS
5388}
5389
0cdd0c9f 5390
c5e6e06b
GM
5391/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
5392 If they are <= 0, this is probably an error. */
5393
5394void
5395x_clear_area (dpy, window, x, y, width, height, exposures)
5396 Display *dpy;
5397 Window window;
5398 int x, y;
5399 int width, height;
5400 int exposures;
5401{
5402 xassert (width > 0 && height > 0);
5403 XClearArea (dpy, window, x, y, width, height, exposures);
5404}
5405
5406
06a2c219
GM
5407/* Erase the current text line from the nominal cursor position
5408 (inclusive) to pixel column TO_X (exclusive). The idea is that
5409 everything from TO_X onward is already erased.
5410
5411 TO_X is a pixel position relative to updated_area of
5412 updated_window. TO_X == -1 means clear to the end of this area. */
dc6f92b8 5413
06a2c219
GM
5414static void
5415x_clear_end_of_line (to_x)
5416 int to_x;
5417{
5418 struct frame *f;
5419 struct window *w = updated_window;
5420 int max_x, min_y, max_y;
5421 int from_x, from_y, to_y;
5422
5423 xassert (updated_window && updated_row);
5424 f = XFRAME (w->frame);
5425
5426 if (updated_row->full_width_p)
5427 {
5428 max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
5429 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
5430 && !w->pseudo_window_p)
5431 max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
0cdd0c9f 5432 }
06a2c219
GM
5433 else
5434 max_x = window_box_width (w, updated_area);
5435 max_y = window_text_bottom_y (w);
dc6f92b8 5436
06a2c219
GM
5437 /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
5438 of window. For TO_X > 0, truncate to end of drawing area. */
5439 if (to_x == 0)
5440 return;
5441 else if (to_x < 0)
5442 to_x = max_x;
5443 else
5444 to_x = min (to_x, max_x);
dbc4e1c1 5445
06a2c219
GM
5446 to_y = min (max_y, output_cursor.y + updated_row->height);
5447
5448 /* Notice if the cursor will be cleared by this operation. */
5449 if (!updated_row->full_width_p)
5450 note_overwritten_text_cursor (w, output_cursor.hpos, -1);
dbc4e1c1 5451
06a2c219
GM
5452 from_x = output_cursor.x;
5453
5454 /* Translate to frame coordinates. */
5455 if (updated_row->full_width_p)
5456 {
5457 from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
5458 to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
5459 }
0cdd0c9f
RS
5460 else
5461 {
06a2c219
GM
5462 from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
5463 to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
5464 }
5465
045dee35 5466 min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
06a2c219
GM
5467 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
5468 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
5469
5470 /* Prevent inadvertently clearing to end of the X window. */
5471 if (to_x > from_x && to_y > from_y)
5472 {
5473 BLOCK_INPUT;
c5e6e06b
GM
5474 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5475 from_x, from_y, to_x - from_x, to_y - from_y,
5476 False);
06a2c219 5477 UNBLOCK_INPUT;
0cdd0c9f 5478 }
0cdd0c9f 5479}
dbc4e1c1 5480
0cdd0c9f 5481
06a2c219 5482/* Clear entire frame. If updating_frame is non-null, clear that
b86bd3dd 5483 frame. Otherwise clear the selected frame. */
06a2c219
GM
5484
5485static void
5486x_clear_frame ()
0cdd0c9f 5487{
06a2c219 5488 struct frame *f;
0cdd0c9f 5489
06a2c219
GM
5490 if (updating_frame)
5491 f = updating_frame;
0cdd0c9f 5492 else
b86bd3dd 5493 f = SELECTED_FRAME ();
58769bee 5494
06a2c219
GM
5495 /* Clearing the frame will erase any cursor, so mark them all as no
5496 longer visible. */
5497 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
5498 output_cursor.hpos = output_cursor.vpos = 0;
5499 output_cursor.x = -1;
5500
5501 /* We don't set the output cursor here because there will always
5502 follow an explicit cursor_to. */
5503 BLOCK_INPUT;
5504 XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
5505
5506 /* We have to clear the scroll bars, too. If we have changed
5507 colors or something like that, then they should be notified. */
5508 x_scroll_bar_clear (f);
0cdd0c9f 5509
06a2c219
GM
5510 XFlush (FRAME_X_DISPLAY (f));
5511 UNBLOCK_INPUT;
dc6f92b8 5512}
06a2c219
GM
5513
5514
dc6f92b8 5515\f
dbc4e1c1
JB
5516/* Invert the middle quarter of the frame for .15 sec. */
5517
06a2c219
GM
5518/* We use the select system call to do the waiting, so we have to make
5519 sure it's available. If it isn't, we just won't do visual bells. */
5520
dbc4e1c1
JB
5521#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
5522
06a2c219
GM
5523
5524/* Subtract the `struct timeval' values X and Y, storing the result in
5525 *RESULT. Return 1 if the difference is negative, otherwise 0. */
dbc4e1c1
JB
5526
5527static int
5528timeval_subtract (result, x, y)
5529 struct timeval *result, x, y;
5530{
06a2c219
GM
5531 /* Perform the carry for the later subtraction by updating y. This
5532 is safer because on some systems the tv_sec member is unsigned. */
dbc4e1c1
JB
5533 if (x.tv_usec < y.tv_usec)
5534 {
5535 int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
5536 y.tv_usec -= 1000000 * nsec;
5537 y.tv_sec += nsec;
5538 }
06a2c219 5539
dbc4e1c1
JB
5540 if (x.tv_usec - y.tv_usec > 1000000)
5541 {
5542 int nsec = (y.tv_usec - x.tv_usec) / 1000000;
5543 y.tv_usec += 1000000 * nsec;
5544 y.tv_sec -= nsec;
5545 }
5546
06a2c219
GM
5547 /* Compute the time remaining to wait. tv_usec is certainly
5548 positive. */
dbc4e1c1
JB
5549 result->tv_sec = x.tv_sec - y.tv_sec;
5550 result->tv_usec = x.tv_usec - y.tv_usec;
5551
06a2c219
GM
5552 /* Return indication of whether the result should be considered
5553 negative. */
dbc4e1c1
JB
5554 return x.tv_sec < y.tv_sec;
5555}
dc6f92b8 5556
dfcf069d 5557void
f676886a
JB
5558XTflash (f)
5559 struct frame *f;
dc6f92b8 5560{
dbc4e1c1 5561 BLOCK_INPUT;
dc6f92b8 5562
dbc4e1c1
JB
5563 {
5564 GC gc;
dc6f92b8 5565
06a2c219
GM
5566 /* Create a GC that will use the GXxor function to flip foreground
5567 pixels into background pixels. */
dbc4e1c1
JB
5568 {
5569 XGCValues values;
dc6f92b8 5570
dbc4e1c1 5571 values.function = GXxor;
7556890b
RS
5572 values.foreground = (f->output_data.x->foreground_pixel
5573 ^ f->output_data.x->background_pixel);
58769bee 5574
334208b7 5575 gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dbc4e1c1
JB
5576 GCFunction | GCForeground, &values);
5577 }
dc6f92b8 5578
dbc4e1c1 5579 {
e84e14c3
RS
5580 /* Get the height not including a menu bar widget. */
5581 int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
5582 /* Height of each line to flash. */
5583 int flash_height = FRAME_LINE_HEIGHT (f);
5584 /* These will be the left and right margins of the rectangles. */
5585 int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
5586 int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
5587
5588 int width;
5589
5590 /* Don't flash the area between a scroll bar and the frame
5591 edge it is next to. */
5592 switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
5593 {
5594 case vertical_scroll_bar_left:
5595 flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5596 break;
5597
5598 case vertical_scroll_bar_right:
5599 flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
5600 break;
06a2c219
GM
5601
5602 default:
5603 break;
e84e14c3
RS
5604 }
5605
5606 width = flash_right - flash_left;
5607
5608 /* If window is tall, flash top and bottom line. */
5609 if (height > 3 * FRAME_LINE_HEIGHT (f))
5610 {
5611 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5612 flash_left,
5613 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5614 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5615 width, flash_height);
5616 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5617 flash_left,
5618 (height - flash_height
5619 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5620 width, flash_height);
5621 }
5622 else
5623 /* If it is short, flash it all. */
5624 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5625 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5626 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
dc6f92b8 5627
06a2c219 5628 x_flush (f);
dc6f92b8 5629
dbc4e1c1 5630 {
06a2c219 5631 struct timeval wakeup;
dc6f92b8 5632
66c30ea1 5633 EMACS_GET_TIME (wakeup);
dc6f92b8 5634
dbc4e1c1
JB
5635 /* Compute time to wait until, propagating carry from usecs. */
5636 wakeup.tv_usec += 150000;
5637 wakeup.tv_sec += (wakeup.tv_usec / 1000000);
5638 wakeup.tv_usec %= 1000000;
5639
101922c3
GM
5640 /* Keep waiting until past the time wakeup or any input gets
5641 available. */
5642 while (! detect_input_pending ())
dbc4e1c1 5643 {
101922c3 5644 struct timeval current;
dbc4e1c1
JB
5645 struct timeval timeout;
5646
101922c3 5647 EMACS_GET_TIME (current);
dbc4e1c1 5648
101922c3
GM
5649 /* Break if result would be negative. */
5650 if (timeval_subtract (&current, wakeup, current))
dbc4e1c1
JB
5651 break;
5652
101922c3
GM
5653 /* How long `select' should wait. */
5654 timeout.tv_sec = 0;
5655 timeout.tv_usec = 10000;
5656
dbc4e1c1 5657 /* Try to wait that long--but we might wake up sooner. */
c32cdd9a 5658 select (0, NULL, NULL, NULL, &timeout);
dbc4e1c1
JB
5659 }
5660 }
58769bee 5661
e84e14c3
RS
5662 /* If window is tall, flash top and bottom line. */
5663 if (height > 3 * FRAME_LINE_HEIGHT (f))
5664 {
5665 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
06a2c219
GM
5666 flash_left,
5667 (FRAME_INTERNAL_BORDER_WIDTH (f)
9ea173e8 5668 + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
e84e14c3
RS
5669 width, flash_height);
5670 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5671 flash_left,
5672 (height - flash_height
5673 - FRAME_INTERNAL_BORDER_WIDTH (f)),
5674 width, flash_height);
5675 }
5676 else
5677 /* If it is short, flash it all. */
5678 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
5679 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
5680 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
5681
334208b7 5682 XFreeGC (FRAME_X_DISPLAY (f), gc);
06a2c219 5683 x_flush (f);
dc6f92b8 5684 }
dbc4e1c1
JB
5685 }
5686
5687 UNBLOCK_INPUT;
dc6f92b8
JB
5688}
5689
06a2c219 5690#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
dbc4e1c1
JB
5691
5692
dc6f92b8
JB
5693/* Make audible bell. */
5694
dfcf069d 5695void
dc6f92b8
JB
5696XTring_bell ()
5697{
b86bd3dd
GM
5698 struct frame *f = SELECTED_FRAME ();
5699
5700 if (FRAME_X_DISPLAY (f))
5701 {
dbc4e1c1 5702#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
b86bd3dd
GM
5703 if (visible_bell)
5704 XTflash (f);
5705 else
dbc4e1c1 5706#endif
b86bd3dd
GM
5707 {
5708 BLOCK_INPUT;
5709 XBell (FRAME_X_DISPLAY (f), 0);
5710 XFlush (FRAME_X_DISPLAY (f));
5711 UNBLOCK_INPUT;
5712 }
dc6f92b8
JB
5713 }
5714}
06a2c219 5715
dc6f92b8 5716\f
06a2c219
GM
5717/* Specify how many text lines, from the top of the window,
5718 should be affected by insert-lines and delete-lines operations.
5719 This, and those operations, are used only within an update
5720 that is bounded by calls to x_update_begin and x_update_end. */
dc6f92b8 5721
dfcf069d 5722static void
06a2c219
GM
5723XTset_terminal_window (n)
5724 register int n;
dc6f92b8 5725{
06a2c219 5726 /* This function intentionally left blank. */
dc6f92b8
JB
5727}
5728
06a2c219
GM
5729
5730\f
5731/***********************************************************************
5732 Line Dance
5733 ***********************************************************************/
5734
5735/* Perform an insert-lines or delete-lines operation, inserting N
5736 lines or deleting -N lines at vertical position VPOS. */
5737
dfcf069d 5738static void
06a2c219
GM
5739x_ins_del_lines (vpos, n)
5740 int vpos, n;
dc6f92b8
JB
5741{
5742 abort ();
5743}
06a2c219
GM
5744
5745
5746/* Scroll part of the display as described by RUN. */
dc6f92b8 5747
dfcf069d 5748static void
06a2c219
GM
5749x_scroll_run (w, run)
5750 struct window *w;
5751 struct run *run;
dc6f92b8 5752{
06a2c219
GM
5753 struct frame *f = XFRAME (w->frame);
5754 int x, y, width, height, from_y, to_y, bottom_y;
5755
5756 /* Get frame-relative bounding box of the text display area of W,
5757 without mode lines. Include in this box the flags areas to the
5758 left and right of W. */
5759 window_box (w, -1, &x, &y, &width, &height);
110859fc
GM
5760 width += FRAME_X_FLAGS_AREA_WIDTH (f);
5761 x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
5762
5763 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
5764 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
5765 bottom_y = y + height;
dc6f92b8 5766
06a2c219
GM
5767 if (to_y < from_y)
5768 {
5769 /* Scrolling up. Make sure we don't copy part of the mode
5770 line at the bottom. */
5771 if (from_y + run->height > bottom_y)
5772 height = bottom_y - from_y;
5773 else
5774 height = run->height;
5775 }
dc6f92b8 5776 else
06a2c219
GM
5777 {
5778 /* Scolling down. Make sure we don't copy over the mode line.
5779 at the bottom. */
5780 if (to_y + run->height > bottom_y)
5781 height = bottom_y - to_y;
5782 else
5783 height = run->height;
5784 }
7a13e894 5785
06a2c219
GM
5786 BLOCK_INPUT;
5787
5788 /* Cursor off. Will be switched on again in x_update_window_end. */
5789 updated_window = w;
5790 x_clear_cursor (w);
5791
5792 XCopyArea (FRAME_X_DISPLAY (f),
5793 FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
5794 f->output_data.x->normal_gc,
5795 x, from_y,
5796 width, height,
5797 x, to_y);
5798
5799 UNBLOCK_INPUT;
5800}
dc6f92b8 5801
dc6f92b8 5802
06a2c219
GM
5803\f
5804/***********************************************************************
5805 Exposure Events
5806 ***********************************************************************/
5807
5808/* Redisplay an exposed area of frame F. X and Y are the upper-left
5809 corner of the exposed rectangle. W and H are width and height of
5810 the exposed area. All are pixel values. W or H zero means redraw
5811 the entire frame. */
dc6f92b8 5812
06a2c219
GM
5813static void
5814expose_frame (f, x, y, w, h)
5815 struct frame *f;
5816 int x, y, w, h;
dc6f92b8 5817{
06a2c219 5818 XRectangle r;
82f053ab 5819 int mouse_face_overwritten_p = 0;
dc6f92b8 5820
06a2c219 5821 TRACE ((stderr, "expose_frame "));
dc6f92b8 5822
06a2c219
GM
5823 /* No need to redraw if frame will be redrawn soon. */
5824 if (FRAME_GARBAGED_P (f))
dc6f92b8 5825 {
06a2c219
GM
5826 TRACE ((stderr, " garbaged\n"));
5827 return;
5828 }
5829
5830 /* If basic faces haven't been realized yet, there is no point in
5831 trying to redraw anything. This can happen when we get an expose
5832 event while Emacs is starting, e.g. by moving another window. */
5833 if (FRAME_FACE_CACHE (f) == NULL
5834 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5835 {
5836 TRACE ((stderr, " no faces\n"));
5837 return;
58769bee 5838 }
06a2c219
GM
5839
5840 if (w == 0 || h == 0)
58769bee 5841 {
06a2c219
GM
5842 r.x = r.y = 0;
5843 r.width = CANON_X_UNIT (f) * f->width;
5844 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5845 }
5846 else
5847 {
06a2c219
GM
5848 r.x = x;
5849 r.y = y;
5850 r.width = w;
5851 r.height = h;
5852 }
5853
5854 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
82f053ab 5855 mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
06a2c219 5856
9ea173e8 5857 if (WINDOWP (f->tool_bar_window))
82f053ab
GM
5858 mouse_face_overwritten_p
5859 |= expose_window (XWINDOW (f->tool_bar_window), &r);
06a2c219
GM
5860
5861#ifndef USE_X_TOOLKIT
5862 if (WINDOWP (f->menu_bar_window))
82f053ab
GM
5863 mouse_face_overwritten_p
5864 |= expose_window (XWINDOW (f->menu_bar_window), &r);
06a2c219 5865#endif /* not USE_X_TOOLKIT */
82f053ab
GM
5866
5867 /* Some window managers support a focus-follows-mouse style with
5868 delayed raising of frames. Imagine a partially obscured frame,
5869 and moving the mouse into partially obscured mouse-face on that
5870 frame. The visible part of the mouse-face will be highlighted,
5871 then the WM raises the obscured frame. With at least one WM, KDE
5872 2.1, Emacs is not getting any event for the raising of the frame
5873 (even tried with SubstructureRedirectMask), only Expose events.
5874 These expose events will draw text normally, i.e. not
5875 highlighted. Which means we must redo the highlight here.
5876 Subsume it under ``we love X''. --gerd 2001-08-15 */
5877 if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
5878 {
5879 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
5880 if (f == dpyinfo->mouse_face_mouse_frame)
5881 {
5882 int x = dpyinfo->mouse_face_mouse_x;
5883 int y = dpyinfo->mouse_face_mouse_y;
5884 clear_mouse_face (dpyinfo);
5885 note_mouse_highlight (f, x, y);
5886 }
5887 }
dc6f92b8
JB
5888}
5889
06a2c219
GM
5890
5891/* Redraw (parts) of all windows in the window tree rooted at W that
82f053ab
GM
5892 intersect R. R contains frame pixel coordinates. Value is
5893 non-zero if the exposure overwrites mouse-face. */
06a2c219 5894
82f053ab 5895static int
06a2c219
GM
5896expose_window_tree (w, r)
5897 struct window *w;
5898 XRectangle *r;
dc6f92b8 5899{
82f053ab
GM
5900 struct frame *f = XFRAME (w->frame);
5901 int mouse_face_overwritten_p = 0;
5902
5903 while (w && !FRAME_GARBAGED_P (f))
06a2c219
GM
5904 {
5905 if (!NILP (w->hchild))
82f053ab
GM
5906 mouse_face_overwritten_p
5907 |= expose_window_tree (XWINDOW (w->hchild), r);
06a2c219 5908 else if (!NILP (w->vchild))
82f053ab
GM
5909 mouse_face_overwritten_p
5910 |= expose_window_tree (XWINDOW (w->vchild), r);
5911 else
5912 mouse_face_overwritten_p |= expose_window (w, r);
5913
a02f1be0 5914 w = NILP (w->next) ? NULL : XWINDOW (w->next);
06a2c219 5915 }
82f053ab
GM
5916
5917 return mouse_face_overwritten_p;
06a2c219 5918}
58769bee 5919
dc6f92b8 5920
06a2c219
GM
5921/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5922 which intersects rectangle R. R is in window-relative coordinates. */
5923
5924static void
5925expose_area (w, row, r, area)
5926 struct window *w;
5927 struct glyph_row *row;
5928 XRectangle *r;
5929 enum glyph_row_area area;
5930{
06a2c219
GM
5931 struct glyph *first = row->glyphs[area];
5932 struct glyph *end = row->glyphs[area] + row->used[area];
5933 struct glyph *last;
4bc6dcc7 5934 int first_x, start_x, x;
06a2c219 5935
6fb13182
GM
5936 if (area == TEXT_AREA && row->fill_line_p)
5937 /* If row extends face to end of line write the whole line. */
4bc6dcc7 5938 x_draw_glyphs (w, 0, row, area,
6fb13182 5939 0, row->used[area],
06a2c219 5940 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5941 NULL, NULL, 0);
6fb13182
GM
5942 else
5943 {
4bc6dcc7
GM
5944 /* Set START_X to the window-relative start position for drawing glyphs of
5945 AREA. The first glyph of the text area can be partially visible.
5946 The first glyphs of other areas cannot. */
5947 if (area == LEFT_MARGIN_AREA)
5948 start_x = 0;
5949 else if (area == TEXT_AREA)
5950 start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5951 else
5952 start_x = (window_box_width (w, LEFT_MARGIN_AREA)
5953 + window_box_width (w, TEXT_AREA));
5954 x = start_x;
5955
6fb13182
GM
5956 /* Find the first glyph that must be redrawn. */
5957 while (first < end
5958 && x + first->pixel_width < r->x)
5959 {
5960 x += first->pixel_width;
5961 ++first;
5962 }
5963
5964 /* Find the last one. */
5965 last = first;
5966 first_x = x;
5967 while (last < end
5968 && x < r->x + r->width)
5969 {
5970 x += last->pixel_width;
5971 ++last;
5972 }
5973
5974 /* Repaint. */
5975 if (last > first)
4bc6dcc7 5976 x_draw_glyphs (w, first_x - start_x, row, area,
6fb13182
GM
5977 first - row->glyphs[area],
5978 last - row->glyphs[area],
5979 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5980 NULL, NULL, 0);
5981 }
06a2c219
GM
5982}
5983
58769bee 5984
06a2c219 5985/* Redraw the parts of the glyph row ROW on window W intersecting
82f053ab
GM
5986 rectangle R. R is in window-relative coordinates. Value is
5987 non-zero if mouse-face was overwritten. */
dc6f92b8 5988
82f053ab 5989static int
06a2c219
GM
5990expose_line (w, row, r)
5991 struct window *w;
5992 struct glyph_row *row;
5993 XRectangle *r;
5994{
5995 xassert (row->enabled_p);
5996
5997 if (row->mode_line_p || w->pseudo_window_p)
5998 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
5999 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 6000 NULL, NULL, 0);
06a2c219
GM
6001 else
6002 {
6003 if (row->used[LEFT_MARGIN_AREA])
6004 expose_area (w, row, r, LEFT_MARGIN_AREA);
6005 if (row->used[TEXT_AREA])
6006 expose_area (w, row, r, TEXT_AREA);
6007 if (row->used[RIGHT_MARGIN_AREA])
6008 expose_area (w, row, r, RIGHT_MARGIN_AREA);
6009 x_draw_row_bitmaps (w, row);
6010 }
82f053ab
GM
6011
6012 return row->mouse_face_p;
06a2c219 6013}
dc6f92b8 6014
58769bee 6015
06a2c219
GM
6016/* Return non-zero if W's cursor intersects rectangle R. */
6017
6018static int
6019x_phys_cursor_in_rect_p (w, r)
6020 struct window *w;
6021 XRectangle *r;
6022{
6023 XRectangle cr, result;
6024 struct glyph *cursor_glyph;
6025
6026 cursor_glyph = get_phys_cursor_glyph (w);
6027 if (cursor_glyph)
6028 {
6029 cr.x = w->phys_cursor.x;
6030 cr.y = w->phys_cursor.y;
6031 cr.width = cursor_glyph->pixel_width;
6032 cr.height = w->phys_cursor_height;
6033 return x_intersect_rectangles (&cr, r, &result);
6034 }
6035 else
6036 return 0;
dc6f92b8 6037}
dc6f92b8 6038
06a2c219 6039
a02f1be0
GM
6040/* Redraw the part of window W intersection rectangle FR. Pixel
6041 coordinates in FR are frame-relative. Call this function with
82f053ab
GM
6042 input blocked. Value is non-zero if the exposure overwrites
6043 mouse-face. */
dc6f92b8 6044
a39202f6 6045static int
a02f1be0 6046expose_window (w, fr)
06a2c219 6047 struct window *w;
a02f1be0 6048 XRectangle *fr;
dc6f92b8 6049{
a02f1be0 6050 struct frame *f = XFRAME (w->frame);
a02f1be0 6051 XRectangle wr, r;
82f053ab 6052 int mouse_face_overwritten_p = 0;
dc6f92b8 6053
80c32bcc
GM
6054 /* If window is not yet fully initialized, do nothing. This can
6055 happen when toolkit scroll bars are used and a window is split.
6056 Reconfiguring the scroll bar will generate an expose for a newly
6057 created window. */
a39202f6 6058 if (w->current_matrix == NULL)
82f053ab 6059 return 0;
a39202f6
GM
6060
6061 /* When we're currently updating the window, display and current
6062 matrix usually don't agree. Arrange for a thorough display
6063 later. */
6064 if (w == updated_window)
6065 {
6066 SET_FRAME_GARBAGED (f);
6067 return 0;
6068 }
80c32bcc 6069
a39202f6 6070 /* Frame-relative pixel rectangle of W. */
a02f1be0
GM
6071 wr.x = XFASTINT (w->left) * CANON_X_UNIT (f);
6072 wr.y = XFASTINT (w->top) * CANON_Y_UNIT (f);
6073 wr.width = XFASTINT (w->width) * CANON_X_UNIT (f);
6074 wr.height = XFASTINT (w->height) * CANON_Y_UNIT (f);
6075
a39202f6
GM
6076 if (x_intersect_rectangles (fr, &wr, &r))
6077 {
6078 int yb = window_text_bottom_y (w);
6079 struct glyph_row *row;
6080 int cursor_cleared_p;
a02f1be0 6081
a39202f6
GM
6082 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
6083 r.x, r.y, r.width, r.height));
dc6f92b8 6084
a39202f6
GM
6085 /* Convert to window coordinates. */
6086 r.x = FRAME_TO_WINDOW_PIXEL_X (w, r.x);
6087 r.y = FRAME_TO_WINDOW_PIXEL_Y (w, r.y);
dc6f92b8 6088
a39202f6
GM
6089 /* Turn off the cursor. */
6090 if (!w->pseudo_window_p
6091 && x_phys_cursor_in_rect_p (w, &r))
6092 {
6093 x_clear_cursor (w);
6094 cursor_cleared_p = 1;
6095 }
6096 else
6097 cursor_cleared_p = 0;
06a2c219 6098
a39202f6
GM
6099 /* Find the first row intersecting the rectangle R. */
6100 for (row = w->current_matrix->rows;
6101 row->enabled_p;
6102 ++row)
6103 {
6104 int y0 = row->y;
6105 int y1 = MATRIX_ROW_BOTTOM_Y (row);
6106
6107 if ((y0 >= r.y && y0 < r.y + r.height)
6108 || (y1 > r.y && y1 < r.y + r.height)
6109 || (r.y >= y0 && r.y < y1)
6110 || (r.y + r.height > y0 && r.y + r.height < y1))
82f053ab
GM
6111 {
6112 if (expose_line (w, row, &r))
6113 mouse_face_overwritten_p = 1;
6114 }
6115
a39202f6
GM
6116 if (y1 >= yb)
6117 break;
6118 }
dc6f92b8 6119
a39202f6
GM
6120 /* Display the mode line if there is one. */
6121 if (WINDOW_WANTS_MODELINE_P (w)
6122 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
6123 row->enabled_p)
6124 && row->y < r.y + r.height)
82f053ab
GM
6125 {
6126 if (expose_line (w, row, &r))
6127 mouse_face_overwritten_p = 1;
6128 }
a39202f6
GM
6129
6130 if (!w->pseudo_window_p)
6131 {
6132 /* Draw border between windows. */
6133 x_draw_vertical_border (w);
06a2c219 6134
a39202f6
GM
6135 /* Turn the cursor on again. */
6136 if (cursor_cleared_p)
6137 x_update_window_cursor (w, 1);
6138 }
06a2c219 6139 }
82f053ab
GM
6140
6141 return mouse_face_overwritten_p;
06a2c219 6142}
dc6f92b8 6143
dc6f92b8 6144
06a2c219
GM
6145/* Determine the intersection of two rectangles R1 and R2. Return
6146 the intersection in *RESULT. Value is non-zero if RESULT is not
6147 empty. */
6148
6149static int
6150x_intersect_rectangles (r1, r2, result)
6151 XRectangle *r1, *r2, *result;
6152{
6153 XRectangle *left, *right;
6154 XRectangle *upper, *lower;
6155 int intersection_p = 0;
6156
6157 /* Rearrange so that R1 is the left-most rectangle. */
6158 if (r1->x < r2->x)
6159 left = r1, right = r2;
6160 else
6161 left = r2, right = r1;
6162
6163 /* X0 of the intersection is right.x0, if this is inside R1,
6164 otherwise there is no intersection. */
6165 if (right->x <= left->x + left->width)
6166 {
6167 result->x = right->x;
6168
6169 /* The right end of the intersection is the minimum of the
6170 the right ends of left and right. */
6171 result->width = (min (left->x + left->width, right->x + right->width)
6172 - result->x);
6173
6174 /* Same game for Y. */
6175 if (r1->y < r2->y)
6176 upper = r1, lower = r2;
6177 else
6178 upper = r2, lower = r1;
6179
6180 /* The upper end of the intersection is lower.y0, if this is inside
6181 of upper. Otherwise, there is no intersection. */
6182 if (lower->y <= upper->y + upper->height)
dc43ef94 6183 {
06a2c219
GM
6184 result->y = lower->y;
6185
6186 /* The lower end of the intersection is the minimum of the lower
6187 ends of upper and lower. */
6188 result->height = (min (lower->y + lower->height,
6189 upper->y + upper->height)
6190 - result->y);
6191 intersection_p = 1;
dc43ef94 6192 }
dc6f92b8
JB
6193 }
6194
06a2c219 6195 return intersection_p;
dc6f92b8 6196}
06a2c219
GM
6197
6198
6199
6200
dc6f92b8 6201\f
dc6f92b8 6202static void
334208b7
RS
6203frame_highlight (f)
6204 struct frame *f;
dc6f92b8 6205{
b3e1e05c
JB
6206 /* We used to only do this if Vx_no_window_manager was non-nil, but
6207 the ICCCM (section 4.1.6) says that the window's border pixmap
6208 and border pixel are window attributes which are "private to the
6209 client", so we can always change it to whatever we want. */
6210 BLOCK_INPUT;
334208b7 6211 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6212 f->output_data.x->border_pixel);
b3e1e05c 6213 UNBLOCK_INPUT;
5d46f928 6214 x_update_cursor (f, 1);
dc6f92b8
JB
6215}
6216
6217static void
334208b7
RS
6218frame_unhighlight (f)
6219 struct frame *f;
dc6f92b8 6220{
b3e1e05c
JB
6221 /* We used to only do this if Vx_no_window_manager was non-nil, but
6222 the ICCCM (section 4.1.6) says that the window's border pixmap
6223 and border pixel are window attributes which are "private to the
6224 client", so we can always change it to whatever we want. */
6225 BLOCK_INPUT;
334208b7 6226 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6227 f->output_data.x->border_tile);
b3e1e05c 6228 UNBLOCK_INPUT;
5d46f928 6229 x_update_cursor (f, 1);
dc6f92b8 6230}
dc6f92b8 6231
f676886a
JB
6232/* The focus has changed. Update the frames as necessary to reflect
6233 the new situation. Note that we can't change the selected frame
c5acd733 6234 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 6235 Each event gets marked with the frame in which it occurred, so the
c5acd733 6236 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 6237
6d4238f3 6238static void
0f941935
KH
6239x_new_focus_frame (dpyinfo, frame)
6240 struct x_display_info *dpyinfo;
f676886a 6241 struct frame *frame;
dc6f92b8 6242{
0f941935 6243 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 6244
0f941935 6245 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 6246 {
58769bee 6247 /* Set this before calling other routines, so that they see
f676886a 6248 the correct value of x_focus_frame. */
0f941935 6249 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
6250
6251 if (old_focus && old_focus->auto_lower)
f676886a 6252 x_lower_frame (old_focus);
dc6f92b8
JB
6253
6254#if 0
f676886a 6255 selected_frame = frame;
e0c1aef2
KH
6256 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6257 selected_frame);
f676886a
JB
6258 Fselect_window (selected_frame->selected_window);
6259 choose_minibuf_frame ();
c118dd06 6260#endif /* ! 0 */
dc6f92b8 6261
0f941935
KH
6262 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6263 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
6264 else
6265 pending_autoraise_frame = 0;
6d4238f3 6266 }
dc6f92b8 6267
0f941935 6268 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
6269}
6270
37c2c98b
RS
6271/* Handle an event saying the mouse has moved out of an Emacs frame. */
6272
6273void
0f941935
KH
6274x_mouse_leave (dpyinfo)
6275 struct x_display_info *dpyinfo;
37c2c98b 6276{
0f941935 6277 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 6278}
6d4238f3 6279
f451eb13
JB
6280/* The focus has changed, or we have redirected a frame's focus to
6281 another frame (this happens when a frame uses a surrogate
06a2c219 6282 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
6283
6284 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 6285 frame is being highlighted or un-highlighted; we only use it to find
0f941935 6286 the appropriate X display info. */
06a2c219 6287
6d4238f3 6288static void
0f941935
KH
6289XTframe_rehighlight (frame)
6290 struct frame *frame;
6d4238f3 6291{
0f941935
KH
6292 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6293}
6d4238f3 6294
0f941935
KH
6295static void
6296x_frame_rehighlight (dpyinfo)
6297 struct x_display_info *dpyinfo;
6298{
6299 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6300
6301 if (dpyinfo->x_focus_frame)
6d4238f3 6302 {
0f941935
KH
6303 dpyinfo->x_highlight_frame
6304 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6305 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6306 : dpyinfo->x_focus_frame);
6307 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 6308 {
0f941935
KH
6309 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6310 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 6311 }
dc6f92b8 6312 }
6d4238f3 6313 else
0f941935 6314 dpyinfo->x_highlight_frame = 0;
dc6f92b8 6315
0f941935 6316 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
6317 {
6318 if (old_highlight)
f676886a 6319 frame_unhighlight (old_highlight);
0f941935
KH
6320 if (dpyinfo->x_highlight_frame)
6321 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 6322 }
dc6f92b8 6323}
06a2c219
GM
6324
6325
dc6f92b8 6326\f
06a2c219 6327/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 6328
28430d3c
JB
6329/* Initialize mode_switch_bit and modifier_meaning. */
6330static void
334208b7
RS
6331x_find_modifier_meanings (dpyinfo)
6332 struct x_display_info *dpyinfo;
28430d3c 6333{
f689eb05 6334 int min_code, max_code;
28430d3c
JB
6335 KeySym *syms;
6336 int syms_per_code;
6337 XModifierKeymap *mods;
6338
334208b7
RS
6339 dpyinfo->meta_mod_mask = 0;
6340 dpyinfo->shift_lock_mask = 0;
6341 dpyinfo->alt_mod_mask = 0;
6342 dpyinfo->super_mod_mask = 0;
6343 dpyinfo->hyper_mod_mask = 0;
58769bee 6344
9658a521 6345#ifdef HAVE_X11R4
334208b7 6346 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 6347#else
4a60f8c5
RS
6348 min_code = dpyinfo->display->min_keycode;
6349 max_code = dpyinfo->display->max_keycode;
9658a521
JB
6350#endif
6351
334208b7 6352 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
6353 min_code, max_code - min_code + 1,
6354 &syms_per_code);
334208b7 6355 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 6356
58769bee 6357 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 6358 Alt keysyms are on. */
28430d3c 6359 {
06a2c219 6360 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
6361
6362 for (row = 3; row < 8; row++)
6363 for (col = 0; col < mods->max_keypermod; col++)
6364 {
0299d313
RS
6365 KeyCode code
6366 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 6367
af92970c
KH
6368 /* Zeroes are used for filler. Skip them. */
6369 if (code == 0)
6370 continue;
6371
28430d3c
JB
6372 /* Are any of this keycode's keysyms a meta key? */
6373 {
6374 int code_col;
6375
6376 for (code_col = 0; code_col < syms_per_code; code_col++)
6377 {
f689eb05 6378 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 6379
f689eb05 6380 switch (sym)
28430d3c 6381 {
f689eb05
JB
6382 case XK_Meta_L:
6383 case XK_Meta_R:
334208b7 6384 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 6385 break;
f689eb05
JB
6386
6387 case XK_Alt_L:
6388 case XK_Alt_R:
334208b7 6389 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
6390 break;
6391
6392 case XK_Hyper_L:
6393 case XK_Hyper_R:
334208b7 6394 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
6395 break;
6396
6397 case XK_Super_L:
6398 case XK_Super_R:
334208b7 6399 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 6400 break;
11edeb03
JB
6401
6402 case XK_Shift_Lock:
6403 /* Ignore this if it's not on the lock modifier. */
6404 if ((1 << row) == LockMask)
334208b7 6405 dpyinfo->shift_lock_mask = LockMask;
11edeb03 6406 break;
28430d3c
JB
6407 }
6408 }
6409 }
6410 }
6411 }
6412
f689eb05 6413 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 6414 if (! dpyinfo->meta_mod_mask)
a3c44b14 6415 {
334208b7
RS
6416 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6417 dpyinfo->alt_mod_mask = 0;
a3c44b14 6418 }
f689eb05 6419
148c4b70
RS
6420 /* If some keys are both alt and meta,
6421 make them just meta, not alt. */
334208b7 6422 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 6423 {
334208b7 6424 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 6425 }
58769bee 6426
28430d3c 6427 XFree ((char *) syms);
f689eb05 6428 XFreeModifiermap (mods);
28430d3c
JB
6429}
6430
dfeccd2d
JB
6431/* Convert between the modifier bits X uses and the modifier bits
6432 Emacs uses. */
06a2c219 6433
7c5283e4 6434static unsigned int
334208b7
RS
6435x_x_to_emacs_modifiers (dpyinfo, state)
6436 struct x_display_info *dpyinfo;
dc6f92b8
JB
6437 unsigned int state;
6438{
334208b7
RS
6439 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
6440 | ((state & ControlMask) ? ctrl_modifier : 0)
6441 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
6442 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
6443 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
6444 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
6445}
6446
dfeccd2d 6447static unsigned int
334208b7
RS
6448x_emacs_to_x_modifiers (dpyinfo, state)
6449 struct x_display_info *dpyinfo;
dfeccd2d
JB
6450 unsigned int state;
6451{
334208b7
RS
6452 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
6453 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6454 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6455 | ((state & shift_modifier) ? ShiftMask : 0)
6456 | ((state & ctrl_modifier) ? ControlMask : 0)
6457 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6458}
d047c4eb
KH
6459
6460/* Convert a keysym to its name. */
6461
6462char *
6463x_get_keysym_name (keysym)
6464 KeySym keysym;
6465{
6466 char *value;
6467
6468 BLOCK_INPUT;
6469 value = XKeysymToString (keysym);
6470 UNBLOCK_INPUT;
6471
6472 return value;
6473}
06a2c219
GM
6474
6475
e4571a43
JB
6476\f
6477/* Mouse clicks and mouse movement. Rah. */
e4571a43 6478
06a2c219
GM
6479/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6480 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6481 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6482 not force the value into range. */
69388238 6483
c8dba240 6484void
69388238 6485pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6486 FRAME_PTR f;
69388238 6487 register int pix_x, pix_y;
e4571a43
JB
6488 register int *x, *y;
6489 XRectangle *bounds;
69388238 6490 int noclip;
e4571a43 6491{
06a2c219 6492 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6493 even for negative values. */
6494 if (pix_x < 0)
7556890b 6495 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6496 if (pix_y < 0)
7556890b 6497 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6498
e4571a43
JB
6499 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6500 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6501
6502 if (bounds)
6503 {
7556890b
RS
6504 bounds->width = FONT_WIDTH (f->output_data.x->font);
6505 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6506 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6507 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6508 }
6509
69388238
RS
6510 if (!noclip)
6511 {
6512 if (pix_x < 0)
6513 pix_x = 0;
3cbd2e0b
RS
6514 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6515 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6516
6517 if (pix_y < 0)
6518 pix_y = 0;
6519 else if (pix_y > f->height)
6520 pix_y = f->height;
6521 }
e4571a43
JB
6522
6523 *x = pix_x;
6524 *y = pix_y;
6525}
6526
06a2c219
GM
6527
6528/* Given HPOS/VPOS in the current matrix of W, return corresponding
6529 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6530 can't tell the positions because W's display is not up to date,
6531 return 0. */
6532
6533int
6534glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6535 struct window *w;
6536 int hpos, vpos;
6537 int *frame_x, *frame_y;
2b5c9e71 6538{
06a2c219
GM
6539 int success_p;
6540
6541 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6542 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6543
6544 if (display_completed)
6545 {
6546 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6547 struct glyph *glyph = row->glyphs[TEXT_AREA];
6548 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6549
6550 *frame_y = row->y;
6551 *frame_x = row->x;
6552 while (glyph < end)
6553 {
6554 *frame_x += glyph->pixel_width;
6555 ++glyph;
6556 }
6557
6558 success_p = 1;
6559 }
6560 else
6561 {
6562 *frame_y = *frame_x = 0;
6563 success_p = 0;
6564 }
6565
6566 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6567 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6568 return success_p;
2b5c9e71
RS
6569}
6570
06a2c219 6571
dc6f92b8
JB
6572/* Prepare a mouse-event in *RESULT for placement in the input queue.
6573
6574 If the event is a button press, then note that we have grabbed
f451eb13 6575 the mouse. */
dc6f92b8
JB
6576
6577static Lisp_Object
f451eb13 6578construct_mouse_click (result, event, f)
dc6f92b8
JB
6579 struct input_event *result;
6580 XButtonEvent *event;
f676886a 6581 struct frame *f;
dc6f92b8 6582{
f451eb13 6583 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6584 otherwise. */
f451eb13 6585 result->kind = mouse_click;
69388238 6586 result->code = event->button - Button1;
1113d9db 6587 result->timestamp = event->time;
334208b7
RS
6588 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6589 event->state)
f689eb05 6590 | (event->type == ButtonRelease
58769bee 6591 ? up_modifier
f689eb05 6592 : down_modifier));
dc6f92b8 6593
06a2c219
GM
6594 XSETINT (result->x, event->x);
6595 XSETINT (result->y, event->y);
6596 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6597 result->arg = Qnil;
06a2c219 6598 return Qnil;
dc6f92b8 6599}
b849c413 6600
69388238 6601\f
90e65f07
JB
6602/* Function to report a mouse movement to the mainstream Emacs code.
6603 The input handler calls this.
6604
6605 We have received a mouse movement event, which is given in *event.
6606 If the mouse is over a different glyph than it was last time, tell
6607 the mainstream emacs code by setting mouse_moved. If not, ask for
6608 another motion event, so we can check again the next time it moves. */
b8009dd1 6609
06a2c219
GM
6610static XMotionEvent last_mouse_motion_event;
6611static Lisp_Object last_mouse_motion_frame;
6612
90e65f07 6613static void
12ba150f 6614note_mouse_movement (frame, event)
f676886a 6615 FRAME_PTR frame;
90e65f07 6616 XMotionEvent *event;
90e65f07 6617{
e5d77022 6618 last_mouse_movement_time = event->time;
06a2c219
GM
6619 last_mouse_motion_event = *event;
6620 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6621
27f338af
RS
6622 if (event->window != FRAME_X_WINDOW (frame))
6623 {
39d8bb4d 6624 frame->mouse_moved = 1;
27f338af 6625 last_mouse_scroll_bar = Qnil;
27f338af 6626 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6627 }
6628
90e65f07 6629 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6630 else if (event->x < last_mouse_glyph.x
6631 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6632 || event->y < last_mouse_glyph.y
6633 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6634 {
39d8bb4d 6635 frame->mouse_moved = 1;
ab648270 6636 last_mouse_scroll_bar = Qnil;
b8009dd1 6637 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6638 }
6639}
6640
bf1c0ba1 6641/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6642
06a2c219
GM
6643 int disable_mouse_highlight;
6644
6645
6646\f
6647/************************************************************************
6648 Mouse Face
6649 ************************************************************************/
6650
6651/* Find the glyph under window-relative coordinates X/Y in window W.
6652 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6653 strings. Return in *HPOS and *VPOS the row and column number of
6654 the glyph found. Return in *AREA the glyph area containing X.
6655 Value is a pointer to the glyph found or null if X/Y is not on
6656 text, or we can't tell because W's current matrix is not up to
6657 date. */
6658
6659static struct glyph *
f9db2310 6660x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
06a2c219
GM
6661 struct window *w;
6662 int x, y;
6663 int *hpos, *vpos, *area;
f9db2310 6664 int buffer_only_p;
06a2c219
GM
6665{
6666 struct glyph *glyph, *end;
3e71d8f2 6667 struct glyph_row *row = NULL;
06a2c219
GM
6668 int x0, i, left_area_width;
6669
6670 /* Find row containing Y. Give up if some row is not enabled. */
6671 for (i = 0; i < w->current_matrix->nrows; ++i)
6672 {
6673 row = MATRIX_ROW (w->current_matrix, i);
6674 if (!row->enabled_p)
6675 return NULL;
6676 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6677 break;
6678 }
6679
6680 *vpos = i;
6681 *hpos = 0;
6682
6683 /* Give up if Y is not in the window. */
6684 if (i == w->current_matrix->nrows)
6685 return NULL;
6686
6687 /* Get the glyph area containing X. */
6688 if (w->pseudo_window_p)
6689 {
6690 *area = TEXT_AREA;
6691 x0 = 0;
6692 }
6693 else
6694 {
6695 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6696 if (x < left_area_width)
6697 {
6698 *area = LEFT_MARGIN_AREA;
6699 x0 = 0;
6700 }
6701 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6702 {
6703 *area = TEXT_AREA;
6704 x0 = row->x + left_area_width;
6705 }
6706 else
6707 {
6708 *area = RIGHT_MARGIN_AREA;
6709 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6710 }
6711 }
6712
6713 /* Find glyph containing X. */
6714 glyph = row->glyphs[*area];
6715 end = glyph + row->used[*area];
6716 while (glyph < end)
6717 {
6718 if (x < x0 + glyph->pixel_width)
6719 {
6720 if (w->pseudo_window_p)
6721 break;
f9db2310 6722 else if (!buffer_only_p || BUFFERP (glyph->object))
06a2c219
GM
6723 break;
6724 }
6725
6726 x0 += glyph->pixel_width;
6727 ++glyph;
6728 }
6729
6730 if (glyph == end)
6731 return NULL;
6732
6733 *hpos = glyph - row->glyphs[*area];
6734 return glyph;
6735}
6736
6737
6738/* Convert frame-relative x/y to coordinates relative to window W.
6739 Takes pseudo-windows into account. */
6740
6741static void
6742frame_to_window_pixel_xy (w, x, y)
6743 struct window *w;
6744 int *x, *y;
6745{
6746 if (w->pseudo_window_p)
6747 {
6748 /* A pseudo-window is always full-width, and starts at the
6749 left edge of the frame, plus a frame border. */
6750 struct frame *f = XFRAME (w->frame);
6751 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6752 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6753 }
6754 else
6755 {
6756 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6757 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6758 }
6759}
6760
6761
e371a781 6762/* Take proper action when mouse has moved to the mode or header line of
06a2c219
GM
6763 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6764 mode line. X is relative to the start of the text display area of
6765 W, so the width of bitmap areas and scroll bars must be subtracted
6766 to get a position relative to the start of the mode line. */
6767
6768static void
6769note_mode_line_highlight (w, x, mode_line_p)
6770 struct window *w;
6771 int x, mode_line_p;
6772{
6773 struct frame *f = XFRAME (w->frame);
6774 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6775 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6776 struct glyph_row *row;
6777
6778 if (mode_line_p)
6779 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6780 else
045dee35 6781 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
e371a781 6782
06a2c219
GM
6783 if (row->enabled_p)
6784 {
6785 struct glyph *glyph, *end;
6786 Lisp_Object help, map;
6787 int x0;
6788
6789 /* Find the glyph under X. */
6790 glyph = row->glyphs[TEXT_AREA];
6791 end = glyph + row->used[TEXT_AREA];
6792 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
110859fc 6793 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
e371a781 6794
06a2c219
GM
6795 while (glyph < end
6796 && x >= x0 + glyph->pixel_width)
6797 {
6798 x0 += glyph->pixel_width;
6799 ++glyph;
6800 }
6801
6802 if (glyph < end
6803 && STRINGP (glyph->object)
6804 && XSTRING (glyph->object)->intervals
6805 && glyph->charpos >= 0
6806 && glyph->charpos < XSTRING (glyph->object)->size)
6807 {
6808 /* If we're on a string with `help-echo' text property,
6809 arrange for the help to be displayed. This is done by
6810 setting the global variable help_echo to the help string. */
6811 help = Fget_text_property (make_number (glyph->charpos),
6812 Qhelp_echo, glyph->object);
b7e80413 6813 if (!NILP (help))
be010514
GM
6814 {
6815 help_echo = help;
7cea38bc 6816 XSETWINDOW (help_echo_window, w);
be010514
GM
6817 help_echo_object = glyph->object;
6818 help_echo_pos = glyph->charpos;
6819 }
06a2c219
GM
6820
6821 /* Change the mouse pointer according to what is under X/Y. */
6822 map = Fget_text_property (make_number (glyph->charpos),
6823 Qlocal_map, glyph->object);
02067692 6824 if (KEYMAPP (map))
06a2c219 6825 cursor = f->output_data.x->nontext_cursor;
be010514
GM
6826 else
6827 {
6828 map = Fget_text_property (make_number (glyph->charpos),
6829 Qkeymap, glyph->object);
02067692 6830 if (KEYMAPP (map))
be010514
GM
6831 cursor = f->output_data.x->nontext_cursor;
6832 }
06a2c219
GM
6833 }
6834 }
6835
6836 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6837}
6838
6839
6840/* Take proper action when the mouse has moved to position X, Y on
6841 frame F as regards highlighting characters that have mouse-face
6842 properties. Also de-highlighting chars where the mouse was before.
27f338af 6843 X and Y can be negative or out of range. */
b8009dd1
RS
6844
6845static void
6846note_mouse_highlight (f, x, y)
06a2c219 6847 struct frame *f;
c32cdd9a 6848 int x, y;
b8009dd1 6849{
06a2c219
GM
6850 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6851 int portion;
b8009dd1
RS
6852 Lisp_Object window;
6853 struct window *w;
0d487c52
GM
6854 Cursor cursor = None;
6855 struct buffer *b;
b8009dd1 6856
06a2c219
GM
6857 /* When a menu is active, don't highlight because this looks odd. */
6858#ifdef USE_X_TOOLKIT
6859 if (popup_activated ())
6860 return;
6861#endif
6862
04fff9c0
GM
6863 if (disable_mouse_highlight
6864 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6865 return;
6866
06a2c219
GM
6867 dpyinfo->mouse_face_mouse_x = x;
6868 dpyinfo->mouse_face_mouse_y = y;
6869 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6870
06a2c219 6871 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6872 return;
6873
514e4681
RS
6874 if (gc_in_progress)
6875 {
06a2c219 6876 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6877 return;
6878 }
6879
b8009dd1 6880 /* Which window is that in? */
06a2c219 6881 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6882
6883 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6884 if (! EQ (window, dpyinfo->mouse_face_window))
6885 clear_mouse_face (dpyinfo);
6886
6887 /* Not on a window -> return. */
6888 if (!WINDOWP (window))
6889 return;
6890
6891 /* Convert to window-relative pixel coordinates. */
6892 w = XWINDOW (window);
6893 frame_to_window_pixel_xy (w, &x, &y);
6894
9ea173e8 6895 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6896 buffer. */
9ea173e8 6897 if (EQ (window, f->tool_bar_window))
06a2c219 6898 {
9ea173e8 6899 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6900 return;
6901 }
6902
0d487c52 6903 /* Mouse is on the mode or header line? */
06a2c219
GM
6904 if (portion == 1 || portion == 3)
6905 {
06a2c219
GM
6906 note_mode_line_highlight (w, x, portion == 1);
6907 return;
6908 }
0d487c52
GM
6909
6910 if (portion == 2)
6911 cursor = f->output_data.x->horizontal_drag_cursor;
06a2c219 6912 else
0d487c52 6913 cursor = f->output_data.x->text_cursor;
b8009dd1 6914
0cdd0c9f
RS
6915 /* Are we in a window whose display is up to date?
6916 And verify the buffer's text has not changed. */
0d487c52 6917 b = XBUFFER (w->buffer);
06a2c219
GM
6918 if (/* Within text portion of the window. */
6919 portion == 0
0cdd0c9f 6920 && EQ (w->window_end_valid, w->buffer)
0d487c52
GM
6921 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
6922 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
b8009dd1 6923 {
06a2c219
GM
6924 int hpos, vpos, pos, i, area;
6925 struct glyph *glyph;
f9db2310 6926 Lisp_Object object;
0d487c52
GM
6927 Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
6928 Lisp_Object *overlay_vec = NULL;
6929 int len, noverlays;
6930 struct buffer *obuf;
6931 int obegv, ozv, same_region;
b8009dd1 6932
06a2c219 6933 /* Find the glyph under X/Y. */
f9db2310 6934 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
06a2c219
GM
6935
6936 /* Clear mouse face if X/Y not over text. */
6937 if (glyph == NULL
6938 || area != TEXT_AREA
6939 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6940 {
fa262c07
GM
6941 if (clear_mouse_face (dpyinfo))
6942 cursor = None;
6943 goto set_cursor;
06a2c219
GM
6944 }
6945
6946 pos = glyph->charpos;
f9db2310
GM
6947 object = glyph->object;
6948 if (!STRINGP (object) && !BUFFERP (object))
fa262c07 6949 goto set_cursor;
06a2c219 6950
0d487c52
GM
6951 /* If we get an out-of-range value, return now; avoid an error. */
6952 if (BUFFERP (object) && pos > BUF_Z (b))
fa262c07 6953 goto set_cursor;
06a2c219 6954
0d487c52
GM
6955 /* Make the window's buffer temporarily current for
6956 overlays_at and compute_char_face. */
6957 obuf = current_buffer;
6958 current_buffer = b;
6959 obegv = BEGV;
6960 ozv = ZV;
6961 BEGV = BEG;
6962 ZV = Z;
06a2c219 6963
0d487c52
GM
6964 /* Is this char mouse-active or does it have help-echo? */
6965 position = make_number (pos);
f9db2310 6966
0d487c52
GM
6967 if (BUFFERP (object))
6968 {
6969 /* Put all the overlays we want in a vector in overlay_vec.
6970 Store the length in len. If there are more than 10, make
6971 enough space for all, and try again. */
6972 len = 10;
6973 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6974 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
6975 if (noverlays > len)
6976 {
6977 len = noverlays;
6978 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6979 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
6980 }
f8349001 6981
0d487c52
GM
6982 /* Sort overlays into increasing priority order. */
6983 noverlays = sort_overlays (overlay_vec, noverlays, w);
6984 }
6985 else
6986 noverlays = 0;
6987
6988 same_region = (EQ (window, dpyinfo->mouse_face_window)
6989 && vpos >= dpyinfo->mouse_face_beg_row
6990 && vpos <= dpyinfo->mouse_face_end_row
6991 && (vpos > dpyinfo->mouse_face_beg_row
6992 || hpos >= dpyinfo->mouse_face_beg_col)
6993 && (vpos < dpyinfo->mouse_face_end_row
6994 || hpos < dpyinfo->mouse_face_end_col
6995 || dpyinfo->mouse_face_past_end));
6996
6997 if (same_region)
6998 cursor = None;
6999
7000 /* Check mouse-face highlighting. */
7001 if (! same_region
7002 /* If there exists an overlay with mouse-face overlapping
7003 the one we are currently highlighting, we have to
7004 check if we enter the overlapping overlay, and then
7005 highlight only that. */
7006 || (OVERLAYP (dpyinfo->mouse_face_overlay)
7007 && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
7008 {
0d487c52
GM
7009 /* Find the highest priority overlay that has a mouse-face
7010 property. */
7011 overlay = Qnil;
7012 for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
7013 {
7014 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
7015 if (!NILP (mouse_face))
7016 overlay = overlay_vec[i];
7017 }
8bd189fb
GM
7018
7019 /* If we're actually highlighting the same overlay as
7020 before, there's no need to do that again. */
7021 if (!NILP (overlay)
7022 && EQ (overlay, dpyinfo->mouse_face_overlay))
7023 goto check_help_echo;
f9db2310 7024
8bd189fb
GM
7025 dpyinfo->mouse_face_overlay = overlay;
7026
7027 /* Clear the display of the old active region, if any. */
7028 if (clear_mouse_face (dpyinfo))
7029 cursor = None;
7030
0d487c52
GM
7031 /* If no overlay applies, get a text property. */
7032 if (NILP (overlay))
7033 mouse_face = Fget_text_property (position, Qmouse_face, object);
06a2c219 7034
0d487c52
GM
7035 /* Handle the overlay case. */
7036 if (!NILP (overlay))
7037 {
7038 /* Find the range of text around this char that
7039 should be active. */
7040 Lisp_Object before, after;
7041 int ignore;
7042
7043 before = Foverlay_start (overlay);
7044 after = Foverlay_end (overlay);
7045 /* Record this as the current active region. */
7046 fast_find_position (w, XFASTINT (before),
7047 &dpyinfo->mouse_face_beg_col,
7048 &dpyinfo->mouse_face_beg_row,
7049 &dpyinfo->mouse_face_beg_x,
7e376260
GM
7050 &dpyinfo->mouse_face_beg_y, Qnil);
7051
0d487c52
GM
7052 dpyinfo->mouse_face_past_end
7053 = !fast_find_position (w, XFASTINT (after),
7054 &dpyinfo->mouse_face_end_col,
7055 &dpyinfo->mouse_face_end_row,
7056 &dpyinfo->mouse_face_end_x,
7e376260 7057 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7058 dpyinfo->mouse_face_window = window;
7059 dpyinfo->mouse_face_face_id
7060 = face_at_buffer_position (w, pos, 0, 0,
7061 &ignore, pos + 1, 1);
7062
7063 /* Display it as active. */
7064 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7065 cursor = None;
0d487c52
GM
7066 }
7067 /* Handle the text property case. */
7068 else if (!NILP (mouse_face) && BUFFERP (object))
7069 {
7070 /* Find the range of text around this char that
7071 should be active. */
7072 Lisp_Object before, after, beginning, end;
7073 int ignore;
7074
7075 beginning = Fmarker_position (w->start);
7076 end = make_number (BUF_Z (XBUFFER (object))
7077 - XFASTINT (w->window_end_pos));
7078 before
7079 = Fprevious_single_property_change (make_number (pos + 1),
7080 Qmouse_face,
7081 object, beginning);
7082 after
7083 = Fnext_single_property_change (position, Qmouse_face,
7084 object, end);
7085
7086 /* Record this as the current active region. */
7087 fast_find_position (w, XFASTINT (before),
7088 &dpyinfo->mouse_face_beg_col,
7089 &dpyinfo->mouse_face_beg_row,
7090 &dpyinfo->mouse_face_beg_x,
7e376260 7091 &dpyinfo->mouse_face_beg_y, Qnil);
0d487c52
GM
7092 dpyinfo->mouse_face_past_end
7093 = !fast_find_position (w, XFASTINT (after),
7094 &dpyinfo->mouse_face_end_col,
7095 &dpyinfo->mouse_face_end_row,
7096 &dpyinfo->mouse_face_end_x,
7e376260 7097 &dpyinfo->mouse_face_end_y, Qnil);
0d487c52
GM
7098 dpyinfo->mouse_face_window = window;
7099
7100 if (BUFFERP (object))
06a2c219
GM
7101 dpyinfo->mouse_face_face_id
7102 = face_at_buffer_position (w, pos, 0, 0,
7103 &ignore, pos + 1, 1);
7104
0d487c52
GM
7105 /* Display it as active. */
7106 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7107 cursor = None;
0d487c52
GM
7108 }
7109 else if (!NILP (mouse_face) && STRINGP (object))
7110 {
7111 Lisp_Object b, e;
7112 int ignore;
f9db2310 7113
0d487c52
GM
7114 b = Fprevious_single_property_change (make_number (pos + 1),
7115 Qmouse_face,
7116 object, Qnil);
7117 e = Fnext_single_property_change (position, Qmouse_face,
7118 object, Qnil);
7119 if (NILP (b))
7120 b = make_number (0);
7121 if (NILP (e))
7122 e = make_number (XSTRING (object)->size - 1);
7123 fast_find_string_pos (w, XINT (b), object,
06a2c219
GM
7124 &dpyinfo->mouse_face_beg_col,
7125 &dpyinfo->mouse_face_beg_row,
7126 &dpyinfo->mouse_face_beg_x,
0d487c52
GM
7127 &dpyinfo->mouse_face_beg_y, 0);
7128 fast_find_string_pos (w, XINT (e), object,
7129 &dpyinfo->mouse_face_end_col,
7130 &dpyinfo->mouse_face_end_row,
7131 &dpyinfo->mouse_face_end_x,
7132 &dpyinfo->mouse_face_end_y, 1);
7133 dpyinfo->mouse_face_past_end = 0;
7134 dpyinfo->mouse_face_window = window;
7135 dpyinfo->mouse_face_face_id
7136 = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
7137 glyph->face_id, 1);
7138 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7139 cursor = None;
0d487c52 7140 }
7e376260
GM
7141 else if (STRINGP (object) && NILP (mouse_face))
7142 {
7143 /* A string which doesn't have mouse-face, but
7144 the text ``under'' it might have. */
7145 struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
7146 int start = MATRIX_ROW_START_CHARPOS (r);
7147
7148 pos = string_buffer_position (w, object, start);
7149 if (pos > 0)
7150 mouse_face = get_char_property_and_overlay (make_number (pos),
7151 Qmouse_face,
7152 w->buffer,
7153 &overlay);
7154 if (!NILP (mouse_face) && !NILP (overlay))
7155 {
7156 Lisp_Object before = Foverlay_start (overlay);
7157 Lisp_Object after = Foverlay_end (overlay);
7158 Lisp_Object ignore;
7159
7160 /* Note that we might not be able to find position
7161 BEFORE in the glyph matrix if the overlay is
7162 entirely covered by a `display' property. In
7163 this case, we overshoot. So let's stop in
7164 the glyph matrix before glyphs for OBJECT. */
7165 fast_find_position (w, XFASTINT (before),
7166 &dpyinfo->mouse_face_beg_col,
7167 &dpyinfo->mouse_face_beg_row,
7168 &dpyinfo->mouse_face_beg_x,
7169 &dpyinfo->mouse_face_beg_y,
7170 object);
7171
7172 dpyinfo->mouse_face_past_end
7173 = !fast_find_position (w, XFASTINT (after),
7174 &dpyinfo->mouse_face_end_col,
7175 &dpyinfo->mouse_face_end_row,
7176 &dpyinfo->mouse_face_end_x,
7177 &dpyinfo->mouse_face_end_y,
7178 Qnil);
7179 dpyinfo->mouse_face_window = window;
7180 dpyinfo->mouse_face_face_id
7181 = face_at_buffer_position (w, pos, 0, 0,
7182 &ignore, pos + 1, 1);
7183
7184 /* Display it as active. */
7185 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
7186 cursor = None;
7187 }
7188 }
0d487c52 7189 }
06a2c219 7190
8bd189fb
GM
7191 check_help_echo:
7192
0d487c52
GM
7193 /* Look for a `help-echo' property. */
7194 {
7195 Lisp_Object help, overlay;
06a2c219 7196
0d487c52
GM
7197 /* Check overlays first. */
7198 help = overlay = Qnil;
7199 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
7200 {
7201 overlay = overlay_vec[i];
7202 help = Foverlay_get (overlay, Qhelp_echo);
7203 }
be010514 7204
0d487c52
GM
7205 if (!NILP (help))
7206 {
7207 help_echo = help;
7208 help_echo_window = window;
7209 help_echo_object = overlay;
7210 help_echo_pos = pos;
7211 }
7212 else
7213 {
7214 Lisp_Object object = glyph->object;
7215 int charpos = glyph->charpos;
7177d86b 7216
0d487c52
GM
7217 /* Try text properties. */
7218 if (STRINGP (object)
7219 && charpos >= 0
7220 && charpos < XSTRING (object)->size)
7221 {
7222 help = Fget_text_property (make_number (charpos),
7223 Qhelp_echo, object);
7224 if (NILP (help))
7225 {
7226 /* If the string itself doesn't specify a help-echo,
7227 see if the buffer text ``under'' it does. */
7228 struct glyph_row *r
7229 = MATRIX_ROW (w->current_matrix, vpos);
7230 int start = MATRIX_ROW_START_CHARPOS (r);
7231 int pos = string_buffer_position (w, object, start);
7232 if (pos > 0)
7233 {
7e376260 7234 help = Fget_char_property (make_number (pos),
0d487c52
GM
7235 Qhelp_echo, w->buffer);
7236 if (!NILP (help))
7237 {
7238 charpos = pos;
7239 object = w->buffer;
7240 }
7241 }
7242 }
7243 }
7244 else if (BUFFERP (object)
7245 && charpos >= BEGV
7246 && charpos < ZV)
7247 help = Fget_text_property (make_number (charpos), Qhelp_echo,
7248 object);
06a2c219 7249
0d487c52
GM
7250 if (!NILP (help))
7251 {
7252 help_echo = help;
7253 help_echo_window = window;
7254 help_echo_object = object;
7255 help_echo_pos = charpos;
7256 }
7257 }
06a2c219 7258 }
0d487c52
GM
7259
7260 BEGV = obegv;
7261 ZV = ozv;
7262 current_buffer = obuf;
06a2c219 7263 }
0d487c52 7264
fa262c07
GM
7265 set_cursor:
7266
0d487c52
GM
7267 if (cursor != None)
7268 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
06a2c219
GM
7269}
7270
7271static void
7272redo_mouse_highlight ()
7273{
7274 if (!NILP (last_mouse_motion_frame)
7275 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
7276 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
7277 last_mouse_motion_event.x,
7278 last_mouse_motion_event.y);
7279}
7280
7281
7282\f
7283/***********************************************************************
9ea173e8 7284 Tool-bars
06a2c219
GM
7285 ***********************************************************************/
7286
9ea173e8
GM
7287static int x_tool_bar_item P_ ((struct frame *, int, int,
7288 struct glyph **, int *, int *, int *));
06a2c219 7289
9ea173e8 7290/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
7291 or -1. */
7292
9ea173e8 7293static int last_tool_bar_item;
06a2c219
GM
7294
7295
9ea173e8
GM
7296/* Get information about the tool-bar item at position X/Y on frame F.
7297 Return in *GLYPH a pointer to the glyph of the tool-bar item in
7298 the current matrix of the tool-bar window of F, or NULL if not
7299 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
8daf1204 7300 item in F->tool_bar_items. Value is
06a2c219 7301
9ea173e8 7302 -1 if X/Y is not on a tool-bar item
06a2c219
GM
7303 0 if X/Y is on the same item that was highlighted before.
7304 1 otherwise. */
7305
7306static int
9ea173e8 7307x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
7308 struct frame *f;
7309 int x, y;
7310 struct glyph **glyph;
7311 int *hpos, *vpos, *prop_idx;
7312{
7313 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7314 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7315 int area;
7316
7317 /* Find the glyph under X/Y. */
f9db2310 7318 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
06a2c219
GM
7319 if (*glyph == NULL)
7320 return -1;
7321
9ea173e8 7322 /* Get the start of this tool-bar item's properties in
8daf1204 7323 f->tool_bar_items. */
9ea173e8 7324 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
7325 return -1;
7326
7327 /* Is mouse on the highlighted item? */
9ea173e8 7328 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
7329 && *vpos >= dpyinfo->mouse_face_beg_row
7330 && *vpos <= dpyinfo->mouse_face_end_row
7331 && (*vpos > dpyinfo->mouse_face_beg_row
7332 || *hpos >= dpyinfo->mouse_face_beg_col)
7333 && (*vpos < dpyinfo->mouse_face_end_row
7334 || *hpos < dpyinfo->mouse_face_end_col
7335 || dpyinfo->mouse_face_past_end))
7336 return 0;
7337
7338 return 1;
7339}
7340
7341
9ea173e8 7342/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
7343 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
7344 or ButtonRelase. */
7345
7346static void
9ea173e8 7347x_handle_tool_bar_click (f, button_event)
06a2c219
GM
7348 struct frame *f;
7349 XButtonEvent *button_event;
7350{
7351 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7352 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7353 int hpos, vpos, prop_idx;
7354 struct glyph *glyph;
7355 Lisp_Object enabled_p;
7356 int x = button_event->x;
7357 int y = button_event->y;
7358
9ea173e8 7359 /* If not on the highlighted tool-bar item, return. */
06a2c219 7360 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 7361 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
7362 return;
7363
7364 /* If item is disabled, do nothing. */
8daf1204 7365 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7366 if (NILP (enabled_p))
7367 return;
7368
7369 if (button_event->type == ButtonPress)
7370 {
7371 /* Show item in pressed state. */
7372 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
7373 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 7374 last_tool_bar_item = prop_idx;
06a2c219
GM
7375 }
7376 else
7377 {
7378 Lisp_Object key, frame;
7379 struct input_event event;
7380
7381 /* Show item in released state. */
7382 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
7383 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
7384
8daf1204 7385 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
06a2c219
GM
7386
7387 XSETFRAME (frame, f);
9ea173e8 7388 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7389 event.frame_or_window = frame;
7390 event.arg = frame;
06a2c219
GM
7391 kbd_buffer_store_event (&event);
7392
9ea173e8 7393 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7394 event.frame_or_window = frame;
7395 event.arg = key;
06a2c219
GM
7396 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7397 button_event->state);
7398 kbd_buffer_store_event (&event);
9ea173e8 7399 last_tool_bar_item = -1;
06a2c219
GM
7400 }
7401}
7402
7403
9ea173e8
GM
7404/* Possibly highlight a tool-bar item on frame F when mouse moves to
7405 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
7406 note_mouse_highlight. */
7407
7408static void
9ea173e8 7409note_tool_bar_highlight (f, x, y)
06a2c219
GM
7410 struct frame *f;
7411 int x, y;
7412{
9ea173e8 7413 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
7414 struct window *w = XWINDOW (window);
7415 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7416 int hpos, vpos;
7417 struct glyph *glyph;
7418 struct glyph_row *row;
5c187dee 7419 int i;
06a2c219
GM
7420 Lisp_Object enabled_p;
7421 int prop_idx;
140330de 7422 enum draw_glyphs_face draw;
5c187dee 7423 int mouse_down_p, rc;
06a2c219
GM
7424
7425 /* Function note_mouse_highlight is called with negative x(y
7426 values when mouse moves outside of the frame. */
7427 if (x <= 0 || y <= 0)
7428 {
7429 clear_mouse_face (dpyinfo);
7430 return;
7431 }
7432
9ea173e8 7433 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
7434 if (rc < 0)
7435 {
9ea173e8 7436 /* Not on tool-bar item. */
06a2c219
GM
7437 clear_mouse_face (dpyinfo);
7438 return;
7439 }
7440 else if (rc == 0)
06a2c219 7441 goto set_help_echo;
b8009dd1 7442
06a2c219
GM
7443 clear_mouse_face (dpyinfo);
7444
9ea173e8 7445 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
7446 mouse_down_p = (dpyinfo->grabbed
7447 && f == last_mouse_frame
7448 && FRAME_LIVE_P (f));
7449 if (mouse_down_p
9ea173e8 7450 && last_tool_bar_item != prop_idx)
06a2c219
GM
7451 return;
7452
7453 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7454 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7455
9ea173e8 7456 /* If tool-bar item is not enabled, don't highlight it. */
8daf1204 7457 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7458 if (!NILP (enabled_p))
7459 {
7460 /* Compute the x-position of the glyph. In front and past the
7461 image is a space. We include this is the highlighted area. */
7462 row = MATRIX_ROW (w->current_matrix, vpos);
7463 for (i = x = 0; i < hpos; ++i)
7464 x += row->glyphs[TEXT_AREA][i].pixel_width;
7465
7466 /* Record this as the current active region. */
7467 dpyinfo->mouse_face_beg_col = hpos;
7468 dpyinfo->mouse_face_beg_row = vpos;
7469 dpyinfo->mouse_face_beg_x = x;
7470 dpyinfo->mouse_face_beg_y = row->y;
7471 dpyinfo->mouse_face_past_end = 0;
7472
7473 dpyinfo->mouse_face_end_col = hpos + 1;
7474 dpyinfo->mouse_face_end_row = vpos;
7475 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7476 dpyinfo->mouse_face_end_y = row->y;
7477 dpyinfo->mouse_face_window = window;
9ea173e8 7478 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
7479
7480 /* Display it as active. */
7481 show_mouse_face (dpyinfo, draw);
7482 dpyinfo->mouse_face_image_state = draw;
b8009dd1 7483 }
06a2c219
GM
7484
7485 set_help_echo:
7486
9ea173e8 7487 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 7488 XTread_socket does the rest. */
7cea38bc 7489 help_echo_object = help_echo_window = Qnil;
be010514 7490 help_echo_pos = -1;
8daf1204 7491 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
b7e80413 7492 if (NILP (help_echo))
8daf1204 7493 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
b8009dd1 7494}
4d73d038 7495
06a2c219
GM
7496
7497\f
9f8531e5
GM
7498/* Find the glyph matrix position of buffer position CHARPOS in window
7499 *W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7500 current glyphs must be up to date. If CHARPOS is above window
7501 start return (0, 0, 0, 0). If CHARPOS is after end of W, return end
7502 of last line in W. In the row containing CHARPOS, stop before glyphs
7e376260 7503 having STOP as object. */
b8009dd1 7504
9f8531e5
GM
7505#if 0 /* This is a version of fast_find_position that's more correct
7506 in the presence of hscrolling, for example. I didn't install
7507 it right away because the problem fixed is minor, it failed
7508 in 20.x as well, and I think it's too risky to install
7509 so near the release of 21.1. 2001-09-25 gerd. */
7510
7511static int
7512fast_find_position (w, charpos, hpos, vpos, x, y, stop)
7513 struct window *w;
7514 int charpos;
7515 int *hpos, *vpos, *x, *y;
7516 Lisp_Object stop;
7517{
7518 struct glyph_row *row, *first;
7519 struct glyph *glyph, *end;
7520 int i, past_end = 0;
7521
7522 first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7523 row = row_containing_pos (w, charpos, first, NULL);
7524 if (row == NULL)
7525 {
7526 if (charpos < MATRIX_ROW_START_CHARPOS (first))
7527 {
7528 *x = *y = *hpos = *vpos = 0;
7529 return 0;
7530 }
7531 else
7532 {
7533 row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
7534 past_end = 1;
7535 }
7536 }
7537
7538 *x = row->x;
7539 *y = row->y;
7540 *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7541
7542 glyph = row->glyphs[TEXT_AREA];
7543 end = glyph + row->used[TEXT_AREA];
7544
7545 /* Skip over glyphs not having an object at the start of the row.
7546 These are special glyphs like truncation marks on terminal
7547 frames. */
7548 if (row->displays_text_p)
7549 while (glyph < end
7550 && INTEGERP (glyph->object)
7551 && !EQ (stop, glyph->object)
7552 && glyph->charpos < 0)
7553 {
7554 *x += glyph->pixel_width;
7555 ++glyph;
7556 }
7557
7558 while (glyph < end
7559 && !INTEGERP (glyph->object)
7560 && !EQ (stop, glyph->object)
7561 && (!BUFFERP (glyph->object)
7562 || glyph->charpos < charpos))
7563 {
7564 *x += glyph->pixel_width;
7565 ++glyph;
7566 }
7567
7568 *hpos = glyph - row->glyphs[TEXT_AREA];
7569 return past_end;
7570}
7571
7572#else /* not 0 */
7573
b8009dd1 7574static int
7e376260 7575fast_find_position (w, pos, hpos, vpos, x, y, stop)
06a2c219 7576 struct window *w;
b8009dd1 7577 int pos;
06a2c219 7578 int *hpos, *vpos, *x, *y;
7e376260 7579 Lisp_Object stop;
b8009dd1 7580{
b8009dd1 7581 int i;
bf1c0ba1 7582 int lastcol;
06a2c219
GM
7583 int maybe_next_line_p = 0;
7584 int line_start_position;
7585 int yb = window_text_bottom_y (w);
03d1a189
GM
7586 struct glyph_row *row, *best_row;
7587 int row_vpos, best_row_vpos;
06a2c219
GM
7588 int current_x;
7589
03d1a189
GM
7590 row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7591 row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7592
06a2c219 7593 while (row->y < yb)
b8009dd1 7594 {
06a2c219
GM
7595 if (row->used[TEXT_AREA])
7596 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7597 else
7598 line_start_position = 0;
7599
7600 if (line_start_position > pos)
b8009dd1 7601 break;
77b68646
RS
7602 /* If the position sought is the end of the buffer,
7603 don't include the blank lines at the bottom of the window. */
06a2c219
GM
7604 else if (line_start_position == pos
7605 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 7606 {
06a2c219 7607 maybe_next_line_p = 1;
77b68646
RS
7608 break;
7609 }
06a2c219
GM
7610 else if (line_start_position > 0)
7611 {
7612 best_row = row;
7613 best_row_vpos = row_vpos;
7614 }
4b0bb6f3
GM
7615
7616 if (row->y + row->height >= yb)
7617 break;
06a2c219
GM
7618
7619 ++row;
7620 ++row_vpos;
b8009dd1 7621 }
06a2c219
GM
7622
7623 /* Find the right column within BEST_ROW. */
7624 lastcol = 0;
7625 current_x = best_row->x;
7626 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 7627 {
06a2c219 7628 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7e376260 7629 int charpos = glyph->charpos;
06a2c219 7630
7e376260 7631 if (BUFFERP (glyph->object))
bf1c0ba1 7632 {
7e376260
GM
7633 if (charpos == pos)
7634 {
7635 *hpos = i;
7636 *vpos = best_row_vpos;
7637 *x = current_x;
7638 *y = best_row->y;
7639 return 1;
7640 }
7641 else if (charpos > pos)
7642 break;
bf1c0ba1 7643 }
7e376260 7644 else if (EQ (glyph->object, stop))
4d73d038 7645 break;
06a2c219 7646
7e376260
GM
7647 if (charpos > 0)
7648 lastcol = i;
06a2c219 7649 current_x += glyph->pixel_width;
bf1c0ba1 7650 }
b8009dd1 7651
77b68646
RS
7652 /* If we're looking for the end of the buffer,
7653 and we didn't find it in the line we scanned,
7654 use the start of the following line. */
06a2c219 7655 if (maybe_next_line_p)
77b68646 7656 {
06a2c219
GM
7657 ++best_row;
7658 ++best_row_vpos;
7659 lastcol = 0;
7660 current_x = best_row->x;
77b68646
RS
7661 }
7662
06a2c219
GM
7663 *vpos = best_row_vpos;
7664 *hpos = lastcol + 1;
7665 *x = current_x;
7666 *y = best_row->y;
b8009dd1
RS
7667 return 0;
7668}
7669
9f8531e5
GM
7670#endif /* not 0 */
7671
06a2c219 7672
f9db2310
GM
7673/* Find the position of the the glyph for position POS in OBJECT in
7674 window W's current matrix, and return in *X/*Y the pixel
7675 coordinates, and return in *HPOS/*VPOS the column/row of the glyph.
7676
7677 RIGHT_P non-zero means return the position of the right edge of the
7678 glyph, RIGHT_P zero means return the left edge position.
7679
7680 If no glyph for POS exists in the matrix, return the position of
7681 the glyph with the next smaller position that is in the matrix, if
7682 RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS
7683 exists in the matrix, return the position of the glyph with the
7684 next larger position in OBJECT.
7685
7686 Value is non-zero if a glyph was found. */
7687
7688static int
7689fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
7690 struct window *w;
7691 int pos;
7692 Lisp_Object object;
7693 int *hpos, *vpos, *x, *y;
7694 int right_p;
7695{
7696 int yb = window_text_bottom_y (w);
7697 struct glyph_row *r;
7698 struct glyph *best_glyph = NULL;
7699 struct glyph_row *best_row = NULL;
7700 int best_x = 0;
7701
7702 for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7703 r->enabled_p && r->y < yb;
7704 ++r)
7705 {
7706 struct glyph *g = r->glyphs[TEXT_AREA];
7707 struct glyph *e = g + r->used[TEXT_AREA];
7708 int gx;
7709
7710 for (gx = r->x; g < e; gx += g->pixel_width, ++g)
7711 if (EQ (g->object, object))
7712 {
7713 if (g->charpos == pos)
7714 {
7715 best_glyph = g;
7716 best_x = gx;
7717 best_row = r;
7718 goto found;
7719 }
7720 else if (best_glyph == NULL
7721 || ((abs (g->charpos - pos)
7722 < abs (best_glyph->charpos - pos))
7723 && (right_p
7724 ? g->charpos < pos
7725 : g->charpos > pos)))
7726 {
7727 best_glyph = g;
7728 best_x = gx;
7729 best_row = r;
7730 }
7731 }
7732 }
7733
7734 found:
7735
7736 if (best_glyph)
7737 {
7738 *x = best_x;
7739 *hpos = best_glyph - best_row->glyphs[TEXT_AREA];
7740
7741 if (right_p)
7742 {
7743 *x += best_glyph->pixel_width;
7744 ++*hpos;
7745 }
7746
7747 *y = best_row->y;
7748 *vpos = best_row - w->current_matrix->rows;
7749 }
7750
7751 return best_glyph != NULL;
7752}
7753
7754
b8009dd1
RS
7755/* Display the active region described by mouse_face_*
7756 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7757
7758static void
06a2c219 7759show_mouse_face (dpyinfo, draw)
7a13e894 7760 struct x_display_info *dpyinfo;
06a2c219 7761 enum draw_glyphs_face draw;
b8009dd1 7762{
7a13e894 7763 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7764 struct frame *f = XFRAME (WINDOW_FRAME (w));
b8009dd1 7765 int i;
06a2c219
GM
7766 int cursor_off_p = 0;
7767 struct cursor_pos saved_cursor;
7768
7769 saved_cursor = output_cursor;
7770
7771 /* If window is in the process of being destroyed, don't bother
7772 to do anything. */
7773 if (w->current_matrix == NULL)
7774 goto set_x_cursor;
7775
7776 /* Recognize when we are called to operate on rows that don't exist
7777 anymore. This can happen when a window is split. */
7778 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
7779 goto set_x_cursor;
7780
7781 set_output_cursor (&w->phys_cursor);
7782
7783 /* Note that mouse_face_beg_row etc. are window relative. */
7784 for (i = dpyinfo->mouse_face_beg_row;
7785 i <= dpyinfo->mouse_face_end_row;
7786 i++)
7787 {
7788 int start_hpos, end_hpos, start_x;
7789 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
7790
7791 /* Don't do anything if row doesn't have valid contents. */
7792 if (!row->enabled_p)
7793 continue;
7794
7795 /* For all but the first row, the highlight starts at column 0. */
7796 if (i == dpyinfo->mouse_face_beg_row)
7797 {
7798 start_hpos = dpyinfo->mouse_face_beg_col;
7799 start_x = dpyinfo->mouse_face_beg_x;
7800 }
7801 else
7802 {
7803 start_hpos = 0;
7804 start_x = 0;
7805 }
7806
7807 if (i == dpyinfo->mouse_face_end_row)
7808 end_hpos = dpyinfo->mouse_face_end_col;
7809 else
7810 end_hpos = row->used[TEXT_AREA];
7811
7812 /* If the cursor's in the text we are about to rewrite, turn the
7813 cursor off. */
7814 if (!w->pseudo_window_p
7815 && i == output_cursor.vpos
7816 && output_cursor.hpos >= start_hpos - 1
7817 && output_cursor.hpos <= end_hpos)
514e4681 7818 {
06a2c219
GM
7819 x_update_window_cursor (w, 0);
7820 cursor_off_p = 1;
514e4681 7821 }
b8009dd1 7822
06a2c219 7823 if (end_hpos > start_hpos)
64f26cf5 7824 {
64f26cf5
GM
7825 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7826 start_hpos, end_hpos, draw, NULL, NULL, 0);
7b0870b2 7827 row->mouse_face_p = draw == DRAW_MOUSE_FACE || DRAW_IMAGE_RAISED;
64f26cf5 7828 }
b8009dd1
RS
7829 }
7830
514e4681 7831 /* If we turned the cursor off, turn it back on. */
06a2c219
GM
7832 if (cursor_off_p)
7833 x_display_cursor (w, 1,
7834 output_cursor.hpos, output_cursor.vpos,
7835 output_cursor.x, output_cursor.y);
2729a2b5 7836
06a2c219 7837 output_cursor = saved_cursor;
fb3b7de5 7838
06a2c219
GM
7839 set_x_cursor:
7840
7841 /* Change the mouse cursor. */
7842 if (draw == DRAW_NORMAL_TEXT)
7843 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7844 f->output_data.x->text_cursor);
7845 else if (draw == DRAW_MOUSE_FACE)
334208b7 7846 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7847 f->output_data.x->cross_cursor);
27ead1d5 7848 else
334208b7 7849 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7850 f->output_data.x->nontext_cursor);
b8009dd1
RS
7851}
7852
7853/* Clear out the mouse-highlighted active region.
fa262c07
GM
7854 Redraw it un-highlighted first. Value is non-zero if mouse
7855 face was actually drawn unhighlighted. */
b8009dd1 7856
fa262c07 7857static int
7a13e894
RS
7858clear_mouse_face (dpyinfo)
7859 struct x_display_info *dpyinfo;
b8009dd1 7860{
fa262c07 7861 int cleared = 0;
06a2c219 7862
fa262c07
GM
7863 if (!NILP (dpyinfo->mouse_face_window))
7864 {
7865 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
7866 cleared = 1;
7867 }
b8009dd1 7868
7a13e894
RS
7869 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7870 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7871 dpyinfo->mouse_face_window = Qnil;
1b85dc1c 7872 dpyinfo->mouse_face_overlay = Qnil;
fa262c07 7873 return cleared;
b8009dd1 7874}
e687d06e 7875
71b8321e
GM
7876
7877/* Clear any mouse-face on window W. This function is part of the
7878 redisplay interface, and is called from try_window_id and similar
7879 functions to ensure the mouse-highlight is off. */
7880
7881static void
7882x_clear_mouse_face (w)
7883 struct window *w;
7884{
7885 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7886 Lisp_Object window;
7887
2e636f9d 7888 BLOCK_INPUT;
71b8321e
GM
7889 XSETWINDOW (window, w);
7890 if (EQ (window, dpyinfo->mouse_face_window))
7891 clear_mouse_face (dpyinfo);
2e636f9d 7892 UNBLOCK_INPUT;
71b8321e
GM
7893}
7894
7895
e687d06e
RS
7896/* Just discard the mouse face information for frame F, if any.
7897 This is used when the size of F is changed. */
7898
dfcf069d 7899void
e687d06e
RS
7900cancel_mouse_face (f)
7901 FRAME_PTR f;
7902{
7903 Lisp_Object window;
7904 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7905
7906 window = dpyinfo->mouse_face_window;
7907 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7908 {
7909 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7910 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7911 dpyinfo->mouse_face_window = Qnil;
7912 }
7913}
b52b65bd 7914
b8009dd1 7915\f
b52b65bd
GM
7916static int glyph_rect P_ ((struct frame *f, int, int, XRectangle *));
7917
7918
7919/* Try to determine frame pixel position and size of the glyph under
7920 frame pixel coordinates X/Y on frame F . Return the position and
7921 size in *RECT. Value is non-zero if we could compute these
7922 values. */
7923
7924static int
7925glyph_rect (f, x, y, rect)
7926 struct frame *f;
7927 int x, y;
7928 XRectangle *rect;
7929{
7930 Lisp_Object window;
7931 int part, found = 0;
7932
7933 window = window_from_coordinates (f, x, y, &part, 0);
7934 if (!NILP (window))
7935 {
7936 struct window *w = XWINDOW (window);
7937 struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7938 struct glyph_row *end = r + w->current_matrix->nrows - 1;
7939 int area;
7940
7941 frame_to_window_pixel_xy (w, &x, &y);
7942
7943 for (; !found && r < end && r->enabled_p; ++r)
7944 if (r->y >= y)
7945 {
7946 struct glyph *g = r->glyphs[TEXT_AREA];
7947 struct glyph *end = g + r->used[TEXT_AREA];
7948 int gx;
7949
7950 for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
7951 if (gx >= x)
7952 {
7953 rect->width = g->pixel_width;
7954 rect->height = r->height;
7955 rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
7956 rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
7957 found = 1;
7958 }
7959 }
7960 }
7961
7962 return found;
7963}
7964
12ba150f 7965
90e65f07 7966/* Return the current position of the mouse.
b52b65bd 7967 *FP should be a frame which indicates which display to ask about.
90e65f07 7968
b52b65bd
GM
7969 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
7970 and *PART to the frame, window, and scroll bar part that the mouse
7971 is over. Set *X and *Y to the portion and whole of the mouse's
ab648270 7972 position on the scroll bar.
12ba150f 7973
b52b65bd
GM
7974 If the mouse movement started elsewhere, set *FP to the frame the
7975 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
12ba150f
JB
7976 the mouse is over.
7977
b52b65bd 7978 Set *TIME to the server time-stamp for the time at which the mouse
12ba150f
JB
7979 was at this position.
7980
a135645a
RS
7981 Don't store anything if we don't have a valid set of values to report.
7982
90e65f07 7983 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7984 movement. */
90e65f07
JB
7985
7986static void
1cf412ec 7987XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7988 FRAME_PTR *fp;
1cf412ec 7989 int insist;
12ba150f 7990 Lisp_Object *bar_window;
ab648270 7991 enum scroll_bar_part *part;
90e65f07 7992 Lisp_Object *x, *y;
e5d77022 7993 unsigned long *time;
90e65f07 7994{
a135645a
RS
7995 FRAME_PTR f1;
7996
90e65f07
JB
7997 BLOCK_INPUT;
7998
8bcee03e 7999 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 8000 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
8001 else
8002 {
12ba150f
JB
8003 Window root;
8004 int root_x, root_y;
90e65f07 8005
12ba150f
JB
8006 Window dummy_window;
8007 int dummy;
8008
39d8bb4d
KH
8009 Lisp_Object frame, tail;
8010
8011 /* Clear the mouse-moved flag for every frame on this display. */
8012 FOR_EACH_FRAME (tail, frame)
8013 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
8014 XFRAME (frame)->mouse_moved = 0;
8015
ab648270 8016 last_mouse_scroll_bar = Qnil;
12ba150f
JB
8017
8018 /* Figure out which root window we're on. */
334208b7
RS
8019 XQueryPointer (FRAME_X_DISPLAY (*fp),
8020 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
8021
8022 /* The root window which contains the pointer. */
8023 &root,
8024
8025 /* Trash which we can't trust if the pointer is on
8026 a different screen. */
8027 &dummy_window,
8028
8029 /* The position on that root window. */
58769bee 8030 &root_x, &root_y,
12ba150f
JB
8031
8032 /* More trash we can't trust. */
8033 &dummy, &dummy,
8034
8035 /* Modifier keys and pointer buttons, about which
8036 we don't care. */
8037 (unsigned int *) &dummy);
8038
8039 /* Now we have a position on the root; find the innermost window
8040 containing the pointer. */
8041 {
8042 Window win, child;
8043 int win_x, win_y;
06a2c219 8044 int parent_x = 0, parent_y = 0;
e99db5a1 8045 int count;
12ba150f
JB
8046
8047 win = root;
69388238 8048
2d7fc7e8
RS
8049 /* XTranslateCoordinates can get errors if the window
8050 structure is changing at the same time this function
8051 is running. So at least we must not crash from them. */
8052
e99db5a1 8053 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 8054
334208b7 8055 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 8056 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 8057 {
69388238
RS
8058 /* If mouse was grabbed on a frame, give coords for that frame
8059 even if the mouse is now outside it. */
334208b7 8060 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 8061
12ba150f 8062 /* From-window, to-window. */
69388238 8063 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
8064
8065 /* From-position, to-position. */
8066 root_x, root_y, &win_x, &win_y,
8067
8068 /* Child of win. */
8069 &child);
69388238
RS
8070 f1 = last_mouse_frame;
8071 }
8072 else
8073 {
8074 while (1)
8075 {
334208b7 8076 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 8077
69388238
RS
8078 /* From-window, to-window. */
8079 root, win,
12ba150f 8080
69388238
RS
8081 /* From-position, to-position. */
8082 root_x, root_y, &win_x, &win_y,
8083
8084 /* Child of win. */
8085 &child);
8086
9af3143a 8087 if (child == None || child == win)
69388238
RS
8088 break;
8089
8090 win = child;
8091 parent_x = win_x;
8092 parent_y = win_y;
8093 }
12ba150f 8094
69388238
RS
8095 /* Now we know that:
8096 win is the innermost window containing the pointer
8097 (XTC says it has no child containing the pointer),
8098 win_x and win_y are the pointer's position in it
8099 (XTC did this the last time through), and
8100 parent_x and parent_y are the pointer's position in win's parent.
8101 (They are what win_x and win_y were when win was child.
8102 If win is the root window, it has no parent, and
8103 parent_{x,y} are invalid, but that's okay, because we'll
8104 never use them in that case.) */
8105
8106 /* Is win one of our frames? */
19126e11 8107 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
aad0f6ab
GM
8108
8109#ifdef USE_X_TOOLKIT
8110 /* If we end up with the menu bar window, say it's not
8111 on the frame. */
8112 if (f1 != NULL
8113 && f1->output_data.x->menubar_widget
8114 && win == XtWindow (f1->output_data.x->menubar_widget))
8115 f1 = NULL;
8116#endif /* USE_X_TOOLKIT */
69388238 8117 }
58769bee 8118
2d7fc7e8
RS
8119 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
8120 f1 = 0;
8121
e99db5a1 8122 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 8123
ab648270 8124 /* If not, is it one of our scroll bars? */
a135645a 8125 if (! f1)
12ba150f 8126 {
ab648270 8127 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
8128
8129 if (bar)
8130 {
a135645a 8131 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
8132 win_x = parent_x;
8133 win_y = parent_y;
8134 }
8135 }
90e65f07 8136
8bcee03e 8137 if (f1 == 0 && insist > 0)
b86bd3dd 8138 f1 = SELECTED_FRAME ();
1cf412ec 8139
a135645a 8140 if (f1)
12ba150f 8141 {
06a2c219
GM
8142 /* Ok, we found a frame. Store all the values.
8143 last_mouse_glyph is a rectangle used to reduce the
8144 generation of mouse events. To not miss any motion
8145 events, we must divide the frame into rectangles of the
8146 size of the smallest character that could be displayed
8147 on it, i.e. into the same rectangles that matrices on
8148 the frame are divided into. */
8149
b52b65bd
GM
8150 int width, height, gx, gy;
8151 XRectangle rect;
8152
8153 if (glyph_rect (f1, win_x, win_y, &rect))
8154 last_mouse_glyph = rect;
8155 else
8156 {
8157 width = FRAME_SMALLEST_CHAR_WIDTH (f1);
8158 height = FRAME_SMALLEST_FONT_HEIGHT (f1);
8159 gx = win_x;
8160 gy = win_y;
06a2c219 8161
b52b65bd
GM
8162 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
8163 round down even for negative values. */
8164 if (gx < 0)
8165 gx -= width - 1;
4f00e84d 8166 if (gy < 0)
b52b65bd
GM
8167 gy -= height - 1;
8168 gx = (gx + width - 1) / width * width;
8169 gy = (gy + height - 1) / height * height;
8170
8171 last_mouse_glyph.width = width;
8172 last_mouse_glyph.height = height;
8173 last_mouse_glyph.x = gx;
8174 last_mouse_glyph.y = gy;
8175 }
12ba150f
JB
8176
8177 *bar_window = Qnil;
8178 *part = 0;
334208b7 8179 *fp = f1;
e0c1aef2
KH
8180 XSETINT (*x, win_x);
8181 XSETINT (*y, win_y);
12ba150f
JB
8182 *time = last_mouse_movement_time;
8183 }
8184 }
8185 }
90e65f07
JB
8186
8187 UNBLOCK_INPUT;
8188}
f451eb13 8189
06a2c219 8190
06a2c219 8191#ifdef USE_X_TOOLKIT
bffcfca9
GM
8192
8193/* Atimer callback function for TIMER. Called every 0.1s to process
8194 Xt timeouts, if needed. We must avoid calling XtAppPending as
8195 much as possible because that function does an implicit XFlush
8196 that slows us down. */
8197
8198static void
8199x_process_timeouts (timer)
8200 struct atimer *timer;
8201{
8202 if (toolkit_scroll_bar_interaction || popup_activated_flag)
8203 {
8204 BLOCK_INPUT;
8205 while (XtAppPending (Xt_app_con) & XtIMTimer)
8206 XtAppProcessEvent (Xt_app_con, XtIMTimer);
8207 UNBLOCK_INPUT;
8208 }
06a2c219
GM
8209}
8210
bffcfca9 8211#endif /* USE_X_TOOLKIT */
06a2c219
GM
8212
8213\f
8214/* Scroll bar support. */
8215
8216/* Given an X window ID, find the struct scroll_bar which manages it.
8217 This can be called in GC, so we have to make sure to strip off mark
8218 bits. */
bffcfca9 8219
06a2c219
GM
8220static struct scroll_bar *
8221x_window_to_scroll_bar (window_id)
8222 Window window_id;
8223{
8224 Lisp_Object tail;
8225
8226 for (tail = Vframe_list;
8227 XGCTYPE (tail) == Lisp_Cons;
8e713be6 8228 tail = XCDR (tail))
06a2c219
GM
8229 {
8230 Lisp_Object frame, bar, condemned;
8231
8e713be6 8232 frame = XCAR (tail);
06a2c219
GM
8233 /* All elements of Vframe_list should be frames. */
8234 if (! GC_FRAMEP (frame))
8235 abort ();
8236
8237 /* Scan this frame's scroll bar list for a scroll bar with the
8238 right window ID. */
8239 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
8240 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
8241 /* This trick allows us to search both the ordinary and
8242 condemned scroll bar lists with one loop. */
8243 ! GC_NILP (bar) || (bar = condemned,
8244 condemned = Qnil,
8245 ! GC_NILP (bar));
8246 bar = XSCROLL_BAR (bar)->next)
8247 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
8248 return XSCROLL_BAR (bar);
8249 }
8250
8251 return 0;
8252}
8253
8254
c95fc5f1
GM
8255#if defined USE_X_TOOLKIT && defined USE_LUCID
8256
8257/* Return the Lucid menu bar WINDOW is part of. Return null
8258 if WINDOW is not part of a menu bar. */
8259
8260static Widget
8261x_window_to_menu_bar (window)
8262 Window window;
8263{
8264 Lisp_Object tail;
8265
8266 for (tail = Vframe_list;
8267 XGCTYPE (tail) == Lisp_Cons;
8268 tail = XCDR (tail))
8269 {
8270 Lisp_Object frame = XCAR (tail);
8271 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
8272
8273 if (menu_bar && xlwmenu_window_p (menu_bar, window))
8274 return menu_bar;
8275 }
8276
8277 return NULL;
8278}
8279
8280#endif /* USE_X_TOOLKIT && USE_LUCID */
8281
06a2c219
GM
8282\f
8283/************************************************************************
8284 Toolkit scroll bars
8285 ************************************************************************/
8286
eccc05db 8287#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8288
8289static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
8290static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
8291static void x_create_toolkit_scroll_bar P_ ((struct frame *,
8292 struct scroll_bar *));
8293static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
8294 int, int, int));
8295
8296
8297/* Id of action hook installed for scroll bars. */
8298
8299static XtActionHookId action_hook_id;
8300
8301/* Lisp window being scrolled. Set when starting to interact with
8302 a toolkit scroll bar, reset to nil when ending the interaction. */
8303
8304static Lisp_Object window_being_scrolled;
8305
8306/* Last scroll bar part sent in xm_scroll_callback. */
8307
8308static int last_scroll_bar_part;
8309
ec18280f
SM
8310/* Whether this is an Xaw with arrow-scrollbars. This should imply
8311 that movements of 1/20 of the screen size are mapped to up/down. */
8312
8313static Boolean xaw3d_arrow_scroll;
8314
8315/* Whether the drag scrolling maintains the mouse at the top of the
8316 thumb. If not, resizing the thumb needs to be done more carefully
8317 to avoid jerkyness. */
8318
8319static Boolean xaw3d_pick_top;
8320
06a2c219
GM
8321
8322/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 8323 bars are used.. The hook is responsible for detecting when
06a2c219
GM
8324 the user ends an interaction with the scroll bar, and generates
8325 a `end-scroll' scroll_bar_click' event if so. */
8326
8327static void
8328xt_action_hook (widget, client_data, action_name, event, params,
8329 num_params)
8330 Widget widget;
8331 XtPointer client_data;
8332 String action_name;
8333 XEvent *event;
8334 String *params;
8335 Cardinal *num_params;
8336{
8337 int scroll_bar_p;
8338 char *end_action;
8339
8340#ifdef USE_MOTIF
8341 scroll_bar_p = XmIsScrollBar (widget);
8342 end_action = "Release";
ec18280f 8343#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8344 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
8345 end_action = "EndScroll";
ec18280f 8346#endif /* USE_MOTIF */
06a2c219 8347
06a2c219
GM
8348 if (scroll_bar_p
8349 && strcmp (action_name, end_action) == 0
8350 && WINDOWP (window_being_scrolled))
8351 {
8352 struct window *w;
8353
8354 x_send_scroll_bar_event (window_being_scrolled,
8355 scroll_bar_end_scroll, 0, 0);
8356 w = XWINDOW (window_being_scrolled);
8357 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
8358 window_being_scrolled = Qnil;
8359 last_scroll_bar_part = -1;
bffcfca9
GM
8360
8361 /* Xt timeouts no longer needed. */
8362 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
8363 }
8364}
8365
07b3d16e
GM
8366/* A vector of windows used for communication between
8367 x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
8368
8369static struct window **scroll_bar_windows;
8370static int scroll_bar_windows_size;
8371
06a2c219
GM
8372
8373/* Send a client message with message type Xatom_Scrollbar for a
8374 scroll action to the frame of WINDOW. PART is a value identifying
8375 the part of the scroll bar that was clicked on. PORTION is the
8376 amount to scroll of a whole of WHOLE. */
8377
8378static void
8379x_send_scroll_bar_event (window, part, portion, whole)
8380 Lisp_Object window;
8381 int part, portion, whole;
8382{
8383 XEvent event;
8384 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
07b3d16e
GM
8385 struct window *w = XWINDOW (window);
8386 struct frame *f = XFRAME (w->frame);
8387 int i;
06a2c219 8388
07b3d16e
GM
8389 BLOCK_INPUT;
8390
06a2c219
GM
8391 /* Construct a ClientMessage event to send to the frame. */
8392 ev->type = ClientMessage;
8393 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
8394 ev->display = FRAME_X_DISPLAY (f);
8395 ev->window = FRAME_X_WINDOW (f);
8396 ev->format = 32;
07b3d16e
GM
8397
8398 /* We can only transfer 32 bits in the XClientMessageEvent, which is
8399 not enough to store a pointer or Lisp_Object on a 64 bit system.
8400 So, store the window in scroll_bar_windows and pass the index
8401 into that array in the event. */
8402 for (i = 0; i < scroll_bar_windows_size; ++i)
8403 if (scroll_bar_windows[i] == NULL)
8404 break;
8405
8406 if (i == scroll_bar_windows_size)
8407 {
8408 int new_size = max (10, 2 * scroll_bar_windows_size);
8409 size_t nbytes = new_size * sizeof *scroll_bar_windows;
8410 size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows;
8411
8412 scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
8413 nbytes);
8414 bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
8415 scroll_bar_windows_size = new_size;
8416 }
8417
8418 scroll_bar_windows[i] = w;
8419 ev->data.l[0] = (long) i;
06a2c219
GM
8420 ev->data.l[1] = (long) part;
8421 ev->data.l[2] = (long) 0;
8422 ev->data.l[3] = (long) portion;
8423 ev->data.l[4] = (long) whole;
8424
bffcfca9
GM
8425 /* Make Xt timeouts work while the scroll bar is active. */
8426 toolkit_scroll_bar_interaction = 1;
8427
06a2c219
GM
8428 /* Setting the event mask to zero means that the message will
8429 be sent to the client that created the window, and if that
8430 window no longer exists, no event will be sent. */
06a2c219
GM
8431 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
8432 UNBLOCK_INPUT;
8433}
8434
8435
8436/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
8437 in *IEVENT. */
8438
8439static void
8440x_scroll_bar_to_input_event (event, ievent)
8441 XEvent *event;
8442 struct input_event *ievent;
8443{
8444 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
8445 Lisp_Object window;
8446 struct frame *f;
07b3d16e
GM
8447 struct window *w;
8448
8449 w = scroll_bar_windows[ev->data.l[0]];
8450 scroll_bar_windows[ev->data.l[0]] = NULL;
52e386c2 8451
07b3d16e
GM
8452 XSETWINDOW (window, w);
8453 f = XFRAME (w->frame);
06a2c219
GM
8454
8455 ievent->kind = scroll_bar_click;
8456 ievent->frame_or_window = window;
0f8aabe9 8457 ievent->arg = Qnil;
06a2c219
GM
8458 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
8459 ievent->part = ev->data.l[1];
8460 ievent->code = ev->data.l[2];
8461 ievent->x = make_number ((int) ev->data.l[3]);
8462 ievent->y = make_number ((int) ev->data.l[4]);
8463 ievent->modifiers = 0;
8464}
8465
8466
8467#ifdef USE_MOTIF
8468
8469/* Minimum and maximum values used for Motif scroll bars. */
8470
8471#define XM_SB_MIN 1
8472#define XM_SB_MAX 10000000
8473#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
8474
8475
8476/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
8477 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
8478 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
8479
8480static void
8481xm_scroll_callback (widget, client_data, call_data)
8482 Widget widget;
8483 XtPointer client_data, call_data;
8484{
8485 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8486 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
8487 double percent;
8488 int part = -1, whole = 0, portion = 0;
8489
8490 switch (cs->reason)
8491 {
8492 case XmCR_DECREMENT:
8493 bar->dragging = Qnil;
8494 part = scroll_bar_up_arrow;
8495 break;
8496
8497 case XmCR_INCREMENT:
8498 bar->dragging = Qnil;
8499 part = scroll_bar_down_arrow;
8500 break;
8501
8502 case XmCR_PAGE_DECREMENT:
8503 bar->dragging = Qnil;
8504 part = scroll_bar_above_handle;
8505 break;
8506
8507 case XmCR_PAGE_INCREMENT:
8508 bar->dragging = Qnil;
8509 part = scroll_bar_below_handle;
8510 break;
8511
8512 case XmCR_TO_TOP:
8513 bar->dragging = Qnil;
8514 part = scroll_bar_to_top;
8515 break;
8516
8517 case XmCR_TO_BOTTOM:
8518 bar->dragging = Qnil;
8519 part = scroll_bar_to_bottom;
8520 break;
8521
8522 case XmCR_DRAG:
8523 {
8524 int slider_size;
8525 int dragging_down_p = (INTEGERP (bar->dragging)
8526 && XINT (bar->dragging) <= cs->value);
8527
8528 /* Get the slider size. */
8529 BLOCK_INPUT;
8530 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
8531 UNBLOCK_INPUT;
8532
8533 /* At the max position of the scroll bar, do a line-wise
23442ae4
GM
8534 movement. Without doing anything, we would be called with
8535 the same cs->value again and again. If we want to make
8536 sure that we can reach the end of the buffer, we have to do
8537 something.
06a2c219
GM
8538
8539 Implementation note: setting bar->dragging always to
8540 cs->value gives a smoother movement at the max position.
8541 Setting it to nil when doing line-wise movement gives
8542 a better slider behavior. */
8543
8544 if (cs->value + slider_size == XM_SB_MAX
8545 || (dragging_down_p
8546 && last_scroll_bar_part == scroll_bar_down_arrow))
8547 {
8548 part = scroll_bar_down_arrow;
8549 bar->dragging = Qnil;
8550 }
8551 else
8552 {
8553 whole = XM_SB_RANGE;
8554 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
8555 part = scroll_bar_handle;
8556 bar->dragging = make_number (cs->value);
8557 }
8558 }
8559 break;
8560
8561 case XmCR_VALUE_CHANGED:
8562 break;
8563 };
8564
8565 if (part >= 0)
8566 {
8567 window_being_scrolled = bar->window;
8568 last_scroll_bar_part = part;
8569 x_send_scroll_bar_event (bar->window, part, portion, whole);
8570 }
8571}
8572
8573
ec18280f 8574#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
8575
8576
ec18280f 8577/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
8578 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
8579 scroll bar struct. CALL_DATA is a pointer to a float saying where
8580 the thumb is. */
8581
8582static void
ec18280f 8583xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
8584 Widget widget;
8585 XtPointer client_data, call_data;
8586{
8587 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8588 float top = *(float *) call_data;
8589 float shown;
ec18280f
SM
8590 int whole, portion, height;
8591 int part;
06a2c219
GM
8592
8593 /* Get the size of the thumb, a value between 0 and 1. */
8594 BLOCK_INPUT;
ec18280f 8595 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
8596 UNBLOCK_INPUT;
8597
8598 whole = 10000000;
8599 portion = shown < 1 ? top * whole : 0;
06a2c219 8600
ec18280f
SM
8601 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
8602 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
8603 the bottom, so we force the scrolling whenever we see that we're
8604 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
8605 we try to ensure that we always stay two pixels away from the
8606 bottom). */
06a2c219
GM
8607 part = scroll_bar_down_arrow;
8608 else
8609 part = scroll_bar_handle;
8610
8611 window_being_scrolled = bar->window;
8612 bar->dragging = make_number (portion);
8613 last_scroll_bar_part = part;
8614 x_send_scroll_bar_event (bar->window, part, portion, whole);
8615}
8616
8617
ec18280f
SM
8618/* Xaw scroll bar callback. Invoked for incremental scrolling.,
8619 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
8620 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
8621 the scroll bar. CALL_DATA is an integer specifying the action that
8622 has taken place. It's magnitude is in the range 0..height of the
8623 scroll bar. Negative values mean scroll towards buffer start.
8624 Values < height of scroll bar mean line-wise movement. */
8625
8626static void
ec18280f 8627xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
8628 Widget widget;
8629 XtPointer client_data, call_data;
8630{
8631 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8632 int position = (int) call_data;
8633 Dimension height;
8634 int part;
8635
8636 /* Get the height of the scroll bar. */
8637 BLOCK_INPUT;
8638 XtVaGetValues (widget, XtNheight, &height, NULL);
8639 UNBLOCK_INPUT;
8640
ec18280f
SM
8641 if (abs (position) >= height)
8642 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
8643
8644 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
8645 it maps line-movement to call_data = max(5, height/20). */
8646 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
8647 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 8648 else
ec18280f 8649 part = scroll_bar_move_ratio;
06a2c219
GM
8650
8651 window_being_scrolled = bar->window;
8652 bar->dragging = Qnil;
8653 last_scroll_bar_part = part;
ec18280f 8654 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
8655}
8656
8657
8658#endif /* not USE_MOTIF */
8659
8660
8661/* Create the widget for scroll bar BAR on frame F. Record the widget
8662 and X window of the scroll bar in BAR. */
8663
8664static void
8665x_create_toolkit_scroll_bar (f, bar)
8666 struct frame *f;
8667 struct scroll_bar *bar;
8668{
8669 Window xwindow;
8670 Widget widget;
8671 Arg av[20];
8672 int ac = 0;
8673 char *scroll_bar_name = "verticalScrollBar";
8674 unsigned long pixel;
8675
8676 BLOCK_INPUT;
8677
8678#ifdef USE_MOTIF
06a2c219
GM
8679 /* Set resources. Create the widget. */
8680 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8681 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
8682 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
8683 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
8684 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
8685 XtSetArg (av[ac], XmNincrement, 1); ++ac;
8686 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
8687
8688 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8689 if (pixel != -1)
8690 {
8691 XtSetArg (av[ac], XmNforeground, pixel);
8692 ++ac;
8693 }
8694
8695 pixel = f->output_data.x->scroll_bar_background_pixel;
8696 if (pixel != -1)
8697 {
8698 XtSetArg (av[ac], XmNbackground, pixel);
8699 ++ac;
8700 }
8701
8702 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
8703 scroll_bar_name, av, ac);
8704
8705 /* Add one callback for everything that can happen. */
8706 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
8707 (XtPointer) bar);
8708 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
8709 (XtPointer) bar);
8710 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
8711 (XtPointer) bar);
8712 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
8713 (XtPointer) bar);
8714 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
8715 (XtPointer) bar);
8716 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
8717 (XtPointer) bar);
8718 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
8719 (XtPointer) bar);
8720
8721 /* Realize the widget. Only after that is the X window created. */
8722 XtRealizeWidget (widget);
8723
8724 /* Set the cursor to an arrow. I didn't find a resource to do that.
8725 And I'm wondering why it hasn't an arrow cursor by default. */
8726 XDefineCursor (XtDisplay (widget), XtWindow (widget),
8727 f->output_data.x->nontext_cursor);
8728
ec18280f 8729#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8730
8731 /* Set resources. Create the widget. The background of the
8732 Xaw3d scroll bar widget is a little bit light for my taste.
8733 We don't alter it here to let users change it according
8734 to their taste with `emacs*verticalScrollBar.background: xxx'. */
8735 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8736 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
8737 /* For smoother scrolling with Xaw3d -sm */
8738 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
06a2c219
GM
8739
8740 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8741 if (pixel != -1)
8742 {
8743 XtSetArg (av[ac], XtNforeground, pixel);
8744 ++ac;
8745 }
8746
8747 pixel = f->output_data.x->scroll_bar_background_pixel;
8748 if (pixel != -1)
8749 {
8750 XtSetArg (av[ac], XtNbackground, pixel);
8751 ++ac;
8752 }
7c1bef7a
MB
8753
8754 /* Top/bottom shadow colors. */
8755
8756 /* Allocate them, if necessary. */
8757 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
8758 {
8759 pixel = f->output_data.x->scroll_bar_background_pixel;
8760 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8761 &pixel, 1.2, 0x8000))
8762 pixel = -1;
8763 f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
8764 }
8765 if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8766 {
8767 pixel = f->output_data.x->scroll_bar_background_pixel;
8768 if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
8769 &pixel, 0.6, 0x4000))
8770 pixel = -1;
8771 f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
8772 }
8773
8774 /* Tell the toolkit about them. */
8775 if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
8776 || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
8777 /* We tried to allocate a color for the top/bottom shadow, and
8778 failed, so tell Xaw3d to use dithering instead. */
8779 {
8780 XtSetArg (av[ac], XtNbeNiceToColormap, True);
8781 ++ac;
8782 }
8783 else
8784 /* Tell what colors Xaw3d should use for the top/bottom shadow, to
8785 be more consistent with other emacs 3d colors, and since Xaw3d is
8786 not good at dealing with allocation failure. */
8787 {
8788 /* This tells Xaw3d to use real colors instead of dithering for
8789 the shadows. */
8790 XtSetArg (av[ac], XtNbeNiceToColormap, False);
8791 ++ac;
8792
8793 /* Specify the colors. */
8794 pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
8795 if (pixel != -1)
8796 {
8797 XtSetArg (av[ac], "topShadowPixel", pixel);
8798 ++ac;
8799 }
8800 pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
8801 if (pixel != -1)
8802 {
8803 XtSetArg (av[ac], "bottomShadowPixel", pixel);
8804 ++ac;
8805 }
8806 }
8807
06a2c219
GM
8808 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
8809 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
8810
8811 {
8812 char *initial = "";
8813 char *val = initial;
8814 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
8815 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
8816 if (val == initial)
8817 { /* ARROW_SCROLL */
8818 xaw3d_arrow_scroll = True;
8819 /* Isn't that just a personal preference ? -sm */
8820 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
8821 }
8822 }
06a2c219
GM
8823
8824 /* Define callbacks. */
ec18280f
SM
8825 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
8826 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
8827 (XtPointer) bar);
8828
8829 /* Realize the widget. Only after that is the X window created. */
8830 XtRealizeWidget (widget);
8831
ec18280f 8832#endif /* !USE_MOTIF */
06a2c219
GM
8833
8834 /* Install an action hook that let's us detect when the user
8835 finishes interacting with a scroll bar. */
8836 if (action_hook_id == 0)
8837 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
8838
8839 /* Remember X window and widget in the scroll bar vector. */
8840 SET_SCROLL_BAR_X_WIDGET (bar, widget);
8841 xwindow = XtWindow (widget);
8842 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
8843
8844 UNBLOCK_INPUT;
8845}
8846
8847
8848/* Set the thumb size and position of scroll bar BAR. We are currently
8849 displaying PORTION out of a whole WHOLE, and our position POSITION. */
8850
8851static void
8852x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
8853 struct scroll_bar *bar;
8854 int portion, position, whole;
f451eb13 8855{
e83dc917
GM
8856 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8857 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
06a2c219 8858 float top, shown;
f451eb13 8859
06a2c219
GM
8860 if (whole == 0)
8861 top = 0, shown = 1;
8862 else
f451eb13 8863 {
06a2c219
GM
8864 top = (float) position / whole;
8865 shown = (float) portion / whole;
8866 }
f451eb13 8867
06a2c219 8868 BLOCK_INPUT;
f451eb13 8869
06a2c219
GM
8870#ifdef USE_MOTIF
8871 {
8872 int size, value;
06a2c219
GM
8873 XmScrollBarWidget sb;
8874
ec18280f 8875 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
8876 is the scroll bar's maximum and MIN is the scroll bar's minimum
8877 value. */
8878 size = shown * XM_SB_RANGE;
8879 size = min (size, XM_SB_RANGE);
8880 size = max (size, 1);
8881
8882 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
8883 value = top * XM_SB_RANGE;
8884 value = min (value, XM_SB_MAX - size);
8885 value = max (value, XM_SB_MIN);
8886
06a2c219
GM
8887 if (NILP (bar->dragging))
8888 XmScrollBarSetValues (widget, value, size, 0, 0, False);
8889 else if (last_scroll_bar_part == scroll_bar_down_arrow)
8890 /* This has the negative side effect that the slider value is
ec18280f 8891 not what it would be if we scrolled here using line-wise or
06a2c219
GM
8892 page-wise movement. */
8893 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
8894 else
8895 {
8896 /* If currently dragging, only update the slider size.
8897 This reduces flicker effects. */
8898 int old_value, old_size, increment, page_increment;
8899
8900 XmScrollBarGetValues (widget, &old_value, &old_size,
8901 &increment, &page_increment);
8902 XmScrollBarSetValues (widget, old_value,
8903 min (size, XM_SB_RANGE - old_value),
8904 0, 0, False);
8905 }
06a2c219 8906 }
ec18280f 8907#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 8908 {
ec18280f
SM
8909 float old_top, old_shown;
8910 Dimension height;
8911 XtVaGetValues (widget,
8912 XtNtopOfThumb, &old_top,
8913 XtNshown, &old_shown,
8914 XtNheight, &height,
8915 NULL);
8916
8917 /* Massage the top+shown values. */
8918 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8919 top = max (0, min (1, top));
8920 else
8921 top = old_top;
8922 /* Keep two pixels available for moving the thumb down. */
8923 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8924
8925 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8926 check that your system's configuration file contains a define
8927 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8928 if (top != old_top || shown != old_shown)
eb393530 8929 {
ec18280f 8930 if (NILP (bar->dragging))
eb393530 8931 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8932 else
8933 {
ec18280f
SM
8934#ifdef HAVE_XAW3D
8935 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8936 int scroll_mode = 0;
ec18280f
SM
8937
8938 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8939 if (xaw3d_arrow_scroll)
8940 {
8941 /* Xaw3d stupidly ignores resize requests while dragging
8942 so we have to make it believe it's not in dragging mode. */
8943 scroll_mode = sb->scrollbar.scroll_mode;
8944 if (scroll_mode == 2)
8945 sb->scrollbar.scroll_mode = 0;
8946 }
8947#endif
8948 /* Try to make the scrolling a tad smoother. */
8949 if (!xaw3d_pick_top)
8950 shown = min (shown, old_shown);
8951
8952 XawScrollbarSetThumb (widget, top, shown);
8953
8954#ifdef HAVE_XAW3D
8955 if (xaw3d_arrow_scroll && scroll_mode == 2)
8956 sb->scrollbar.scroll_mode = scroll_mode;
8957#endif
06a2c219 8958 }
06a2c219
GM
8959 }
8960 }
ec18280f 8961#endif /* !USE_MOTIF */
06a2c219
GM
8962
8963 UNBLOCK_INPUT;
f451eb13
JB
8964}
8965
06a2c219
GM
8966#endif /* USE_TOOLKIT_SCROLL_BARS */
8967
8968
8969\f
8970/************************************************************************
8971 Scroll bars, general
8972 ************************************************************************/
8973
8974/* Create a scroll bar and return the scroll bar vector for it. W is
8975 the Emacs window on which to create the scroll bar. TOP, LEFT,
8976 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8977 scroll bar. */
8978
ab648270 8979static struct scroll_bar *
06a2c219
GM
8980x_scroll_bar_create (w, top, left, width, height)
8981 struct window *w;
f451eb13
JB
8982 int top, left, width, height;
8983{
06a2c219 8984 struct frame *f = XFRAME (w->frame);
334208b7
RS
8985 struct scroll_bar *bar
8986 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8987
8988 BLOCK_INPUT;
8989
eccc05db 8990#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8991 x_create_toolkit_scroll_bar (f, bar);
8992#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8993 {
8994 XSetWindowAttributes a;
8995 unsigned long mask;
5c187dee 8996 Window window;
06a2c219
GM
8997
8998 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8999 if (a.background_pixel == -1)
9000 a.background_pixel = f->output_data.x->background_pixel;
9001
12ba150f 9002 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 9003 | ButtonMotionMask | PointerMotionHintMask
12ba150f 9004 | ExposureMask);
7a13e894 9005 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 9006
dbc4e1c1 9007 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 9008
06a2c219
GM
9009 /* Clear the area of W that will serve as a scroll bar. This is
9010 for the case that a window has been split horizontally. In
9011 this case, no clear_frame is generated to reduce flickering. */
c5e6e06b
GM
9012 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9013 left, top, width,
9014 window_box_height (w), False);
06a2c219
GM
9015
9016 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9017 /* Position and size of scroll bar. */
9018 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9019 top,
9020 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
9021 height,
9022 /* Border width, depth, class, and visual. */
9023 0,
9024 CopyFromParent,
9025 CopyFromParent,
9026 CopyFromParent,
9027 /* Attributes. */
9028 mask, &a);
9029 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 9030 }
06a2c219 9031#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9032
06a2c219 9033 XSETWINDOW (bar->window, w);
e0c1aef2
KH
9034 XSETINT (bar->top, top);
9035 XSETINT (bar->left, left);
9036 XSETINT (bar->width, width);
9037 XSETINT (bar->height, height);
9038 XSETINT (bar->start, 0);
9039 XSETINT (bar->end, 0);
12ba150f 9040 bar->dragging = Qnil;
f451eb13
JB
9041
9042 /* Add bar to its frame's list of scroll bars. */
334208b7 9043 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 9044 bar->prev = Qnil;
334208b7 9045 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 9046 if (!NILP (bar->next))
e0c1aef2 9047 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 9048
06a2c219 9049 /* Map the window/widget. */
eccc05db 9050#ifdef USE_TOOLKIT_SCROLL_BARS
f964b4d7
GM
9051 {
9052 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
9053 XtConfigureWidget (scroll_bar,
9054 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9055 top,
9056 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
9057 max (height, 1), 0);
9058 XtMapWidget (scroll_bar);
9059 }
06a2c219 9060#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 9061 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 9062#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9063
9064 UNBLOCK_INPUT;
12ba150f 9065 return bar;
f451eb13
JB
9066}
9067
06a2c219 9068
12ba150f 9069/* Draw BAR's handle in the proper position.
06a2c219 9070
12ba150f
JB
9071 If the handle is already drawn from START to END, don't bother
9072 redrawing it, unless REBUILD is non-zero; in that case, always
9073 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 9074 events.)
12ba150f
JB
9075
9076 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
9077 fit inside its rectangle, but if the user is dragging the scroll
9078 bar handle, we want to let them drag it down all the way, so that
9079 the bar's top is as far down as it goes; otherwise, there's no way
9080 to move to the very end of the buffer. */
9081
5c187dee
GM
9082#ifndef USE_TOOLKIT_SCROLL_BARS
9083
f451eb13 9084static void
ab648270
JB
9085x_scroll_bar_set_handle (bar, start, end, rebuild)
9086 struct scroll_bar *bar;
f451eb13 9087 int start, end;
12ba150f 9088 int rebuild;
f451eb13 9089{
12ba150f 9090 int dragging = ! NILP (bar->dragging);
ab648270 9091 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9092 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9093 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
9094
9095 /* If the display is already accurate, do nothing. */
9096 if (! rebuild
9097 && start == XINT (bar->start)
9098 && end == XINT (bar->end))
9099 return;
9100
f451eb13
JB
9101 BLOCK_INPUT;
9102
9103 {
d9cdbb3d
RS
9104 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
9105 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
9106 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
9107
9108 /* Make sure the values are reasonable, and try to preserve
9109 the distance between start and end. */
12ba150f
JB
9110 {
9111 int length = end - start;
9112
9113 if (start < 0)
9114 start = 0;
9115 else if (start > top_range)
9116 start = top_range;
9117 end = start + length;
9118
9119 if (end < start)
9120 end = start;
9121 else if (end > top_range && ! dragging)
9122 end = top_range;
9123 }
f451eb13 9124
ab648270 9125 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
9126 XSETINT (bar->start, start);
9127 XSETINT (bar->end, end);
f451eb13 9128
12ba150f
JB
9129 /* Clip the end position, just for display. */
9130 if (end > top_range)
9131 end = top_range;
f451eb13 9132
ab648270 9133 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
9134 below top positions, to make sure the handle is always at least
9135 that many pixels tall. */
ab648270 9136 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 9137
12ba150f
JB
9138 /* Draw the empty space above the handle. Note that we can't clear
9139 zero-height areas; that means "clear to end of window." */
9140 if (0 < start)
c5e6e06b
GM
9141 x_clear_area (FRAME_X_DISPLAY (f), w,
9142 /* x, y, width, height, and exposures. */
9143 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9144 VERTICAL_SCROLL_BAR_TOP_BORDER,
9145 inside_width, start,
9146 False);
f451eb13 9147
06a2c219
GM
9148 /* Change to proper foreground color if one is specified. */
9149 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9150 XSetForeground (FRAME_X_DISPLAY (f), gc,
9151 f->output_data.x->scroll_bar_foreground_pixel);
9152
12ba150f 9153 /* Draw the handle itself. */
334208b7 9154 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
12ba150f 9155 /* x, y, width, height */
ab648270
JB
9156 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9157 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 9158 inside_width, end - start);
f451eb13 9159
06a2c219
GM
9160 /* Restore the foreground color of the GC if we changed it above. */
9161 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
9162 XSetForeground (FRAME_X_DISPLAY (f), gc,
9163 f->output_data.x->foreground_pixel);
f451eb13 9164
12ba150f
JB
9165 /* Draw the empty space below the handle. Note that we can't
9166 clear zero-height areas; that means "clear to end of window." */
9167 if (end < inside_height)
c5e6e06b
GM
9168 x_clear_area (FRAME_X_DISPLAY (f), w,
9169 /* x, y, width, height, and exposures. */
9170 VERTICAL_SCROLL_BAR_LEFT_BORDER,
9171 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
9172 inside_width, inside_height - end,
9173 False);
f451eb13 9174
f451eb13
JB
9175 }
9176
f451eb13
JB
9177 UNBLOCK_INPUT;
9178}
9179
5c187dee 9180#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 9181
06a2c219
GM
9182/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
9183 nil. */
58769bee 9184
12ba150f 9185static void
ab648270
JB
9186x_scroll_bar_remove (bar)
9187 struct scroll_bar *bar;
12ba150f 9188{
e83dc917 9189 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
9190 BLOCK_INPUT;
9191
eccc05db 9192#ifdef USE_TOOLKIT_SCROLL_BARS
e83dc917
GM
9193 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
9194#else
9195 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
9196#endif
06a2c219 9197
ab648270
JB
9198 /* Disassociate this scroll bar from its window. */
9199 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
9200
9201 UNBLOCK_INPUT;
9202}
9203
06a2c219 9204
12ba150f
JB
9205/* Set the handle of the vertical scroll bar for WINDOW to indicate
9206 that we are displaying PORTION characters out of a total of WHOLE
ab648270 9207 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 9208 create one. */
06a2c219 9209
12ba150f 9210static void
06a2c219
GM
9211XTset_vertical_scroll_bar (w, portion, whole, position)
9212 struct window *w;
f451eb13
JB
9213 int portion, whole, position;
9214{
06a2c219 9215 struct frame *f = XFRAME (w->frame);
ab648270 9216 struct scroll_bar *bar;
3c6ede7b 9217 int top, height, left, sb_left, width, sb_width;
06a2c219 9218 int window_x, window_y, window_width, window_height;
06a2c219 9219
3c6ede7b 9220 /* Get window dimensions. */
06a2c219 9221 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
9222 top = window_y;
9223 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9224 height = window_height;
06a2c219 9225
3c6ede7b 9226 /* Compute the left edge of the scroll bar area. */
06a2c219 9227 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
9228 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
9229 else
9230 left = XFASTINT (w->left);
9231 left *= CANON_X_UNIT (f);
9232 left += FRAME_INTERNAL_BORDER_WIDTH (f);
9233
9234 /* Compute the width of the scroll bar which might be less than
9235 the width of the area reserved for the scroll bar. */
9236 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
9237 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 9238 else
3c6ede7b 9239 sb_width = width;
12ba150f 9240
3c6ede7b
GM
9241 /* Compute the left edge of the scroll bar. */
9242#ifdef USE_TOOLKIT_SCROLL_BARS
9243 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9244 sb_left = left + width - sb_width - (width - sb_width) / 2;
9245 else
9246 sb_left = left + (width - sb_width) / 2;
9247#else
9248 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9249 sb_left = left + width - sb_width;
9250 else
9251 sb_left = left;
9252#endif
9253
ab648270 9254 /* Does the scroll bar exist yet? */
06a2c219 9255 if (NILP (w->vertical_scroll_bar))
3c6ede7b 9256 {
80c32bcc 9257 BLOCK_INPUT;
f964b4d7
GM
9258 if (width && height)
9259 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9260 left, top, width, height, False);
80c32bcc 9261 UNBLOCK_INPUT;
3c6ede7b
GM
9262 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
9263 }
f451eb13 9264 else
12ba150f
JB
9265 {
9266 /* It may just need to be moved and resized. */
06a2c219
GM
9267 unsigned int mask = 0;
9268
9269 bar = XSCROLL_BAR (w->vertical_scroll_bar);
9270
9271 BLOCK_INPUT;
9272
3c6ede7b 9273 if (sb_left != XINT (bar->left))
06a2c219 9274 mask |= CWX;
3c6ede7b 9275 if (top != XINT (bar->top))
06a2c219 9276 mask |= CWY;
3c6ede7b 9277 if (sb_width != XINT (bar->width))
06a2c219 9278 mask |= CWWidth;
3c6ede7b 9279 if (height != XINT (bar->height))
06a2c219
GM
9280 mask |= CWHeight;
9281
9282#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
9283
9284 /* Since toolkit scroll bars are smaller than the space reserved
9285 for them on the frame, we have to clear "under" them. */
f964b4d7
GM
9286 if (width && height)
9287 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9288 left, top, width, height, False);
06a2c219
GM
9289
9290 /* Move/size the scroll bar widget. */
9291 if (mask)
e83dc917 9292 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
3c6ede7b
GM
9293 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9294 top,
9295 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
f964b4d7 9296 max (height, 1), 0);
06a2c219
GM
9297
9298#else /* not USE_TOOLKIT_SCROLL_BARS */
9299
357e7376
GM
9300 /* Clear areas not covered by the scroll bar because of
9301 VERTICAL_SCROLL_BAR_WIDTH_TRIM. */
e1f6572f
RS
9302 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
9303 {
c5e6e06b
GM
9304 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9305 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9306 height, False);
9307 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9308 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9309 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9310 height, False);
e1f6572f 9311 }
357e7376
GM
9312
9313 /* Clear areas not covered by the scroll bar because it's not as
9314 wide as the area reserved for it . This makes sure a
9315 previous mode line display is cleared after C-x 2 C-x 1, for
9316 example. */
9317 {
9318 int area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9319 int rest = area_width - sb_width;
9320 if (rest > 0)
9321 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9322 left + area_width - rest, 0,
9323 rest, max (height, 1), False);
9324 }
06a2c219
GM
9325
9326 /* Move/size the scroll bar window. */
9327 if (mask)
9328 {
9329 XWindowChanges wc;
9330
3c6ede7b
GM
9331 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
9332 wc.y = top;
9333 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
9334 wc.height = height;
06a2c219
GM
9335 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
9336 mask, &wc);
9337 }
9338
9339#endif /* not USE_TOOLKIT_SCROLL_BARS */
9340
9341 /* Remember new settings. */
3c6ede7b
GM
9342 XSETINT (bar->left, sb_left);
9343 XSETINT (bar->top, top);
9344 XSETINT (bar->width, sb_width);
9345 XSETINT (bar->height, height);
06a2c219
GM
9346
9347 UNBLOCK_INPUT;
12ba150f 9348 }
f451eb13 9349
eccc05db 9350#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
9351 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
9352#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 9353 /* Set the scroll bar's current state, unless we're currently being
f451eb13 9354 dragged. */
12ba150f 9355 if (NILP (bar->dragging))
f451eb13 9356 {
92857db0 9357 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 9358
12ba150f 9359 if (whole == 0)
ab648270 9360 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
9361 else
9362 {
43f868f5
JB
9363 int start = ((double) position * top_range) / whole;
9364 int end = ((double) (position + portion) * top_range) / whole;
ab648270 9365 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 9366 }
f451eb13 9367 }
06a2c219 9368#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9369
06a2c219 9370 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
9371}
9372
12ba150f 9373
f451eb13 9374/* The following three hooks are used when we're doing a thorough
ab648270 9375 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 9376 are going to be deleted, because keeping track of when windows go
12ba150f
JB
9377 away is a real pain - "Can you say set-window-configuration, boys
9378 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 9379 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 9380 from the fiery pit when we actually redisplay its window. */
f451eb13 9381
ab648270
JB
9382/* Arrange for all scroll bars on FRAME to be removed at the next call
9383 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
9384 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
9385
58769bee 9386static void
ab648270 9387XTcondemn_scroll_bars (frame)
f451eb13
JB
9388 FRAME_PTR frame;
9389{
f9e24cb9
RS
9390 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
9391 while (! NILP (FRAME_SCROLL_BARS (frame)))
9392 {
9393 Lisp_Object bar;
9394 bar = FRAME_SCROLL_BARS (frame);
9395 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
9396 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
9397 XSCROLL_BAR (bar)->prev = Qnil;
9398 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
9399 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
9400 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
9401 }
f451eb13
JB
9402}
9403
fa2dfc30 9404
06a2c219 9405/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 9406 Note that WINDOW isn't necessarily condemned at all. */
fa2dfc30 9407
f451eb13 9408static void
ab648270 9409XTredeem_scroll_bar (window)
12ba150f 9410 struct window *window;
f451eb13 9411{
ab648270 9412 struct scroll_bar *bar;
fa2dfc30 9413 struct frame *f;
12ba150f 9414
ab648270
JB
9415 /* We can't redeem this window's scroll bar if it doesn't have one. */
9416 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
9417 abort ();
9418
ab648270 9419 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
9420
9421 /* Unlink it from the condemned list. */
fa2dfc30
GM
9422 f = XFRAME (WINDOW_FRAME (window));
9423 if (NILP (bar->prev))
9424 {
9425 /* If the prev pointer is nil, it must be the first in one of
9426 the lists. */
9427 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
9428 /* It's not condemned. Everything's fine. */
9429 return;
9430 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
9431 window->vertical_scroll_bar))
9432 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
9433 else
9434 /* If its prev pointer is nil, it must be at the front of
9435 one or the other! */
9436 abort ();
9437 }
9438 else
9439 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f 9440
fa2dfc30
GM
9441 if (! NILP (bar->next))
9442 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 9443
fa2dfc30
GM
9444 bar->next = FRAME_SCROLL_BARS (f);
9445 bar->prev = Qnil;
9446 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
9447 if (! NILP (bar->next))
9448 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13
JB
9449}
9450
ab648270
JB
9451/* Remove all scroll bars on FRAME that haven't been saved since the
9452 last call to `*condemn_scroll_bars_hook'. */
06a2c219 9453
f451eb13 9454static void
ab648270 9455XTjudge_scroll_bars (f)
12ba150f 9456 FRAME_PTR f;
f451eb13 9457{
12ba150f 9458 Lisp_Object bar, next;
f451eb13 9459
ab648270 9460 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
9461
9462 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
9463 more events on the hapless scroll bars. */
9464 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
9465
9466 for (; ! NILP (bar); bar = next)
f451eb13 9467 {
ab648270 9468 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 9469
ab648270 9470 x_scroll_bar_remove (b);
12ba150f
JB
9471
9472 next = b->next;
9473 b->next = b->prev = Qnil;
f451eb13 9474 }
12ba150f 9475
ab648270 9476 /* Now there should be no references to the condemned scroll bars,
12ba150f 9477 and they should get garbage-collected. */
f451eb13
JB
9478}
9479
9480
06a2c219
GM
9481/* Handle an Expose or GraphicsExpose event on a scroll bar. This
9482 is a no-op when using toolkit scroll bars.
ab648270
JB
9483
9484 This may be called from a signal handler, so we have to ignore GC
9485 mark bits. */
06a2c219 9486
f451eb13 9487static void
ab648270
JB
9488x_scroll_bar_expose (bar, event)
9489 struct scroll_bar *bar;
f451eb13
JB
9490 XEvent *event;
9491{
06a2c219
GM
9492#ifndef USE_TOOLKIT_SCROLL_BARS
9493
ab648270 9494 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9495 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9496 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 9497 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 9498
f451eb13
JB
9499 BLOCK_INPUT;
9500
ab648270 9501 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 9502
06a2c219 9503 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 9504 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
9505
9506 /* x, y, width, height */
d9cdbb3d 9507 0, 0,
3cbd2e0b 9508 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
9509 XINT (bar->height) - 1);
9510
f451eb13 9511 UNBLOCK_INPUT;
06a2c219
GM
9512
9513#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9514}
9515
ab648270
JB
9516/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
9517 is set to something other than no_event, it is enqueued.
9518
9519 This may be called from a signal handler, so we have to ignore GC
9520 mark bits. */
06a2c219 9521
5c187dee
GM
9522#ifndef USE_TOOLKIT_SCROLL_BARS
9523
f451eb13 9524static void
ab648270
JB
9525x_scroll_bar_handle_click (bar, event, emacs_event)
9526 struct scroll_bar *bar;
f451eb13
JB
9527 XEvent *event;
9528 struct input_event *emacs_event;
9529{
0299d313 9530 if (! GC_WINDOWP (bar->window))
12ba150f
JB
9531 abort ();
9532
ab648270 9533 emacs_event->kind = scroll_bar_click;
69388238 9534 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
9535 emacs_event->modifiers
9536 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
9537 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
9538 event->xbutton.state)
9539 | (event->type == ButtonRelease
9540 ? up_modifier
9541 : down_modifier));
12ba150f 9542 emacs_event->frame_or_window = bar->window;
0f8aabe9 9543 emacs_event->arg = Qnil;
f451eb13 9544 emacs_event->timestamp = event->xbutton.time;
12ba150f 9545 {
06a2c219 9546#if 0
d9cdbb3d 9547 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 9548 int internal_height
d9cdbb3d 9549 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9550#endif
0299d313 9551 int top_range
d9cdbb3d 9552 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 9553 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
9554
9555 if (y < 0) y = 0;
9556 if (y > top_range) y = top_range;
9557
9558 if (y < XINT (bar->start))
ab648270
JB
9559 emacs_event->part = scroll_bar_above_handle;
9560 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9561 emacs_event->part = scroll_bar_handle;
12ba150f 9562 else
ab648270 9563 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
9564
9565 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
9566 they want to drag it. Lisp code needs to be able to decide
9567 whether or not we're dragging. */
929787e1 9568#if 0
12ba150f
JB
9569 /* If the user has just clicked on the handle, record where they're
9570 holding it. */
9571 if (event->type == ButtonPress
ab648270 9572 && emacs_event->part == scroll_bar_handle)
e0c1aef2 9573 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 9574#endif
12ba150f
JB
9575
9576 /* If the user has released the handle, set it to its final position. */
9577 if (event->type == ButtonRelease
9578 && ! NILP (bar->dragging))
9579 {
9580 int new_start = y - XINT (bar->dragging);
9581 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 9582
ab648270 9583 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
9584 bar->dragging = Qnil;
9585 }
f451eb13 9586
5116f055
JB
9587 /* Same deal here as the other #if 0. */
9588#if 0
58769bee 9589 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 9590 the handle. */
ab648270 9591 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
9592 emacs_event->x = bar->start;
9593 else
e0c1aef2 9594 XSETINT (emacs_event->x, y);
5116f055 9595#else
e0c1aef2 9596 XSETINT (emacs_event->x, y);
5116f055 9597#endif
f451eb13 9598
e0c1aef2 9599 XSETINT (emacs_event->y, top_range);
12ba150f
JB
9600 }
9601}
f451eb13 9602
ab648270
JB
9603/* Handle some mouse motion while someone is dragging the scroll bar.
9604
9605 This may be called from a signal handler, so we have to ignore GC
9606 mark bits. */
06a2c219 9607
f451eb13 9608static void
ab648270
JB
9609x_scroll_bar_note_movement (bar, event)
9610 struct scroll_bar *bar;
f451eb13
JB
9611 XEvent *event;
9612{
39d8bb4d
KH
9613 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
9614
f451eb13
JB
9615 last_mouse_movement_time = event->xmotion.time;
9616
39d8bb4d 9617 f->mouse_moved = 1;
e0c1aef2 9618 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
9619
9620 /* If we're dragging the bar, display it. */
ab648270 9621 if (! GC_NILP (bar->dragging))
f451eb13
JB
9622 {
9623 /* Where should the handle be now? */
12ba150f 9624 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 9625
12ba150f 9626 if (new_start != XINT (bar->start))
f451eb13 9627 {
12ba150f 9628 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 9629
ab648270 9630 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
9631 }
9632 }
f451eb13
JB
9633}
9634
5c187dee
GM
9635#endif /* !USE_TOOLKIT_SCROLL_BARS */
9636
12ba150f 9637/* Return information to the user about the current position of the mouse
ab648270 9638 on the scroll bar. */
06a2c219 9639
12ba150f 9640static void
334208b7
RS
9641x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
9642 FRAME_PTR *fp;
12ba150f 9643 Lisp_Object *bar_window;
ab648270 9644 enum scroll_bar_part *part;
12ba150f
JB
9645 Lisp_Object *x, *y;
9646 unsigned long *time;
9647{
ab648270 9648 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
9649 Window w = SCROLL_BAR_X_WINDOW (bar);
9650 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 9651 int win_x, win_y;
559cb2fb
JB
9652 Window dummy_window;
9653 int dummy_coord;
9654 unsigned int dummy_mask;
12ba150f 9655
cf7cb199
JB
9656 BLOCK_INPUT;
9657
ab648270 9658 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 9659 report that. */
334208b7 9660 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 9661
559cb2fb
JB
9662 /* Root, child, root x and root y. */
9663 &dummy_window, &dummy_window,
9664 &dummy_coord, &dummy_coord,
12ba150f 9665
559cb2fb
JB
9666 /* Position relative to scroll bar. */
9667 &win_x, &win_y,
12ba150f 9668
559cb2fb
JB
9669 /* Mouse buttons and modifier keys. */
9670 &dummy_mask))
7a13e894 9671 ;
559cb2fb
JB
9672 else
9673 {
06a2c219 9674#if 0
559cb2fb 9675 int inside_height
d9cdbb3d 9676 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9677#endif
559cb2fb 9678 int top_range
d9cdbb3d 9679 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
9680
9681 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
9682
9683 if (! NILP (bar->dragging))
9684 win_y -= XINT (bar->dragging);
9685
9686 if (win_y < 0)
9687 win_y = 0;
9688 if (win_y > top_range)
9689 win_y = top_range;
9690
334208b7 9691 *fp = f;
7a13e894 9692 *bar_window = bar->window;
559cb2fb
JB
9693
9694 if (! NILP (bar->dragging))
9695 *part = scroll_bar_handle;
9696 else if (win_y < XINT (bar->start))
9697 *part = scroll_bar_above_handle;
9698 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9699 *part = scroll_bar_handle;
9700 else
9701 *part = scroll_bar_below_handle;
12ba150f 9702
e0c1aef2
KH
9703 XSETINT (*x, win_y);
9704 XSETINT (*y, top_range);
12ba150f 9705
39d8bb4d 9706 f->mouse_moved = 0;
559cb2fb
JB
9707 last_mouse_scroll_bar = Qnil;
9708 }
12ba150f 9709
559cb2fb 9710 *time = last_mouse_movement_time;
cf7cb199 9711
cf7cb199 9712 UNBLOCK_INPUT;
12ba150f
JB
9713}
9714
f451eb13 9715
dbc4e1c1 9716/* The screen has been cleared so we may have changed foreground or
ab648270
JB
9717 background colors, and the scroll bars may need to be redrawn.
9718 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
9719 redraw them. */
9720
dfcf069d 9721void
ab648270 9722x_scroll_bar_clear (f)
dbc4e1c1
JB
9723 FRAME_PTR f;
9724{
06a2c219 9725#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
9726 Lisp_Object bar;
9727
b80c363e
RS
9728 /* We can have scroll bars even if this is 0,
9729 if we just turned off scroll bar mode.
9730 But in that case we should not clear them. */
9731 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
9732 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
9733 bar = XSCROLL_BAR (bar)->next)
c5e6e06b
GM
9734 XClearArea (FRAME_X_DISPLAY (f),
9735 SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
b80c363e 9736 0, 0, 0, 0, True);
06a2c219 9737#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
9738}
9739
06a2c219 9740/* This processes Expose events from the menu-bar specific X event
19126e11 9741 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 9742 when handling menu-bar or pop-up items. */
3afe33e7 9743
06a2c219 9744int
3afe33e7
RS
9745process_expose_from_menu (event)
9746 XEvent event;
9747{
9748 FRAME_PTR f;
19126e11 9749 struct x_display_info *dpyinfo;
06a2c219 9750 int frame_exposed_p = 0;
3afe33e7 9751
f94397b5
KH
9752 BLOCK_INPUT;
9753
19126e11
KH
9754 dpyinfo = x_display_info_for_display (event.xexpose.display);
9755 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
9756 if (f)
9757 {
9758 if (f->async_visible == 0)
9759 {
9760 f->async_visible = 1;
9761 f->async_iconified = 0;
06c488fd 9762 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
9763 SET_FRAME_GARBAGED (f);
9764 }
9765 else
9766 {
06a2c219
GM
9767 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
9768 event.xexpose.x, event.xexpose.y,
9769 event.xexpose.width, event.xexpose.height);
9770 frame_exposed_p = 1;
3afe33e7
RS
9771 }
9772 }
9773 else
9774 {
9775 struct scroll_bar *bar
9776 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9777
3afe33e7
RS
9778 if (bar)
9779 x_scroll_bar_expose (bar, &event);
9780 }
f94397b5
KH
9781
9782 UNBLOCK_INPUT;
06a2c219 9783 return frame_exposed_p;
3afe33e7 9784}
09756a85
RS
9785\f
9786/* Define a queue to save up SelectionRequest events for later handling. */
9787
9788struct selection_event_queue
9789 {
9790 XEvent event;
9791 struct selection_event_queue *next;
9792 };
9793
9794static struct selection_event_queue *queue;
9795
9796/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 9797
09756a85
RS
9798static int x_queue_selection_requests;
9799
9800/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 9801
09756a85 9802static void
334208b7
RS
9803x_queue_event (f, event)
9804 FRAME_PTR f;
09756a85
RS
9805 XEvent *event;
9806{
9807 struct selection_event_queue *queue_tmp
06a2c219 9808 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 9809
58769bee 9810 if (queue_tmp != NULL)
09756a85
RS
9811 {
9812 queue_tmp->event = *event;
9813 queue_tmp->next = queue;
9814 queue = queue_tmp;
9815 }
9816}
9817
9818/* Take all the queued events and put them back
9819 so that they get processed afresh. */
9820
9821static void
db3906fd
RS
9822x_unqueue_events (display)
9823 Display *display;
09756a85 9824{
58769bee 9825 while (queue != NULL)
09756a85
RS
9826 {
9827 struct selection_event_queue *queue_tmp = queue;
db3906fd 9828 XPutBackEvent (display, &queue_tmp->event);
09756a85 9829 queue = queue_tmp->next;
06a2c219 9830 xfree ((char *)queue_tmp);
09756a85
RS
9831 }
9832}
9833
9834/* Start queuing SelectionRequest events. */
9835
9836void
db3906fd
RS
9837x_start_queuing_selection_requests (display)
9838 Display *display;
09756a85
RS
9839{
9840 x_queue_selection_requests++;
9841}
9842
9843/* Stop queuing SelectionRequest events. */
9844
9845void
db3906fd
RS
9846x_stop_queuing_selection_requests (display)
9847 Display *display;
09756a85
RS
9848{
9849 x_queue_selection_requests--;
db3906fd 9850 x_unqueue_events (display);
09756a85 9851}
f451eb13
JB
9852\f
9853/* The main X event-reading loop - XTread_socket. */
dc6f92b8 9854
06a2c219 9855/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
9856 but we have to put it out here, since static variables within functions
9857 sometimes don't work. */
06a2c219 9858
dc6f92b8
JB
9859static Time enter_timestamp;
9860
11edeb03 9861/* This holds the state XLookupString needs to implement dead keys
58769bee 9862 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
9863 says that a portable program can't use this, but Stephen Gildea assures
9864 me that letting the compiler initialize it to zeros will work okay.
9865
9866 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
9867 given for enter_time stamp, above. */
9868
11edeb03
JB
9869static XComposeStatus compose_status;
9870
10e6549c
RS
9871/* Record the last 100 characters stored
9872 to help debug the loss-of-chars-during-GC problem. */
06a2c219 9873
2224b905
RS
9874static int temp_index;
9875static short temp_buffer[100];
10e6549c 9876
7a13e894
RS
9877/* Set this to nonzero to fake an "X I/O error"
9878 on a particular display. */
06a2c219 9879
7a13e894
RS
9880struct x_display_info *XTread_socket_fake_io_error;
9881
2224b905
RS
9882/* When we find no input here, we occasionally do a no-op command
9883 to verify that the X server is still running and we can still talk with it.
9884 We try all the open displays, one by one.
9885 This variable is used for cycling thru the displays. */
06a2c219 9886
2224b905
RS
9887static struct x_display_info *next_noop_dpyinfo;
9888
06a2c219
GM
9889#define SET_SAVED_MENU_EVENT(size) \
9890 do \
9891 { \
9892 if (f->output_data.x->saved_menu_event == 0) \
9893 f->output_data.x->saved_menu_event \
9894 = (XEvent *) xmalloc (sizeof (XEvent)); \
9895 bcopy (&event, f->output_data.x->saved_menu_event, size); \
9896 if (numchars >= 1) \
9897 { \
9898 bufp->kind = menu_bar_activate_event; \
9899 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 9900 bufp->arg = Qnil; \
06a2c219
GM
9901 bufp++; \
9902 count++; \
9903 numchars--; \
9904 } \
9905 } \
9906 while (0)
9907
8805890a 9908#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 9909#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 9910
dc6f92b8
JB
9911/* Read events coming from the X server.
9912 This routine is called by the SIGIO handler.
9913 We return as soon as there are no more events to be read.
9914
9915 Events representing keys are stored in buffer BUFP,
9916 which can hold up to NUMCHARS characters.
9917 We return the number of characters stored into the buffer,
9918 thus pretending to be `read'.
9919
dc6f92b8
JB
9920 EXPECTED is nonzero if the caller knows input is available. */
9921
7c5283e4 9922int
f66868ba 9923XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 9924 register int sd;
8805890a
KH
9925 /* register */ struct input_event *bufp;
9926 /* register */ int numchars;
dc6f92b8
JB
9927 int expected;
9928{
9929 int count = 0;
9930 int nbytes = 0;
dc6f92b8 9931 XEvent event;
f676886a 9932 struct frame *f;
66f55a9d 9933 int event_found = 0;
334208b7 9934 struct x_display_info *dpyinfo;
379b5ac0 9935 struct coding_system coding;
dc6f92b8 9936
9ac0d9e0 9937 if (interrupt_input_blocked)
dc6f92b8 9938 {
9ac0d9e0 9939 interrupt_input_pending = 1;
dc6f92b8
JB
9940 return -1;
9941 }
9942
9ac0d9e0 9943 interrupt_input_pending = 0;
dc6f92b8 9944 BLOCK_INPUT;
c0a04927
RS
9945
9946 /* So people can tell when we have read the available input. */
9947 input_signal_count++;
9948
dc6f92b8 9949 if (numchars <= 0)
06a2c219 9950 abort (); /* Don't think this happens. */
dc6f92b8 9951
bde5503b
GM
9952 ++handling_signal;
9953
379b5ac0
KH
9954 /* The input should be decoded if it is from XIM. Currently the
9955 locale of XIM is the same as that of the system. So, we can use
9956 Vlocale_coding_system which is initialized properly at Emacs
9957 startup time. */
9958 setup_coding_system (Vlocale_coding_system, &coding);
9959 coding.src_multibyte = 0;
9960 coding.dst_multibyte = 1;
9961 /* The input is converted to events, thus we can't handle
9962 composition. Anyway, there's no XIM that gives us composition
9963 information. */
9964 coding.composing = COMPOSITION_DISABLED;
9965
7a13e894
RS
9966 /* Find the display we are supposed to read input for.
9967 It's the one communicating on descriptor SD. */
9968 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9969 {
9970#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9971#ifdef FIOSNBIO
7a13e894
RS
9972 /* If available, Xlib uses FIOSNBIO to make the socket
9973 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9974 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9975 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9976 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9977#endif /* ! defined (FIOSNBIO) */
7a13e894 9978#endif
dc6f92b8 9979
7a13e894
RS
9980#if 0 /* This code can't be made to work, with multiple displays,
9981 and appears not to be used on any system any more.
9982 Also keyboard.c doesn't turn O_NDELAY on and off
9983 for X connections. */
dc6f92b8
JB
9984#ifndef SIGIO
9985#ifndef HAVE_SELECT
7a13e894
RS
9986 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9987 {
9988 extern int read_alarm_should_throw;
9989 read_alarm_should_throw = 1;
9990 XPeekEvent (dpyinfo->display, &event);
9991 read_alarm_should_throw = 0;
9992 }
c118dd06
JB
9993#endif /* HAVE_SELECT */
9994#endif /* SIGIO */
7a13e894 9995#endif
dc6f92b8 9996
7a13e894
RS
9997 /* For debugging, this gives a way to fake an I/O error. */
9998 if (dpyinfo == XTread_socket_fake_io_error)
9999 {
10000 XTread_socket_fake_io_error = 0;
10001 x_io_error_quitter (dpyinfo->display);
10002 }
dc6f92b8 10003
06a2c219 10004 while (XPending (dpyinfo->display))
dc6f92b8 10005 {
7a13e894 10006 XNextEvent (dpyinfo->display, &event);
06a2c219 10007
531483fb 10008#ifdef HAVE_X_I18N
d1bc4182 10009 {
f2be1146
GM
10010 /* Filter events for the current X input method.
10011 XFilterEvent returns non-zero if the input method has
10012 consumed the event. We pass the frame's X window to
10013 XFilterEvent because that's the one for which the IC
10014 was created. */
f5d11644
GM
10015 struct frame *f1 = x_any_window_to_frame (dpyinfo,
10016 event.xclient.window);
10017 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
10018 break;
10019 }
0cd6403b 10020#endif
7a13e894
RS
10021 event_found = 1;
10022
10023 switch (event.type)
10024 {
10025 case ClientMessage:
c047688c 10026 {
7a13e894
RS
10027 if (event.xclient.message_type
10028 == dpyinfo->Xatom_wm_protocols
10029 && event.xclient.format == 32)
c047688c 10030 {
7a13e894
RS
10031 if (event.xclient.data.l[0]
10032 == dpyinfo->Xatom_wm_take_focus)
c047688c 10033 {
8c1a6a84
RS
10034 /* Use x_any_window_to_frame because this
10035 could be the shell widget window
10036 if the frame has no title bar. */
10037 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
10038#ifdef HAVE_X_I18N
10039 /* Not quite sure this is needed -pd */
8c1a6a84 10040 if (f && FRAME_XIC (f))
6c183ba5
RS
10041 XSetICFocus (FRAME_XIC (f));
10042#endif
f1da8f06
GM
10043#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
10044 instructs the WM to set the input focus automatically for
10045 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
10046 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
10047 it has set the focus. So, XSetInputFocus below is not
10048 needed.
10049
10050 The call to XSetInputFocus below has also caused trouble. In
10051 cases where the XSetInputFocus done by the WM and the one
10052 below are temporally close (on a fast machine), the call
10053 below can generate additional FocusIn events which confuse
10054 Emacs. */
10055
bf7253f4
RS
10056 /* Since we set WM_TAKE_FOCUS, we must call
10057 XSetInputFocus explicitly. But not if f is null,
10058 since that might be an event for a deleted frame. */
7a13e894 10059 if (f)
bf7253f4
RS
10060 {
10061 Display *d = event.xclient.display;
10062 /* Catch and ignore errors, in case window has been
10063 iconified by a window manager such as GWM. */
10064 int count = x_catch_errors (d);
10065 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
10066 /* The ICCCM says this is
10067 the only valid choice. */
10068 RevertToParent,
bf7253f4
RS
10069 event.xclient.data.l[1]);
10070 /* This is needed to detect the error
10071 if there is an error. */
10072 XSync (d, False);
10073 x_uncatch_errors (d, count);
10074 }
7a13e894 10075 /* Not certain about handling scroll bars here */
f1da8f06 10076#endif /* 0 */
c047688c 10077 }
7a13e894
RS
10078 else if (event.xclient.data.l[0]
10079 == dpyinfo->Xatom_wm_save_yourself)
10080 {
10081 /* Save state modify the WM_COMMAND property to
06a2c219 10082 something which can reinstate us. This notifies
7a13e894
RS
10083 the session manager, who's looking for such a
10084 PropertyNotify. Can restart processing when
06a2c219 10085 a keyboard or mouse event arrives. */
7a13e894
RS
10086 if (numchars > 0)
10087 {
19126e11
KH
10088 f = x_top_window_to_frame (dpyinfo,
10089 event.xclient.window);
7a13e894
RS
10090
10091 /* This is just so we only give real data once
10092 for a single Emacs process. */
b86bd3dd 10093 if (f == SELECTED_FRAME ())
7a13e894
RS
10094 XSetCommand (FRAME_X_DISPLAY (f),
10095 event.xclient.window,
10096 initial_argv, initial_argc);
f000f5c5 10097 else if (f)
7a13e894
RS
10098 XSetCommand (FRAME_X_DISPLAY (f),
10099 event.xclient.window,
10100 0, 0);
10101 }
10102 }
10103 else if (event.xclient.data.l[0]
10104 == dpyinfo->Xatom_wm_delete_window)
1fb20991 10105 {
19126e11
KH
10106 struct frame *f
10107 = x_any_window_to_frame (dpyinfo,
10108 event.xclient.window);
1fb20991 10109
7a13e894
RS
10110 if (f)
10111 {
10112 if (numchars == 0)
10113 abort ();
1fb20991 10114
7a13e894
RS
10115 bufp->kind = delete_window_event;
10116 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10117 bufp->arg = Qnil;
7a13e894
RS
10118 bufp++;
10119
10120 count += 1;
10121 numchars -= 1;
10122 }
1fb20991 10123 }
c047688c 10124 }
7a13e894
RS
10125 else if (event.xclient.message_type
10126 == dpyinfo->Xatom_wm_configure_denied)
10127 {
10128 }
10129 else if (event.xclient.message_type
10130 == dpyinfo->Xatom_wm_window_moved)
10131 {
10132 int new_x, new_y;
19126e11
KH
10133 struct frame *f
10134 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 10135
7a13e894
RS
10136 new_x = event.xclient.data.s[0];
10137 new_y = event.xclient.data.s[1];
1fb20991 10138
7a13e894
RS
10139 if (f)
10140 {
7556890b
RS
10141 f->output_data.x->left_pos = new_x;
10142 f->output_data.x->top_pos = new_y;
7a13e894 10143 }
1fb20991 10144 }
0fdff6bb 10145#ifdef HACK_EDITRES
7a13e894
RS
10146 else if (event.xclient.message_type
10147 == dpyinfo->Xatom_editres)
10148 {
19126e11
KH
10149 struct frame *f
10150 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 10151 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 10152 &event, NULL);
7a13e894 10153 }
0fdff6bb 10154#endif /* HACK_EDITRES */
06a2c219
GM
10155 else if ((event.xclient.message_type
10156 == dpyinfo->Xatom_DONE)
10157 || (event.xclient.message_type
10158 == dpyinfo->Xatom_PAGE))
10159 {
10160 /* Ghostview job completed. Kill it. We could
10161 reply with "Next" if we received "Page", but we
10162 currently never do because we are interested in
10163 images, only, which should have 1 page. */
06a2c219
GM
10164 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
10165 struct frame *f
10166 = x_window_to_frame (dpyinfo, event.xclient.window);
10167 x_kill_gs_process (pixmap, f);
10168 expose_frame (f, 0, 0, 0, 0);
10169 }
10170#ifdef USE_TOOLKIT_SCROLL_BARS
10171 /* Scroll bar callbacks send a ClientMessage from which
10172 we construct an input_event. */
10173 else if (event.xclient.message_type
10174 == dpyinfo->Xatom_Scrollbar)
10175 {
10176 x_scroll_bar_to_input_event (&event, bufp);
10177 ++bufp, ++count, --numchars;
10178 goto out;
10179 }
10180#endif /* USE_TOOLKIT_SCROLL_BARS */
10181 else
10182 goto OTHER;
7a13e894
RS
10183 }
10184 break;
dc6f92b8 10185
7a13e894 10186 case SelectionNotify:
3afe33e7 10187#ifdef USE_X_TOOLKIT
19126e11 10188 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 10189 goto OTHER;
3afe33e7 10190#endif /* not USE_X_TOOLKIT */
dfcf069d 10191 x_handle_selection_notify (&event.xselection);
7a13e894 10192 break;
d56a553a 10193
06a2c219 10194 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 10195#ifdef USE_X_TOOLKIT
19126e11 10196 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 10197 goto OTHER;
3afe33e7 10198#endif /* USE_X_TOOLKIT */
7a13e894
RS
10199 {
10200 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 10201
7a13e894
RS
10202 if (numchars == 0)
10203 abort ();
d56a553a 10204
7a13e894
RS
10205 bufp->kind = selection_clear_event;
10206 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10207 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10208 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10209 bufp->frame_or_window = Qnil;
0f8aabe9 10210 bufp->arg = Qnil;
7a13e894 10211 bufp++;
d56a553a 10212
7a13e894
RS
10213 count += 1;
10214 numchars -= 1;
10215 }
10216 break;
dc6f92b8 10217
06a2c219 10218 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 10219#ifdef USE_X_TOOLKIT
19126e11 10220 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 10221 goto OTHER;
3afe33e7 10222#endif /* USE_X_TOOLKIT */
7a13e894 10223 if (x_queue_selection_requests)
19126e11 10224 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
10225 &event);
10226 else
10227 {
1d2b2268
GM
10228 XSelectionRequestEvent *eventp
10229 = (XSelectionRequestEvent *) &event;
dc6f92b8 10230
7a13e894
RS
10231 if (numchars == 0)
10232 abort ();
10233
10234 bufp->kind = selection_request_event;
10235 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10236 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
10237 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10238 SELECTION_EVENT_TARGET (bufp) = eventp->target;
10239 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
10240 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10241 bufp->frame_or_window = Qnil;
0f8aabe9 10242 bufp->arg = Qnil;
7a13e894
RS
10243 bufp++;
10244
10245 count += 1;
10246 numchars -= 1;
10247 }
10248 break;
10249
10250 case PropertyNotify:
1d2b2268
GM
10251#if 0 /* This is plain wrong. In the case that we are waiting for a
10252 PropertyNotify used as an ACK in incremental selection
10253 transfer, the property will be on the receiver's window. */
10254#if defined USE_X_TOOLKIT
19126e11 10255 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 10256 goto OTHER;
1d2b2268
GM
10257#endif
10258#endif
dfcf069d 10259 x_handle_property_notify (&event.xproperty);
1d2b2268 10260 goto OTHER;
dc6f92b8 10261
7a13e894 10262 case ReparentNotify:
19126e11 10263 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
10264 if (f)
10265 {
10266 int x, y;
7556890b 10267 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 10268 x_real_positions (f, &x, &y);
7556890b
RS
10269 f->output_data.x->left_pos = x;
10270 f->output_data.x->top_pos = y;
7a13e894
RS
10271 }
10272 break;
3bd330d4 10273
7a13e894 10274 case Expose:
19126e11 10275 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 10276 if (f)
dc6f92b8 10277 {
7a13e894
RS
10278 if (f->async_visible == 0)
10279 {
10280 f->async_visible = 1;
10281 f->async_iconified = 0;
06c488fd 10282 f->output_data.x->has_been_visible = 1;
7a13e894
RS
10283 SET_FRAME_GARBAGED (f);
10284 }
10285 else
06a2c219
GM
10286 expose_frame (x_window_to_frame (dpyinfo,
10287 event.xexpose.window),
10288 event.xexpose.x, event.xexpose.y,
10289 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
10290 }
10291 else
7a13e894 10292 {
12949a7f
EZ
10293#ifndef USE_TOOLKIT_SCROLL_BARS
10294 struct scroll_bar *bar;
10295#endif
c95fc5f1
GM
10296#if defined USE_X_TOOLKIT && defined USE_LUCID
10297 /* Submenus of the Lucid menu bar aren't widgets
10298 themselves, so there's no way to dispatch events
10299 to them. Recognize this case separately. */
10300 {
10301 Widget widget
10302 = x_window_to_menu_bar (event.xexpose.window);
10303 if (widget)
10304 xlwmenu_redisplay (widget);
10305 }
10306#endif /* USE_X_TOOLKIT && USE_LUCID */
10307
06a2c219
GM
10308#ifdef USE_TOOLKIT_SCROLL_BARS
10309 /* Dispatch event to the widget. */
10310 goto OTHER;
10311#else /* not USE_TOOLKIT_SCROLL_BARS */
12949a7f 10312 bar = x_window_to_scroll_bar (event.xexpose.window);
58769bee 10313
7a13e894
RS
10314 if (bar)
10315 x_scroll_bar_expose (bar, &event);
3afe33e7 10316#ifdef USE_X_TOOLKIT
7a13e894
RS
10317 else
10318 goto OTHER;
3afe33e7 10319#endif /* USE_X_TOOLKIT */
06a2c219 10320#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10321 }
10322 break;
dc6f92b8 10323
7a13e894
RS
10324 case GraphicsExpose: /* This occurs when an XCopyArea's
10325 source area was obscured or not
10326 available.*/
19126e11 10327 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
10328 if (f)
10329 {
06a2c219
GM
10330 expose_frame (f,
10331 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
10332 event.xgraphicsexpose.width,
10333 event.xgraphicsexpose.height);
7a13e894 10334 }
3afe33e7 10335#ifdef USE_X_TOOLKIT
7a13e894
RS
10336 else
10337 goto OTHER;
3afe33e7 10338#endif /* USE_X_TOOLKIT */
7a13e894 10339 break;
dc6f92b8 10340
7a13e894 10341 case NoExpose: /* This occurs when an XCopyArea's
06a2c219
GM
10342 source area was completely
10343 available */
7a13e894 10344 break;
dc6f92b8 10345
7a13e894 10346 case UnmapNotify:
06a2c219
GM
10347 /* Redo the mouse-highlight after the tooltip has gone. */
10348 if (event.xmap.window == tip_window)
10349 {
10350 tip_window = 0;
10351 redo_mouse_highlight ();
10352 }
10353
91ea2a7a 10354 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894
RS
10355 if (f) /* F may no longer exist if
10356 the frame was deleted. */
10357 {
10358 /* While a frame is unmapped, display generation is
10359 disabled; you don't want to spend time updating a
10360 display that won't ever be seen. */
10361 f->async_visible = 0;
10362 /* We can't distinguish, from the event, whether the window
10363 has become iconified or invisible. So assume, if it
10364 was previously visible, than now it is iconified.
1aa6072f
RS
10365 But x_make_frame_invisible clears both
10366 the visible flag and the iconified flag;
10367 and that way, we know the window is not iconified now. */
7a13e894 10368 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
10369 {
10370 f->async_iconified = 1;
bddd097c 10371
1aa6072f
RS
10372 bufp->kind = iconify_event;
10373 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10374 bufp->arg = Qnil;
1aa6072f
RS
10375 bufp++;
10376 count++;
10377 numchars--;
10378 }
7a13e894 10379 }
7a13e894 10380 goto OTHER;
dc6f92b8 10381
7a13e894 10382 case MapNotify:
06a2c219
GM
10383 if (event.xmap.window == tip_window)
10384 /* The tooltip has been drawn already. Avoid
10385 the SET_FRAME_GARBAGED below. */
10386 goto OTHER;
10387
10388 /* We use x_top_window_to_frame because map events can
10389 come for sub-windows and they don't mean that the
10390 frame is visible. */
19126e11 10391 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
10392 if (f)
10393 {
10394 f->async_visible = 1;
10395 f->async_iconified = 0;
06c488fd 10396 f->output_data.x->has_been_visible = 1;
dc6f92b8 10397
7a13e894
RS
10398 /* wait_reading_process_input will notice this and update
10399 the frame's display structures. */
10400 SET_FRAME_GARBAGED (f);
bddd097c 10401
d806e720
RS
10402 if (f->iconified)
10403 {
10404 bufp->kind = deiconify_event;
10405 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10406 bufp->arg = Qnil;
d806e720
RS
10407 bufp++;
10408 count++;
10409 numchars--;
10410 }
e73ec6fa 10411 else if (! NILP (Vframe_list)
8e713be6 10412 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
10413 /* Force a redisplay sooner or later
10414 to update the frame titles
10415 in case this is the second frame. */
10416 record_asynch_buffer_change ();
7a13e894 10417 }
7a13e894 10418 goto OTHER;
dc6f92b8 10419
7a13e894 10420 case KeyPress:
19126e11 10421 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 10422
eccc05db 10423#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
10424 if (f == 0)
10425 {
2564ea1b
GM
10426 /* Scroll bars consume key events, but we want
10427 the keys to go to the scroll bar's frame. */
06a2c219
GM
10428 Widget widget = XtWindowToWidget (dpyinfo->display,
10429 event.xkey.window);
10430 if (widget && XmIsScrollBar (widget))
10431 {
10432 widget = XtParent (widget);
10433 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
10434 }
10435 }
eccc05db 10436#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
06a2c219 10437
7a13e894
RS
10438 if (f != 0)
10439 {
10440 KeySym keysym, orig_keysym;
379b5ac0
KH
10441 /* al%imercury@uunet.uu.net says that making this 81
10442 instead of 80 fixed a bug whereby meta chars made
10443 his Emacs hang.
10444
10445 It seems that some version of XmbLookupString has
10446 a bug of not returning XBufferOverflow in
10447 status_return even if the input is too long to
10448 fit in 81 bytes. So, we must prepare sufficient
10449 bytes for copy_buffer. 513 bytes (256 chars for
10450 two-byte character set) seems to be a faily good
10451 approximation. -- 2000.8.10 handa@etl.go.jp */
10452 unsigned char copy_buffer[513];
10453 unsigned char *copy_bufptr = copy_buffer;
10454 int copy_bufsiz = sizeof (copy_buffer);
7a13e894 10455 int modifiers;
64bb1782 10456
7a13e894
RS
10457 event.xkey.state
10458 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
10459 extra_keyboard_modifiers);
10460 modifiers = event.xkey.state;
3a2712f9 10461
7a13e894 10462 /* This will have to go some day... */
752a043f 10463
7a13e894
RS
10464 /* make_lispy_event turns chars into control chars.
10465 Don't do it here because XLookupString is too eager. */
10466 event.xkey.state &= ~ControlMask;
5d46f928
RS
10467 event.xkey.state &= ~(dpyinfo->meta_mod_mask
10468 | dpyinfo->super_mod_mask
10469 | dpyinfo->hyper_mod_mask
10470 | dpyinfo->alt_mod_mask);
10471
1cf4a0d1
RS
10472 /* In case Meta is ComposeCharacter,
10473 clear its status. According to Markus Ehrnsperger
10474 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
10475 this enables ComposeCharacter to work whether or
10476 not it is combined with Meta. */
10477 if (modifiers & dpyinfo->meta_mod_mask)
10478 bzero (&compose_status, sizeof (compose_status));
10479
6c183ba5
RS
10480#ifdef HAVE_X_I18N
10481 if (FRAME_XIC (f))
10482 {
f5d11644
GM
10483 Status status_return;
10484
6c183ba5 10485 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
10486 &event.xkey, copy_bufptr,
10487 copy_bufsiz, &keysym,
6c183ba5 10488 &status_return);
f5d11644
GM
10489 if (status_return == XBufferOverflow)
10490 {
10491 copy_bufsiz = nbytes + 1;
10492 copy_bufptr = (char *) alloca (copy_bufsiz);
10493 nbytes = XmbLookupString (FRAME_XIC (f),
10494 &event.xkey, copy_bufptr,
10495 copy_bufsiz, &keysym,
10496 &status_return);
10497 }
10498
1decb680
PE
10499 if (status_return == XLookupNone)
10500 break;
10501 else if (status_return == XLookupChars)
fdd9d55e
GM
10502 {
10503 keysym = NoSymbol;
10504 modifiers = 0;
10505 }
1decb680
PE
10506 else if (status_return != XLookupKeySym
10507 && status_return != XLookupBoth)
10508 abort ();
6c183ba5
RS
10509 }
10510 else
379b5ac0
KH
10511 nbytes = XLookupString (&event.xkey, copy_bufptr,
10512 copy_bufsiz, &keysym,
10513 &compose_status);
6c183ba5 10514#else
379b5ac0
KH
10515 nbytes = XLookupString (&event.xkey, copy_bufptr,
10516 copy_bufsiz, &keysym,
10517 &compose_status);
6c183ba5 10518#endif
dc6f92b8 10519
7a13e894 10520 orig_keysym = keysym;
55123275 10521
7a13e894
RS
10522 if (numchars > 1)
10523 {
10524 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
10525 || keysym == XK_Delete
1097aea0 10526#ifdef XK_ISO_Left_Tab
441affdb 10527 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 10528#endif
852bff8f 10529 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
10530 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
10531 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 10532#ifdef HPUX
7a13e894
RS
10533 /* This recognizes the "extended function keys".
10534 It seems there's no cleaner way.
10535 Test IsModifierKey to avoid handling mode_switch
10536 incorrectly. */
10537 || ((unsigned) (keysym) >= XK_Select
10538 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
10539#endif
10540#ifdef XK_dead_circumflex
7a13e894 10541 || orig_keysym == XK_dead_circumflex
69388238
RS
10542#endif
10543#ifdef XK_dead_grave
7a13e894 10544 || orig_keysym == XK_dead_grave
69388238
RS
10545#endif
10546#ifdef XK_dead_tilde
7a13e894 10547 || orig_keysym == XK_dead_tilde
69388238
RS
10548#endif
10549#ifdef XK_dead_diaeresis
7a13e894 10550 || orig_keysym == XK_dead_diaeresis
69388238
RS
10551#endif
10552#ifdef XK_dead_macron
7a13e894 10553 || orig_keysym == XK_dead_macron
69388238
RS
10554#endif
10555#ifdef XK_dead_degree
7a13e894 10556 || orig_keysym == XK_dead_degree
69388238
RS
10557#endif
10558#ifdef XK_dead_acute
7a13e894 10559 || orig_keysym == XK_dead_acute
69388238
RS
10560#endif
10561#ifdef XK_dead_cedilla
7a13e894 10562 || orig_keysym == XK_dead_cedilla
69388238
RS
10563#endif
10564#ifdef XK_dead_breve
7a13e894 10565 || orig_keysym == XK_dead_breve
69388238
RS
10566#endif
10567#ifdef XK_dead_ogonek
7a13e894 10568 || orig_keysym == XK_dead_ogonek
69388238
RS
10569#endif
10570#ifdef XK_dead_caron
7a13e894 10571 || orig_keysym == XK_dead_caron
69388238
RS
10572#endif
10573#ifdef XK_dead_doubleacute
7a13e894 10574 || orig_keysym == XK_dead_doubleacute
69388238
RS
10575#endif
10576#ifdef XK_dead_abovedot
7a13e894 10577 || orig_keysym == XK_dead_abovedot
c34790e0 10578#endif
7a13e894
RS
10579 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
10580 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
10581 /* Any "vendor-specific" key is ok. */
f0e299de
GM
10582 || (orig_keysym & (1 << 28))
10583 || (keysym != NoSymbol && nbytes == 0))
7a13e894 10584 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
10585#ifndef HAVE_X11R5
10586#ifdef XK_Mode_switch
7a13e894 10587 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
10588#endif
10589#ifdef XK_Num_Lock
7a13e894 10590 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
10591#endif
10592#endif /* not HAVE_X11R5 */
7a13e894 10593 ))
dc6f92b8 10594 {
10e6549c
RS
10595 if (temp_index == sizeof temp_buffer / sizeof (short))
10596 temp_index = 0;
7a13e894
RS
10597 temp_buffer[temp_index++] = keysym;
10598 bufp->kind = non_ascii_keystroke;
10599 bufp->code = keysym;
e0c1aef2 10600 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10601 bufp->arg = Qnil;
334208b7
RS
10602 bufp->modifiers
10603 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10604 modifiers);
1113d9db 10605 bufp->timestamp = event.xkey.time;
dc6f92b8 10606 bufp++;
7a13e894
RS
10607 count++;
10608 numchars--;
dc6f92b8 10609 }
7a13e894
RS
10610 else if (numchars > nbytes)
10611 {
10612 register int i;
379b5ac0 10613 register int c;
379b5ac0 10614 int nchars, len;
7a13e894
RS
10615
10616 for (i = 0; i < nbytes; i++)
10617 {
379b5ac0
KH
10618 if (temp_index == (sizeof temp_buffer
10619 / sizeof (short)))
7a13e894 10620 temp_index = 0;
379b5ac0
KH
10621 temp_buffer[temp_index++] = copy_bufptr[i];
10622 }
10623
10624 if (/* If the event is not from XIM, */
10625 event.xkey.keycode != 0
10626 /* or the current locale doesn't request
10627 decoding of the intup data, ... */
10628 || coding.type == coding_type_raw_text
10629 || coding.type == coding_type_no_conversion)
10630 {
10631 /* ... we can use the input data as is. */
10632 nchars = nbytes;
10633 }
10634 else
10635 {
10636 /* We have to decode the input data. */
10637 int require;
10638 unsigned char *p;
10639
10640 require = decoding_buffer_size (&coding, nbytes);
10641 p = (unsigned char *) alloca (require);
10642 coding.mode |= CODING_MODE_LAST_BLOCK;
10643 decode_coding (&coding, copy_bufptr, p,
10644 nbytes, require);
10645 nbytes = coding.produced;
10646 nchars = coding.produced_char;
10647 copy_bufptr = p;
10648 }
10649
10650 /* Convert the input data to a sequence of
10651 character events. */
10652 for (i = 0; i < nbytes; i += len)
10653 {
10654 c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
10655 nbytes - i, len);
10656 bufp->kind = (SINGLE_BYTE_CHAR_P (c)
10657 ? ascii_keystroke
10658 : multibyte_char_keystroke);
10659 bufp->code = c;
7a13e894 10660 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10661 bufp->arg = Qnil;
7a13e894
RS
10662 bufp->modifiers
10663 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10664 modifiers);
10665 bufp->timestamp = event.xkey.time;
10666 bufp++;
10667 }
10668
379b5ac0
KH
10669 count += nchars;
10670 numchars -= nchars;
1decb680
PE
10671
10672 if (keysym == NoSymbol)
10673 break;
7a13e894
RS
10674 }
10675 else
10676 abort ();
dc6f92b8 10677 }
10e6549c
RS
10678 else
10679 abort ();
dc6f92b8 10680 }
59ddecde
GM
10681#ifdef HAVE_X_I18N
10682 /* Don't dispatch this event since XtDispatchEvent calls
10683 XFilterEvent, and two calls in a row may freeze the
10684 client. */
10685 break;
10686#else
717ca130 10687 goto OTHER;
59ddecde 10688#endif
f451eb13 10689
f5d11644 10690 case KeyRelease:
59ddecde
GM
10691#ifdef HAVE_X_I18N
10692 /* Don't dispatch this event since XtDispatchEvent calls
10693 XFilterEvent, and two calls in a row may freeze the
10694 client. */
10695 break;
10696#else
f5d11644 10697 goto OTHER;
59ddecde 10698#endif
f5d11644 10699
7a13e894 10700 /* Here's a possible interpretation of the whole
06a2c219
GM
10701 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
10702 you get a FocusIn event, you have to get a FocusOut
10703 event before you relinquish the focus. If you
10704 haven't received a FocusIn event, then a mere
10705 LeaveNotify is enough to free you. */
f451eb13 10706
7a13e894 10707 case EnterNotify:
06a2c219 10708 {
06a2c219
GM
10709 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
10710
582c60f8 10711 if (event.xcrossing.focus)
06a2c219
GM
10712 {
10713 /* Avoid nasty pop/raise loops. */
10714 if (f && (!(f->auto_raise)
10715 || !(f->auto_lower)
10716 || (event.xcrossing.time - enter_timestamp) > 500))
10717 {
10718 x_new_focus_frame (dpyinfo, f);
10719 enter_timestamp = event.xcrossing.time;
10720 }
10721 }
10722 else if (f == dpyinfo->x_focus_frame)
10723 x_new_focus_frame (dpyinfo, 0);
10724
10725 /* EnterNotify counts as mouse movement,
10726 so update things that depend on mouse position. */
2533c408 10727 if (f && !f->output_data.x->hourglass_p)
06a2c219
GM
10728 note_mouse_movement (f, &event.xmotion);
10729 goto OTHER;
10730 }
dc6f92b8 10731
7a13e894 10732 case FocusIn:
19126e11 10733 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10734 if (event.xfocus.detail != NotifyPointer)
0f941935 10735 dpyinfo->x_focus_event_frame = f;
7a13e894 10736 if (f)
eb72635f
GM
10737 {
10738 x_new_focus_frame (dpyinfo, f);
10739
10740 /* Don't stop displaying the initial startup message
10741 for a switch-frame event we don't need. */
10742 if (GC_NILP (Vterminal_frame)
10743 && GC_CONSP (Vframe_list)
10744 && !GC_NILP (XCDR (Vframe_list)))
10745 {
10746 bufp->kind = FOCUS_IN_EVENT;
10747 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10748 bufp->arg = Qnil;
eb72635f
GM
10749 ++bufp, ++count, --numchars;
10750 }
10751 }
f9e24cb9 10752
6c183ba5
RS
10753#ifdef HAVE_X_I18N
10754 if (f && FRAME_XIC (f))
10755 XSetICFocus (FRAME_XIC (f));
10756#endif
10757
7a13e894 10758 goto OTHER;
10c5e63d 10759
7a13e894 10760 case LeaveNotify:
19126e11 10761 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 10762 if (f)
10c5e63d 10763 {
7a13e894 10764 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
10765 {
10766 /* If we move outside the frame, then we're
10767 certainly no longer on any text in the frame. */
10768 clear_mouse_face (dpyinfo);
10769 dpyinfo->mouse_face_mouse_frame = 0;
10770 }
10771
10772 /* Generate a nil HELP_EVENT to cancel a help-echo.
10773 Do it only if there's something to cancel.
10774 Otherwise, the startup message is cleared when
10775 the mouse leaves the frame. */
10776 if (any_help_event_p)
10777 {
be010514
GM
10778 Lisp_Object frame;
10779 int n;
10780
06a2c219 10781 XSETFRAME (frame, f);
82c5d67a 10782 help_echo = Qnil;
5ab2570d
GM
10783 n = gen_help_event (bufp, numchars,
10784 Qnil, frame, Qnil, Qnil, 0);
be010514 10785 bufp += n, count += n, numchars -= n;
06a2c219 10786 }
7a13e894 10787
582c60f8 10788 if (event.xcrossing.focus)
0f941935 10789 x_mouse_leave (dpyinfo);
10c5e63d 10790 else
7a13e894 10791 {
0f941935
KH
10792 if (f == dpyinfo->x_focus_event_frame)
10793 dpyinfo->x_focus_event_frame = 0;
10794 if (f == dpyinfo->x_focus_frame)
10795 x_new_focus_frame (dpyinfo, 0);
7a13e894 10796 }
10c5e63d 10797 }
7a13e894 10798 goto OTHER;
dc6f92b8 10799
7a13e894 10800 case FocusOut:
19126e11 10801 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10802 if (event.xfocus.detail != NotifyPointer
0f941935
KH
10803 && f == dpyinfo->x_focus_event_frame)
10804 dpyinfo->x_focus_event_frame = 0;
10805 if (f && f == dpyinfo->x_focus_frame)
10806 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 10807
6c183ba5
RS
10808#ifdef HAVE_X_I18N
10809 if (f && FRAME_XIC (f))
10810 XUnsetICFocus (FRAME_XIC (f));
10811#endif
10812
7a13e894 10813 goto OTHER;
dc6f92b8 10814
7a13e894 10815 case MotionNotify:
dc6f92b8 10816 {
06a2c219 10817 previous_help_echo = help_echo;
7cea38bc 10818 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 10819 help_echo_pos = -1;
06a2c219 10820
7a13e894
RS
10821 if (dpyinfo->grabbed && last_mouse_frame
10822 && FRAME_LIVE_P (last_mouse_frame))
10823 f = last_mouse_frame;
10824 else
19126e11 10825 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 10826
7a13e894
RS
10827 if (f)
10828 note_mouse_movement (f, &event.xmotion);
10829 else
10830 {
e88b3c50 10831#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10832 struct scroll_bar *bar
10833 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 10834
7a13e894
RS
10835 if (bar)
10836 x_scroll_bar_note_movement (bar, &event);
e88b3c50 10837#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 10838
06a2c219
GM
10839 /* If we move outside the frame, then we're
10840 certainly no longer on any text in the frame. */
7a13e894
RS
10841 clear_mouse_face (dpyinfo);
10842 }
06a2c219
GM
10843
10844 /* If the contents of the global variable help_echo
10845 has changed, generate a HELP_EVENT. */
b7e80413
SM
10846 if (!NILP (help_echo)
10847 || !NILP (previous_help_echo))
06a2c219
GM
10848 {
10849 Lisp_Object frame;
be010514 10850 int n;
06a2c219
GM
10851
10852 if (f)
10853 XSETFRAME (frame, f);
10854 else
10855 frame = Qnil;
10856
10857 any_help_event_p = 1;
5ab2570d 10858 n = gen_help_event (bufp, numchars, help_echo, frame,
7cea38bc
GM
10859 help_echo_window, help_echo_object,
10860 help_echo_pos);
be010514 10861 bufp += n, count += n, numchars -= n;
06a2c219
GM
10862 }
10863
10864 goto OTHER;
dc6f92b8 10865 }
dc6f92b8 10866
7a13e894 10867 case ConfigureNotify:
9829ddba
RS
10868 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
10869 if (f)
af395ec1 10870 {
5c187dee 10871#ifndef USE_X_TOOLKIT
bf1b7b30
KH
10872 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
10873 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 10874
2d7fc7e8
RS
10875 /* In the toolkit version, change_frame_size
10876 is called by the code that handles resizing
10877 of the EmacsFrame widget. */
7a13e894 10878
7a13e894
RS
10879 /* Even if the number of character rows and columns has
10880 not changed, the font size may have changed, so we need
10881 to check the pixel dimensions as well. */
10882 if (columns != f->width
10883 || rows != f->height
7556890b
RS
10884 || event.xconfigure.width != f->output_data.x->pixel_width
10885 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 10886 {
7d1e984f 10887 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 10888 SET_FRAME_GARBAGED (f);
e687d06e 10889 cancel_mouse_face (f);
7a13e894 10890 }
2d7fc7e8 10891#endif
af395ec1 10892
7556890b
RS
10893 f->output_data.x->pixel_width = event.xconfigure.width;
10894 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
10895
10896 /* What we have now is the position of Emacs's own window.
10897 Convert that to the position of the window manager window. */
dcb07ae9
RS
10898 x_real_positions (f, &f->output_data.x->left_pos,
10899 &f->output_data.x->top_pos);
10900
f5d11644
GM
10901#ifdef HAVE_X_I18N
10902 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
10903 xic_set_statusarea (f);
10904#endif
10905
dcb07ae9
RS
10906 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
10907 {
10908 /* Since the WM decorations come below top_pos now,
10909 we must put them below top_pos in the future. */
10910 f->output_data.x->win_gravity = NorthWestGravity;
10911 x_wm_set_size_hint (f, (long) 0, 0);
10912 }
8f08dc93
KH
10913#ifdef USE_MOTIF
10914 /* Some window managers pass (0,0) as the location of
10915 the window, and the Motif event handler stores it
10916 in the emacs widget, which messes up Motif menus. */
10917 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
10918 {
10919 event.xconfigure.x = f->output_data.x->widget->core.x;
10920 event.xconfigure.y = f->output_data.x->widget->core.y;
10921 }
06a2c219 10922#endif /* USE_MOTIF */
7a13e894 10923 }
2d7fc7e8 10924 goto OTHER;
dc6f92b8 10925
7a13e894
RS
10926 case ButtonPress:
10927 case ButtonRelease:
10928 {
10929 /* If we decide we want to generate an event to be seen
10930 by the rest of Emacs, we put it here. */
10931 struct input_event emacs_event;
9ea173e8 10932 int tool_bar_p = 0;
06a2c219 10933
7a13e894 10934 emacs_event.kind = no_event;
7a13e894 10935 bzero (&compose_status, sizeof (compose_status));
9b07615b 10936
06a2c219
GM
10937 if (dpyinfo->grabbed
10938 && last_mouse_frame
9f67f20b
RS
10939 && FRAME_LIVE_P (last_mouse_frame))
10940 f = last_mouse_frame;
10941 else
2224b905 10942 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 10943
06a2c219
GM
10944 if (f)
10945 {
9ea173e8
GM
10946 /* Is this in the tool-bar? */
10947 if (WINDOWP (f->tool_bar_window)
10948 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
10949 {
10950 Lisp_Object window;
10951 int p, x, y;
10952
10953 x = event.xbutton.x;
10954 y = event.xbutton.y;
10955
10956 /* Set x and y. */
10957 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 10958 if (EQ (window, f->tool_bar_window))
06a2c219 10959 {
9ea173e8
GM
10960 x_handle_tool_bar_click (f, &event.xbutton);
10961 tool_bar_p = 1;
06a2c219
GM
10962 }
10963 }
10964
9ea173e8 10965 if (!tool_bar_p)
06a2c219
GM
10966 if (!dpyinfo->x_focus_frame
10967 || f == dpyinfo->x_focus_frame)
10968 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
10969 }
10970 else
10971 {
06a2c219 10972#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10973 struct scroll_bar *bar
10974 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 10975
7a13e894
RS
10976 if (bar)
10977 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 10978#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10979 }
10980
10981 if (event.type == ButtonPress)
10982 {
10983 dpyinfo->grabbed |= (1 << event.xbutton.button);
10984 last_mouse_frame = f;
edad46f6
KH
10985 /* Ignore any mouse motion that happened
10986 before this event; any subsequent mouse-movement
10987 Emacs events should reflect only motion after
10988 the ButtonPress. */
a00e91cd
KH
10989 if (f != 0)
10990 f->mouse_moved = 0;
06a2c219 10991
9ea173e8
GM
10992 if (!tool_bar_p)
10993 last_tool_bar_item = -1;
7a13e894 10994 }
3afe33e7
RS
10995 else
10996 {
7a13e894 10997 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10998 }
23faf38f 10999
7a13e894
RS
11000 if (numchars >= 1 && emacs_event.kind != no_event)
11001 {
11002 bcopy (&emacs_event, bufp, sizeof (struct input_event));
11003 bufp++;
11004 count++;
11005 numchars--;
11006 }
3afe33e7
RS
11007
11008#ifdef USE_X_TOOLKIT
2224b905
RS
11009 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
11010 /* For a down-event in the menu bar,
11011 don't pass it to Xt right now.
11012 Instead, save it away
11013 and we will pass it to Xt from kbd_buffer_get_event.
11014 That way, we can run some Lisp code first. */
91375f8f
RS
11015 if (f && event.type == ButtonPress
11016 /* Verify the event is really within the menu bar
11017 and not just sent to it due to grabbing. */
11018 && event.xbutton.x >= 0
11019 && event.xbutton.x < f->output_data.x->pixel_width
11020 && event.xbutton.y >= 0
11021 && event.xbutton.y < f->output_data.x->menubar_height
11022 && event.xbutton.same_screen)
2224b905 11023 {
8805890a 11024 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
11025 XSETFRAME (last_mouse_press_frame, f);
11026 }
11027 else if (event.type == ButtonPress)
11028 {
11029 last_mouse_press_frame = Qnil;
30e671c3 11030 goto OTHER;
ce89ef46 11031 }
06a2c219 11032
2237cac9
RS
11033#ifdef USE_MOTIF /* This should do not harm for Lucid,
11034 but I am trying to be cautious. */
ce89ef46
RS
11035 else if (event.type == ButtonRelease)
11036 {
2237cac9 11037 if (!NILP (last_mouse_press_frame))
f10ded1c 11038 {
2237cac9
RS
11039 f = XFRAME (last_mouse_press_frame);
11040 if (f->output_data.x)
06a2c219 11041 SET_SAVED_BUTTON_EVENT;
f10ded1c 11042 }
06a2c219 11043 else
30e671c3 11044 goto OTHER;
2224b905 11045 }
2237cac9 11046#endif /* USE_MOTIF */
2224b905
RS
11047 else
11048 goto OTHER;
3afe33e7 11049#endif /* USE_X_TOOLKIT */
7a13e894
RS
11050 }
11051 break;
dc6f92b8 11052
7a13e894 11053 case CirculateNotify:
06a2c219
GM
11054 goto OTHER;
11055
7a13e894 11056 case CirculateRequest:
06a2c219
GM
11057 goto OTHER;
11058
11059 case VisibilityNotify:
11060 goto OTHER;
dc6f92b8 11061
7a13e894
RS
11062 case MappingNotify:
11063 /* Someone has changed the keyboard mapping - update the
11064 local cache. */
11065 switch (event.xmapping.request)
11066 {
11067 case MappingModifier:
11068 x_find_modifier_meanings (dpyinfo);
11069 /* This is meant to fall through. */
11070 case MappingKeyboard:
11071 XRefreshKeyboardMapping (&event.xmapping);
11072 }
7a13e894 11073 goto OTHER;
dc6f92b8 11074
7a13e894 11075 default:
7a13e894 11076 OTHER:
717ca130 11077#ifdef USE_X_TOOLKIT
7a13e894
RS
11078 BLOCK_INPUT;
11079 XtDispatchEvent (&event);
11080 UNBLOCK_INPUT;
3afe33e7 11081#endif /* USE_X_TOOLKIT */
7a13e894
RS
11082 break;
11083 }
dc6f92b8
JB
11084 }
11085 }
11086
06a2c219
GM
11087 out:;
11088
9a5196d0
RS
11089 /* On some systems, an X bug causes Emacs to get no more events
11090 when the window is destroyed. Detect that. (1994.) */
58769bee 11091 if (! event_found)
ef2a22d0 11092 {
ef2a22d0
RS
11093 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
11094 One XNOOP in 100 loops will make Emacs terminate.
11095 B. Bretthauer, 1994 */
11096 x_noop_count++;
58769bee 11097 if (x_noop_count >= 100)
ef2a22d0
RS
11098 {
11099 x_noop_count=0;
2224b905
RS
11100
11101 if (next_noop_dpyinfo == 0)
11102 next_noop_dpyinfo = x_display_list;
11103
11104 XNoOp (next_noop_dpyinfo->display);
11105
11106 /* Each time we get here, cycle through the displays now open. */
11107 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
11108 }
11109 }
502add23 11110
06a2c219 11111 /* If the focus was just given to an auto-raising frame,
0134a210 11112 raise it now. */
7a13e894 11113 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
11114 if (pending_autoraise_frame)
11115 {
11116 x_raise_frame (pending_autoraise_frame);
11117 pending_autoraise_frame = 0;
11118 }
0134a210 11119
dc6f92b8 11120 UNBLOCK_INPUT;
bde5503b 11121 --handling_signal;
dc6f92b8
JB
11122 return count;
11123}
06a2c219
GM
11124
11125
11126
dc6f92b8 11127\f
06a2c219
GM
11128/***********************************************************************
11129 Text Cursor
11130 ***********************************************************************/
11131
11132/* Note if the text cursor of window W has been overwritten by a
11133 drawing operation that outputs N glyphs starting at HPOS in the
11134 line given by output_cursor.vpos. N < 0 means all the rest of the
11135 line after HPOS has been written. */
11136
11137static void
11138note_overwritten_text_cursor (w, hpos, n)
11139 struct window *w;
11140 int hpos, n;
11141{
11142 if (updated_area == TEXT_AREA
11143 && output_cursor.vpos == w->phys_cursor.vpos
11144 && hpos <= w->phys_cursor.hpos
11145 && (n < 0
11146 || hpos + n > w->phys_cursor.hpos))
11147 w->phys_cursor_on_p = 0;
11148}
f451eb13
JB
11149
11150
06a2c219
GM
11151/* Set clipping for output in glyph row ROW. W is the window in which
11152 we operate. GC is the graphics context to set clipping in.
11153 WHOLE_LINE_P non-zero means include the areas used for truncation
11154 mark display and alike in the clipping rectangle.
11155
11156 ROW may be a text row or, e.g., a mode line. Text rows must be
11157 clipped to the interior of the window dedicated to text display,
11158 mode lines must be clipped to the whole window. */
dc6f92b8
JB
11159
11160static void
06a2c219
GM
11161x_clip_to_row (w, row, gc, whole_line_p)
11162 struct window *w;
11163 struct glyph_row *row;
11164 GC gc;
11165 int whole_line_p;
dc6f92b8 11166{
06a2c219
GM
11167 struct frame *f = XFRAME (WINDOW_FRAME (w));
11168 XRectangle clip_rect;
11169 int window_x, window_y, window_width, window_height;
dc6f92b8 11170
06a2c219 11171 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 11172
06a2c219
GM
11173 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
11174 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
11175 clip_rect.y = max (clip_rect.y, window_y);
11176 clip_rect.width = window_width;
11177 clip_rect.height = row->visible_height;
5c1aae96 11178
06a2c219
GM
11179 /* If clipping to the whole line, including trunc marks, extend
11180 the rectangle to the left and increase its width. */
11181 if (whole_line_p)
11182 {
110859fc
GM
11183 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
11184 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 11185 }
5c1aae96 11186
06a2c219 11187 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
11188}
11189
06a2c219
GM
11190
11191/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
11192
11193static void
06a2c219
GM
11194x_draw_hollow_cursor (w, row)
11195 struct window *w;
11196 struct glyph_row *row;
dc6f92b8 11197{
06a2c219
GM
11198 struct frame *f = XFRAME (WINDOW_FRAME (w));
11199 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11200 Display *dpy = FRAME_X_DISPLAY (f);
11201 int x, y, wd, h;
11202 XGCValues xgcv;
11203 struct glyph *cursor_glyph;
11204 GC gc;
11205
11206 /* Compute frame-relative coordinates from window-relative
11207 coordinates. */
11208 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11209 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
11210 + row->ascent - w->phys_cursor_ascent);
11211 h = row->height - 1;
11212
11213 /* Get the glyph the cursor is on. If we can't tell because
11214 the current matrix is invalid or such, give up. */
11215 cursor_glyph = get_phys_cursor_glyph (w);
11216 if (cursor_glyph == NULL)
dc6f92b8
JB
11217 return;
11218
06a2c219
GM
11219 /* Compute the width of the rectangle to draw. If on a stretch
11220 glyph, and `x-stretch-block-cursor' is nil, don't draw a
11221 rectangle as wide as the glyph, but use a canonical character
11222 width instead. */
11223 wd = cursor_glyph->pixel_width - 1;
11224 if (cursor_glyph->type == STRETCH_GLYPH
11225 && !x_stretch_cursor_p)
11226 wd = min (CANON_X_UNIT (f), wd);
11227
11228 /* The foreground of cursor_gc is typically the same as the normal
11229 background color, which can cause the cursor box to be invisible. */
11230 xgcv.foreground = f->output_data.x->cursor_pixel;
11231 if (dpyinfo->scratch_cursor_gc)
11232 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
11233 else
11234 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
11235 GCForeground, &xgcv);
11236 gc = dpyinfo->scratch_cursor_gc;
11237
11238 /* Set clipping, draw the rectangle, and reset clipping again. */
11239 x_clip_to_row (w, row, gc, 0);
11240 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
11241 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
11242}
11243
06a2c219
GM
11244
11245/* Draw a bar cursor on window W in glyph row ROW.
11246
11247 Implementation note: One would like to draw a bar cursor with an
11248 angle equal to the one given by the font property XA_ITALIC_ANGLE.
11249 Unfortunately, I didn't find a font yet that has this property set.
11250 --gerd. */
dc6f92b8
JB
11251
11252static void
f02d8aa0 11253x_draw_bar_cursor (w, row, width)
06a2c219
GM
11254 struct window *w;
11255 struct glyph_row *row;
f02d8aa0 11256 int width;
dc6f92b8 11257{
92f424df
GM
11258 struct frame *f = XFRAME (w->frame);
11259 struct glyph *cursor_glyph;
11260 GC gc;
11261 int x;
11262 unsigned long mask;
11263 XGCValues xgcv;
11264 Display *dpy;
11265 Window window;
06a2c219 11266
92f424df
GM
11267 /* If cursor is out of bounds, don't draw garbage. This can happen
11268 in mini-buffer windows when switching between echo area glyphs
11269 and mini-buffer. */
11270 cursor_glyph = get_phys_cursor_glyph (w);
11271 if (cursor_glyph == NULL)
11272 return;
06a2c219 11273
92f424df
GM
11274 /* If on an image, draw like a normal cursor. That's usually better
11275 visible than drawing a bar, esp. if the image is large so that
11276 the bar might not be in the window. */
11277 if (cursor_glyph->type == IMAGE_GLYPH)
11278 {
11279 struct glyph_row *row;
11280 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
11281 x_draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
11282 }
11283 else
11284 {
06a2c219
GM
11285 xgcv.background = f->output_data.x->cursor_pixel;
11286 xgcv.foreground = f->output_data.x->cursor_pixel;
11287 xgcv.graphics_exposures = 0;
11288 mask = GCForeground | GCBackground | GCGraphicsExposures;
11289 dpy = FRAME_X_DISPLAY (f);
11290 window = FRAME_X_WINDOW (f);
11291 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
92f424df 11292
06a2c219
GM
11293 if (gc)
11294 XChangeGC (dpy, gc, mask, &xgcv);
11295 else
11296 {
11297 gc = XCreateGC (dpy, window, mask, &xgcv);
11298 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
11299 }
92f424df 11300
f02d8aa0
GM
11301 if (width < 0)
11302 width = f->output_data.x->cursor_width;
92f424df 11303
06a2c219
GM
11304 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11305 x_clip_to_row (w, row, gc, 0);
11306 XFillRectangle (dpy, window, gc,
11307 x,
11308 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
f02d8aa0 11309 min (cursor_glyph->pixel_width, width),
06a2c219
GM
11310 row->height);
11311 XSetClipMask (dpy, gc, None);
11312 }
dc6f92b8
JB
11313}
11314
06a2c219
GM
11315
11316/* Clear the cursor of window W to background color, and mark the
11317 cursor as not shown. This is used when the text where the cursor
11318 is is about to be rewritten. */
11319
dc6f92b8 11320static void
06a2c219
GM
11321x_clear_cursor (w)
11322 struct window *w;
dc6f92b8 11323{
06a2c219
GM
11324 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
11325 x_update_window_cursor (w, 0);
11326}
90e65f07 11327
dbc4e1c1 11328
06a2c219
GM
11329/* Draw the cursor glyph of window W in glyph row ROW. See the
11330 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 11331
06a2c219
GM
11332static void
11333x_draw_phys_cursor_glyph (w, row, hl)
11334 struct window *w;
11335 struct glyph_row *row;
11336 enum draw_glyphs_face hl;
11337{
11338 /* If cursor hpos is out of bounds, don't draw garbage. This can
11339 happen in mini-buffer windows when switching between echo area
11340 glyphs and mini-buffer. */
11341 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e
GM
11342 {
11343 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
11344 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
11345 hl, 0, 0, 0);
11346
11347 /* When we erase the cursor, and ROW is overlapped by other
11348 rows, make sure that these overlapping parts of other rows
11349 are redrawn. */
11350 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
11351 {
11352 if (row > w->current_matrix->rows
11353 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
11354 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
11355
11356 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
11357 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
11358 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
11359 }
11360 }
06a2c219 11361}
dbc4e1c1 11362
eea6af04 11363
06a2c219 11364/* Erase the image of a cursor of window W from the screen. */
eea6af04 11365
06a2c219
GM
11366static void
11367x_erase_phys_cursor (w)
11368 struct window *w;
11369{
11370 struct frame *f = XFRAME (w->frame);
11371 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11372 int hpos = w->phys_cursor.hpos;
11373 int vpos = w->phys_cursor.vpos;
11374 int mouse_face_here_p = 0;
11375 struct glyph_matrix *active_glyphs = w->current_matrix;
11376 struct glyph_row *cursor_row;
11377 struct glyph *cursor_glyph;
11378 enum draw_glyphs_face hl;
11379
11380 /* No cursor displayed or row invalidated => nothing to do on the
11381 screen. */
11382 if (w->phys_cursor_type == NO_CURSOR)
11383 goto mark_cursor_off;
11384
11385 /* VPOS >= active_glyphs->nrows means that window has been resized.
11386 Don't bother to erase the cursor. */
11387 if (vpos >= active_glyphs->nrows)
11388 goto mark_cursor_off;
11389
11390 /* If row containing cursor is marked invalid, there is nothing we
11391 can do. */
11392 cursor_row = MATRIX_ROW (active_glyphs, vpos);
11393 if (!cursor_row->enabled_p)
11394 goto mark_cursor_off;
11395
11396 /* This can happen when the new row is shorter than the old one.
11397 In this case, either x_draw_glyphs or clear_end_of_line
11398 should have cleared the cursor. Note that we wouldn't be
11399 able to erase the cursor in this case because we don't have a
11400 cursor glyph at hand. */
11401 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
11402 goto mark_cursor_off;
11403
11404 /* If the cursor is in the mouse face area, redisplay that when
11405 we clear the cursor. */
8801a864
KR
11406 if (! NILP (dpyinfo->mouse_face_window)
11407 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
11408 && (vpos > dpyinfo->mouse_face_beg_row
11409 || (vpos == dpyinfo->mouse_face_beg_row
11410 && hpos >= dpyinfo->mouse_face_beg_col))
11411 && (vpos < dpyinfo->mouse_face_end_row
11412 || (vpos == dpyinfo->mouse_face_end_row
11413 && hpos < dpyinfo->mouse_face_end_col))
11414 /* Don't redraw the cursor's spot in mouse face if it is at the
11415 end of a line (on a newline). The cursor appears there, but
11416 mouse highlighting does not. */
11417 && cursor_row->used[TEXT_AREA] > hpos)
11418 mouse_face_here_p = 1;
11419
11420 /* Maybe clear the display under the cursor. */
11421 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
11422 {
11423 int x;
045dee35 11424 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 11425
06a2c219
GM
11426 cursor_glyph = get_phys_cursor_glyph (w);
11427 if (cursor_glyph == NULL)
11428 goto mark_cursor_off;
dbc4e1c1 11429
e0300d33 11430 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
06a2c219 11431
c5e6e06b
GM
11432 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11433 x,
11434 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
11435 cursor_row->y)),
11436 cursor_glyph->pixel_width,
11437 cursor_row->visible_height,
11438 False);
dbc4e1c1 11439 }
06a2c219
GM
11440
11441 /* Erase the cursor by redrawing the character underneath it. */
11442 if (mouse_face_here_p)
11443 hl = DRAW_MOUSE_FACE;
11444 else if (cursor_row->inverse_p)
11445 hl = DRAW_INVERSE_VIDEO;
11446 else
11447 hl = DRAW_NORMAL_TEXT;
11448 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 11449
06a2c219
GM
11450 mark_cursor_off:
11451 w->phys_cursor_on_p = 0;
11452 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
11453}
11454
11455
b7f83f9e
GM
11456/* Non-zero if physical cursor of window W is within mouse face. */
11457
11458static int
11459cursor_in_mouse_face_p (w)
11460 struct window *w;
11461{
11462 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
11463 int in_mouse_face = 0;
11464
11465 if (WINDOWP (dpyinfo->mouse_face_window)
11466 && XWINDOW (dpyinfo->mouse_face_window) == w)
11467 {
11468 int hpos = w->phys_cursor.hpos;
11469 int vpos = w->phys_cursor.vpos;
11470
11471 if (vpos >= dpyinfo->mouse_face_beg_row
11472 && vpos <= dpyinfo->mouse_face_end_row
11473 && (vpos > dpyinfo->mouse_face_beg_row
11474 || hpos >= dpyinfo->mouse_face_beg_col)
11475 && (vpos < dpyinfo->mouse_face_end_row
11476 || hpos < dpyinfo->mouse_face_end_col
11477 || dpyinfo->mouse_face_past_end))
11478 in_mouse_face = 1;
11479 }
11480
11481 return in_mouse_face;
11482}
11483
11484
06a2c219
GM
11485/* Display or clear cursor of window W. If ON is zero, clear the
11486 cursor. If it is non-zero, display the cursor. If ON is nonzero,
11487 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 11488
06a2c219
GM
11489void
11490x_display_and_set_cursor (w, on, hpos, vpos, x, y)
11491 struct window *w;
11492 int on, hpos, vpos, x, y;
dbc4e1c1 11493{
06a2c219
GM
11494 struct frame *f = XFRAME (w->frame);
11495 int new_cursor_type;
f02d8aa0 11496 int new_cursor_width;
06a2c219
GM
11497 struct glyph_matrix *current_glyphs;
11498 struct glyph_row *glyph_row;
11499 struct glyph *glyph;
dbc4e1c1 11500
49d838ea 11501 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
11502 windows and frames; in the latter case, the frame or window may
11503 be in the midst of changing its size, and x and y may be off the
11504 window. */
11505 if (! FRAME_VISIBLE_P (f)
11506 || FRAME_GARBAGED_P (f)
11507 || vpos >= w->current_matrix->nrows
11508 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
11509 return;
11510
11511 /* If cursor is off and we want it off, return quickly. */
06a2c219 11512 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
11513 return;
11514
06a2c219
GM
11515 current_glyphs = w->current_matrix;
11516 glyph_row = MATRIX_ROW (current_glyphs, vpos);
11517 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
11518
11519 /* If cursor row is not enabled, we don't really know where to
11520 display the cursor. */
11521 if (!glyph_row->enabled_p)
11522 {
11523 w->phys_cursor_on_p = 0;
11524 return;
11525 }
11526
11527 xassert (interrupt_input_blocked);
11528
11529 /* Set new_cursor_type to the cursor we want to be displayed. In a
11530 mini-buffer window, we want the cursor only to appear if we are
11531 reading input from this window. For the selected window, we want
11532 the cursor type given by the frame parameter. If explicitly
11533 marked off, draw no cursor. In all other cases, we want a hollow
11534 box cursor. */
f02d8aa0 11535 new_cursor_width = -1;
9b4a7047
GM
11536 if (cursor_in_echo_area
11537 && FRAME_HAS_MINIBUF_P (f)
11538 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 11539 {
9b4a7047
GM
11540 if (w == XWINDOW (echo_area_window))
11541 new_cursor_type = FRAME_DESIRED_CURSOR (f);
06a2c219
GM
11542 else
11543 new_cursor_type = HOLLOW_BOX_CURSOR;
11544 }
06a2c219 11545 else
9b4a7047 11546 {
7a58ab59
GM
11547 if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
11548 || w != XWINDOW (f->selected_window))
9b4a7047 11549 {
e55a0b79
GM
11550 extern int cursor_in_non_selected_windows;
11551
5cefa566
GM
11552 if (MINI_WINDOW_P (w)
11553 || !cursor_in_non_selected_windows
11554 || NILP (XBUFFER (w->buffer)->cursor_type))
9b4a7047
GM
11555 new_cursor_type = NO_CURSOR;
11556 else
11557 new_cursor_type = HOLLOW_BOX_CURSOR;
11558 }
11559 else if (w->cursor_off_p)
11560 new_cursor_type = NO_CURSOR;
11561 else
f02d8aa0
GM
11562 {
11563 struct buffer *b = XBUFFER (w->buffer);
11564
11565 if (EQ (b->cursor_type, Qt))
11566 new_cursor_type = FRAME_DESIRED_CURSOR (f);
11567 else
11568 new_cursor_type = x_specified_cursor_type (b->cursor_type,
11569 &new_cursor_width);
11570 }
9b4a7047 11571 }
06a2c219
GM
11572
11573 /* If cursor is currently being shown and we don't want it to be or
11574 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 11575 erase it. */
06a2c219 11576 if (w->phys_cursor_on_p
dc6f92b8 11577 && (!on
06a2c219
GM
11578 || w->phys_cursor.x != x
11579 || w->phys_cursor.y != y
11580 || new_cursor_type != w->phys_cursor_type))
11581 x_erase_phys_cursor (w);
11582
11583 /* If the cursor is now invisible and we want it to be visible,
11584 display it. */
11585 if (on && !w->phys_cursor_on_p)
11586 {
11587 w->phys_cursor_ascent = glyph_row->ascent;
11588 w->phys_cursor_height = glyph_row->height;
11589
11590 /* Set phys_cursor_.* before x_draw_.* is called because some
11591 of them may need the information. */
11592 w->phys_cursor.x = x;
11593 w->phys_cursor.y = glyph_row->y;
11594 w->phys_cursor.hpos = hpos;
11595 w->phys_cursor.vpos = vpos;
11596 w->phys_cursor_type = new_cursor_type;
11597 w->phys_cursor_on_p = 1;
11598
11599 switch (new_cursor_type)
dc6f92b8 11600 {
06a2c219
GM
11601 case HOLLOW_BOX_CURSOR:
11602 x_draw_hollow_cursor (w, glyph_row);
11603 break;
11604
11605 case FILLED_BOX_CURSOR:
11606 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
11607 break;
11608
11609 case BAR_CURSOR:
f02d8aa0 11610 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
11611 break;
11612
11613 case NO_CURSOR:
11614 break;
dc6f92b8 11615
06a2c219
GM
11616 default:
11617 abort ();
11618 }
59ddecde
GM
11619
11620#ifdef HAVE_X_I18N
11621 if (w == XWINDOW (f->selected_window))
11622 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
11623 xic_set_preeditarea (w, x, y);
11624#endif
dc6f92b8
JB
11625 }
11626
06a2c219 11627#ifndef XFlush
f676886a 11628 if (updating_frame != f)
334208b7 11629 XFlush (FRAME_X_DISPLAY (f));
06a2c219 11630#endif
dc6f92b8
JB
11631}
11632
06a2c219
GM
11633
11634/* Display the cursor on window W, or clear it. X and Y are window
11635 relative pixel coordinates. HPOS and VPOS are glyph matrix
11636 positions. If W is not the selected window, display a hollow
11637 cursor. ON non-zero means display the cursor at X, Y which
11638 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 11639
dfcf069d 11640void
06a2c219
GM
11641x_display_cursor (w, on, hpos, vpos, x, y)
11642 struct window *w;
11643 int on, hpos, vpos, x, y;
dc6f92b8 11644{
f94397b5 11645 BLOCK_INPUT;
06a2c219 11646 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
11647 UNBLOCK_INPUT;
11648}
11649
06a2c219
GM
11650
11651/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
11652 Don't change the cursor's position. */
11653
dfcf069d 11654void
06a2c219 11655x_update_cursor (f, on_p)
5d46f928 11656 struct frame *f;
5d46f928 11657{
06a2c219
GM
11658 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
11659}
11660
11661
11662/* Call x_update_window_cursor with parameter ON_P on all leaf windows
11663 in the window tree rooted at W. */
11664
11665static void
11666x_update_cursor_in_window_tree (w, on_p)
11667 struct window *w;
11668 int on_p;
11669{
11670 while (w)
11671 {
11672 if (!NILP (w->hchild))
11673 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
11674 else if (!NILP (w->vchild))
11675 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
11676 else
11677 x_update_window_cursor (w, on_p);
11678
11679 w = NILP (w->next) ? 0 : XWINDOW (w->next);
11680 }
11681}
5d46f928 11682
f94397b5 11683
06a2c219
GM
11684/* Switch the display of W's cursor on or off, according to the value
11685 of ON. */
11686
11687static void
11688x_update_window_cursor (w, on)
11689 struct window *w;
11690 int on;
11691{
16b5d424
GM
11692 /* Don't update cursor in windows whose frame is in the process
11693 of being deleted. */
11694 if (w->current_matrix)
11695 {
11696 BLOCK_INPUT;
11697 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
11698 w->phys_cursor.x, w->phys_cursor.y);
11699 UNBLOCK_INPUT;
11700 }
dc6f92b8 11701}
06a2c219
GM
11702
11703
11704
dc6f92b8
JB
11705\f
11706/* Icons. */
11707
dbc4e1c1 11708/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
11709
11710int
990ba854 11711x_bitmap_icon (f, file)
f676886a 11712 struct frame *f;
990ba854 11713 Lisp_Object file;
dc6f92b8 11714{
06a2c219 11715 int bitmap_id;
dc6f92b8 11716
c118dd06 11717 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11718 return 1;
11719
990ba854 11720 /* Free up our existing icon bitmap if any. */
7556890b
RS
11721 if (f->output_data.x->icon_bitmap > 0)
11722 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11723 f->output_data.x->icon_bitmap = 0;
990ba854
RS
11724
11725 if (STRINGP (file))
7f2ae036
RS
11726 bitmap_id = x_create_bitmap_from_file (f, file);
11727 else
11728 {
990ba854 11729 /* Create the GNU bitmap if necessary. */
5bf01b68 11730 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
11731 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
11732 = x_create_bitmap_from_data (f, gnu_bits,
11733 gnu_width, gnu_height);
990ba854
RS
11734
11735 /* The first time we create the GNU bitmap,
06a2c219 11736 this increments the ref-count one extra time.
990ba854
RS
11737 As a result, the GNU bitmap is never freed.
11738 That way, we don't have to worry about allocating it again. */
334208b7 11739 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 11740
334208b7 11741 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
11742 }
11743
11744 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 11745 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
11746
11747 return 0;
11748}
11749
11750
1be2d067
KH
11751/* Make the x-window of frame F use a rectangle with text.
11752 Use ICON_NAME as the text. */
dc6f92b8
JB
11753
11754int
f676886a
JB
11755x_text_icon (f, icon_name)
11756 struct frame *f;
dc6f92b8
JB
11757 char *icon_name;
11758{
c118dd06 11759 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11760 return 1;
11761
1be2d067
KH
11762#ifdef HAVE_X11R4
11763 {
11764 XTextProperty text;
11765 text.value = (unsigned char *) icon_name;
11766 text.encoding = XA_STRING;
11767 text.format = 8;
11768 text.nitems = strlen (icon_name);
11769#ifdef USE_X_TOOLKIT
7556890b 11770 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
11771 &text);
11772#else /* not USE_X_TOOLKIT */
11773 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
11774#endif /* not USE_X_TOOLKIT */
11775 }
11776#else /* not HAVE_X11R4 */
11777 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
11778#endif /* not HAVE_X11R4 */
58769bee 11779
7556890b
RS
11780 if (f->output_data.x->icon_bitmap > 0)
11781 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11782 f->output_data.x->icon_bitmap = 0;
b1c884c3 11783 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
11784
11785 return 0;
11786}
11787\f
e99db5a1
RS
11788#define X_ERROR_MESSAGE_SIZE 200
11789
11790/* If non-nil, this should be a string.
11791 It means catch X errors and store the error message in this string. */
11792
11793static Lisp_Object x_error_message_string;
11794
11795/* An X error handler which stores the error message in
11796 x_error_message_string. This is called from x_error_handler if
11797 x_catch_errors is in effect. */
11798
06a2c219 11799static void
e99db5a1
RS
11800x_error_catcher (display, error)
11801 Display *display;
11802 XErrorEvent *error;
11803{
11804 XGetErrorText (display, error->error_code,
11805 XSTRING (x_error_message_string)->data,
11806 X_ERROR_MESSAGE_SIZE);
11807}
11808
11809/* Begin trapping X errors for display DPY. Actually we trap X errors
11810 for all displays, but DPY should be the display you are actually
11811 operating on.
11812
11813 After calling this function, X protocol errors no longer cause
11814 Emacs to exit; instead, they are recorded in the string
11815 stored in x_error_message_string.
11816
11817 Calling x_check_errors signals an Emacs error if an X error has
11818 occurred since the last call to x_catch_errors or x_check_errors.
11819
11820 Calling x_uncatch_errors resumes the normal error handling. */
11821
11822void x_check_errors ();
11823static Lisp_Object x_catch_errors_unwind ();
11824
11825int
11826x_catch_errors (dpy)
11827 Display *dpy;
11828{
11829 int count = specpdl_ptr - specpdl;
11830
11831 /* Make sure any errors from previous requests have been dealt with. */
11832 XSync (dpy, False);
11833
11834 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
11835
11836 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
11837 XSTRING (x_error_message_string)->data[0] = 0;
11838
11839 return count;
11840}
11841
11842/* Unbind the binding that we made to check for X errors. */
11843
11844static Lisp_Object
11845x_catch_errors_unwind (old_val)
11846 Lisp_Object old_val;
11847{
11848 x_error_message_string = old_val;
11849 return Qnil;
11850}
11851
11852/* If any X protocol errors have arrived since the last call to
11853 x_catch_errors or x_check_errors, signal an Emacs error using
11854 sprintf (a buffer, FORMAT, the x error message text) as the text. */
11855
11856void
11857x_check_errors (dpy, format)
11858 Display *dpy;
11859 char *format;
11860{
11861 /* Make sure to catch any errors incurred so far. */
11862 XSync (dpy, False);
11863
11864 if (XSTRING (x_error_message_string)->data[0])
11865 error (format, XSTRING (x_error_message_string)->data);
11866}
11867
9829ddba
RS
11868/* Nonzero if we had any X protocol errors
11869 since we did x_catch_errors on DPY. */
e99db5a1
RS
11870
11871int
11872x_had_errors_p (dpy)
11873 Display *dpy;
11874{
11875 /* Make sure to catch any errors incurred so far. */
11876 XSync (dpy, False);
11877
11878 return XSTRING (x_error_message_string)->data[0] != 0;
11879}
11880
9829ddba
RS
11881/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
11882
06a2c219 11883void
9829ddba
RS
11884x_clear_errors (dpy)
11885 Display *dpy;
11886{
11887 XSTRING (x_error_message_string)->data[0] = 0;
11888}
11889
e99db5a1
RS
11890/* Stop catching X protocol errors and let them make Emacs die.
11891 DPY should be the display that was passed to x_catch_errors.
11892 COUNT should be the value that was returned by
11893 the corresponding call to x_catch_errors. */
11894
11895void
11896x_uncatch_errors (dpy, count)
11897 Display *dpy;
11898 int count;
11899{
11900 unbind_to (count, Qnil);
11901}
11902
11903#if 0
11904static unsigned int x_wire_count;
11905x_trace_wire ()
11906{
11907 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
11908}
11909#endif /* ! 0 */
11910
11911\f
11912/* Handle SIGPIPE, which can happen when the connection to a server
11913 simply goes away. SIGPIPE is handled by x_connection_signal.
11914 Don't need to do anything, because the write which caused the
11915 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 11916 which will do the appropriate cleanup for us. */
e99db5a1
RS
11917
11918static SIGTYPE
11919x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 11920 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
11921{
11922#ifdef USG
11923 /* USG systems forget handlers when they are used;
11924 must reestablish each time */
11925 signal (signalnum, x_connection_signal);
11926#endif /* USG */
11927}
0da1ab50 11928
e99db5a1 11929\f
0da1ab50
GM
11930/************************************************************************
11931 Handling X errors
11932 ************************************************************************/
4746118a 11933
f0e299de
GM
11934/* Error message passed to x_connection_closed. */
11935
11936static char *error_msg;
11937
11938/* Function installed as fatal_error_signal_hook.in
11939 x_connection_closed. Print the X error message, and exit normally,
11940 instead of dumping core when XtCloseDisplay fails. */
11941
11942static void
11943x_fatal_error_signal ()
11944{
11945 fprintf (stderr, "%s\n", error_msg);
11946 exit (70);
11947}
11948
0da1ab50
GM
11949/* Handle the loss of connection to display DPY. ERROR_MESSAGE is
11950 the text of an error message that lead to the connection loss. */
16bd92ea 11951
4746118a 11952static SIGTYPE
5978125e
GM
11953x_connection_closed (dpy, error_message)
11954 Display *dpy;
7a13e894 11955 char *error_message;
4746118a 11956{
5978125e 11957 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
7a13e894 11958 Lisp_Object frame, tail;
0da1ab50 11959 int count;
0da1ab50 11960
f0e299de
GM
11961 error_msg = (char *) alloca (strlen (error_message) + 1);
11962 strcpy (error_msg, error_message);
1a532e54
GM
11963 handling_signal = 0;
11964
0da1ab50
GM
11965 /* Prevent being called recursively because of an error condition
11966 below. Otherwise, we might end up with printing ``can't find per
11967 display information'' in the recursive call instead of printing
11968 the original message here. */
11969 count = x_catch_errors (dpy);
11970
8a4f36cc
GM
11971 /* We have to close the display to inform Xt that it doesn't
11972 exist anymore. If we don't, Xt will continue to wait for
11973 events from the display. As a consequence, a sequence of
11974
11975 M-x make-frame-on-display RET :1 RET
11976 ...kill the new frame, so that we get an IO error...
11977 M-x make-frame-on-display RET :1 RET
11978
11979 will indefinitely wait in Xt for events for display `:1', opened
11980 in the first class to make-frame-on-display.
6186a4a0 11981
8a4f36cc
GM
11982 Closing the display is reported to lead to a bus error on
11983 OpenWindows in certain situations. I suspect that is a bug
11984 in OpenWindows. I don't know how to cicumvent it here. */
11985
f613a4c8 11986#ifdef USE_X_TOOLKIT
ae24cb3b
GM
11987 /* If DPYINFO is null, this means we didn't open the display
11988 in the first place, so don't try to close it. */
11989 if (dpyinfo)
f0e299de
GM
11990 {
11991 extern void (*fatal_error_signal_hook) P_ ((void));
11992 fatal_error_signal_hook = x_fatal_error_signal;
11993 XtCloseDisplay (dpy);
11994 fatal_error_signal_hook = NULL;
11995 }
f613a4c8 11996#endif
adabc3a9 11997
8a4f36cc 11998 /* Indicate that this display is dead. */
9e80b57d
KR
11999 if (dpyinfo)
12000 dpyinfo->display = 0;
6186a4a0 12001
06a2c219 12002 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
12003 that are on the dead display. */
12004 FOR_EACH_FRAME (tail, frame)
12005 {
12006 Lisp_Object minibuf_frame;
12007 minibuf_frame
12008 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
12009 if (FRAME_X_P (XFRAME (frame))
12010 && FRAME_X_P (XFRAME (minibuf_frame))
12011 && ! EQ (frame, minibuf_frame)
12012 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
12013 Fdelete_frame (frame, Qt);
12014 }
12015
12016 /* Now delete all remaining frames on the dead display.
06a2c219 12017 We are now sure none of these is used as the mini-buffer
7a13e894
RS
12018 for another frame that we need to delete. */
12019 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
12020 if (FRAME_X_P (XFRAME (frame))
12021 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
12022 {
12023 /* Set this to t so that Fdelete_frame won't get confused
12024 trying to find a replacement. */
12025 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
12026 Fdelete_frame (frame, Qt);
12027 }
7a13e894 12028
482a1bd2
KH
12029 if (dpyinfo)
12030 x_delete_display (dpyinfo);
7a13e894 12031
0da1ab50
GM
12032 x_uncatch_errors (dpy, count);
12033
7a13e894
RS
12034 if (x_display_list == 0)
12035 {
f0e299de 12036 fprintf (stderr, "%s\n", error_msg);
7a13e894
RS
12037 shut_down_emacs (0, 0, Qnil);
12038 exit (70);
12039 }
12ba150f 12040
7a13e894
RS
12041 /* Ordinary stack unwind doesn't deal with these. */
12042#ifdef SIGIO
12043 sigunblock (sigmask (SIGIO));
12044#endif
12045 sigunblock (sigmask (SIGALRM));
12046 TOTALLY_UNBLOCK_INPUT;
12047
aa4d9a9e 12048 clear_waiting_for_input ();
f0e299de 12049 error ("%s", error_msg);
4746118a
JB
12050}
12051
0da1ab50 12052
7a13e894
RS
12053/* This is the usual handler for X protocol errors.
12054 It kills all frames on the display that we got the error for.
12055 If that was the only one, it prints an error message and kills Emacs. */
12056
06a2c219 12057static void
c118dd06
JB
12058x_error_quitter (display, error)
12059 Display *display;
12060 XErrorEvent *error;
12061{
7a13e894 12062 char buf[256], buf1[356];
dc6f92b8 12063
58769bee 12064 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 12065 original error handler. */
dc6f92b8 12066
c118dd06 12067 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 12068 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 12069 buf, error->request_code);
7a13e894 12070 x_connection_closed (display, buf1);
dc6f92b8
JB
12071}
12072
0da1ab50 12073
e99db5a1
RS
12074/* This is the first-level handler for X protocol errors.
12075 It calls x_error_quitter or x_error_catcher. */
7a13e894 12076
8922af5f 12077static int
e99db5a1 12078x_error_handler (display, error)
8922af5f 12079 Display *display;
e99db5a1 12080 XErrorEvent *error;
8922af5f 12081{
e99db5a1
RS
12082 if (! NILP (x_error_message_string))
12083 x_error_catcher (display, error);
12084 else
12085 x_error_quitter (display, error);
06a2c219 12086 return 0;
f9e24cb9 12087}
c118dd06 12088
e99db5a1
RS
12089/* This is the handler for X IO errors, always.
12090 It kills all frames on the display that we lost touch with.
12091 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 12092
c118dd06 12093static int
e99db5a1 12094x_io_error_quitter (display)
c118dd06 12095 Display *display;
c118dd06 12096{
e99db5a1 12097 char buf[256];
dc6f92b8 12098
e99db5a1
RS
12099 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
12100 x_connection_closed (display, buf);
06a2c219 12101 return 0;
dc6f92b8 12102}
dc6f92b8 12103\f
f451eb13
JB
12104/* Changing the font of the frame. */
12105
76bcdf39
RS
12106/* Give frame F the font named FONTNAME as its default font, and
12107 return the full name of that font. FONTNAME may be a wildcard
12108 pattern; in that case, we choose some font that fits the pattern.
12109 The return value shows which font we chose. */
12110
b5cf7a0e 12111Lisp_Object
f676886a
JB
12112x_new_font (f, fontname)
12113 struct frame *f;
dc6f92b8
JB
12114 register char *fontname;
12115{
dc43ef94 12116 struct font_info *fontp
ee569018 12117 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 12118
dc43ef94
KH
12119 if (!fontp)
12120 return Qnil;
2224a5fc 12121
dc43ef94 12122 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 12123 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
12124 f->output_data.x->fontset = -1;
12125
b2cad826
KH
12126 /* Compute the scroll bar width in character columns. */
12127 if (f->scroll_bar_pixel_width > 0)
12128 {
7556890b 12129 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
12130 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
12131 }
12132 else
4e61bddf
RS
12133 {
12134 int wid = FONT_WIDTH (f->output_data.x->font);
12135 f->scroll_bar_cols = (14 + wid - 1) / wid;
12136 }
b2cad826 12137
f676886a 12138 /* Now make the frame display the given font. */
c118dd06 12139 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 12140 {
7556890b
RS
12141 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
12142 f->output_data.x->font->fid);
12143 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
12144 f->output_data.x->font->fid);
12145 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
12146 f->output_data.x->font->fid);
f676886a 12147
a27f9f86 12148 frame_update_line_height (f);
3497f73e
GM
12149
12150 /* Don't change the size of a tip frame; there's no point in
12151 doing it because it's done in Fx_show_tip, and it leads to
12152 problems because the tip frame has no widget. */
12153 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
12154 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 12155 }
a27f9f86
RS
12156 else
12157 /* If we are setting a new frame's font for the first time,
12158 there are no faces yet, so this font's height is the line height. */
7556890b 12159 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 12160
dc43ef94
KH
12161 return build_string (fontp->full_name);
12162}
12163
12164/* Give frame F the fontset named FONTSETNAME as its default font, and
12165 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
12166 pattern; in that case, we choose some fontset that fits the pattern.
12167 The return value shows which fontset we chose. */
b5cf7a0e 12168
dc43ef94
KH
12169Lisp_Object
12170x_new_fontset (f, fontsetname)
12171 struct frame *f;
12172 char *fontsetname;
12173{
ee569018 12174 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 12175 Lisp_Object result;
b5cf7a0e 12176
dc43ef94
KH
12177 if (fontset < 0)
12178 return Qnil;
b5cf7a0e 12179
2da424f1
KH
12180 if (f->output_data.x->fontset == fontset)
12181 /* This fontset is already set in frame F. There's nothing more
12182 to do. */
ee569018 12183 return fontset_name (fontset);
dc43ef94 12184
ee569018 12185 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
12186
12187 if (!STRINGP (result))
12188 /* Can't load ASCII font. */
12189 return Qnil;
12190
12191 /* Since x_new_font doesn't update any fontset information, do it now. */
12192 f->output_data.x->fontset = fontset;
dc43ef94 12193
f5d11644
GM
12194#ifdef HAVE_X_I18N
12195 if (FRAME_XIC (f)
12196 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 12197 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
12198#endif
12199
dc43ef94 12200 return build_string (fontsetname);
dc6f92b8 12201}
f5d11644
GM
12202
12203\f
12204/***********************************************************************
12205 X Input Methods
12206 ***********************************************************************/
12207
12208#ifdef HAVE_X_I18N
12209
12210#ifdef HAVE_X11R6
12211
12212/* XIM destroy callback function, which is called whenever the
12213 connection to input method XIM dies. CLIENT_DATA contains a
12214 pointer to the x_display_info structure corresponding to XIM. */
12215
12216static void
12217xim_destroy_callback (xim, client_data, call_data)
12218 XIM xim;
12219 XPointer client_data;
12220 XPointer call_data;
12221{
12222 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
12223 Lisp_Object frame, tail;
12224
12225 BLOCK_INPUT;
12226
12227 /* No need to call XDestroyIC.. */
12228 FOR_EACH_FRAME (tail, frame)
12229 {
12230 struct frame *f = XFRAME (frame);
12231 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
12232 {
12233 FRAME_XIC (f) = NULL;
12234 if (FRAME_XIC_FONTSET (f))
12235 {
12236 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
12237 FRAME_XIC_FONTSET (f) = NULL;
12238 }
12239 }
12240 }
12241
12242 /* No need to call XCloseIM. */
12243 dpyinfo->xim = NULL;
12244 XFree (dpyinfo->xim_styles);
12245 UNBLOCK_INPUT;
12246}
12247
12248#endif /* HAVE_X11R6 */
12249
12250/* Open the connection to the XIM server on display DPYINFO.
12251 RESOURCE_NAME is the resource name Emacs uses. */
12252
12253static void
12254xim_open_dpy (dpyinfo, resource_name)
12255 struct x_display_info *dpyinfo;
12256 char *resource_name;
12257{
287f7dd6 12258#ifdef USE_XIM
f5d11644
GM
12259 XIM xim;
12260
12261 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
12262 dpyinfo->xim = xim;
12263
12264 if (xim)
12265 {
f5d11644
GM
12266#ifdef HAVE_X11R6
12267 XIMCallback destroy;
12268#endif
12269
12270 /* Get supported styles and XIM values. */
12271 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
12272
12273#ifdef HAVE_X11R6
12274 destroy.callback = xim_destroy_callback;
12275 destroy.client_data = (XPointer)dpyinfo;
cea2ad76 12276 /* This isn't prototyped in OSF 5.0. */
f5d11644
GM
12277 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
12278#endif
12279 }
287f7dd6
GM
12280
12281#else /* not USE_XIM */
12282 dpyinfo->xim = NULL;
12283#endif /* not USE_XIM */
f5d11644
GM
12284}
12285
12286
b9de836c 12287#ifdef HAVE_X11R6_XIM
f5d11644
GM
12288
12289struct xim_inst_t
12290{
12291 struct x_display_info *dpyinfo;
12292 char *resource_name;
12293};
12294
12295/* XIM instantiate callback function, which is called whenever an XIM
12296 server is available. DISPLAY is teh display of the XIM.
12297 CLIENT_DATA contains a pointer to an xim_inst_t structure created
12298 when the callback was registered. */
12299
12300static void
12301xim_instantiate_callback (display, client_data, call_data)
12302 Display *display;
12303 XPointer client_data;
12304 XPointer call_data;
12305{
12306 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
12307 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
12308
12309 /* We don't support multiple XIM connections. */
12310 if (dpyinfo->xim)
12311 return;
12312
12313 xim_open_dpy (dpyinfo, xim_inst->resource_name);
12314
12315 /* Create XIC for the existing frames on the same display, as long
12316 as they have no XIC. */
12317 if (dpyinfo->xim && dpyinfo->reference_count > 0)
12318 {
12319 Lisp_Object tail, frame;
12320
12321 BLOCK_INPUT;
12322 FOR_EACH_FRAME (tail, frame)
12323 {
12324 struct frame *f = XFRAME (frame);
12325
12326 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
12327 if (FRAME_XIC (f) == NULL)
12328 {
12329 create_frame_xic (f);
12330 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
12331 xic_set_statusarea (f);
12332 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
12333 {
12334 struct window *w = XWINDOW (f->selected_window);
12335 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
12336 }
12337 }
12338 }
12339
12340 UNBLOCK_INPUT;
12341 }
12342}
12343
b9de836c 12344#endif /* HAVE_X11R6_XIM */
f5d11644
GM
12345
12346
12347/* Open a connection to the XIM server on display DPYINFO.
12348 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
12349 connection only at the first time. On X11R6, open the connection
12350 in the XIM instantiate callback function. */
12351
12352static void
12353xim_initialize (dpyinfo, resource_name)
12354 struct x_display_info *dpyinfo;
12355 char *resource_name;
12356{
287f7dd6 12357#ifdef USE_XIM
b9de836c 12358#ifdef HAVE_X11R6_XIM
f5d11644
GM
12359 struct xim_inst_t *xim_inst;
12360 int len;
12361
12362 dpyinfo->xim = NULL;
12363 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
12364 xim_inst->dpyinfo = dpyinfo;
12365 len = strlen (resource_name);
12366 xim_inst->resource_name = (char *) xmalloc (len + 1);
12367 bcopy (resource_name, xim_inst->resource_name, len + 1);
12368 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12369 resource_name, EMACS_CLASS,
12370 xim_instantiate_callback,
2ebb2f8b
DL
12371 /* Fixme: This is XPointer in
12372 XFree86 but (XPointer *) on
12373 Tru64, at least. */
12374 (XPointer) xim_inst);
b9de836c 12375#else /* not HAVE_X11R6_XIM */
f5d11644
GM
12376 dpyinfo->xim = NULL;
12377 xim_open_dpy (dpyinfo, resource_name);
b9de836c 12378#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
12379
12380#else /* not USE_XIM */
12381 dpyinfo->xim = NULL;
12382#endif /* not USE_XIM */
f5d11644
GM
12383}
12384
12385
12386/* Close the connection to the XIM server on display DPYINFO. */
12387
12388static void
12389xim_close_dpy (dpyinfo)
12390 struct x_display_info *dpyinfo;
12391{
287f7dd6 12392#ifdef USE_XIM
b9de836c 12393#ifdef HAVE_X11R6_XIM
8a4f36cc
GM
12394 if (dpyinfo->display)
12395 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12396 NULL, EMACS_CLASS,
12397 xim_instantiate_callback, NULL);
b9de836c 12398#endif /* not HAVE_X11R6_XIM */
8a4f36cc
GM
12399 if (dpyinfo->display)
12400 XCloseIM (dpyinfo->xim);
f5d11644
GM
12401 dpyinfo->xim = NULL;
12402 XFree (dpyinfo->xim_styles);
287f7dd6 12403#endif /* USE_XIM */
f5d11644
GM
12404}
12405
b9de836c 12406#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
12407
12408
dc6f92b8 12409\f
2e365682
RS
12410/* Calculate the absolute position in frame F
12411 from its current recorded position values and gravity. */
12412
dfcf069d 12413void
43bca5d5 12414x_calc_absolute_position (f)
f676886a 12415 struct frame *f;
dc6f92b8 12416{
06a2c219 12417 Window child;
6dba1858 12418 int win_x = 0, win_y = 0;
7556890b 12419 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
12420 int this_window;
12421
9829ddba
RS
12422 /* We have nothing to do if the current position
12423 is already for the top-left corner. */
12424 if (! ((flags & XNegative) || (flags & YNegative)))
12425 return;
12426
c81412a0 12427#ifdef USE_X_TOOLKIT
7556890b 12428 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
12429#else
12430 this_window = FRAME_X_WINDOW (f);
12431#endif
6dba1858
RS
12432
12433 /* Find the position of the outside upper-left corner of
9829ddba
RS
12434 the inner window, with respect to the outer window.
12435 But do this only if we will need the results. */
7556890b 12436 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 12437 {
9829ddba
RS
12438 int count;
12439
6dba1858 12440 BLOCK_INPUT;
9829ddba
RS
12441 count = x_catch_errors (FRAME_X_DISPLAY (f));
12442 while (1)
12443 {
12444 x_clear_errors (FRAME_X_DISPLAY (f));
12445 XTranslateCoordinates (FRAME_X_DISPLAY (f),
12446
12447 /* From-window, to-window. */
12448 this_window,
12449 f->output_data.x->parent_desc,
12450
12451 /* From-position, to-position. */
12452 0, 0, &win_x, &win_y,
12453
12454 /* Child of win. */
12455 &child);
12456 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12457 {
12458 Window newroot, newparent = 0xdeadbeef;
12459 Window *newchildren;
2ebb2f8b 12460 unsigned int nchildren;
9829ddba
RS
12461
12462 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
12463 &newparent, &newchildren, &nchildren))
12464 break;
58769bee 12465
7c3c78a3 12466 XFree ((char *) newchildren);
6dba1858 12467
9829ddba
RS
12468 f->output_data.x->parent_desc = newparent;
12469 }
12470 else
12471 break;
12472 }
6dba1858 12473
9829ddba 12474 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
12475 UNBLOCK_INPUT;
12476 }
12477
12478 /* Treat negative positions as relative to the leftmost bottommost
12479 position that fits on the screen. */
20f55f9a 12480 if (flags & XNegative)
7556890b 12481 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
12482 - 2 * f->output_data.x->border_width - win_x
12483 - PIXEL_WIDTH (f)
12484 + f->output_data.x->left_pos);
dc6f92b8 12485
7708ced0
GM
12486 {
12487 int height = PIXEL_HEIGHT (f);
06a2c219 12488
7708ced0
GM
12489#if defined USE_X_TOOLKIT && defined USE_MOTIF
12490 /* Something is fishy here. When using Motif, starting Emacs with
12491 `-g -0-0', the frame appears too low by a few pixels.
12492
12493 This seems to be so because initially, while Emacs is starting,
12494 the column widget's height and the frame's pixel height are
12495 different. The column widget's height is the right one. In
12496 later invocations, when Emacs is up, the frame's pixel height
12497 is right, though.
12498
12499 It's not obvious where the initial small difference comes from.
12500 2000-12-01, gerd. */
12501
12502 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
06a2c219 12503#endif
2e365682 12504
7708ced0
GM
12505 if (flags & YNegative)
12506 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
12507 - 2 * f->output_data.x->border_width
12508 - win_y
12509 - height
12510 + f->output_data.x->top_pos);
12511 }
12512
3a35ab44
RS
12513 /* The left_pos and top_pos
12514 are now relative to the top and left screen edges,
12515 so the flags should correspond. */
7556890b 12516 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
12517}
12518
3a35ab44
RS
12519/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
12520 to really change the position, and 0 when calling from
12521 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
12522 position values). It is -1 when calling from x_set_frame_parameters,
12523 which means, do adjust for borders but don't change the gravity. */
3a35ab44 12524
dfcf069d 12525void
dc05a16b 12526x_set_offset (f, xoff, yoff, change_gravity)
f676886a 12527 struct frame *f;
dc6f92b8 12528 register int xoff, yoff;
dc05a16b 12529 int change_gravity;
dc6f92b8 12530{
4a4cbdd5
KH
12531 int modified_top, modified_left;
12532
aa3ff7c9 12533 if (change_gravity > 0)
3a35ab44 12534 {
7556890b
RS
12535 f->output_data.x->top_pos = yoff;
12536 f->output_data.x->left_pos = xoff;
12537 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 12538 if (xoff < 0)
7556890b 12539 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 12540 if (yoff < 0)
7556890b
RS
12541 f->output_data.x->size_hint_flags |= YNegative;
12542 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 12543 }
43bca5d5 12544 x_calc_absolute_position (f);
dc6f92b8
JB
12545
12546 BLOCK_INPUT;
c32cdd9a 12547 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 12548
7556890b
RS
12549 modified_left = f->output_data.x->left_pos;
12550 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
12551#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
12552 this seems to be unnecessary and incorrect. rms, 4/17/97. */
12553 /* It is a mystery why we need to add the border_width here
12554 when the frame is already visible, but experiment says we do. */
aa3ff7c9 12555 if (change_gravity != 0)
4a4cbdd5 12556 {
7556890b
RS
12557 modified_left += f->output_data.x->border_width;
12558 modified_top += f->output_data.x->border_width;
4a4cbdd5 12559 }
e73ec6fa 12560#endif
4a4cbdd5 12561
3afe33e7 12562#ifdef USE_X_TOOLKIT
7556890b 12563 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 12564 modified_left, modified_top);
3afe33e7 12565#else /* not USE_X_TOOLKIT */
334208b7 12566 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 12567 modified_left, modified_top);
3afe33e7 12568#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12569 UNBLOCK_INPUT;
12570}
12571
dc6f92b8 12572
499b1844
GM
12573/* Change the size of frame F's X window to COLS/ROWS in the case F
12574 doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
12575 top-left-corner window gravity for this size change and subsequent
12576 size changes. Otherwise we leave the window gravity unchanged. */
12577
12578static void
12579x_set_window_size_1 (f, change_gravity, cols, rows)
f676886a 12580 struct frame *f;
bc20ebbf 12581 int change_gravity;
b1c884c3 12582 int cols, rows;
dc6f92b8
JB
12583{
12584 int pixelwidth, pixelheight;
80fd1fe2 12585
b1c884c3 12586 check_frame_size (f, &rows, &cols);
7556890b 12587 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
12588 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
12589 ? 0
12590 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 12591 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 12592 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 12593 f->output_data.x->flags_areas_extra
110859fc 12594 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
12595 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
12596 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 12597
7556890b 12598 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 12599 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 12600
334208b7
RS
12601 XSync (FRAME_X_DISPLAY (f), False);
12602 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12603 pixelwidth, pixelheight);
b1c884c3
JB
12604
12605 /* Now, strictly speaking, we can't be sure that this is accurate,
12606 but the window manager will get around to dealing with the size
12607 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
12608 ConfigureNotify event gets here.
12609
12610 We could just not bother storing any of this information here,
12611 and let the ConfigureNotify event set everything up, but that
fddd5ceb 12612 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 12613 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
12614 point in the future when the ConfigureNotify event arrives.
12615
12616 We pass 1 for DELAY since we can't run Lisp code inside of
12617 a BLOCK_INPUT. */
7d1e984f 12618 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
12619 PIXEL_WIDTH (f) = pixelwidth;
12620 PIXEL_HEIGHT (f) = pixelheight;
12621
aee9a898
RS
12622 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
12623 receive in the ConfigureNotify event; if we get what we asked
12624 for, then the event won't cause the screen to become garbaged, so
12625 we have to make sure to do it here. */
12626 SET_FRAME_GARBAGED (f);
12627
12628 XFlush (FRAME_X_DISPLAY (f));
499b1844
GM
12629}
12630
12631
12632/* Call this to change the size of frame F's x-window.
12633 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
12634 for this size change and subsequent size changes.
12635 Otherwise we leave the window gravity unchanged. */
aee9a898 12636
499b1844
GM
12637void
12638x_set_window_size (f, change_gravity, cols, rows)
12639 struct frame *f;
12640 int change_gravity;
12641 int cols, rows;
12642{
12643 BLOCK_INPUT;
12644
12645#ifdef USE_X_TOOLKIT
12646
f1f4d345 12647 if (f->output_data.x->widget != NULL)
499b1844
GM
12648 {
12649 /* The x and y position of the widget is clobbered by the
12650 call to XtSetValues within EmacsFrameSetCharSize.
12651 This is a real kludge, but I don't understand Xt so I can't
12652 figure out a correct fix. Can anyone else tell me? -- rms. */
12653 int xpos = f->output_data.x->widget->core.x;
12654 int ypos = f->output_data.x->widget->core.y;
12655 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
12656 f->output_data.x->widget->core.x = xpos;
12657 f->output_data.x->widget->core.y = ypos;
12658 }
12659 else
12660 x_set_window_size_1 (f, change_gravity, cols, rows);
12661
12662#else /* not USE_X_TOOLKIT */
12663
12664 x_set_window_size_1 (f, change_gravity, cols, rows);
12665
aee9a898
RS
12666#endif /* not USE_X_TOOLKIT */
12667
4d73d038 12668 /* If cursor was outside the new size, mark it as off. */
06a2c219 12669 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 12670
aee9a898
RS
12671 /* Clear out any recollection of where the mouse highlighting was,
12672 since it might be in a place that's outside the new frame size.
12673 Actually checking whether it is outside is a pain in the neck,
12674 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 12675 cancel_mouse_face (f);
dbc4e1c1 12676
dc6f92b8
JB
12677 UNBLOCK_INPUT;
12678}
dc6f92b8 12679\f
d047c4eb 12680/* Mouse warping. */
dc6f92b8 12681
9b378208 12682void
f676886a
JB
12683x_set_mouse_position (f, x, y)
12684 struct frame *f;
dc6f92b8
JB
12685 int x, y;
12686{
12687 int pix_x, pix_y;
12688
7556890b
RS
12689 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
12690 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
12691
12692 if (pix_x < 0) pix_x = 0;
12693 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
12694
12695 if (pix_y < 0) pix_y = 0;
12696 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
12697
12698 BLOCK_INPUT;
dc6f92b8 12699
334208b7
RS
12700 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12701 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
12702 UNBLOCK_INPUT;
12703}
12704
9b378208
RS
12705/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
12706
12707void
12708x_set_mouse_pixel_position (f, pix_x, pix_y)
12709 struct frame *f;
12710 int pix_x, pix_y;
12711{
12712 BLOCK_INPUT;
12713
334208b7
RS
12714 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12715 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
12716 UNBLOCK_INPUT;
12717}
d047c4eb
KH
12718\f
12719/* focus shifting, raising and lowering. */
9b378208 12720
dfcf069d 12721void
f676886a
JB
12722x_focus_on_frame (f)
12723 struct frame *f;
dc6f92b8 12724{
1fb20991 12725#if 0 /* This proves to be unpleasant. */
f676886a 12726 x_raise_frame (f);
1fb20991 12727#endif
6d4238f3
JB
12728#if 0
12729 /* I don't think that the ICCCM allows programs to do things like this
12730 without the interaction of the window manager. Whatever you end up
f676886a 12731 doing with this code, do it to x_unfocus_frame too. */
334208b7 12732 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 12733 RevertToPointerRoot, CurrentTime);
c118dd06 12734#endif /* ! 0 */
dc6f92b8
JB
12735}
12736
dfcf069d 12737void
f676886a
JB
12738x_unfocus_frame (f)
12739 struct frame *f;
dc6f92b8 12740{
6d4238f3 12741#if 0
f676886a 12742 /* Look at the remarks in x_focus_on_frame. */
0f941935 12743 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 12744 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 12745 RevertToPointerRoot, CurrentTime);
c118dd06 12746#endif /* ! 0 */
dc6f92b8
JB
12747}
12748
f676886a 12749/* Raise frame F. */
dc6f92b8 12750
dfcf069d 12751void
f676886a
JB
12752x_raise_frame (f)
12753 struct frame *f;
dc6f92b8 12754{
3a88c238 12755 if (f->async_visible)
dc6f92b8
JB
12756 {
12757 BLOCK_INPUT;
3afe33e7 12758#ifdef USE_X_TOOLKIT
7556890b 12759 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12760#else /* not USE_X_TOOLKIT */
334208b7 12761 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12762#endif /* not USE_X_TOOLKIT */
334208b7 12763 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12764 UNBLOCK_INPUT;
12765 }
12766}
12767
f676886a 12768/* Lower frame F. */
dc6f92b8 12769
dfcf069d 12770void
f676886a
JB
12771x_lower_frame (f)
12772 struct frame *f;
dc6f92b8 12773{
3a88c238 12774 if (f->async_visible)
dc6f92b8
JB
12775 {
12776 BLOCK_INPUT;
3afe33e7 12777#ifdef USE_X_TOOLKIT
7556890b 12778 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12779#else /* not USE_X_TOOLKIT */
334208b7 12780 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12781#endif /* not USE_X_TOOLKIT */
334208b7 12782 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12783 UNBLOCK_INPUT;
12784 }
12785}
12786
dbc4e1c1 12787static void
6b0442dc 12788XTframe_raise_lower (f, raise_flag)
dbc4e1c1 12789 FRAME_PTR f;
6b0442dc 12790 int raise_flag;
dbc4e1c1 12791{
6b0442dc 12792 if (raise_flag)
dbc4e1c1
JB
12793 x_raise_frame (f);
12794 else
12795 x_lower_frame (f);
12796}
d047c4eb
KH
12797\f
12798/* Change of visibility. */
dc6f92b8 12799
9382638d
KH
12800/* This tries to wait until the frame is really visible.
12801 However, if the window manager asks the user where to position
12802 the frame, this will return before the user finishes doing that.
12803 The frame will not actually be visible at that time,
12804 but it will become visible later when the window manager
12805 finishes with it. */
12806
dfcf069d 12807void
f676886a
JB
12808x_make_frame_visible (f)
12809 struct frame *f;
dc6f92b8 12810{
990ba854 12811 Lisp_Object type;
1aa6072f 12812 int original_top, original_left;
31be9251
GM
12813 int retry_count = 2;
12814
12815 retry:
dc6f92b8 12816
dc6f92b8 12817 BLOCK_INPUT;
dc6f92b8 12818
990ba854
RS
12819 type = x_icon_type (f);
12820 if (!NILP (type))
12821 x_bitmap_icon (f, type);
bdcd49ba 12822
f676886a 12823 if (! FRAME_VISIBLE_P (f))
90e65f07 12824 {
1aa6072f
RS
12825 /* We test FRAME_GARBAGED_P here to make sure we don't
12826 call x_set_offset a second time
12827 if we get to x_make_frame_visible a second time
12828 before the window gets really visible. */
12829 if (! FRAME_ICONIFIED_P (f)
12830 && ! f->output_data.x->asked_for_visible)
12831 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
12832
12833 f->output_data.x->asked_for_visible = 1;
12834
90e65f07 12835 if (! EQ (Vx_no_window_manager, Qt))
f676886a 12836 x_wm_set_window_state (f, NormalState);
3afe33e7 12837#ifdef USE_X_TOOLKIT
d7a38a2e 12838 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 12839 XtMapWidget (f->output_data.x->widget);
3afe33e7 12840#else /* not USE_X_TOOLKIT */
7f9c7f94 12841 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12842#endif /* not USE_X_TOOLKIT */
0134a210
RS
12843#if 0 /* This seems to bring back scroll bars in the wrong places
12844 if the window configuration has changed. They seem
12845 to come back ok without this. */
ab648270 12846 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 12847 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 12848#endif
90e65f07 12849 }
dc6f92b8 12850
334208b7 12851 XFlush (FRAME_X_DISPLAY (f));
90e65f07 12852
0dacf791
RS
12853 /* Synchronize to ensure Emacs knows the frame is visible
12854 before we do anything else. We do this loop with input not blocked
12855 so that incoming events are handled. */
12856 {
12857 Lisp_Object frame;
12ce2351 12858 int count;
28c01ffe
RS
12859 /* This must be before UNBLOCK_INPUT
12860 since events that arrive in response to the actions above
12861 will set it when they are handled. */
12862 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
12863
12864 original_left = f->output_data.x->left_pos;
12865 original_top = f->output_data.x->top_pos;
c0a04927
RS
12866
12867 /* This must come after we set COUNT. */
12868 UNBLOCK_INPUT;
12869
2745e6c4 12870 /* We unblock here so that arriving X events are processed. */
1aa6072f 12871
dcb07ae9
RS
12872 /* Now move the window back to where it was "supposed to be".
12873 But don't do it if the gravity is negative.
12874 When the gravity is negative, this uses a position
28c01ffe
RS
12875 that is 3 pixels too low. Perhaps that's really the border width.
12876
12877 Don't do this if the window has never been visible before,
12878 because the window manager may choose the position
12879 and we don't want to override it. */
1aa6072f 12880
4d3f5d9a 12881 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 12882 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 12883 && previously_visible)
1aa6072f 12884 {
2745e6c4
RS
12885 Drawable rootw;
12886 int x, y;
12887 unsigned int width, height, border, depth;
06a2c219 12888
1aa6072f 12889 BLOCK_INPUT;
9829ddba 12890
06a2c219
GM
12891 /* On some window managers (such as FVWM) moving an existing
12892 window, even to the same place, causes the window manager
12893 to introduce an offset. This can cause the window to move
12894 to an unexpected location. Check the geometry (a little
12895 slow here) and then verify that the window is in the right
12896 place. If the window is not in the right place, move it
12897 there, and take the potential window manager hit. */
2745e6c4
RS
12898 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12899 &rootw, &x, &y, &width, &height, &border, &depth);
12900
12901 if (original_left != x || original_top != y)
12902 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12903 original_left, original_top);
12904
1aa6072f
RS
12905 UNBLOCK_INPUT;
12906 }
9829ddba 12907
e0c1aef2 12908 XSETFRAME (frame, f);
c0a04927 12909
12ce2351
GM
12910 /* Wait until the frame is visible. Process X events until a
12911 MapNotify event has been seen, or until we think we won't get a
12912 MapNotify at all.. */
12913 for (count = input_signal_count + 10;
12914 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 12915 {
12ce2351 12916 /* Force processing of queued events. */
334208b7 12917 x_sync (f);
12ce2351
GM
12918
12919 /* Machines that do polling rather than SIGIO have been
12920 observed to go into a busy-wait here. So we'll fake an
12921 alarm signal to let the handler know that there's something
12922 to be read. We used to raise a real alarm, but it seems
12923 that the handler isn't always enabled here. This is
12924 probably a bug. */
8b2f8d4e 12925 if (input_polling_used ())
3b2fa4e6 12926 {
12ce2351
GM
12927 /* It could be confusing if a real alarm arrives while
12928 processing the fake one. Turn it off and let the
12929 handler reset it. */
3e71d8f2 12930 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
12931 int old_poll_suppress_count = poll_suppress_count;
12932 poll_suppress_count = 1;
12933 poll_for_input_1 ();
12934 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 12935 }
12ce2351
GM
12936
12937 /* See if a MapNotify event has been processed. */
12938 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 12939 }
31be9251
GM
12940
12941 /* 2000-09-28: In
12942
12943 (let ((f (selected-frame)))
12944 (iconify-frame f)
12945 (raise-frame f))
12946
12947 the frame is not raised with various window managers on
12948 FreeBSD, Linux and Solaris. It turns out that, for some
12949 unknown reason, the call to XtMapWidget is completely ignored.
12950 Mapping the widget a second time works. */
12951
12952 if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
12953 goto retry;
0dacf791 12954 }
dc6f92b8
JB
12955}
12956
06a2c219 12957/* Change from mapped state to withdrawn state. */
dc6f92b8 12958
d047c4eb
KH
12959/* Make the frame visible (mapped and not iconified). */
12960
dfcf069d 12961void
f676886a
JB
12962x_make_frame_invisible (f)
12963 struct frame *f;
dc6f92b8 12964{
546e6d5b
RS
12965 Window window;
12966
12967#ifdef USE_X_TOOLKIT
12968 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 12969 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
12970#else /* not USE_X_TOOLKIT */
12971 window = FRAME_X_WINDOW (f);
12972#endif /* not USE_X_TOOLKIT */
dc6f92b8 12973
9319ae23 12974 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
12975 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
12976 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 12977
5627c40e 12978#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 12979 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 12980 return;
5627c40e 12981#endif
dc6f92b8
JB
12982
12983 BLOCK_INPUT;
c118dd06 12984
af31d76f
RS
12985 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
12986 that the current position of the window is user-specified, rather than
12987 program-specified, so that when the window is mapped again, it will be
12988 placed at the same location, without forcing the user to position it
12989 by hand again (they have already done that once for this window.) */
c32cdd9a 12990 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 12991
c118dd06
JB
12992#ifdef HAVE_X11R4
12993
334208b7
RS
12994 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
12995 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
12996 {
12997 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12998 error ("Can't notify window manager of window withdrawal");
c118dd06 12999 }
c118dd06 13000#else /* ! defined (HAVE_X11R4) */
16bd92ea 13001
c118dd06 13002 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
13003 if (! EQ (Vx_no_window_manager, Qt))
13004 {
16bd92ea 13005 XEvent unmap;
dc6f92b8 13006
16bd92ea 13007 unmap.xunmap.type = UnmapNotify;
546e6d5b 13008 unmap.xunmap.window = window;
334208b7 13009 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 13010 unmap.xunmap.from_configure = False;
334208b7
RS
13011 if (! XSendEvent (FRAME_X_DISPLAY (f),
13012 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 13013 False,
06a2c219 13014 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
13015 &unmap))
13016 {
13017 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13018 error ("Can't notify window manager of withdrawal");
16bd92ea 13019 }
dc6f92b8
JB
13020 }
13021
16bd92ea 13022 /* Unmap the window ourselves. Cheeky! */
334208b7 13023 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 13024#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 13025
5627c40e
RS
13026 /* We can't distinguish this from iconification
13027 just by the event that we get from the server.
13028 So we can't win using the usual strategy of letting
13029 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
13030 and synchronize with the server to make sure we agree. */
13031 f->visible = 0;
13032 FRAME_ICONIFIED_P (f) = 0;
13033 f->async_visible = 0;
13034 f->async_iconified = 0;
13035
334208b7 13036 x_sync (f);
5627c40e 13037
dc6f92b8
JB
13038 UNBLOCK_INPUT;
13039}
13040
06a2c219 13041/* Change window state from mapped to iconified. */
dc6f92b8 13042
dfcf069d 13043void
f676886a
JB
13044x_iconify_frame (f)
13045 struct frame *f;
dc6f92b8 13046{
3afe33e7 13047 int result;
990ba854 13048 Lisp_Object type;
dc6f92b8 13049
9319ae23 13050 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
13051 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
13052 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 13053
3a88c238 13054 if (f->async_iconified)
dc6f92b8
JB
13055 return;
13056
3afe33e7 13057 BLOCK_INPUT;
546e6d5b 13058
9af3143a
RS
13059 FRAME_SAMPLE_VISIBILITY (f);
13060
990ba854
RS
13061 type = x_icon_type (f);
13062 if (!NILP (type))
13063 x_bitmap_icon (f, type);
bdcd49ba
RS
13064
13065#ifdef USE_X_TOOLKIT
13066
546e6d5b
RS
13067 if (! FRAME_VISIBLE_P (f))
13068 {
13069 if (! EQ (Vx_no_window_manager, Qt))
13070 x_wm_set_window_state (f, IconicState);
13071 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 13072 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
13073 /* The server won't give us any event to indicate
13074 that an invisible frame was changed to an icon,
13075 so we have to record it here. */
13076 f->iconified = 1;
1e6bc770 13077 f->visible = 1;
9cf30a30 13078 f->async_iconified = 1;
1e6bc770 13079 f->async_visible = 0;
546e6d5b
RS
13080 UNBLOCK_INPUT;
13081 return;
13082 }
13083
334208b7 13084 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 13085 XtWindow (f->output_data.x->widget),
334208b7 13086 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
13087 UNBLOCK_INPUT;
13088
13089 if (!result)
546e6d5b 13090 error ("Can't notify window manager of iconification");
3afe33e7
RS
13091
13092 f->async_iconified = 1;
1e6bc770
RS
13093 f->async_visible = 0;
13094
8c002a25
KH
13095
13096 BLOCK_INPUT;
334208b7 13097 XFlush (FRAME_X_DISPLAY (f));
8c002a25 13098 UNBLOCK_INPUT;
3afe33e7
RS
13099#else /* not USE_X_TOOLKIT */
13100
fd13dbb2
RS
13101 /* Make sure the X server knows where the window should be positioned,
13102 in case the user deiconifies with the window manager. */
13103 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 13104 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 13105
16bd92ea
JB
13106 /* Since we don't know which revision of X we're running, we'll use both
13107 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
13108
13109 /* X11R4: send a ClientMessage to the window manager using the
13110 WM_CHANGE_STATE type. */
13111 {
13112 XEvent message;
58769bee 13113
c118dd06 13114 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 13115 message.xclient.type = ClientMessage;
334208b7 13116 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
13117 message.xclient.format = 32;
13118 message.xclient.data.l[0] = IconicState;
13119
334208b7
RS
13120 if (! XSendEvent (FRAME_X_DISPLAY (f),
13121 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
13122 False,
13123 SubstructureRedirectMask | SubstructureNotifyMask,
13124 &message))
dc6f92b8
JB
13125 {
13126 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 13127 error ("Can't notify window manager of iconification");
dc6f92b8 13128 }
16bd92ea 13129 }
dc6f92b8 13130
58769bee 13131 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
13132 IconicState. */
13133 x_wm_set_window_state (f, IconicState);
dc6f92b8 13134
a9c00105
RS
13135 if (!FRAME_VISIBLE_P (f))
13136 {
13137 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 13138 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
13139 }
13140
3a88c238 13141 f->async_iconified = 1;
1e6bc770 13142 f->async_visible = 0;
dc6f92b8 13143
334208b7 13144 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 13145 UNBLOCK_INPUT;
8c002a25 13146#endif /* not USE_X_TOOLKIT */
dc6f92b8 13147}
19f71add 13148
d047c4eb 13149\f
19f71add 13150/* Free X resources of frame F. */
dc6f92b8 13151
dfcf069d 13152void
19f71add 13153x_free_frame_resources (f)
f676886a 13154 struct frame *f;
dc6f92b8 13155{
7f9c7f94
RS
13156 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13157
dc6f92b8 13158 BLOCK_INPUT;
c0ff3fab 13159
6186a4a0
RS
13160 /* If a display connection is dead, don't try sending more
13161 commands to the X server. */
19f71add 13162 if (dpyinfo->display)
6186a4a0 13163 {
19f71add 13164 if (f->output_data.x->icon_desc)
6186a4a0 13165 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
19f71add 13166
31f41daf 13167#ifdef HAVE_X_I18N
f5d11644
GM
13168 if (FRAME_XIC (f))
13169 free_frame_xic (f);
31f41daf 13170#endif
19f71add 13171
2662734b 13172 if (FRAME_X_WINDOW (f))
19f71add
GM
13173 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13174
3afe33e7 13175#ifdef USE_X_TOOLKIT
06a2c219 13176 if (f->output_data.x->widget)
30ca89f5
GM
13177 {
13178 XtDestroyWidget (f->output_data.x->widget);
13179 f->output_data.x->widget = NULL;
13180 }
6186a4a0 13181 free_frame_menubar (f);
3afe33e7
RS
13182#endif /* USE_X_TOOLKIT */
13183
3e71d8f2
GM
13184 unload_color (f, f->output_data.x->foreground_pixel);
13185 unload_color (f, f->output_data.x->background_pixel);
13186 unload_color (f, f->output_data.x->cursor_pixel);
13187 unload_color (f, f->output_data.x->cursor_foreground_pixel);
13188 unload_color (f, f->output_data.x->border_pixel);
13189 unload_color (f, f->output_data.x->mouse_pixel);
19f71add 13190
3e71d8f2
GM
13191 if (f->output_data.x->scroll_bar_background_pixel != -1)
13192 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
13193 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
13194 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
7c1bef7a
MB
13195#ifdef USE_TOOLKIT_SCROLL_BARS
13196 /* Scrollbar shadow colors. */
13197 if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
13198 unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
13199 if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
13200 unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
13201#endif /* USE_TOOLKIT_SCROLL_BARS */
3e71d8f2
GM
13202 if (f->output_data.x->white_relief.allocated_p)
13203 unload_color (f, f->output_data.x->white_relief.pixel);
13204 if (f->output_data.x->black_relief.allocated_p)
13205 unload_color (f, f->output_data.x->black_relief.pixel);
4ca78676 13206
19f71add
GM
13207 if (FRAME_FACE_CACHE (f))
13208 free_frame_faces (f);
13209
4ca78676 13210 x_free_gcs (f);
6186a4a0
RS
13211 XFlush (FRAME_X_DISPLAY (f));
13212 }
dc6f92b8 13213
df89d8a4 13214 if (f->output_data.x->saved_menu_event)
06a2c219 13215 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 13216
7556890b 13217 xfree (f->output_data.x);
19f71add
GM
13218 f->output_data.x = NULL;
13219
0f941935
KH
13220 if (f == dpyinfo->x_focus_frame)
13221 dpyinfo->x_focus_frame = 0;
13222 if (f == dpyinfo->x_focus_event_frame)
13223 dpyinfo->x_focus_event_frame = 0;
13224 if (f == dpyinfo->x_highlight_frame)
13225 dpyinfo->x_highlight_frame = 0;
c0ff3fab 13226
7f9c7f94 13227 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 13228 {
7f9c7f94
RS
13229 dpyinfo->mouse_face_beg_row
13230 = dpyinfo->mouse_face_beg_col = -1;
13231 dpyinfo->mouse_face_end_row
13232 = dpyinfo->mouse_face_end_col = -1;
13233 dpyinfo->mouse_face_window = Qnil;
21323706
RS
13234 dpyinfo->mouse_face_deferred_gc = 0;
13235 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 13236 }
0134a210 13237
c0ff3fab 13238 UNBLOCK_INPUT;
dc6f92b8 13239}
19f71add
GM
13240
13241
13242/* Destroy the X window of frame F. */
13243
13244void
13245x_destroy_window (f)
13246 struct frame *f;
13247{
13248 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13249
13250 /* If a display connection is dead, don't try sending more
13251 commands to the X server. */
13252 if (dpyinfo->display != 0)
13253 x_free_frame_resources (f);
13254
13255 dpyinfo->reference_count--;
13256}
13257
dc6f92b8 13258\f
f451eb13
JB
13259/* Setting window manager hints. */
13260
af31d76f
RS
13261/* Set the normal size hints for the window manager, for frame F.
13262 FLAGS is the flags word to use--or 0 meaning preserve the flags
13263 that the window now has.
13264 If USER_POSITION is nonzero, we set the USPosition
13265 flag (this is useful when FLAGS is 0). */
6dba1858 13266
dfcf069d 13267void
af31d76f 13268x_wm_set_size_hint (f, flags, user_position)
f676886a 13269 struct frame *f;
af31d76f
RS
13270 long flags;
13271 int user_position;
dc6f92b8
JB
13272{
13273 XSizeHints size_hints;
3afe33e7
RS
13274
13275#ifdef USE_X_TOOLKIT
7e4f2521
FP
13276 Arg al[2];
13277 int ac = 0;
13278 Dimension widget_width, widget_height;
7556890b 13279 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 13280#else /* not USE_X_TOOLKIT */
c118dd06 13281 Window window = FRAME_X_WINDOW (f);
3afe33e7 13282#endif /* not USE_X_TOOLKIT */
dc6f92b8 13283
b72a58fd
RS
13284 /* Setting PMaxSize caused various problems. */
13285 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 13286
7556890b
RS
13287 size_hints.x = f->output_data.x->left_pos;
13288 size_hints.y = f->output_data.x->top_pos;
7553a6b7 13289
7e4f2521
FP
13290#ifdef USE_X_TOOLKIT
13291 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
13292 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 13293 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
13294 size_hints.height = widget_height;
13295 size_hints.width = widget_width;
13296#else /* not USE_X_TOOLKIT */
f676886a
JB
13297 size_hints.height = PIXEL_HEIGHT (f);
13298 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 13299#endif /* not USE_X_TOOLKIT */
7553a6b7 13300
7556890b
RS
13301 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
13302 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
13303 size_hints.max_width
13304 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
13305 size_hints.max_height
13306 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 13307
d067ea8b
KH
13308 /* Calculate the base and minimum sizes.
13309
13310 (When we use the X toolkit, we don't do it here.
13311 Instead we copy the values that the widgets are using, below.) */
13312#ifndef USE_X_TOOLKIT
b1c884c3 13313 {
b0342f17 13314 int base_width, base_height;
0134a210 13315 int min_rows = 0, min_cols = 0;
b0342f17 13316
f451eb13
JB
13317 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
13318 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 13319
0134a210 13320 check_frame_size (f, &min_rows, &min_cols);
b0342f17 13321
0134a210
RS
13322 /* The window manager uses the base width hints to calculate the
13323 current number of rows and columns in the frame while
13324 resizing; min_width and min_height aren't useful for this
13325 purpose, since they might not give the dimensions for a
13326 zero-row, zero-column frame.
58769bee 13327
0134a210
RS
13328 We use the base_width and base_height members if we have
13329 them; otherwise, we set the min_width and min_height members
13330 to the size for a zero x zero frame. */
b0342f17
JB
13331
13332#ifdef HAVE_X11R4
0134a210
RS
13333 size_hints.flags |= PBaseSize;
13334 size_hints.base_width = base_width;
13335 size_hints.base_height = base_height;
13336 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
13337 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 13338#else
0134a210
RS
13339 size_hints.min_width = base_width;
13340 size_hints.min_height = base_height;
b0342f17 13341#endif
b1c884c3 13342 }
dc6f92b8 13343
d067ea8b 13344 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 13345 if (flags)
dc6f92b8 13346 {
d067ea8b
KH
13347 size_hints.flags |= flags;
13348 goto no_read;
13349 }
13350#endif /* not USE_X_TOOLKIT */
13351
13352 {
13353 XSizeHints hints; /* Sometimes I hate X Windows... */
13354 long supplied_return;
13355 int value;
af31d76f
RS
13356
13357#ifdef HAVE_X11R4
d067ea8b
KH
13358 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
13359 &supplied_return);
af31d76f 13360#else
d067ea8b 13361 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 13362#endif
58769bee 13363
d067ea8b
KH
13364#ifdef USE_X_TOOLKIT
13365 size_hints.base_height = hints.base_height;
13366 size_hints.base_width = hints.base_width;
13367 size_hints.min_height = hints.min_height;
13368 size_hints.min_width = hints.min_width;
13369#endif
13370
13371 if (flags)
13372 size_hints.flags |= flags;
13373 else
13374 {
13375 if (value == 0)
13376 hints.flags = 0;
13377 if (hints.flags & PSize)
13378 size_hints.flags |= PSize;
13379 if (hints.flags & PPosition)
13380 size_hints.flags |= PPosition;
13381 if (hints.flags & USPosition)
13382 size_hints.flags |= USPosition;
13383 if (hints.flags & USSize)
13384 size_hints.flags |= USSize;
13385 }
13386 }
13387
06a2c219 13388#ifndef USE_X_TOOLKIT
d067ea8b 13389 no_read:
06a2c219 13390#endif
0134a210 13391
af31d76f 13392#ifdef PWinGravity
7556890b 13393 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 13394 size_hints.flags |= PWinGravity;
dc05a16b 13395
af31d76f 13396 if (user_position)
6dba1858 13397 {
af31d76f
RS
13398 size_hints.flags &= ~ PPosition;
13399 size_hints.flags |= USPosition;
6dba1858 13400 }
2554751d 13401#endif /* PWinGravity */
6dba1858 13402
b0342f17 13403#ifdef HAVE_X11R4
334208b7 13404 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13405#else
334208b7 13406 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13407#endif
dc6f92b8
JB
13408}
13409
13410/* Used for IconicState or NormalState */
06a2c219 13411
dfcf069d 13412void
f676886a
JB
13413x_wm_set_window_state (f, state)
13414 struct frame *f;
dc6f92b8
JB
13415 int state;
13416{
3afe33e7 13417#ifdef USE_X_TOOLKIT
546e6d5b
RS
13418 Arg al[1];
13419
13420 XtSetArg (al[0], XtNinitialState, state);
7556890b 13421 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 13422#else /* not USE_X_TOOLKIT */
c118dd06 13423 Window window = FRAME_X_WINDOW (f);
dc6f92b8 13424
7556890b
RS
13425 f->output_data.x->wm_hints.flags |= StateHint;
13426 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 13427
7556890b 13428 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 13429#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13430}
13431
dfcf069d 13432void
7f2ae036 13433x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 13434 struct frame *f;
7f2ae036 13435 int pixmap_id;
dc6f92b8 13436{
d2bd6bc4
RS
13437 Pixmap icon_pixmap;
13438
06a2c219 13439#ifndef USE_X_TOOLKIT
c118dd06 13440 Window window = FRAME_X_WINDOW (f);
75231bad 13441#endif
dc6f92b8 13442
7f2ae036 13443 if (pixmap_id > 0)
dbc4e1c1 13444 {
d2bd6bc4 13445 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 13446 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
13447 }
13448 else
68568555
RS
13449 {
13450 /* It seems there is no way to turn off use of an icon pixmap.
13451 The following line does it, only if no icon has yet been created,
13452 for some window managers. But with mwm it crashes.
13453 Some people say it should clear the IconPixmapHint bit in this case,
13454 but that doesn't work, and the X consortium said it isn't the
13455 right thing at all. Since there is no way to win,
13456 best to explicitly give up. */
13457#if 0
13458 f->output_data.x->wm_hints.icon_pixmap = None;
13459#else
13460 return;
13461#endif
13462 }
b1c884c3 13463
d2bd6bc4
RS
13464#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
13465
13466 {
13467 Arg al[1];
13468 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
13469 XtSetValues (f->output_data.x->widget, al, 1);
13470 }
13471
13472#else /* not USE_X_TOOLKIT */
13473
7556890b
RS
13474 f->output_data.x->wm_hints.flags |= IconPixmapHint;
13475 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
13476
13477#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13478}
13479
dfcf069d 13480void
f676886a
JB
13481x_wm_set_icon_position (f, icon_x, icon_y)
13482 struct frame *f;
dc6f92b8
JB
13483 int icon_x, icon_y;
13484{
75231bad 13485#ifdef USE_X_TOOLKIT
7556890b 13486 Window window = XtWindow (f->output_data.x->widget);
75231bad 13487#else
c118dd06 13488 Window window = FRAME_X_WINDOW (f);
75231bad 13489#endif
dc6f92b8 13490
7556890b
RS
13491 f->output_data.x->wm_hints.flags |= IconPositionHint;
13492 f->output_data.x->wm_hints.icon_x = icon_x;
13493 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 13494
7556890b 13495 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
13496}
13497
13498\f
06a2c219
GM
13499/***********************************************************************
13500 Fonts
13501 ***********************************************************************/
dc43ef94
KH
13502
13503/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 13504
dc43ef94
KH
13505struct font_info *
13506x_get_font_info (f, font_idx)
13507 FRAME_PTR f;
13508 int font_idx;
13509{
13510 return (FRAME_X_FONT_TABLE (f) + font_idx);
13511}
13512
13513
9c11f79e
GM
13514/* Return a list of names of available fonts matching PATTERN on frame F.
13515
13516 If SIZE is > 0, it is the size (maximum bounds width) of fonts
13517 to be listed.
13518
13519 SIZE < 0 means include scalable fonts.
13520
13521 Frame F null means we have not yet created any frame on X, and
13522 consult the first display in x_display_list. MAXNAMES sets a limit
13523 on how many fonts to match. */
dc43ef94
KH
13524
13525Lisp_Object
13526x_list_fonts (f, pattern, size, maxnames)
9c11f79e 13527 struct frame *f;
dc43ef94
KH
13528 Lisp_Object pattern;
13529 int size;
13530 int maxnames;
13531{
06a2c219
GM
13532 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
13533 Lisp_Object tem, second_best;
9c11f79e
GM
13534 struct x_display_info *dpyinfo
13535 = f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
13536 Display *dpy = dpyinfo->display;
09c6077f 13537 int try_XLoadQueryFont = 0;
53ca4657 13538 int count;
9c11f79e
GM
13539 int allow_scalable_fonts_p = 0;
13540
13541 if (size < 0)
13542 {
13543 allow_scalable_fonts_p = 1;
13544 size = 0;
13545 }
dc43ef94 13546
6b0efe73 13547 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
13548 if (NILP (patterns))
13549 patterns = Fcons (pattern, Qnil);
81ba44e5 13550
09c6077f
KH
13551 if (maxnames == 1 && !size)
13552 /* We can return any single font matching PATTERN. */
13553 try_XLoadQueryFont = 1;
9a32686f 13554
8e713be6 13555 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 13556 {
dc43ef94 13557 int num_fonts;
3e71d8f2 13558 char **names = NULL;
dc43ef94 13559
8e713be6 13560 pattern = XCAR (patterns);
536f4067
RS
13561 /* See if we cached the result for this particular query.
13562 The cache is an alist of the form:
9c11f79e
GM
13563 ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */
13564 tem = XCDR (dpyinfo->name_list_element);
13565 key = Fcons (Fcons (pattern, make_number (maxnames)),
13566 allow_scalable_fonts_p ? Qt : Qnil);
13567 list = Fassoc (key, tem);
13568 if (!NILP (list))
b5210ea7
KH
13569 {
13570 list = Fcdr_safe (list);
13571 /* We have a cashed list. Don't have to get the list again. */
13572 goto label_cached;
13573 }
13574
13575 /* At first, put PATTERN in the cache. */
09c6077f 13576
dc43ef94 13577 BLOCK_INPUT;
17d85edc
KH
13578 count = x_catch_errors (dpy);
13579
09c6077f
KH
13580 if (try_XLoadQueryFont)
13581 {
13582 XFontStruct *font;
13583 unsigned long value;
13584
13585 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
13586 if (x_had_errors_p (dpy))
13587 {
13588 /* This error is perhaps due to insufficient memory on X
13589 server. Let's just ignore it. */
13590 font = NULL;
13591 x_clear_errors (dpy);
13592 }
13593
09c6077f
KH
13594 if (font
13595 && XGetFontProperty (font, XA_FONT, &value))
13596 {
13597 char *name = (char *) XGetAtomName (dpy, (Atom) value);
13598 int len = strlen (name);
01c752b5 13599 char *tmp;
09c6077f 13600
6f6512e8
KH
13601 /* If DXPC (a Differential X Protocol Compressor)
13602 Ver.3.7 is running, XGetAtomName will return null
13603 string. We must avoid such a name. */
13604 if (len == 0)
13605 try_XLoadQueryFont = 0;
13606 else
13607 {
13608 num_fonts = 1;
13609 names = (char **) alloca (sizeof (char *));
13610 /* Some systems only allow alloca assigned to a
13611 simple var. */
13612 tmp = (char *) alloca (len + 1); names[0] = tmp;
13613 bcopy (name, names[0], len + 1);
13614 XFree (name);
13615 }
09c6077f
KH
13616 }
13617 else
13618 try_XLoadQueryFont = 0;
a083fd23
RS
13619
13620 if (font)
13621 XFreeFont (dpy, font);
09c6077f
KH
13622 }
13623
13624 if (!try_XLoadQueryFont)
17d85edc
KH
13625 {
13626 /* We try at least 10 fonts because XListFonts will return
13627 auto-scaled fonts at the head. */
13628 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
13629 &num_fonts);
13630 if (x_had_errors_p (dpy))
13631 {
13632 /* This error is perhaps due to insufficient memory on X
13633 server. Let's just ignore it. */
13634 names = NULL;
13635 x_clear_errors (dpy);
13636 }
13637 }
13638
13639 x_uncatch_errors (dpy, count);
dc43ef94
KH
13640 UNBLOCK_INPUT;
13641
13642 if (names)
13643 {
13644 int i;
dc43ef94
KH
13645
13646 /* Make a list of all the fonts we got back.
13647 Store that in the font cache for the display. */
13648 for (i = 0; i < num_fonts; i++)
13649 {
06a2c219 13650 int width = 0;
dc43ef94 13651 char *p = names[i];
06a2c219
GM
13652 int average_width = -1, dashes = 0;
13653
dc43ef94 13654 /* Count the number of dashes in NAMES[I]. If there are
9c11f79e
GM
13655 14 dashes, and the field value following 12th dash
13656 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
13657 is usually too ugly to be used for editing. Let's
13658 ignore it. */
dc43ef94
KH
13659 while (*p)
13660 if (*p++ == '-')
13661 {
13662 dashes++;
13663 if (dashes == 7) /* PIXEL_SIZE field */
13664 width = atoi (p);
13665 else if (dashes == 12) /* AVERAGE_WIDTH field */
13666 average_width = atoi (p);
13667 }
9c11f79e
GM
13668
13669 if (allow_scalable_fonts_p
13670 || dashes < 14 || average_width != 0)
dc43ef94
KH
13671 {
13672 tem = build_string (names[i]);
13673 if (NILP (Fassoc (tem, list)))
13674 {
13675 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
13676 && ((fast_c_string_match_ignore_case
13677 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
13678 >= 0))
13679 /* We can set the value of PIXEL_SIZE to the
b5210ea7 13680 width of this font. */
dc43ef94
KH
13681 list = Fcons (Fcons (tem, make_number (width)), list);
13682 else
13683 /* For the moment, width is not known. */
13684 list = Fcons (Fcons (tem, Qnil), list);
13685 }
13686 }
13687 }
e38f4136 13688
09c6077f 13689 if (!try_XLoadQueryFont)
e38f4136
GM
13690 {
13691 BLOCK_INPUT;
13692 XFreeFontNames (names);
13693 UNBLOCK_INPUT;
13694 }
dc43ef94
KH
13695 }
13696
b5210ea7 13697 /* Now store the result in the cache. */
9c11f79e
GM
13698 XCDR (dpyinfo->name_list_element)
13699 = Fcons (Fcons (key, list), XCDR (dpyinfo->name_list_element));
dc43ef94 13700
b5210ea7
KH
13701 label_cached:
13702 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 13703
b5210ea7
KH
13704 newlist = second_best = Qnil;
13705 /* Make a list of the fonts that have the right width. */
8e713be6 13706 for (; CONSP (list); list = XCDR (list))
b5210ea7 13707 {
536f4067
RS
13708 int found_size;
13709
8e713be6 13710 tem = XCAR (list);
dc43ef94 13711
8e713be6 13712 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
13713 continue;
13714 if (!size)
13715 {
8e713be6 13716 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
13717 continue;
13718 }
dc43ef94 13719
8e713be6 13720 if (!INTEGERP (XCDR (tem)))
dc43ef94 13721 {
b5210ea7 13722 /* Since we have not yet known the size of this font, we
9c11f79e 13723 must try slow function call XLoadQueryFont. */
dc43ef94
KH
13724 XFontStruct *thisinfo;
13725
13726 BLOCK_INPUT;
17d85edc 13727 count = x_catch_errors (dpy);
dc43ef94 13728 thisinfo = XLoadQueryFont (dpy,
8e713be6 13729 XSTRING (XCAR (tem))->data);
17d85edc
KH
13730 if (x_had_errors_p (dpy))
13731 {
13732 /* This error is perhaps due to insufficient memory on X
13733 server. Let's just ignore it. */
13734 thisinfo = NULL;
13735 x_clear_errors (dpy);
13736 }
13737 x_uncatch_errors (dpy, count);
dc43ef94
KH
13738 UNBLOCK_INPUT;
13739
13740 if (thisinfo)
13741 {
8e713be6 13742 XCDR (tem)
536f4067
RS
13743 = (thisinfo->min_bounds.width == 0
13744 ? make_number (0)
13745 : make_number (thisinfo->max_bounds.width));
e38f4136 13746 BLOCK_INPUT;
dc43ef94 13747 XFreeFont (dpy, thisinfo);
e38f4136 13748 UNBLOCK_INPUT;
dc43ef94
KH
13749 }
13750 else
b5210ea7 13751 /* For unknown reason, the previous call of XListFont had
06a2c219 13752 returned a font which can't be opened. Record the size
b5210ea7 13753 as 0 not to try to open it again. */
8e713be6 13754 XCDR (tem) = make_number (0);
dc43ef94 13755 }
536f4067 13756
8e713be6 13757 found_size = XINT (XCDR (tem));
536f4067 13758 if (found_size == size)
8e713be6 13759 newlist = Fcons (XCAR (tem), newlist);
536f4067 13760 else if (found_size > 0)
b5210ea7 13761 {
536f4067 13762 if (NILP (second_best))
b5210ea7 13763 second_best = tem;
536f4067
RS
13764 else if (found_size < size)
13765 {
8e713be6
KR
13766 if (XINT (XCDR (second_best)) > size
13767 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
13768 second_best = tem;
13769 }
13770 else
13771 {
8e713be6
KR
13772 if (XINT (XCDR (second_best)) > size
13773 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
13774 second_best = tem;
13775 }
b5210ea7
KH
13776 }
13777 }
13778 if (!NILP (newlist))
13779 break;
13780 else if (!NILP (second_best))
13781 {
8e713be6 13782 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 13783 break;
dc43ef94 13784 }
dc43ef94
KH
13785 }
13786
13787 return newlist;
13788}
13789
06a2c219
GM
13790
13791#if GLYPH_DEBUG
13792
13793/* Check that FONT is valid on frame F. It is if it can be found in F's
13794 font table. */
13795
13796static void
13797x_check_font (f, font)
13798 struct frame *f;
13799 XFontStruct *font;
13800{
13801 int i;
13802 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13803
13804 xassert (font != NULL);
13805
13806 for (i = 0; i < dpyinfo->n_fonts; i++)
13807 if (dpyinfo->font_table[i].name
13808 && font == dpyinfo->font_table[i].font)
13809 break;
13810
13811 xassert (i < dpyinfo->n_fonts);
13812}
13813
13814#endif /* GLYPH_DEBUG != 0 */
13815
13816/* Set *W to the minimum width, *H to the minimum font height of FONT.
13817 Note: There are (broken) X fonts out there with invalid XFontStruct
13818 min_bounds contents. For example, handa@etl.go.jp reports that
13819 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
13820 have font->min_bounds.width == 0. */
13821
13822static INLINE void
13823x_font_min_bounds (font, w, h)
13824 XFontStruct *font;
13825 int *w, *h;
13826{
13827 *h = FONT_HEIGHT (font);
13828 *w = font->min_bounds.width;
13829
13830 /* Try to handle the case where FONT->min_bounds has invalid
13831 contents. Since the only font known to have invalid min_bounds
13832 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
13833 if (*w <= 0)
13834 *w = font->max_bounds.width;
13835}
13836
13837
13838/* Compute the smallest character width and smallest font height over
13839 all fonts available on frame F. Set the members smallest_char_width
13840 and smallest_font_height in F's x_display_info structure to
13841 the values computed. Value is non-zero if smallest_font_height or
13842 smallest_char_width become smaller than they were before. */
13843
13844static int
13845x_compute_min_glyph_bounds (f)
13846 struct frame *f;
13847{
13848 int i;
13849 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13850 XFontStruct *font;
13851 int old_width = dpyinfo->smallest_char_width;
13852 int old_height = dpyinfo->smallest_font_height;
13853
13854 dpyinfo->smallest_font_height = 100000;
13855 dpyinfo->smallest_char_width = 100000;
13856
13857 for (i = 0; i < dpyinfo->n_fonts; ++i)
13858 if (dpyinfo->font_table[i].name)
13859 {
13860 struct font_info *fontp = dpyinfo->font_table + i;
13861 int w, h;
13862
13863 font = (XFontStruct *) fontp->font;
13864 xassert (font != (XFontStruct *) ~0);
13865 x_font_min_bounds (font, &w, &h);
13866
13867 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
13868 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
13869 }
13870
13871 xassert (dpyinfo->smallest_char_width > 0
13872 && dpyinfo->smallest_font_height > 0);
13873
13874 return (dpyinfo->n_fonts == 1
13875 || dpyinfo->smallest_char_width < old_width
13876 || dpyinfo->smallest_font_height < old_height);
13877}
13878
13879
dc43ef94
KH
13880/* Load font named FONTNAME of the size SIZE for frame F, and return a
13881 pointer to the structure font_info while allocating it dynamically.
13882 If SIZE is 0, load any size of font.
13883 If loading is failed, return NULL. */
13884
13885struct font_info *
13886x_load_font (f, fontname, size)
13887 struct frame *f;
13888 register char *fontname;
13889 int size;
13890{
13891 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13892 Lisp_Object font_names;
d645aaa4 13893 int count;
dc43ef94
KH
13894
13895 /* Get a list of all the fonts that match this name. Once we
13896 have a list of matching fonts, we compare them against the fonts
13897 we already have by comparing names. */
09c6077f 13898 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
13899
13900 if (!NILP (font_names))
13901 {
13902 Lisp_Object tail;
13903 int i;
13904
13905 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 13906 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
13907 if (dpyinfo->font_table[i].name
13908 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 13909 XSTRING (XCAR (tail))->data)
06a2c219 13910 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 13911 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
13912 return (dpyinfo->font_table + i);
13913 }
13914
13915 /* Load the font and add it to the table. */
13916 {
13917 char *full_name;
13918 XFontStruct *font;
13919 struct font_info *fontp;
13920 unsigned long value;
06a2c219 13921 int i;
dc43ef94 13922
2da424f1
KH
13923 /* If we have found fonts by x_list_font, load one of them. If
13924 not, we still try to load a font by the name given as FONTNAME
13925 because XListFonts (called in x_list_font) of some X server has
13926 a bug of not finding a font even if the font surely exists and
13927 is loadable by XLoadQueryFont. */
e1d6d5b9 13928 if (size > 0 && !NILP (font_names))
8e713be6 13929 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
13930
13931 BLOCK_INPUT;
d645aaa4 13932 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 13933 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
13934 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
13935 {
13936 /* This error is perhaps due to insufficient memory on X
13937 server. Let's just ignore it. */
13938 font = NULL;
13939 x_clear_errors (FRAME_X_DISPLAY (f));
13940 }
13941 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 13942 UNBLOCK_INPUT;
b5210ea7 13943 if (!font)
dc43ef94
KH
13944 return NULL;
13945
06a2c219
GM
13946 /* Find a free slot in the font table. */
13947 for (i = 0; i < dpyinfo->n_fonts; ++i)
13948 if (dpyinfo->font_table[i].name == NULL)
13949 break;
13950
13951 /* If no free slot found, maybe enlarge the font table. */
13952 if (i == dpyinfo->n_fonts
13953 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 13954 {
06a2c219
GM
13955 int sz;
13956 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
13957 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 13958 dpyinfo->font_table
06a2c219 13959 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
13960 }
13961
06a2c219
GM
13962 fontp = dpyinfo->font_table + i;
13963 if (i == dpyinfo->n_fonts)
13964 ++dpyinfo->n_fonts;
dc43ef94
KH
13965
13966 /* Now fill in the slots of *FONTP. */
13967 BLOCK_INPUT;
13968 fontp->font = font;
06a2c219 13969 fontp->font_idx = i;
dc43ef94
KH
13970 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
13971 bcopy (fontname, fontp->name, strlen (fontname) + 1);
13972
13973 /* Try to get the full name of FONT. Put it in FULL_NAME. */
13974 full_name = 0;
13975 if (XGetFontProperty (font, XA_FONT, &value))
13976 {
13977 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
13978 char *p = name;
13979 int dashes = 0;
13980
13981 /* Count the number of dashes in the "full name".
13982 If it is too few, this isn't really the font's full name,
13983 so don't use it.
13984 In X11R4, the fonts did not come with their canonical names
13985 stored in them. */
13986 while (*p)
13987 {
13988 if (*p == '-')
13989 dashes++;
13990 p++;
13991 }
13992
13993 if (dashes >= 13)
13994 {
13995 full_name = (char *) xmalloc (p - name + 1);
13996 bcopy (name, full_name, p - name + 1);
13997 }
13998
13999 XFree (name);
14000 }
14001
14002 if (full_name != 0)
14003 fontp->full_name = full_name;
14004 else
14005 fontp->full_name = fontp->name;
14006
14007 fontp->size = font->max_bounds.width;
d5749adb 14008 fontp->height = FONT_HEIGHT (font);
dc43ef94 14009
2da424f1
KH
14010 if (NILP (font_names))
14011 {
14012 /* We come here because of a bug of XListFonts mentioned at
14013 the head of this block. Let's store this information in
14014 the cache for x_list_fonts. */
14015 Lisp_Object lispy_name = build_string (fontname);
14016 Lisp_Object lispy_full_name = build_string (fontp->full_name);
9c11f79e
GM
14017 Lisp_Object key = Fcons (Fcons (lispy_name, make_number (256)),
14018 Qnil);
2da424f1 14019
8e713be6 14020 XCDR (dpyinfo->name_list_element)
9c11f79e 14021 = Fcons (Fcons (key,
2da424f1
KH
14022 Fcons (Fcons (lispy_full_name,
14023 make_number (fontp->size)),
14024 Qnil)),
8e713be6 14025 XCDR (dpyinfo->name_list_element));
2da424f1 14026 if (full_name)
9c11f79e
GM
14027 {
14028 key = Fcons (Fcons (lispy_full_name, make_number (256)),
14029 Qnil);
14030 XCDR (dpyinfo->name_list_element)
14031 = Fcons (Fcons (key,
14032 Fcons (Fcons (lispy_full_name,
14033 make_number (fontp->size)),
14034 Qnil)),
14035 XCDR (dpyinfo->name_list_element));
14036 }
2da424f1
KH
14037 }
14038
dc43ef94
KH
14039 /* The slot `encoding' specifies how to map a character
14040 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
14041 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
14042 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 14043 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 14044 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
14045 which is never used by any charset. If mapping can't be
14046 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
14047 fontp->encoding[1]
14048 = (font->max_byte1 == 0
14049 /* 1-byte font */
14050 ? (font->min_char_or_byte2 < 0x80
14051 ? (font->max_char_or_byte2 < 0x80
14052 ? 0 /* 0x20..0x7F */
8ff102bd 14053 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
14054 : 1) /* 0xA0..0xFF */
14055 /* 2-byte font */
14056 : (font->min_byte1 < 0x80
14057 ? (font->max_byte1 < 0x80
14058 ? (font->min_char_or_byte2 < 0x80
14059 ? (font->max_char_or_byte2 < 0x80
14060 ? 0 /* 0x2020..0x7F7F */
8ff102bd 14061 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 14062 : 3) /* 0x20A0..0x7FFF */
8ff102bd 14063 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
14064 : (font->min_char_or_byte2 < 0x80
14065 ? (font->max_char_or_byte2 < 0x80
14066 ? 2 /* 0xA020..0xFF7F */
8ff102bd 14067 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
14068 : 1))); /* 0xA0A0..0xFFFF */
14069
14070 fontp->baseline_offset
14071 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
14072 ? (long) value : 0);
14073 fontp->relative_compose
14074 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
14075 ? (long) value : 0);
f78798df
KH
14076 fontp->default_ascent
14077 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
14078 ? (long) value : 0);
dc43ef94 14079
06a2c219
GM
14080 /* Set global flag fonts_changed_p to non-zero if the font loaded
14081 has a character with a smaller width than any other character
14082 before, or if the font loaded has a smalle>r height than any
14083 other font loaded before. If this happens, it will make a
14084 glyph matrix reallocation necessary. */
14085 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 14086 UNBLOCK_INPUT;
dc43ef94
KH
14087 return fontp;
14088 }
14089}
14090
06a2c219
GM
14091
14092/* Return a pointer to struct font_info of a font named FONTNAME for
14093 frame F. If no such font is loaded, return NULL. */
14094
dc43ef94
KH
14095struct font_info *
14096x_query_font (f, fontname)
14097 struct frame *f;
14098 register char *fontname;
14099{
14100 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
14101 int i;
14102
14103 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
14104 if (dpyinfo->font_table[i].name
14105 && (!strcmp (dpyinfo->font_table[i].name, fontname)
14106 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
14107 return (dpyinfo->font_table + i);
14108 return NULL;
14109}
14110
06a2c219
GM
14111
14112/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
14113 `encoder' of the structure. */
14114
14115void
14116x_find_ccl_program (fontp)
14117 struct font_info *fontp;
14118{
a42f54e6 14119 Lisp_Object list, elt;
a6582676 14120
f9b5db02 14121 elt = Qnil;
8e713be6 14122 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 14123 {
8e713be6 14124 elt = XCAR (list);
a6582676 14125 if (CONSP (elt)
8e713be6 14126 && STRINGP (XCAR (elt))
9f2feff6
KH
14127 && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
14128 >= 0)
14129 || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
14130 >= 0)))
a42f54e6
KH
14131 break;
14132 }
f9b5db02 14133
a42f54e6
KH
14134 if (! NILP (list))
14135 {
d27f8ca7
KH
14136 struct ccl_program *ccl
14137 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 14138
8e713be6 14139 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
14140 xfree (ccl);
14141 else
14142 fontp->font_encoder = ccl;
a6582676
KH
14143 }
14144}
14145
06a2c219 14146
dc43ef94 14147\f
06a2c219
GM
14148/***********************************************************************
14149 Initialization
14150 ***********************************************************************/
f451eb13 14151
3afe33e7
RS
14152#ifdef USE_X_TOOLKIT
14153static XrmOptionDescRec emacs_options[] = {
14154 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
14155 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
14156
14157 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
14158 XrmoptionSepArg, NULL},
14159 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
14160
14161 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14162 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14163 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
14164 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14165 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
14166 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
14167 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
14168};
14169#endif /* USE_X_TOOLKIT */
14170
7a13e894
RS
14171static int x_initialized;
14172
29b38361
KH
14173#ifdef MULTI_KBOARD
14174/* Test whether two display-name strings agree up to the dot that separates
14175 the screen number from the server number. */
14176static int
14177same_x_server (name1, name2)
14178 char *name1, *name2;
14179{
14180 int seen_colon = 0;
cf591cc1
RS
14181 unsigned char *system_name = XSTRING (Vsystem_name)->data;
14182 int system_name_length = strlen (system_name);
14183 int length_until_period = 0;
14184
14185 while (system_name[length_until_period] != 0
14186 && system_name[length_until_period] != '.')
14187 length_until_period++;
14188
14189 /* Treat `unix' like an empty host name. */
14190 if (! strncmp (name1, "unix:", 5))
14191 name1 += 4;
14192 if (! strncmp (name2, "unix:", 5))
14193 name2 += 4;
14194 /* Treat this host's name like an empty host name. */
14195 if (! strncmp (name1, system_name, system_name_length)
14196 && name1[system_name_length] == ':')
14197 name1 += system_name_length;
14198 if (! strncmp (name2, system_name, system_name_length)
14199 && name2[system_name_length] == ':')
14200 name2 += system_name_length;
14201 /* Treat this host's domainless name like an empty host name. */
14202 if (! strncmp (name1, system_name, length_until_period)
14203 && name1[length_until_period] == ':')
14204 name1 += length_until_period;
14205 if (! strncmp (name2, system_name, length_until_period)
14206 && name2[length_until_period] == ':')
14207 name2 += length_until_period;
14208
29b38361
KH
14209 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
14210 {
14211 if (*name1 == ':')
14212 seen_colon++;
14213 if (seen_colon && *name1 == '.')
14214 return 1;
14215 }
14216 return (seen_colon
14217 && (*name1 == '.' || *name1 == '\0')
14218 && (*name2 == '.' || *name2 == '\0'));
14219}
14220#endif
14221
334208b7 14222struct x_display_info *
1f8255f2 14223x_term_init (display_name, xrm_option, resource_name)
334208b7 14224 Lisp_Object display_name;
1f8255f2
RS
14225 char *xrm_option;
14226 char *resource_name;
dc6f92b8 14227{
334208b7 14228 int connection;
7a13e894 14229 Display *dpy;
334208b7
RS
14230 struct x_display_info *dpyinfo;
14231 XrmDatabase xrdb;
14232
60439948
KH
14233 BLOCK_INPUT;
14234
7a13e894
RS
14235 if (!x_initialized)
14236 {
14237 x_initialize ();
14238 x_initialized = 1;
14239 }
dc6f92b8 14240
3afe33e7 14241#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
14242 /* weiner@footloose.sps.mot.com reports that this causes
14243 errors with X11R5:
14244 X protocol error: BadAtom (invalid Atom parameter)
14245 on protocol request 18skiloaf.
14246 So let's not use it until R6. */
14247#ifdef HAVE_X11XTR6
bdcd49ba
RS
14248 XtSetLanguageProc (NULL, NULL, NULL);
14249#endif
14250
7f9c7f94
RS
14251 {
14252 int argc = 0;
14253 char *argv[3];
14254
14255 argv[0] = "";
14256 argc = 1;
14257 if (xrm_option)
14258 {
14259 argv[argc++] = "-xrm";
14260 argv[argc++] = xrm_option;
14261 }
14262 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
14263 resource_name, EMACS_CLASS,
14264 emacs_options, XtNumber (emacs_options),
14265 &argc, argv);
39d8bb4d
KH
14266
14267#ifdef HAVE_X11XTR6
10537cb1 14268 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 14269 fixup_locale ();
39d8bb4d 14270#endif
7f9c7f94 14271 }
3afe33e7
RS
14272
14273#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
14274#ifdef HAVE_X11R5
14275 XSetLocaleModifiers ("");
14276#endif
7a13e894 14277 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 14278#endif /* not USE_X_TOOLKIT */
334208b7 14279
7a13e894
RS
14280 /* Detect failure. */
14281 if (dpy == 0)
60439948
KH
14282 {
14283 UNBLOCK_INPUT;
14284 return 0;
14285 }
7a13e894
RS
14286
14287 /* We have definitely succeeded. Record the new connection. */
14288
14289 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
f04e1297 14290 bzero (dpyinfo, sizeof *dpyinfo);
7a13e894 14291
29b38361
KH
14292#ifdef MULTI_KBOARD
14293 {
14294 struct x_display_info *share;
14295 Lisp_Object tail;
14296
14297 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
14298 share = share->next, tail = XCDR (tail))
14299 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
14300 XSTRING (display_name)->data))
14301 break;
14302 if (share)
14303 dpyinfo->kboard = share->kboard;
14304 else
14305 {
14306 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
14307 init_kboard (dpyinfo->kboard);
59e755be
KH
14308 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
14309 {
14310 char *vendor = ServerVendor (dpy);
9b6ed9f3 14311 UNBLOCK_INPUT;
59e755be
KH
14312 dpyinfo->kboard->Vsystem_key_alist
14313 = call1 (Qvendor_specific_keysyms,
14314 build_string (vendor ? vendor : ""));
9b6ed9f3 14315 BLOCK_INPUT;
59e755be
KH
14316 }
14317
29b38361
KH
14318 dpyinfo->kboard->next_kboard = all_kboards;
14319 all_kboards = dpyinfo->kboard;
0ad5446c
KH
14320 /* Don't let the initial kboard remain current longer than necessary.
14321 That would cause problems if a file loaded on startup tries to
06a2c219 14322 prompt in the mini-buffer. */
0ad5446c
KH
14323 if (current_kboard == initial_kboard)
14324 current_kboard = dpyinfo->kboard;
29b38361
KH
14325 }
14326 dpyinfo->kboard->reference_count++;
14327 }
b9737ad3
KH
14328#endif
14329
7a13e894
RS
14330 /* Put this display on the chain. */
14331 dpyinfo->next = x_display_list;
14332 x_display_list = dpyinfo;
14333
14334 /* Put it on x_display_name_list as well, to keep them parallel. */
14335 x_display_name_list = Fcons (Fcons (display_name, Qnil),
14336 x_display_name_list);
8e713be6 14337 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
14338
14339 dpyinfo->display = dpy;
dc6f92b8 14340
dc6f92b8 14341#if 0
7a13e894 14342 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 14343#endif /* ! 0 */
7a13e894
RS
14344
14345 dpyinfo->x_id_name
fc932ac6
RS
14346 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
14347 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
14348 + 2);
14349 sprintf (dpyinfo->x_id_name, "%s@%s",
14350 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
14351
14352 /* Figure out which modifier bits mean what. */
334208b7 14353 x_find_modifier_meanings (dpyinfo);
f451eb13 14354
ab648270 14355 /* Get the scroll bar cursor. */
7a13e894 14356 dpyinfo->vertical_scroll_bar_cursor
334208b7 14357 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 14358
334208b7
RS
14359 xrdb = x_load_resources (dpyinfo->display, xrm_option,
14360 resource_name, EMACS_CLASS);
14361#ifdef HAVE_XRMSETDATABASE
14362 XrmSetDatabase (dpyinfo->display, xrdb);
14363#else
14364 dpyinfo->display->db = xrdb;
14365#endif
547d9db8 14366 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
14367 all versions. */
14368 dpyinfo->xrdb = xrdb;
334208b7
RS
14369
14370 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
14371 DefaultScreen (dpyinfo->display));
5ff67d81 14372 select_visual (dpyinfo);
43bd1b2b 14373 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
14374 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
14375 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
14376 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
14377 dpyinfo->grabbed = 0;
14378 dpyinfo->reference_count = 0;
14379 dpyinfo->icon_bitmap_id = -1;
06a2c219 14380 dpyinfo->font_table = NULL;
7a13e894
RS
14381 dpyinfo->n_fonts = 0;
14382 dpyinfo->font_table_size = 0;
14383 dpyinfo->bitmaps = 0;
14384 dpyinfo->bitmaps_size = 0;
14385 dpyinfo->bitmaps_last = 0;
14386 dpyinfo->scratch_cursor_gc = 0;
14387 dpyinfo->mouse_face_mouse_frame = 0;
14388 dpyinfo->mouse_face_deferred_gc = 0;
14389 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
14390 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 14391 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894 14392 dpyinfo->mouse_face_window = Qnil;
0a61c667 14393 dpyinfo->mouse_face_overlay = Qnil;
7a13e894
RS
14394 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
14395 dpyinfo->mouse_face_defer = 0;
0f941935
KH
14396 dpyinfo->x_focus_frame = 0;
14397 dpyinfo->x_focus_event_frame = 0;
14398 dpyinfo->x_highlight_frame = 0;
06a2c219 14399 dpyinfo->image_cache = make_image_cache ();
334208b7 14400
43bd1b2b 14401 /* See if a private colormap is requested. */
5ff67d81
GM
14402 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
14403 {
14404 if (dpyinfo->visual->class == PseudoColor)
14405 {
14406 Lisp_Object value;
14407 value = display_x_get_resource (dpyinfo,
14408 build_string ("privateColormap"),
14409 build_string ("PrivateColormap"),
14410 Qnil, Qnil);
14411 if (STRINGP (value)
14412 && (!strcmp (XSTRING (value)->data, "true")
14413 || !strcmp (XSTRING (value)->data, "on")))
14414 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
14415 }
43bd1b2b 14416 }
5ff67d81
GM
14417 else
14418 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
14419 dpyinfo->visual, AllocNone);
43bd1b2b 14420
06a2c219
GM
14421 {
14422 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
14423 double pixels = DisplayHeight (dpyinfo->display, screen_number);
14424 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
14425 dpyinfo->resy = pixels * 25.4 / mm;
14426 pixels = DisplayWidth (dpyinfo->display, screen_number);
14427 mm = DisplayWidthMM (dpyinfo->display, screen_number);
14428 dpyinfo->resx = pixels * 25.4 / mm;
14429 }
14430
334208b7
RS
14431 dpyinfo->Xatom_wm_protocols
14432 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
14433 dpyinfo->Xatom_wm_take_focus
14434 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
14435 dpyinfo->Xatom_wm_save_yourself
14436 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
14437 dpyinfo->Xatom_wm_delete_window
14438 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
14439 dpyinfo->Xatom_wm_change_state
14440 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
14441 dpyinfo->Xatom_wm_configure_denied
14442 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
14443 dpyinfo->Xatom_wm_window_moved
14444 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
14445 dpyinfo->Xatom_editres
14446 = XInternAtom (dpyinfo->display, "Editres", False);
14447 dpyinfo->Xatom_CLIPBOARD
14448 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
14449 dpyinfo->Xatom_TIMESTAMP
14450 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
14451 dpyinfo->Xatom_TEXT
14452 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
14453 dpyinfo->Xatom_COMPOUND_TEXT
14454 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
14455 dpyinfo->Xatom_DELETE
14456 = XInternAtom (dpyinfo->display, "DELETE", False);
14457 dpyinfo->Xatom_MULTIPLE
14458 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
14459 dpyinfo->Xatom_INCR
14460 = XInternAtom (dpyinfo->display, "INCR", False);
14461 dpyinfo->Xatom_EMACS_TMP
14462 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
14463 dpyinfo->Xatom_TARGETS
14464 = XInternAtom (dpyinfo->display, "TARGETS", False);
14465 dpyinfo->Xatom_NULL
14466 = XInternAtom (dpyinfo->display, "NULL", False);
14467 dpyinfo->Xatom_ATOM_PAIR
14468 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
14469 /* For properties of font. */
14470 dpyinfo->Xatom_PIXEL_SIZE
14471 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
14472 dpyinfo->Xatom_MULE_BASELINE_OFFSET
14473 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
14474 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
14475 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
14476 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
14477 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 14478
06a2c219
GM
14479 /* Ghostscript support. */
14480 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
14481 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
14482
14483 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
14484 False);
14485
547d9db8
KH
14486 dpyinfo->cut_buffers_initialized = 0;
14487
334208b7
RS
14488 connection = ConnectionNumber (dpyinfo->display);
14489 dpyinfo->connection = connection;
14490
dc43ef94 14491 {
5d7cc324
RS
14492 char null_bits[1];
14493
14494 null_bits[0] = 0x00;
dc43ef94
KH
14495
14496 dpyinfo->null_pixel
14497 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14498 null_bits, 1, 1, (long) 0, (long) 0,
14499 1);
14500 }
14501
06a2c219
GM
14502 {
14503 extern int gray_bitmap_width, gray_bitmap_height;
10659c77 14504 extern char *gray_bitmap_bits;
06a2c219
GM
14505 dpyinfo->gray
14506 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14507 gray_bitmap_bits,
14508 gray_bitmap_width, gray_bitmap_height,
14509 (unsigned long) 1, (unsigned long) 0, 1);
14510 }
14511
f5d11644
GM
14512#ifdef HAVE_X_I18N
14513 xim_initialize (dpyinfo, resource_name);
14514#endif
14515
87485d6f
MW
14516#ifdef subprocesses
14517 /* This is only needed for distinguishing keyboard and process input. */
334208b7 14518 if (connection != 0)
7a13e894 14519 add_keyboard_wait_descriptor (connection);
87485d6f 14520#endif
6d4238f3 14521
041b69ac 14522#ifndef F_SETOWN_BUG
dc6f92b8 14523#ifdef F_SETOWN
dc6f92b8 14524#ifdef F_SETOWN_SOCK_NEG
61c3ce62 14525 /* stdin is a socket here */
334208b7 14526 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 14527#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 14528 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
14529#endif /* ! defined (F_SETOWN_SOCK_NEG) */
14530#endif /* ! defined (F_SETOWN) */
041b69ac 14531#endif /* F_SETOWN_BUG */
dc6f92b8
JB
14532
14533#ifdef SIGIO
eee20f6a
KH
14534 if (interrupt_input)
14535 init_sigio (connection);
c118dd06 14536#endif /* ! defined (SIGIO) */
dc6f92b8 14537
51b592fb 14538#ifdef USE_LUCID
f8c39f51 14539#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
14540 /* Make sure that we have a valid font for dialog boxes
14541 so that Xt does not crash. */
14542 {
14543 Display *dpy = dpyinfo->display;
14544 XrmValue d, fr, to;
14545 Font font;
e99db5a1 14546 int count;
51b592fb
RS
14547
14548 d.addr = (XPointer)&dpy;
14549 d.size = sizeof (Display *);
14550 fr.addr = XtDefaultFont;
14551 fr.size = sizeof (XtDefaultFont);
14552 to.size = sizeof (Font *);
14553 to.addr = (XPointer)&font;
e99db5a1 14554 count = x_catch_errors (dpy);
51b592fb
RS
14555 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
14556 abort ();
14557 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
14558 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 14559 x_uncatch_errors (dpy, count);
51b592fb
RS
14560 }
14561#endif
f8c39f51 14562#endif
51b592fb 14563
34e23e5a
GM
14564 /* See if we should run in synchronous mode. This is useful
14565 for debugging X code. */
14566 {
14567 Lisp_Object value;
14568 value = display_x_get_resource (dpyinfo,
14569 build_string ("synchronous"),
14570 build_string ("Synchronous"),
14571 Qnil, Qnil);
14572 if (STRINGP (value)
14573 && (!strcmp (XSTRING (value)->data, "true")
14574 || !strcmp (XSTRING (value)->data, "on")))
14575 XSynchronize (dpyinfo->display, True);
14576 }
14577
60439948
KH
14578 UNBLOCK_INPUT;
14579
7a13e894
RS
14580 return dpyinfo;
14581}
14582\f
14583/* Get rid of display DPYINFO, assuming all frames are already gone,
14584 and without sending any more commands to the X server. */
dc6f92b8 14585
7a13e894
RS
14586void
14587x_delete_display (dpyinfo)
14588 struct x_display_info *dpyinfo;
14589{
14590 delete_keyboard_wait_descriptor (dpyinfo->connection);
14591
14592 /* Discard this display from x_display_name_list and x_display_list.
14593 We can't use Fdelq because that can quit. */
14594 if (! NILP (x_display_name_list)
8e713be6
KR
14595 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
14596 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
14597 else
14598 {
14599 Lisp_Object tail;
14600
14601 tail = x_display_name_list;
8e713be6 14602 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 14603 {
bffcfca9 14604 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 14605 {
8e713be6 14606 XCDR (tail) = XCDR (XCDR (tail));
7a13e894
RS
14607 break;
14608 }
8e713be6 14609 tail = XCDR (tail);
7a13e894
RS
14610 }
14611 }
14612
9bda743f
GM
14613 if (next_noop_dpyinfo == dpyinfo)
14614 next_noop_dpyinfo = dpyinfo->next;
14615
7a13e894
RS
14616 if (x_display_list == dpyinfo)
14617 x_display_list = dpyinfo->next;
7f9c7f94
RS
14618 else
14619 {
14620 struct x_display_info *tail;
7a13e894 14621
7f9c7f94
RS
14622 for (tail = x_display_list; tail; tail = tail->next)
14623 if (tail->next == dpyinfo)
14624 tail->next = tail->next->next;
14625 }
7a13e894 14626
0d777288
RS
14627#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
14628#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
14629 XrmDestroyDatabase (dpyinfo->xrdb);
14630#endif
0d777288 14631#endif
29b38361
KH
14632#ifdef MULTI_KBOARD
14633 if (--dpyinfo->kboard->reference_count == 0)
39f79001 14634 delete_kboard (dpyinfo->kboard);
b9737ad3 14635#endif
f5d11644
GM
14636#ifdef HAVE_X_I18N
14637 if (dpyinfo->xim)
14638 xim_close_dpy (dpyinfo);
14639#endif
14640
b9737ad3
KH
14641 xfree (dpyinfo->font_table);
14642 xfree (dpyinfo->x_id_name);
f04e1297 14643 xfree (dpyinfo->color_cells);
b9737ad3 14644 xfree (dpyinfo);
7a13e894 14645}
f04e1297 14646
7a13e894
RS
14647\f
14648/* Set up use of X before we make the first connection. */
14649
06a2c219
GM
14650static struct redisplay_interface x_redisplay_interface =
14651{
14652 x_produce_glyphs,
14653 x_write_glyphs,
14654 x_insert_glyphs,
14655 x_clear_end_of_line,
14656 x_scroll_run,
14657 x_after_update_window_line,
14658 x_update_window_begin,
14659 x_update_window_end,
14660 XTcursor_to,
14661 x_flush,
71b8321e 14662 x_clear_mouse_face,
66ac4b0e
GM
14663 x_get_glyph_overhangs,
14664 x_fix_overlapping_area
06a2c219
GM
14665};
14666
dfcf069d 14667void
7a13e894
RS
14668x_initialize ()
14669{
06a2c219
GM
14670 rif = &x_redisplay_interface;
14671
14672 clear_frame_hook = x_clear_frame;
14673 ins_del_lines_hook = x_ins_del_lines;
14674 change_line_highlight_hook = x_change_line_highlight;
14675 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
14676 ring_bell_hook = XTring_bell;
14677 reset_terminal_modes_hook = XTreset_terminal_modes;
14678 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
14679 update_begin_hook = x_update_begin;
14680 update_end_hook = x_update_end;
dc6f92b8
JB
14681 set_terminal_window_hook = XTset_terminal_window;
14682 read_socket_hook = XTread_socket;
b8009dd1 14683 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8 14684 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 14685 mouse_position_hook = XTmouse_position;
f451eb13 14686 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 14687 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
14688 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
14689 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
14690 redeem_scroll_bar_hook = XTredeem_scroll_bar;
14691 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 14692 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 14693
f676886a 14694 scroll_region_ok = 1; /* we'll scroll partial frames */
9017309f 14695 char_ins_del_ok = 1;
dc6f92b8
JB
14696 line_ins_del_ok = 1; /* we'll just blt 'em */
14697 fast_clear_end_of_line = 1; /* X does this well */
58769bee 14698 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
14699 off the bottom */
14700 baud_rate = 19200;
14701
7a13e894 14702 x_noop_count = 0;
9ea173e8 14703 last_tool_bar_item = -1;
06a2c219
GM
14704 any_help_event_p = 0;
14705
b30b24cb
RS
14706 /* Try to use interrupt input; if we can't, then start polling. */
14707 Fset_input_mode (Qt, Qnil, Qt, Qnil);
14708
7f9c7f94
RS
14709#ifdef USE_X_TOOLKIT
14710 XtToolkitInitialize ();
651f03b6 14711
7f9c7f94 14712 Xt_app_con = XtCreateApplicationContext ();
651f03b6
GM
14713
14714 /* Register a converter from strings to pixels, which uses
14715 Emacs' color allocation infrastructure. */
14716 XtAppSetTypeConverter (Xt_app_con,
14717 XtRString, XtRPixel, cvt_string_to_pixel,
14718 cvt_string_to_pixel_args,
14719 XtNumber (cvt_string_to_pixel_args),
14720 XtCacheByDisplay, cvt_pixel_dtor);
14721
665881ad 14722 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
14723
14724 /* Install an asynchronous timer that processes Xt timeout events
14725 every 0.1s. This is necessary because some widget sets use
14726 timeouts internally, for example the LessTif menu bar, or the
14727 Xaw3d scroll bar. When Xt timouts aren't processed, these
14728 widgets don't behave normally. */
14729 {
14730 EMACS_TIME interval;
14731 EMACS_SET_SECS_USECS (interval, 0, 100000);
14732 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
14733 }
db74249b 14734#endif
bffcfca9 14735
eccc05db 14736#ifdef USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
14737 xaw3d_arrow_scroll = False;
14738 xaw3d_pick_top = True;
7f9c7f94
RS
14739#endif
14740
58769bee 14741 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 14742 original error handler. */
e99db5a1 14743 XSetErrorHandler (x_error_handler);
334208b7 14744 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 14745
06a2c219 14746 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
14747#ifdef SIGWINCH
14748 signal (SIGWINCH, SIG_DFL);
c118dd06 14749#endif /* ! defined (SIGWINCH) */
dc6f92b8 14750
92e2441b 14751 signal (SIGPIPE, x_connection_signal);
dc6f92b8 14752}
55123275 14753
06a2c219 14754
55123275
JB
14755void
14756syms_of_xterm ()
14757{
e99db5a1
RS
14758 staticpro (&x_error_message_string);
14759 x_error_message_string = Qnil;
14760
7a13e894
RS
14761 staticpro (&x_display_name_list);
14762 x_display_name_list = Qnil;
334208b7 14763
ab648270 14764 staticpro (&last_mouse_scroll_bar);
e53cb100 14765 last_mouse_scroll_bar = Qnil;
59e755be
KH
14766
14767 staticpro (&Qvendor_specific_keysyms);
14768 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
14769
14770 staticpro (&last_mouse_press_frame);
14771 last_mouse_press_frame = Qnil;
06a2c219 14772
06a2c219 14773 help_echo = Qnil;
be010514
GM
14774 staticpro (&help_echo);
14775 help_echo_object = Qnil;
14776 staticpro (&help_echo_object);
7cea38bc
GM
14777 help_echo_window = Qnil;
14778 staticpro (&help_echo_window);
06a2c219 14779 previous_help_echo = Qnil;
be010514
GM
14780 staticpro (&previous_help_echo);
14781 help_echo_pos = -1;
06a2c219
GM
14782
14783 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
14784 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
14785For example, if a block cursor is over a tab, it will be drawn as\n\
14786wide as that tab on the display.");
14787 x_stretch_cursor_p = 0;
14788
a72d5ce5
GM
14789 DEFVAR_BOOL ("x-use-underline-position-properties",
14790 &x_use_underline_position_properties,
14791 "*Non-nil means make use of UNDERLINE_POSITION font properties.\n\
14792Nil means ignore them. If you encounter fonts with bogus\n\
14793UNDERLINE_POSITION font properties, for example 7x13 on XFree prior\n\
14794to 4.1, set this to nil.");
14795 x_use_underline_position_properties = 1;
14796
5bf04520
GM
14797 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
14798 "What X toolkit scroll bars Emacs uses.\n\
14799A value of nil means Emacs doesn't use X toolkit scroll bars.\n\
14800Otherwise, value is a symbol describing the X toolkit.");
eccc05db 14801#ifdef USE_TOOLKIT_SCROLL_BARS
5bf04520
GM
14802#ifdef USE_MOTIF
14803 Vx_toolkit_scroll_bars = intern ("motif");
14804#elif defined HAVE_XAW3D
14805 Vx_toolkit_scroll_bars = intern ("xaw3d");
14806#else
14807 Vx_toolkit_scroll_bars = intern ("xaw");
14808#endif
06a2c219 14809#else
5bf04520 14810 Vx_toolkit_scroll_bars = Qnil;
06a2c219
GM
14811#endif
14812
06a2c219
GM
14813 staticpro (&last_mouse_motion_frame);
14814 last_mouse_motion_frame = Qnil;
55123275 14815}
6cf0ae86 14816
1d6c120a 14817#endif /* HAVE_X_WINDOWS */