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