(last-sexp-setup-props): New function.
[bpt/emacs.git] / src / xterm.c
CommitLineData
dc6f92b8 1/* X Communication module for terminals which understand the X protocol.
edf36fe6 2 Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001
06a2c219 3 Free Software Foundation, Inc.
dc6f92b8
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
4746118a 9the Free Software Foundation; either version 2, or (at your option)
dc6f92b8
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
dc6f92b8 21
06a2c219 22/* New display code by Gerd Moellmann <gerd@gnu.org>. */
3afe33e7
RS
23/* Xt features made by Fred Pierresteguy. */
24
68c45bf0
PE
25#include <config.h>
26
039440c4 27/* On 4.3 these lose if they come after xterm.h. */
039440c4 28/* Putting these at the beginning seems to be standard for other .c files. */
039440c4
RS
29#include <signal.h>
30
4846819e
RS
31#include <stdio.h>
32
dc6f92b8
JB
33#ifdef HAVE_X_WINDOWS
34
35#include "lisp.h"
9ac0d9e0 36#include "blockinput.h"
dc6f92b8 37
ae79c227
AS
38/* Need syssignal.h for various externs and definitions that may be required
39 by some configurations for calls to signal later in this source file. */
40#include "syssignal.h"
41
dc6f92b8
JB
42/* This may include sys/types.h, and that somehow loses
43 if this is not done before the other system files. */
44#include "xterm.h"
f451eb13 45#include <X11/cursorfont.h>
dc6f92b8
JB
46
47/* Load sys/types.h if not already loaded.
48 In some systems loading it twice is suicidal. */
49#ifndef makedev
50#include <sys/types.h>
c118dd06 51#endif /* makedev */
dc6f92b8 52
6df54671 53#ifdef BSD_SYSTEM
dc6f92b8 54#include <sys/ioctl.h>
6df54671 55#endif /* ! defined (BSD_SYSTEM) */
dc6f92b8 56
2d368234 57#include "systty.h"
3a2712f9 58#include "systime.h"
dc6f92b8 59
b8009dd1 60#ifndef INCLUDED_FCNTL
dc6f92b8 61#include <fcntl.h>
b8009dd1 62#endif
dc6f92b8
JB
63#include <ctype.h>
64#include <errno.h>
65#include <setjmp.h>
66#include <sys/stat.h>
a0a7635f
RS
67/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
68/* #include <sys/param.h> */
dc6f92b8 69
dc43ef94 70#include "charset.h"
379b5ac0 71#include "coding.h"
dc43ef94 72#include "ccl.h"
7a13e894 73#include "frame.h"
dc6f92b8 74#include "dispextern.h"
ee569018 75#include "fontset.h"
dc6f92b8
JB
76#include "termhooks.h"
77#include "termopts.h"
78#include "termchar.h"
79#if 0
80#include "sink.h"
81#include "sinkmask.h"
c118dd06 82#endif /* ! 0 */
dc6f92b8 83#include "gnu.h"
dc6f92b8 84#include "disptab.h"
dc6f92b8 85#include "buffer.h"
f451eb13 86#include "window.h"
3b2fa4e6 87#include "keyboard.h"
bde7c500 88#include "intervals.h"
dfcf069d 89#include "process.h"
bffcfca9 90#include "atimer.h"
dc6f92b8 91
d2bd6bc4
RS
92#ifdef USE_X_TOOLKIT
93#include <X11/Shell.h>
94#endif
95
06a2c219
GM
96#ifdef HAVE_SYS_TIME_H
97#include <sys/time.h>
98#endif
99#ifdef HAVE_UNISTD_H
100#include <unistd.h>
101#endif
102
3afe33e7 103#ifdef USE_X_TOOLKIT
06a2c219 104
952291d9
GM
105extern void free_frame_menubar P_ ((struct frame *));
106extern struct frame *x_menubar_window_to_frame P_ ((struct x_display_info *,
107 int));
06a2c219 108
0fdff6bb
RS
109#if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
110#define HACK_EDITRES
111extern void _XEditResCheckMessages ();
112#endif /* not NO_EDITRES */
06a2c219
GM
113
114/* Include toolkit specific headers for the scroll bar widget. */
115
116#ifdef USE_TOOLKIT_SCROLL_BARS
117#if defined USE_MOTIF
118#include <Xm/Xm.h> /* for LESSTIF_VERSION */
119#include <Xm/ScrollBar.h>
ec18280f
SM
120#else /* !USE_MOTIF i.e. use Xaw */
121
122#ifdef HAVE_XAW3D
06a2c219 123#include <X11/Xaw3d/Simple.h>
06a2c219
GM
124#include <X11/Xaw3d/Scrollbar.h>
125#define ARROW_SCROLLBAR
126#include <X11/Xaw3d/ScrollbarP.h>
ec18280f
SM
127#else /* !HAVE_XAW3D */
128#include <X11/Xaw/Simple.h>
129#include <X11/Xaw/Scrollbar.h>
130#endif /* !HAVE_XAW3D */
131#ifndef XtNpickTop
132#define XtNpickTop "pickTop"
133#endif /* !XtNpickTop */
134#endif /* !USE_MOTIF */
06a2c219
GM
135#endif /* USE_TOOLKIT_SCROLL_BARS */
136
3afe33e7
RS
137#endif /* USE_X_TOOLKIT */
138
b849c413
RS
139#ifndef USE_X_TOOLKIT
140#define x_any_window_to_frame x_window_to_frame
5627c40e 141#define x_top_window_to_frame x_window_to_frame
b849c413
RS
142#endif
143
546e6d5b 144#ifdef USE_X_TOOLKIT
d067ea8b 145#include "widget.h"
546e6d5b
RS
146#ifndef XtNinitialState
147#define XtNinitialState "initialState"
148#endif
149#endif
150
e4b68333 151#ifndef min
06a2c219 152#define min(a,b) ((a) < (b) ? (a) : (b))
e4b68333
RS
153#endif
154#ifndef max
06a2c219
GM
155#define max(a,b) ((a) > (b) ? (a) : (b))
156#endif
157
158#define abs(x) ((x) < 0 ? -(x) : (x))
159
160#define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER))
161
162\f
163/* Bitmaps for truncated lines. */
164
165enum bitmap_type
166{
167 NO_BITMAP,
168 LEFT_TRUNCATION_BITMAP,
169 RIGHT_TRUNCATION_BITMAP,
170 OVERLAY_ARROW_BITMAP,
171 CONTINUED_LINE_BITMAP,
172 CONTINUATION_LINE_BITMAP,
173 ZV_LINE_BITMAP
174};
175
176/* Bitmap drawn to indicate lines not displaying text if
177 `indicate-empty-lines' is non-nil. */
178
179#define zv_width 8
180#define zv_height 8
181static unsigned char zv_bits[] = {
182 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00};
183
184/* An arrow like this: `<-'. */
185
186#define left_width 8
187#define left_height 8
188static unsigned char left_bits[] = {
189 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
190
110859fc
GM
191/* Right truncation arrow bitmap `->'. */
192
193#define right_width 8
194#define right_height 8
195static unsigned char right_bits[] = {
196 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
197
06a2c219
GM
198/* Marker for continued lines. */
199
200#define continued_width 8
201#define continued_height 8
202static unsigned char continued_bits[] = {
110859fc
GM
203 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
204
205/* Marker for continuation lines. */
06a2c219
GM
206
207#define continuation_width 8
208#define continuation_height 8
209static unsigned char continuation_bits[] = {
110859fc 210 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
06a2c219 211
110859fc 212/* Overlay arrow bitmap. */
06a2c219 213
110859fc
GM
214#if 0
215/* A bomb. */
06a2c219
GM
216#define ov_width 8
217#define ov_height 8
218static unsigned char ov_bits[] = {
219 0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
06a2c219 220#else
110859fc 221/* A triangular arrow. */
06a2c219
GM
222#define ov_width 8
223#define ov_height 8
224static unsigned char ov_bits[] = {
110859fc
GM
225 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
226
e4b68333 227#endif
06a2c219
GM
228
229extern Lisp_Object Qhelp_echo;
230
69388238 231\f
5bf04520 232/* Non-nil means Emacs uses toolkit scroll bars. */
06a2c219 233
5bf04520 234Lisp_Object Vx_toolkit_scroll_bars;
06a2c219
GM
235
236/* If a string, XTread_socket generates an event to display that string.
237 (The display is done in read_char.) */
238
239static Lisp_Object help_echo;
7cea38bc 240static Lisp_Object help_echo_window;
be010514
GM
241static Lisp_Object help_echo_object;
242static int help_echo_pos;
06a2c219
GM
243
244/* Temporary variable for XTread_socket. */
245
246static Lisp_Object previous_help_echo;
247
248/* Non-zero means that a HELP_EVENT has been generated since Emacs
249 start. */
250
251static int any_help_event_p;
252
253/* Non-zero means draw block and hollow cursor as wide as the glyph
254 under it. For example, if a block cursor is over a tab, it will be
255 drawn as wide as that tab on the display. */
256
257int x_stretch_cursor_p;
258
a72d5ce5
GM
259/* Non-zero means make use of UNDERLINE_POSITION font properties. */
260
261int x_use_underline_position_properties;
262
06a2c219
GM
263/* This is a chain of structures for all the X displays currently in
264 use. */
265
334208b7 266struct x_display_info *x_display_list;
dc6f92b8 267
06a2c219
GM
268/* This is a list of cons cells, each of the form (NAME
269 . FONT-LIST-CACHE), one for each element of x_display_list and in
270 the same order. NAME is the name of the frame. FONT-LIST-CACHE
271 records previous values returned by x-list-fonts. */
272
7a13e894 273Lisp_Object x_display_name_list;
f451eb13 274
987d2ad1 275/* Frame being updated by update_frame. This is declared in term.c.
06a2c219
GM
276 This is set by update_begin and looked at by all the XT functions.
277 It is zero while not inside an update. In that case, the XT
278 functions assume that `selected_frame' is the frame to apply to. */
279
d0386f2a 280extern struct frame *updating_frame;
dc6f92b8 281
dfcf069d 282extern int waiting_for_input;
0e81d8cd 283
06a2c219
GM
284/* This is a frame waiting to be auto-raised, within XTread_socket. */
285
0134a210
RS
286struct frame *pending_autoraise_frame;
287
7f9c7f94
RS
288#ifdef USE_X_TOOLKIT
289/* The application context for Xt use. */
290XtAppContext Xt_app_con;
06a2c219
GM
291static String Xt_default_resources[] = {0};
292#endif /* USE_X_TOOLKIT */
665881ad 293
06a2c219
GM
294/* Nominal cursor position -- where to draw output.
295 HPOS and VPOS are window relative glyph matrix coordinates.
296 X and Y are window relative pixel coordinates. */
dc6f92b8 297
06a2c219 298struct cursor_pos output_cursor;
dc6f92b8 299
bffcfca9
GM
300/* Non-zero means user is interacting with a toolkit scroll bar. */
301
302static int toolkit_scroll_bar_interaction;
dc6f92b8 303
69388238
RS
304/* Mouse movement.
305
06a2c219 306 Formerly, we used PointerMotionHintMask (in standard_event_mask)
f5bb65ec
RS
307 so that we would have to call XQueryPointer after each MotionNotify
308 event to ask for another such event. However, this made mouse tracking
309 slow, and there was a bug that made it eventually stop.
310
311 Simply asking for MotionNotify all the time seems to work better.
312
69388238
RS
313 In order to avoid asking for motion events and then throwing most
314 of them away or busy-polling the server for mouse positions, we ask
315 the server for pointer motion hints. This means that we get only
316 one event per group of mouse movements. "Groups" are delimited by
317 other kinds of events (focus changes and button clicks, for
318 example), or by XQueryPointer calls; when one of these happens, we
319 get another MotionNotify event the next time the mouse moves. This
320 is at least as efficient as getting motion events when mouse
321 tracking is on, and I suspect only negligibly worse when tracking
f5bb65ec 322 is off. */
69388238
RS
323
324/* Where the mouse was last time we reported a mouse event. */
69388238 325
06a2c219
GM
326FRAME_PTR last_mouse_frame;
327static XRectangle last_mouse_glyph;
2237cac9
RS
328static Lisp_Object last_mouse_press_frame;
329
69388238
RS
330/* The scroll bar in which the last X motion event occurred.
331
06a2c219
GM
332 If the last X motion event occurred in a scroll bar, we set this so
333 XTmouse_position can know whether to report a scroll bar motion or
69388238
RS
334 an ordinary motion.
335
06a2c219
GM
336 If the last X motion event didn't occur in a scroll bar, we set
337 this to Qnil, to tell XTmouse_position to return an ordinary motion
338 event. */
339
69388238
RS
340static Lisp_Object last_mouse_scroll_bar;
341
69388238
RS
342/* This is a hack. We would really prefer that XTmouse_position would
343 return the time associated with the position it returns, but there
06a2c219 344 doesn't seem to be any way to wrest the time-stamp from the server
69388238
RS
345 along with the position query. So, we just keep track of the time
346 of the last movement we received, and return that in hopes that
347 it's somewhat accurate. */
06a2c219 348
69388238
RS
349static Time last_mouse_movement_time;
350
06a2c219
GM
351/* Incremented by XTread_socket whenever it really tries to read
352 events. */
353
c0a04927
RS
354#ifdef __STDC__
355static int volatile input_signal_count;
356#else
357static int input_signal_count;
358#endif
359
7a13e894 360/* Used locally within XTread_socket. */
06a2c219 361
7a13e894 362static int x_noop_count;
dc6f92b8 363
7a13e894 364/* Initial values of argv and argc. */
06a2c219 365
7a13e894
RS
366extern char **initial_argv;
367extern int initial_argc;
dc6f92b8 368
7a13e894 369extern Lisp_Object Vcommand_line_args, Vsystem_name;
dc6f92b8 370
06a2c219 371/* Tells if a window manager is present or not. */
7a13e894
RS
372
373extern Lisp_Object Vx_no_window_manager;
dc6f92b8 374
c2df547c 375extern Lisp_Object Qface, Qmouse_face;
b8009dd1 376
dc6f92b8
JB
377extern int errno;
378
dfeccd2d 379/* A mask of extra modifier bits to put into every keyboard char. */
06a2c219 380
64bb1782
RS
381extern int extra_keyboard_modifiers;
382
59e755be
KH
383static Lisp_Object Qvendor_specific_keysyms;
384
952291d9
GM
385extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
386extern Lisp_Object x_icon_type P_ ((struct frame *));
c32cdd9a 387
7a13e894 388
06a2c219
GM
389/* Enumeration for overriding/changing the face to use for drawing
390 glyphs in x_draw_glyphs. */
391
392enum draw_glyphs_face
393{
394 DRAW_NORMAL_TEXT,
395 DRAW_INVERSE_VIDEO,
396 DRAW_CURSOR,
397 DRAW_MOUSE_FACE,
398 DRAW_IMAGE_RAISED,
399 DRAW_IMAGE_SUNKEN
400};
401
b7f83f9e 402static int cursor_in_mouse_face_p P_ ((struct window *));
fa262c07 403static int clear_mouse_face P_ ((struct x_display_info *));
651f03b6 404static int x_alloc_nearest_color_1 P_ ((Display *, Colormap, XColor *));
499b1844 405static void x_set_window_size_1 P_ ((struct frame *, int, int, int));
651f03b6 406static const XColor *x_color_cells P_ ((Display *, int *));
71b8321e 407static void x_update_window_end P_ ((struct window *, int, int));
06a2c219
GM
408static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
409void x_delete_display P_ ((struct x_display_info *));
410static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
411 unsigned));
412static int fast_find_position P_ ((struct window *, int, int *, int *,
413 int *, int *));
f9db2310
GM
414static int fast_find_string_pos P_ ((struct window *, int, Lisp_Object,
415 int *, int *, int *, int *, int));
06a2c219
GM
416static void set_output_cursor P_ ((struct cursor_pos *));
417static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
f9db2310 418 int *, int *, int *, int));
06a2c219 419static void note_mode_line_highlight P_ ((struct window *, int, int));
06a2c219 420static void note_mouse_highlight P_ ((struct frame *, int, int));
9ea173e8
GM
421static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
422static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
06a2c219
GM
423static void show_mouse_face P_ ((struct x_display_info *,
424 enum draw_glyphs_face));
425static int x_io_error_quitter P_ ((Display *));
426int x_catch_errors P_ ((Display *));
427void x_uncatch_errors P_ ((Display *, int));
428void x_lower_frame P_ ((struct frame *));
429void x_scroll_bar_clear P_ ((struct frame *));
430int x_had_errors_p P_ ((Display *));
431void x_wm_set_size_hint P_ ((struct frame *, long, int));
432void x_raise_frame P_ ((struct frame *));
433void x_set_window_size P_ ((struct frame *, int, int, int));
434void x_wm_set_window_state P_ ((struct frame *, int));
435void x_wm_set_icon_pixmap P_ ((struct frame *, int));
436void x_initialize P_ ((void));
437static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
438static int x_compute_min_glyph_bounds P_ ((struct frame *));
439static void x_draw_phys_cursor_glyph P_ ((struct window *,
440 struct glyph_row *,
441 enum draw_glyphs_face));
442static void x_update_end P_ ((struct frame *));
443static void XTframe_up_to_date P_ ((struct frame *));
444static void XTreassert_line_highlight P_ ((int, int));
445static void x_change_line_highlight P_ ((int, int, int, int));
446static void XTset_terminal_modes P_ ((void));
447static void XTreset_terminal_modes P_ ((void));
448static void XTcursor_to P_ ((int, int, int, int));
449static void x_write_glyphs P_ ((struct glyph *, int));
450static void x_clear_end_of_line P_ ((int));
451static void x_clear_frame P_ ((void));
452static void x_clear_cursor P_ ((struct window *));
453static void frame_highlight P_ ((struct frame *));
454static void frame_unhighlight P_ ((struct frame *));
455static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
456static void XTframe_rehighlight P_ ((struct frame *));
457static void x_frame_rehighlight P_ ((struct x_display_info *));
458static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
f02d8aa0 459static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int));
06a2c219
GM
460static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
461 XRectangle *));
462static void expose_frame P_ ((struct frame *, int, int, int, int));
463static void expose_window_tree P_ ((struct window *, XRectangle *));
a39202f6 464static int expose_window P_ ((struct window *, XRectangle *));
06a2c219
GM
465static void expose_area P_ ((struct window *, struct glyph_row *,
466 XRectangle *, enum glyph_row_area));
467static void expose_line P_ ((struct window *, struct glyph_row *,
468 XRectangle *));
469static void x_update_cursor_in_window_tree P_ ((struct window *, int));
470static void x_update_window_cursor P_ ((struct window *, int));
471static void x_erase_phys_cursor P_ ((struct window *));
472void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
473static void x_draw_bitmap P_ ((struct window *, struct glyph_row *,
474 enum bitmap_type));
475
476static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
477 GC, int));
478static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
479static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
480static void note_overwritten_text_cursor P_ ((struct window *, int, int));
481static void x_flush P_ ((struct frame *f));
952291d9
GM
482static void x_update_begin P_ ((struct frame *));
483static void x_update_window_begin P_ ((struct window *));
484static void x_draw_vertical_border P_ ((struct window *));
485static void x_after_update_window_line P_ ((struct glyph_row *));
486static INLINE void take_vertical_position_into_account P_ ((struct it *));
487static void x_produce_stretch_glyph P_ ((struct it *));
b52b65bd
GM
488static struct scroll_bar *x_window_to_scroll_bar P_ ((Window));
489static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
490 enum scroll_bar_part *,
491 Lisp_Object *, Lisp_Object *,
492 unsigned long *));
06a2c219
GM
493
494/* Flush display of frame F, or of all frames if F is null. */
495
496static void
497x_flush (f)
498 struct frame *f;
499{
500 BLOCK_INPUT;
501 if (f == NULL)
502 {
503 Lisp_Object rest, frame;
504 FOR_EACH_FRAME (rest, frame)
505 x_flush (XFRAME (frame));
506 }
507 else if (FRAME_X_P (f))
508 XFlush (FRAME_X_DISPLAY (f));
509 UNBLOCK_INPUT;
510}
511
dc6f92b8 512
06a2c219
GM
513/* Remove calls to XFlush by defining XFlush to an empty replacement.
514 Calls to XFlush should be unnecessary because the X output buffer
515 is flushed automatically as needed by calls to XPending,
516 XNextEvent, or XWindowEvent according to the XFlush man page.
517 XTread_socket calls XPending. Removing XFlush improves
518 performance. */
519
520#define XFlush(DISPLAY) (void) 0
b8009dd1 521
334208b7 522\f
06a2c219
GM
523/***********************************************************************
524 Debugging
525 ***********************************************************************/
526
9382638d 527#if 0
06a2c219
GM
528
529/* This is a function useful for recording debugging information about
530 the sequence of occurrences in this file. */
9382638d
KH
531
532struct record
533{
534 char *locus;
535 int type;
536};
537
538struct record event_record[100];
539
540int event_record_index;
541
542record_event (locus, type)
543 char *locus;
544 int type;
545{
546 if (event_record_index == sizeof (event_record) / sizeof (struct record))
547 event_record_index = 0;
548
549 event_record[event_record_index].locus = locus;
550 event_record[event_record_index].type = type;
551 event_record_index++;
552}
553
554#endif /* 0 */
06a2c219
GM
555
556
9382638d 557\f
334208b7
RS
558/* Return the struct x_display_info corresponding to DPY. */
559
560struct x_display_info *
561x_display_info_for_display (dpy)
562 Display *dpy;
563{
564 struct x_display_info *dpyinfo;
565
566 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
567 if (dpyinfo->display == dpy)
568 return dpyinfo;
16bd92ea 569
334208b7
RS
570 return 0;
571}
f451eb13 572
06a2c219
GM
573
574\f
575/***********************************************************************
576 Starting and ending an update
577 ***********************************************************************/
578
579/* Start an update of frame F. This function is installed as a hook
580 for update_begin, i.e. it is called when update_begin is called.
581 This function is called prior to calls to x_update_window_begin for
582 each window being updated. Currently, there is nothing to do here
583 because all interesting stuff is done on a window basis. */
dc6f92b8 584
dfcf069d 585static void
06a2c219 586x_update_begin (f)
f676886a 587 struct frame *f;
58769bee 588{
06a2c219
GM
589 /* Nothing to do. */
590}
dc6f92b8 591
dc6f92b8 592
06a2c219
GM
593/* Start update of window W. Set the global variable updated_window
594 to the window being updated and set output_cursor to the cursor
595 position of W. */
dc6f92b8 596
06a2c219
GM
597static void
598x_update_window_begin (w)
599 struct window *w;
600{
601 struct frame *f = XFRAME (WINDOW_FRAME (w));
602 struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
603
604 updated_window = w;
605 set_output_cursor (&w->cursor);
b8009dd1 606
06a2c219 607 BLOCK_INPUT;
d1bc4182 608
06a2c219 609 if (f == display_info->mouse_face_mouse_frame)
b8009dd1 610 {
514e4681 611 /* Don't do highlighting for mouse motion during the update. */
06a2c219 612 display_info->mouse_face_defer = 1;
37c2c98b 613
06a2c219
GM
614 /* If F needs to be redrawn, simply forget about any prior mouse
615 highlighting. */
9f67f20b 616 if (FRAME_GARBAGED_P (f))
06a2c219
GM
617 display_info->mouse_face_window = Qnil;
618
64f26cf5
GM
619#if 0 /* Rows in a current matrix containing glyphs in mouse-face have
620 their mouse_face_p flag set, which means that they are always
621 unequal to rows in a desired matrix which never have that
622 flag set. So, rows containing mouse-face glyphs are never
623 scrolled, and we don't have to switch the mouse highlight off
624 here to prevent it from being scrolled. */
625
06a2c219
GM
626 /* Can we tell that this update does not affect the window
627 where the mouse highlight is? If so, no need to turn off.
628 Likewise, don't do anything if the frame is garbaged;
629 in that case, the frame's current matrix that we would use
630 is all wrong, and we will redisplay that line anyway. */
631 if (!NILP (display_info->mouse_face_window)
632 && w == XWINDOW (display_info->mouse_face_window))
514e4681 633 {
06a2c219 634 int i;
514e4681 635
06a2c219
GM
636 for (i = 0; i < w->desired_matrix->nrows; ++i)
637 if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
514e4681
RS
638 break;
639
06a2c219
GM
640 if (i < w->desired_matrix->nrows)
641 clear_mouse_face (display_info);
514e4681 642 }
64f26cf5 643#endif /* 0 */
b8009dd1 644 }
6ccf47d1 645
dc6f92b8
JB
646 UNBLOCK_INPUT;
647}
648
06a2c219
GM
649
650/* Draw a vertical window border to the right of window W if W doesn't
651 have vertical scroll bars. */
652
dfcf069d 653static void
06a2c219
GM
654x_draw_vertical_border (w)
655 struct window *w;
58769bee 656{
06a2c219
GM
657 struct frame *f = XFRAME (WINDOW_FRAME (w));
658
659 /* Redraw borders between horizontally adjacent windows. Don't
660 do it for frames with vertical scroll bars because either the
661 right scroll bar of a window, or the left scroll bar of its
662 neighbor will suffice as a border. */
663 if (!WINDOW_RIGHTMOST_P (w)
664 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
665 {
666 int x0, x1, y0, y1;
dc6f92b8 667
06a2c219 668 window_box_edges (w, -1, &x0, &y0, &x1, &y1);
110859fc 669 x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
06a2c219
GM
670 y1 -= 1;
671
672 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
673 f->output_data.x->normal_gc, x1, y0, x1, y1);
674 }
675}
676
677
71b8321e
GM
678/* End update of window W (which is equal to updated_window).
679
680 Draw vertical borders between horizontally adjacent windows, and
681 display W's cursor if CURSOR_ON_P is non-zero.
682
683 MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
684 glyphs in mouse-face were overwritten. In that case we have to
685 make sure that the mouse-highlight is properly redrawn.
686
687 W may be a menu bar pseudo-window in case we don't have X toolkit
688 support. Such windows don't have a cursor, so don't display it
689 here. */
06a2c219
GM
690
691static void
71b8321e 692x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
06a2c219 693 struct window *w;
71b8321e 694 int cursor_on_p, mouse_face_overwritten_p;
06a2c219 695{
140330de
GM
696 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
697
06a2c219
GM
698 if (!w->pseudo_window_p)
699 {
700 BLOCK_INPUT;
71b8321e 701
06a2c219
GM
702 if (cursor_on_p)
703 x_display_and_set_cursor (w, 1, output_cursor.hpos,
704 output_cursor.vpos,
705 output_cursor.x, output_cursor.y);
71b8321e 706
06a2c219
GM
707 x_draw_vertical_border (w);
708 UNBLOCK_INPUT;
709 }
710
140330de
GM
711 /* If a row with mouse-face was overwritten, arrange for
712 XTframe_up_to_date to redisplay the mouse highlight. */
713 if (mouse_face_overwritten_p)
714 {
715 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
716 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
717 dpyinfo->mouse_face_window = Qnil;
718 }
719
06a2c219
GM
720 updated_window = NULL;
721}
dc6f92b8 722
dc6f92b8 723
06a2c219
GM
724/* End update of frame F. This function is installed as a hook in
725 update_end. */
726
727static void
728x_update_end (f)
729 struct frame *f;
730{
731 /* Mouse highlight may be displayed again. */
aa8bff2e 732 FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
b8009dd1 733
06a2c219 734 BLOCK_INPUT;
334208b7 735 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
736 UNBLOCK_INPUT;
737}
b8009dd1 738
06a2c219
GM
739
740/* This function is called from various places in xdisp.c whenever a
741 complete update has been performed. The global variable
742 updated_window is not available here. */
b8009dd1 743
dfcf069d 744static void
b8009dd1 745XTframe_up_to_date (f)
06a2c219 746 struct frame *f;
b8009dd1 747{
06a2c219 748 if (FRAME_X_P (f))
514e4681 749 {
06a2c219 750 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
71b8321e 751
06a2c219
GM
752 if (dpyinfo->mouse_face_deferred_gc
753 || f == dpyinfo->mouse_face_mouse_frame)
754 {
755 BLOCK_INPUT;
756 if (dpyinfo->mouse_face_mouse_frame)
757 note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
758 dpyinfo->mouse_face_mouse_x,
759 dpyinfo->mouse_face_mouse_y);
760 dpyinfo->mouse_face_deferred_gc = 0;
761 UNBLOCK_INPUT;
762 }
514e4681 763 }
b8009dd1 764}
06a2c219
GM
765
766
767/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
768 arrow bitmaps, or clear the areas where they would be displayed
769 before DESIRED_ROW is made current. The window being updated is
770 found in updated_window. This function It is called from
771 update_window_line only if it is known that there are differences
772 between bitmaps to be drawn between current row and DESIRED_ROW. */
773
774static void
775x_after_update_window_line (desired_row)
776 struct glyph_row *desired_row;
777{
778 struct window *w = updated_window;
779
780 xassert (w);
781
782 if (!desired_row->mode_line_p && !w->pseudo_window_p)
783 {
c5e6e06b
GM
784 struct frame *f;
785 int width;
786
06a2c219
GM
787 BLOCK_INPUT;
788 x_draw_row_bitmaps (w, desired_row);
789
790 /* When a window has disappeared, make sure that no rest of
791 full-width rows stays visible in the internal border. */
c5e6e06b
GM
792 if (windows_or_buffers_changed
793 && (f = XFRAME (w->frame),
794 width = FRAME_INTERNAL_BORDER_WIDTH (f),
795 width != 0))
06a2c219 796 {
06a2c219 797 int height = desired_row->visible_height;
110859fc
GM
798 int x = (window_box_right (w, -1)
799 + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
06a2c219
GM
800 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
801
c5e6e06b
GM
802 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
803 x, y, width, height, False);
06a2c219
GM
804 }
805
806 UNBLOCK_INPUT;
807 }
808}
809
810
811/* Draw the bitmap WHICH in one of the areas to the left or right of
812 window W. ROW is the glyph row for which to display the bitmap; it
813 determines the vertical position at which the bitmap has to be
814 drawn. */
815
816static void
817x_draw_bitmap (w, row, which)
818 struct window *w;
819 struct glyph_row *row;
820 enum bitmap_type which;
821{
822 struct frame *f = XFRAME (WINDOW_FRAME (w));
823 Display *display = FRAME_X_DISPLAY (f);
824 Window window = FRAME_X_WINDOW (f);
825 int x, y, wd, h, dy;
826 unsigned char *bits;
827 Pixmap pixmap;
828 GC gc = f->output_data.x->normal_gc;
829 struct face *face;
830 int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
831
832 /* Must clip because of partially visible lines. */
833 x_clip_to_row (w, row, gc, 1);
834
835 switch (which)
836 {
837 case LEFT_TRUNCATION_BITMAP:
838 wd = left_width;
839 h = left_height;
840 bits = left_bits;
841 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
842 - wd
110859fc 843 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
844 break;
845
846 case OVERLAY_ARROW_BITMAP:
847 wd = left_width;
848 h = left_height;
849 bits = ov_bits;
850 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
851 - wd
110859fc 852 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
853 break;
854
855 case RIGHT_TRUNCATION_BITMAP:
856 wd = right_width;
857 h = right_height;
858 bits = right_bits;
859 x = window_box_right (w, -1);
110859fc 860 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
861 break;
862
863 case CONTINUED_LINE_BITMAP:
864 wd = right_width;
865 h = right_height;
866 bits = continued_bits;
867 x = window_box_right (w, -1);
110859fc 868 x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
06a2c219
GM
869 break;
870
871 case CONTINUATION_LINE_BITMAP:
872 wd = continuation_width;
873 h = continuation_height;
874 bits = continuation_bits;
875 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
876 - wd
110859fc 877 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
878 break;
879
880 case ZV_LINE_BITMAP:
881 wd = zv_width;
882 h = zv_height;
883 bits = zv_bits;
884 x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
885 - wd
110859fc 886 - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
06a2c219
GM
887 break;
888
889 default:
890 abort ();
891 }
892
893 /* Convert to frame coordinates. Set dy to the offset in the row to
894 start drawing the bitmap. */
895 y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
896 dy = (row->height - h) / 2;
897
898 /* Draw the bitmap. I believe these small pixmaps can be cached
899 by the server. */
900 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
901 pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
902 face->foreground,
903 face->background, depth);
904 XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
905 XFreePixmap (display, pixmap);
906 XSetClipMask (display, gc, None);
907}
908
909
910/* Draw flags bitmaps for glyph row ROW on window W. Call this
911 function with input blocked. */
912
913static void
914x_draw_row_bitmaps (w, row)
915 struct window *w;
916 struct glyph_row *row;
917{
918 struct frame *f = XFRAME (w->frame);
919 enum bitmap_type bitmap;
920 struct face *face;
045dee35 921 int header_line_height = -1;
06a2c219
GM
922
923 xassert (interrupt_input_blocked);
924
925 /* If row is completely invisible, because of vscrolling, we
926 don't have to draw anything. */
927 if (row->visible_height <= 0)
928 return;
929
930 face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
931 PREPARE_FACE_FOR_DISPLAY (f, face);
932
933 /* Decide which bitmap to draw at the left side. */
934 if (row->overlay_arrow_p)
935 bitmap = OVERLAY_ARROW_BITMAP;
936 else if (row->truncated_on_left_p)
937 bitmap = LEFT_TRUNCATION_BITMAP;
938 else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
939 bitmap = CONTINUATION_LINE_BITMAP;
940 else if (row->indicate_empty_line_p)
941 bitmap = ZV_LINE_BITMAP;
942 else
943 bitmap = NO_BITMAP;
944
945 /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
946 the flags area. */
947 if (bitmap == NO_BITMAP
110859fc 948 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
949 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
950 {
951 /* If W has a vertical border to its left, don't draw over it. */
952 int border = ((XFASTINT (w->left) > 0
953 && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
954 ? 1 : 0);
955 int left = window_box_left (w, -1);
956
045dee35
GM
957 if (header_line_height < 0)
958 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
959
960 /* In case the same realized face is used for bitmap areas and
961 for something displayed in the text (e.g. face `region' on
962 mono-displays, the fill style may have been changed to
963 FillSolid in x_draw_glyph_string_background. */
964 if (face->stipple)
965 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
966 else
967 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
968
06a2c219
GM
969 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
970 face->gc,
971 (left
110859fc 972 - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
06a2c219 973 + border),
045dee35 974 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 975 row->y)),
110859fc 976 FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
06a2c219 977 row->visible_height);
dcd08bfb
GM
978 if (!face->stipple)
979 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
980 }
981
982 /* Draw the left bitmap. */
983 if (bitmap != NO_BITMAP)
984 x_draw_bitmap (w, row, bitmap);
985
986 /* Decide which bitmap to draw at the right side. */
987 if (row->truncated_on_right_p)
988 bitmap = RIGHT_TRUNCATION_BITMAP;
989 else if (row->continued_p)
990 bitmap = CONTINUED_LINE_BITMAP;
991 else
992 bitmap = NO_BITMAP;
993
994 /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
995 the flags area. */
996 if (bitmap == NO_BITMAP
110859fc 997 || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
06a2c219
GM
998 || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
999 {
1000 int right = window_box_right (w, -1);
1001
045dee35
GM
1002 if (header_line_height < 0)
1003 header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dcd08bfb
GM
1004
1005 /* In case the same realized face is used for bitmap areas and
1006 for something displayed in the text (e.g. face `region' on
1007 mono-displays, the fill style may have been changed to
1008 FillSolid in x_draw_glyph_string_background. */
1009 if (face->stipple)
1010 XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
1011 else
1012 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
06a2c219
GM
1013 XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
1014 face->gc,
1015 right,
045dee35 1016 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
06a2c219 1017 row->y)),
110859fc 1018 FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
06a2c219 1019 row->visible_height);
dcd08bfb
GM
1020 if (!face->stipple)
1021 XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
06a2c219
GM
1022 }
1023
1024 /* Draw the right bitmap. */
1025 if (bitmap != NO_BITMAP)
1026 x_draw_bitmap (w, row, bitmap);
1027}
1028
dc6f92b8 1029\f
06a2c219
GM
1030/***********************************************************************
1031 Line Highlighting
1032 ***********************************************************************/
dc6f92b8 1033
06a2c219
GM
1034/* External interface to control of standout mode. Not used for X
1035 frames. Aborts when called. */
1036
1037static void
dc6f92b8
JB
1038XTreassert_line_highlight (new, vpos)
1039 int new, vpos;
1040{
06a2c219 1041 abort ();
dc6f92b8
JB
1042}
1043
06a2c219
GM
1044
1045/* Call this when about to modify line at position VPOS and change
1046 whether it is highlighted. Not used for X frames. Aborts when
1047 called. */
dc6f92b8 1048
dfcf069d 1049static void
06a2c219
GM
1050x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
1051 int new_highlight, vpos, y, first_unused_hpos;
dc6f92b8 1052{
06a2c219 1053 abort ();
dc6f92b8
JB
1054}
1055
06a2c219
GM
1056
1057/* This is called when starting Emacs and when restarting after
1058 suspend. When starting Emacs, no X window is mapped. And nothing
1059 must be done to Emacs's own window if it is suspended (though that
1060 rarely happens). */
dc6f92b8 1061
dfcf069d 1062static void
dc6f92b8
JB
1063XTset_terminal_modes ()
1064{
1065}
1066
06a2c219
GM
1067/* This is called when exiting or suspending Emacs. Exiting will make
1068 the X-windows go away, and suspending requires no action. */
dc6f92b8 1069
dfcf069d 1070static void
dc6f92b8
JB
1071XTreset_terminal_modes ()
1072{
dc6f92b8 1073}
06a2c219
GM
1074
1075
dc6f92b8 1076\f
06a2c219
GM
1077/***********************************************************************
1078 Output Cursor
1079 ***********************************************************************/
1080
1081/* Set the global variable output_cursor to CURSOR. All cursor
1082 positions are relative to updated_window. */
dc6f92b8 1083
dfcf069d 1084static void
06a2c219
GM
1085set_output_cursor (cursor)
1086 struct cursor_pos *cursor;
dc6f92b8 1087{
06a2c219
GM
1088 output_cursor.hpos = cursor->hpos;
1089 output_cursor.vpos = cursor->vpos;
1090 output_cursor.x = cursor->x;
1091 output_cursor.y = cursor->y;
1092}
1093
1094
1095/* Set a nominal cursor position.
dc6f92b8 1096
06a2c219
GM
1097 HPOS and VPOS are column/row positions in a window glyph matrix. X
1098 and Y are window text area relative pixel positions.
1099
1100 If this is done during an update, updated_window will contain the
1101 window that is being updated and the position is the future output
1102 cursor position for that window. If updated_window is null, use
1103 selected_window and display the cursor at the given position. */
1104
1105static void
1106XTcursor_to (vpos, hpos, y, x)
1107 int vpos, hpos, y, x;
1108{
1109 struct window *w;
1110
1111 /* If updated_window is not set, work on selected_window. */
1112 if (updated_window)
1113 w = updated_window;
1114 else
1115 w = XWINDOW (selected_window);
dbcb258a 1116
06a2c219
GM
1117 /* Set the output cursor. */
1118 output_cursor.hpos = hpos;
1119 output_cursor.vpos = vpos;
1120 output_cursor.x = x;
1121 output_cursor.y = y;
dc6f92b8 1122
06a2c219
GM
1123 /* If not called as part of an update, really display the cursor.
1124 This will also set the cursor position of W. */
1125 if (updated_window == NULL)
dc6f92b8
JB
1126 {
1127 BLOCK_INPUT;
06a2c219 1128 x_display_cursor (w, 1, hpos, vpos, x, y);
b86bd3dd 1129 XFlush (FRAME_X_DISPLAY (SELECTED_FRAME ()));
dc6f92b8
JB
1130 UNBLOCK_INPUT;
1131 }
1132}
dc43ef94 1133
06a2c219
GM
1134
1135\f
1136/***********************************************************************
1137 Display Iterator
1138 ***********************************************************************/
1139
1140/* Function prototypes of this page. */
1141
1142static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
1143 struct glyph *,
ee569018
KH
1144 XChar2b *,
1145 int *));
06a2c219
GM
1146static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
1147 int, XChar2b *, int));
1148static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
1149static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
1150static void x_append_glyph P_ ((struct it *));
b4192550 1151static void x_append_composite_glyph P_ ((struct it *));
06a2c219
GM
1152static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
1153 int, int, double));
1154static void x_produce_glyphs P_ ((struct it *));
06a2c219 1155static void x_produce_image_glyph P_ ((struct it *it));
ee569018
KH
1156
1157
e2ef8ee6
GM
1158/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
1159 is not contained in the font. */
dc43ef94 1160
06a2c219 1161static INLINE XCharStruct *
ee569018 1162x_per_char_metric (font, char2b)
06a2c219
GM
1163 XFontStruct *font;
1164 XChar2b *char2b;
1165{
1166 /* The result metric information. */
1167 XCharStruct *pcm = NULL;
dc6f92b8 1168
06a2c219 1169 xassert (font && char2b);
dc6f92b8 1170
06a2c219 1171 if (font->per_char != NULL)
dc6f92b8 1172 {
06a2c219 1173 if (font->min_byte1 == 0 && font->max_byte1 == 0)
dc43ef94 1174 {
06a2c219
GM
1175 /* min_char_or_byte2 specifies the linear character index
1176 corresponding to the first element of the per_char array,
1177 max_char_or_byte2 is the index of the last character. A
1178 character with non-zero CHAR2B->byte1 is not in the font.
1179 A character with byte2 less than min_char_or_byte2 or
1180 greater max_char_or_byte2 is not in the font. */
1181 if (char2b->byte1 == 0
1182 && char2b->byte2 >= font->min_char_or_byte2
1183 && char2b->byte2 <= font->max_char_or_byte2)
1184 pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
dc43ef94 1185 }
06a2c219 1186 else
dc6f92b8 1187 {
06a2c219
GM
1188 /* If either min_byte1 or max_byte1 are nonzero, both
1189 min_char_or_byte2 and max_char_or_byte2 are less than
1190 256, and the 2-byte character index values corresponding
1191 to the per_char array element N (counting from 0) are:
1192
1193 byte1 = N/D + min_byte1
1194 byte2 = N\D + min_char_or_byte2
1195
1196 where:
1197
1198 D = max_char_or_byte2 - min_char_or_byte2 + 1
1199 / = integer division
1200 \ = integer modulus */
1201 if (char2b->byte1 >= font->min_byte1
1202 && char2b->byte1 <= font->max_byte1
1203 && char2b->byte2 >= font->min_char_or_byte2
1204 && char2b->byte2 <= font->max_char_or_byte2)
1205 {
1206 pcm = (font->per_char
1207 + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
1208 * (char2b->byte1 - font->min_byte1))
1209 + (char2b->byte2 - font->min_char_or_byte2));
1210 }
dc6f92b8 1211 }
06a2c219
GM
1212 }
1213 else
1214 {
1215 /* If the per_char pointer is null, all glyphs between the first
1216 and last character indexes inclusive have the same
1217 information, as given by both min_bounds and max_bounds. */
1218 if (char2b->byte2 >= font->min_char_or_byte2
1219 && char2b->byte2 <= font->max_char_or_byte2)
1220 pcm = &font->max_bounds;
1221 }
dc6f92b8 1222
ee569018 1223 return ((pcm == NULL
3e71d8f2 1224 || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
ee569018 1225 ? NULL : pcm);
06a2c219 1226}
b73b6aaf 1227
57b03282 1228
06a2c219
GM
1229/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
1230 the two-byte form of C. Encoding is returned in *CHAR2B. */
dc43ef94 1231
06a2c219
GM
1232static INLINE void
1233x_encode_char (c, char2b, font_info)
1234 int c;
1235 XChar2b *char2b;
1236 struct font_info *font_info;
1237{
1238 int charset = CHAR_CHARSET (c);
1239 XFontStruct *font = font_info->font;
1240
1241 /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
1242 This may be either a program in a special encoder language or a
1243 fixed encoding. */
1244 if (font_info->font_encoder)
1245 {
1246 /* It's a program. */
1247 struct ccl_program *ccl = font_info->font_encoder;
1248
1249 if (CHARSET_DIMENSION (charset) == 1)
1250 {
1251 ccl->reg[0] = charset;
1252 ccl->reg[1] = char2b->byte2;
1253 }
1254 else
1255 {
1256 ccl->reg[0] = charset;
1257 ccl->reg[1] = char2b->byte1;
1258 ccl->reg[2] = char2b->byte2;
1259 }
1260
1261 ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
1262
1263 /* We assume that MSBs are appropriately set/reset by CCL
1264 program. */
1265 if (font->max_byte1 == 0) /* 1-byte font */
ee569018 1266 char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
06a2c219
GM
1267 else
1268 char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
1269 }
1270 else if (font_info->encoding[charset])
1271 {
1272 /* Fixed encoding scheme. See fontset.h for the meaning of the
1273 encoding numbers. */
1274 int enc = font_info->encoding[charset];
1275
1276 if ((enc == 1 || enc == 2)
1277 && CHARSET_DIMENSION (charset) == 2)
1278 char2b->byte1 |= 0x80;
1279
1280 if (enc == 1 || enc == 3)
1281 char2b->byte2 |= 0x80;
1282 }
1283}
1284
1285
1286/* Get face and two-byte form of character C in face FACE_ID on frame
1287 F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
1288 means we want to display multibyte text. Value is a pointer to a
1289 realized face that is ready for display. */
1290
1291static INLINE struct face *
1292x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
1293 struct frame *f;
1294 int c, face_id;
1295 XChar2b *char2b;
1296 int multibyte_p;
1297{
1298 struct face *face = FACE_FROM_ID (f, face_id);
1299
1300 if (!multibyte_p)
1301 {
1302 /* Unibyte case. We don't have to encode, but we have to make
1303 sure to use a face suitable for unibyte. */
1304 char2b->byte1 = 0;
1305 char2b->byte2 = c;
ee569018
KH
1306 face_id = FACE_FOR_CHAR (f, face, c);
1307 face = FACE_FROM_ID (f, face_id);
06a2c219
GM
1308 }
1309 else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
1310 {
1311 /* Case of ASCII in a face known to fit ASCII. */
1312 char2b->byte1 = 0;
1313 char2b->byte2 = c;
1314 }
1315 else
1316 {
1317 int c1, c2, charset;
1318
1319 /* Split characters into bytes. If c2 is -1 afterwards, C is
1320 really a one-byte character so that byte1 is zero. */
1321 SPLIT_CHAR (c, charset, c1, c2);
1322 if (c2 > 0)
1323 char2b->byte1 = c1, char2b->byte2 = c2;
1324 else
1325 char2b->byte1 = 0, char2b->byte2 = c1;
1326
06a2c219 1327 /* Maybe encode the character in *CHAR2B. */
ee569018 1328 if (face->font != NULL)
06a2c219
GM
1329 {
1330 struct font_info *font_info
1331 = FONT_INFO_FROM_ID (f, face->font_info_id);
1332 if (font_info)
ee569018 1333 x_encode_char (c, char2b, font_info);
06a2c219
GM
1334 }
1335 }
1336
1337 /* Make sure X resources of the face are allocated. */
1338 xassert (face != NULL);
1339 PREPARE_FACE_FOR_DISPLAY (f, face);
1340
1341 return face;
1342}
1343
1344
1345/* Get face and two-byte form of character glyph GLYPH on frame F.
43d120d8 1346 The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
06a2c219
GM
1347 a pointer to a realized face that is ready for display. */
1348
1349static INLINE struct face *
ee569018 1350x_get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
06a2c219
GM
1351 struct frame *f;
1352 struct glyph *glyph;
1353 XChar2b *char2b;
ee569018 1354 int *two_byte_p;
06a2c219
GM
1355{
1356 struct face *face;
1357
1358 xassert (glyph->type == CHAR_GLYPH);
43d120d8 1359 face = FACE_FROM_ID (f, glyph->face_id);
06a2c219 1360
ee569018
KH
1361 if (two_byte_p)
1362 *two_byte_p = 0;
1363
06a2c219
GM
1364 if (!glyph->multibyte_p)
1365 {
1366 /* Unibyte case. We don't have to encode, but we have to make
1367 sure to use a face suitable for unibyte. */
1368 char2b->byte1 = 0;
43d120d8 1369 char2b->byte2 = glyph->u.ch;
06a2c219 1370 }
43d120d8
KH
1371 else if (glyph->u.ch < 128
1372 && glyph->face_id < BASIC_FACE_ID_SENTINEL)
06a2c219
GM
1373 {
1374 /* Case of ASCII in a face known to fit ASCII. */
1375 char2b->byte1 = 0;
43d120d8 1376 char2b->byte2 = glyph->u.ch;
06a2c219
GM
1377 }
1378 else
1379 {
1380 int c1, c2, charset;
1381
1382 /* Split characters into bytes. If c2 is -1 afterwards, C is
1383 really a one-byte character so that byte1 is zero. */
43d120d8 1384 SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
06a2c219
GM
1385 if (c2 > 0)
1386 char2b->byte1 = c1, char2b->byte2 = c2;
1387 else
1388 char2b->byte1 = 0, char2b->byte2 = c1;
1389
1390 /* Maybe encode the character in *CHAR2B. */
1391 if (charset != CHARSET_ASCII)
1392 {
1393 struct font_info *font_info
1394 = FONT_INFO_FROM_ID (f, face->font_info_id);
1395 if (font_info)
1396 {
43d120d8 1397 x_encode_char (glyph->u.ch, char2b, font_info);
ee569018
KH
1398 if (two_byte_p)
1399 *two_byte_p
1400 = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
06a2c219
GM
1401 }
1402 }
1403 }
1404
1405 /* Make sure X resources of the face are allocated. */
1406 xassert (face != NULL);
1407 PREPARE_FACE_FOR_DISPLAY (f, face);
1408 return face;
1409}
1410
1411
1412/* Store one glyph for IT->char_to_display in IT->glyph_row.
1413 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1414
1415static INLINE void
1416x_append_glyph (it)
1417 struct it *it;
1418{
1419 struct glyph *glyph;
1420 enum glyph_row_area area = it->area;
1421
1422 xassert (it->glyph_row);
1423 xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
1424
1425 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1426 if (glyph < it->glyph_row->glyphs[area + 1])
1427 {
06a2c219
GM
1428 glyph->charpos = CHARPOS (it->position);
1429 glyph->object = it->object;
88d75730 1430 glyph->pixel_width = it->pixel_width;
06a2c219 1431 glyph->voffset = it->voffset;
88d75730 1432 glyph->type = CHAR_GLYPH;
06a2c219 1433 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1434 glyph->left_box_line_p = it->start_of_box_run_p;
1435 glyph->right_box_line_p = it->end_of_box_run_p;
66ac4b0e
GM
1436 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1437 || it->phys_descent > it->descent);
88d75730 1438 glyph->padding_p = 0;
ee569018 1439 glyph->glyph_not_available_p = it->glyph_not_available_p;
88d75730
GM
1440 glyph->face_id = it->face_id;
1441 glyph->u.ch = it->char_to_display;
06a2c219
GM
1442 ++it->glyph_row->used[area];
1443 }
1444}
1445
b4192550
KH
1446/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
1447 Called from x_produce_glyphs when IT->glyph_row is non-null. */
1448
1449static INLINE void
1450x_append_composite_glyph (it)
1451 struct it *it;
1452{
1453 struct glyph *glyph;
1454 enum glyph_row_area area = it->area;
1455
1456 xassert (it->glyph_row);
1457
1458 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1459 if (glyph < it->glyph_row->glyphs[area + 1])
1460 {
b4192550
KH
1461 glyph->charpos = CHARPOS (it->position);
1462 glyph->object = it->object;
88d75730 1463 glyph->pixel_width = it->pixel_width;
b4192550 1464 glyph->voffset = it->voffset;
88d75730 1465 glyph->type = COMPOSITE_GLYPH;
b4192550 1466 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1467 glyph->left_box_line_p = it->start_of_box_run_p;
1468 glyph->right_box_line_p = it->end_of_box_run_p;
b4192550
KH
1469 glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
1470 || it->phys_descent > it->descent);
88d75730
GM
1471 glyph->padding_p = 0;
1472 glyph->glyph_not_available_p = 0;
1473 glyph->face_id = it->face_id;
1474 glyph->u.cmp_id = it->cmp_id;
b4192550
KH
1475 ++it->glyph_row->used[area];
1476 }
1477}
1478
06a2c219
GM
1479
1480/* Change IT->ascent and IT->height according to the setting of
1481 IT->voffset. */
1482
1483static INLINE void
1484take_vertical_position_into_account (it)
1485 struct it *it;
1486{
1487 if (it->voffset)
1488 {
1489 if (it->voffset < 0)
1490 /* Increase the ascent so that we can display the text higher
1491 in the line. */
1492 it->ascent += abs (it->voffset);
1493 else
1494 /* Increase the descent so that we can display the text lower
1495 in the line. */
1496 it->descent += it->voffset;
1497 }
1498}
1499
1500
1501/* Produce glyphs/get display metrics for the image IT is loaded with.
1502 See the description of struct display_iterator in dispextern.h for
1503 an overview of struct display_iterator. */
1504
1505static void
1506x_produce_image_glyph (it)
1507 struct it *it;
1508{
1509 struct image *img;
1510 struct face *face;
1511
1512 xassert (it->what == IT_IMAGE);
1513
1514 face = FACE_FROM_ID (it->f, it->face_id);
1515 img = IMAGE_FROM_ID (it->f, it->image_id);
1516 xassert (img);
1517
1518 /* Make sure X resources of the face and image are loaded. */
1519 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1520 prepare_image_for_display (it->f, img);
1521
95af8492 1522 it->ascent = it->phys_ascent = image_ascent (img, face);
22d650b8
GM
1523 it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
1524 it->pixel_width = img->width + 2 * img->hmargin;
06a2c219
GM
1525
1526 it->nglyphs = 1;
1527
1528 if (face->box != FACE_NO_BOX)
1529 {
ea2ba0d4
KH
1530 if (face->box_line_width > 0)
1531 {
1532 it->ascent += face->box_line_width;
1533 it->descent += face->box_line_width;
1534 }
06a2c219
GM
1535
1536 if (it->start_of_box_run_p)
ea2ba0d4 1537 it->pixel_width += abs (face->box_line_width);
06a2c219 1538 if (it->end_of_box_run_p)
ea2ba0d4 1539 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1540 }
1541
1542 take_vertical_position_into_account (it);
1543
1544 if (it->glyph_row)
1545 {
1546 struct glyph *glyph;
1547 enum glyph_row_area area = it->area;
1548
1549 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1550 if (glyph < it->glyph_row->glyphs[area + 1])
1551 {
06a2c219
GM
1552 glyph->charpos = CHARPOS (it->position);
1553 glyph->object = it->object;
88d75730 1554 glyph->pixel_width = it->pixel_width;
06a2c219 1555 glyph->voffset = it->voffset;
88d75730 1556 glyph->type = IMAGE_GLYPH;
06a2c219 1557 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1558 glyph->left_box_line_p = it->start_of_box_run_p;
1559 glyph->right_box_line_p = it->end_of_box_run_p;
1560 glyph->overlaps_vertically_p = 0;
1561 glyph->padding_p = 0;
1562 glyph->glyph_not_available_p = 0;
1563 glyph->face_id = it->face_id;
1564 glyph->u.img_id = img->id;
06a2c219
GM
1565 ++it->glyph_row->used[area];
1566 }
1567 }
1568}
1569
1570
1571/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
1572 of the glyph, WIDTH and HEIGHT are the width and height of the
1573 stretch. ASCENT is the percentage/100 of HEIGHT to use for the
1574 ascent of the glyph (0 <= ASCENT <= 1). */
1575
1576static void
1577x_append_stretch_glyph (it, object, width, height, ascent)
1578 struct it *it;
1579 Lisp_Object object;
1580 int width, height;
1581 double ascent;
1582{
1583 struct glyph *glyph;
1584 enum glyph_row_area area = it->area;
1585
1586 xassert (ascent >= 0 && ascent <= 1);
1587
1588 glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
1589 if (glyph < it->glyph_row->glyphs[area + 1])
1590 {
06a2c219
GM
1591 glyph->charpos = CHARPOS (it->position);
1592 glyph->object = object;
88d75730 1593 glyph->pixel_width = width;
06a2c219 1594 glyph->voffset = it->voffset;
88d75730 1595 glyph->type = STRETCH_GLYPH;
06a2c219 1596 glyph->multibyte_p = it->multibyte_p;
88d75730
GM
1597 glyph->left_box_line_p = it->start_of_box_run_p;
1598 glyph->right_box_line_p = it->end_of_box_run_p;
1599 glyph->overlaps_vertically_p = 0;
1600 glyph->padding_p = 0;
1601 glyph->glyph_not_available_p = 0;
1602 glyph->face_id = it->face_id;
1603 glyph->u.stretch.ascent = height * ascent;
1604 glyph->u.stretch.height = height;
06a2c219
GM
1605 ++it->glyph_row->used[area];
1606 }
1607}
1608
1609
1610/* Produce a stretch glyph for iterator IT. IT->object is the value
1611 of the glyph property displayed. The value must be a list
1612 `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
1613 being recognized:
1614
1615 1. `:width WIDTH' specifies that the space should be WIDTH *
1616 canonical char width wide. WIDTH may be an integer or floating
1617 point number.
1618
1619 2. `:relative-width FACTOR' specifies that the width of the stretch
1620 should be computed from the width of the first character having the
1621 `glyph' property, and should be FACTOR times that width.
1622
1623 3. `:align-to HPOS' specifies that the space should be wide enough
1624 to reach HPOS, a value in canonical character units.
1625
1626 Exactly one of the above pairs must be present.
1627
1628 4. `:height HEIGHT' specifies that the height of the stretch produced
1629 should be HEIGHT, measured in canonical character units.
1630
1631 5. `:relative-height FACTOR' specifies that the height of the the
1632 stretch should be FACTOR times the height of the characters having
1633 the glyph property.
1634
1635 Either none or exactly one of 4 or 5 must be present.
1636
1637 6. `:ascent ASCENT' specifies that ASCENT percent of the height
1638 of the stretch should be used for the ascent of the stretch.
1639 ASCENT must be in the range 0 <= ASCENT <= 100. */
1640
1641#define NUMVAL(X) \
1642 ((INTEGERP (X) || FLOATP (X)) \
1643 ? XFLOATINT (X) \
1644 : - 1)
1645
1646
1647static void
1648x_produce_stretch_glyph (it)
1649 struct it *it;
1650{
1651 /* (space :width WIDTH :height HEIGHT. */
3e71d8f2
GM
1652#if GLYPH_DEBUG
1653 extern Lisp_Object Qspace;
1654#endif
1655 extern Lisp_Object QCwidth, QCheight, QCascent;
06a2c219
GM
1656 extern Lisp_Object QCrelative_width, QCrelative_height;
1657 extern Lisp_Object QCalign_to;
1658 Lisp_Object prop, plist;
1659 double width = 0, height = 0, ascent = 0;
1660 struct face *face = FACE_FROM_ID (it->f, it->face_id);
1661 XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
1662
1663 PREPARE_FACE_FOR_DISPLAY (it->f, face);
1664
1665 /* List should start with `space'. */
1666 xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
1667 plist = XCDR (it->object);
1668
1669 /* Compute the width of the stretch. */
1670 if (prop = Fplist_get (plist, QCwidth),
1671 NUMVAL (prop) > 0)
1672 /* Absolute width `:width WIDTH' specified and valid. */
1673 width = NUMVAL (prop) * CANON_X_UNIT (it->f);
1674 else if (prop = Fplist_get (plist, QCrelative_width),
1675 NUMVAL (prop) > 0)
1676 {
1677 /* Relative width `:relative-width FACTOR' specified and valid.
1678 Compute the width of the characters having the `glyph'
1679 property. */
1680 struct it it2;
1681 unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
1682
1683 it2 = *it;
1684 if (it->multibyte_p)
1685 {
1686 int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
1687 - IT_BYTEPOS (*it));
1688 it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
1689 }
1690 else
1691 it2.c = *p, it2.len = 1;
1692
1693 it2.glyph_row = NULL;
1694 it2.what = IT_CHARACTER;
1695 x_produce_glyphs (&it2);
1696 width = NUMVAL (prop) * it2.pixel_width;
1697 }
1698 else if (prop = Fplist_get (plist, QCalign_to),
1699 NUMVAL (prop) > 0)
1700 width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
1701 else
1702 /* Nothing specified -> width defaults to canonical char width. */
1703 width = CANON_X_UNIT (it->f);
1704
1705 /* Compute height. */
1706 if (prop = Fplist_get (plist, QCheight),
1707 NUMVAL (prop) > 0)
1708 height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
1709 else if (prop = Fplist_get (plist, QCrelative_height),
1710 NUMVAL (prop) > 0)
1711 height = FONT_HEIGHT (font) * NUMVAL (prop);
1712 else
1713 height = FONT_HEIGHT (font);
1714
1715 /* Compute percentage of height used for ascent. If
1716 `:ascent ASCENT' is present and valid, use that. Otherwise,
1717 derive the ascent from the font in use. */
1718 if (prop = Fplist_get (plist, QCascent),
1719 NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
1720 ascent = NUMVAL (prop) / 100.0;
1721 else
1722 ascent = (double) font->ascent / FONT_HEIGHT (font);
1723
1724 if (width <= 0)
1725 width = 1;
1726 if (height <= 0)
1727 height = 1;
1728
1729 if (it->glyph_row)
1730 {
1731 Lisp_Object object = it->stack[it->sp - 1].string;
1732 if (!STRINGP (object))
1733 object = it->w->buffer;
1734 x_append_stretch_glyph (it, object, width, height, ascent);
1735 }
1736
1737 it->pixel_width = width;
66ac4b0e
GM
1738 it->ascent = it->phys_ascent = height * ascent;
1739 it->descent = it->phys_descent = height - it->ascent;
06a2c219
GM
1740 it->nglyphs = 1;
1741
1742 if (face->box != FACE_NO_BOX)
1743 {
ea2ba0d4
KH
1744 if (face->box_line_width > 0)
1745 {
1746 it->ascent += face->box_line_width;
1747 it->descent += face->box_line_width;
1748 }
06a2c219
GM
1749
1750 if (it->start_of_box_run_p)
ea2ba0d4 1751 it->pixel_width += abs (face->box_line_width);
06a2c219 1752 if (it->end_of_box_run_p)
ea2ba0d4 1753 it->pixel_width += abs (face->box_line_width);
06a2c219
GM
1754 }
1755
1756 take_vertical_position_into_account (it);
1757}
1758
b4192550
KH
1759/* Return proper value to be used as baseline offset of font that has
1760 ASCENT and DESCENT to draw characters by the font at the vertical
1761 center of the line of frame F.
1762
1763 Here, out task is to find the value of BOFF in the following figure;
1764
1765 -------------------------+-----------+-
1766 -+-+---------+-+ | |
1767 | | | | | |
1768 | | | | F_ASCENT F_HEIGHT
1769 | | | ASCENT | |
1770 HEIGHT | | | | |
1771 | | |-|-+------+-----------|------- baseline
1772 | | | | BOFF | |
1773 | |---------|-+-+ | |
1774 | | | DESCENT | |
1775 -+-+---------+-+ F_DESCENT |
1776 -------------------------+-----------+-
1777
1778 -BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
1779 BOFF = DESCENT + (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
1780 DESCENT = FONT->descent
1781 HEIGHT = FONT_HEIGHT (FONT)
1782 F_DESCENT = (F->output_data.x->font->descent
1783 - F->output_data.x->baseline_offset)
1784 F_HEIGHT = FRAME_LINE_HEIGHT (F)
1785*/
1786
458f45fa
KH
1787#define VCENTER_BASELINE_OFFSET(FONT, F) \
1788 ((FONT)->descent \
1789 + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT)) \
1790 + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \
1791 - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
06a2c219
GM
1792
1793/* Produce glyphs/get display metrics for the display element IT is
1794 loaded with. See the description of struct display_iterator in
1795 dispextern.h for an overview of struct display_iterator. */
1796
1797static void
1798x_produce_glyphs (it)
1799 struct it *it;
1800{
ee569018
KH
1801 it->glyph_not_available_p = 0;
1802
06a2c219
GM
1803 if (it->what == IT_CHARACTER)
1804 {
1805 XChar2b char2b;
1806 XFontStruct *font;
ee569018 1807 struct face *face = FACE_FROM_ID (it->f, it->face_id);
06a2c219 1808 XCharStruct *pcm;
06a2c219 1809 int font_not_found_p;
b4192550
KH
1810 struct font_info *font_info;
1811 int boff; /* baseline offset */
a4249304
KH
1812 /* We may change it->multibyte_p upon unibyte<->multibyte
1813 conversion. So, save the current value now and restore it
1814 later.
1815
1816 Note: It seems that we don't have to record multibyte_p in
1817 struct glyph because the character code itself tells if or
1818 not the character is multibyte. Thus, in the future, we must
1819 consider eliminating the field `multibyte_p' in the struct
c347a1c3 1820 glyph. */
a4249304 1821 int saved_multibyte_p = it->multibyte_p;
06a2c219 1822
ee569018
KH
1823 /* Maybe translate single-byte characters to multibyte, or the
1824 other way. */
06a2c219 1825 it->char_to_display = it->c;
ee569018 1826 if (!ASCII_BYTE_P (it->c))
06a2c219 1827 {
ee569018
KH
1828 if (unibyte_display_via_language_environment
1829 && SINGLE_BYTE_CHAR_P (it->c)
1830 && (it->c >= 0240
1831 || !NILP (Vnonascii_translation_table)))
1832 {
1833 it->char_to_display = unibyte_char_to_multibyte (it->c);
a4249304 1834 it->multibyte_p = 1;
ee569018
KH
1835 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1836 face = FACE_FROM_ID (it->f, it->face_id);
1837 }
1838 else if (!SINGLE_BYTE_CHAR_P (it->c)
1839 && !it->multibyte_p)
1840 {
c347a1c3 1841 it->multibyte_p = 1;
ee569018
KH
1842 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
1843 face = FACE_FROM_ID (it->f, it->face_id);
1844 }
06a2c219
GM
1845 }
1846
ee569018
KH
1847 /* Get font to use. Encode IT->char_to_display. */
1848 x_get_char_face_and_encoding (it->f, it->char_to_display,
1849 it->face_id, &char2b,
1850 it->multibyte_p);
06a2c219
GM
1851 font = face->font;
1852
1853 /* When no suitable font found, use the default font. */
1854 font_not_found_p = font == NULL;
1855 if (font_not_found_p)
b4192550
KH
1856 {
1857 font = FRAME_FONT (it->f);
1858 boff = it->f->output_data.x->baseline_offset;
1859 font_info = NULL;
1860 }
1861 else
1862 {
1863 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
1864 boff = font_info->baseline_offset;
1865 if (font_info->vertical_centering)
1866 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
1867 }
06a2c219
GM
1868
1869 if (it->char_to_display >= ' '
1870 && (!it->multibyte_p || it->char_to_display < 128))
1871 {
1872 /* Either unibyte or ASCII. */
1873 int stretched_p;
1874
1875 it->nglyphs = 1;
06a2c219
GM
1876
1877 pcm = x_per_char_metric (font, &char2b);
b4192550
KH
1878 it->ascent = font->ascent + boff;
1879 it->descent = font->descent - boff;
474848ac
GM
1880
1881 if (pcm)
1882 {
1883 it->phys_ascent = pcm->ascent + boff;
1884 it->phys_descent = pcm->descent - boff;
1885 it->pixel_width = pcm->width;
1886 }
1887 else
1888 {
1889 it->glyph_not_available_p = 1;
1890 it->phys_ascent = font->ascent + boff;
1891 it->phys_descent = font->descent - boff;
1892 it->pixel_width = FONT_WIDTH (font);
1893 }
06a2c219
GM
1894
1895 /* If this is a space inside a region of text with
1896 `space-width' property, change its width. */
1897 stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
1898 if (stretched_p)
1899 it->pixel_width *= XFLOATINT (it->space_width);
1900
1901 /* If face has a box, add the box thickness to the character
1902 height. If character has a box line to the left and/or
1903 right, add the box line width to the character's width. */
1904 if (face->box != FACE_NO_BOX)
1905 {
1906 int thick = face->box_line_width;
1907
ea2ba0d4
KH
1908 if (thick > 0)
1909 {
1910 it->ascent += thick;
1911 it->descent += thick;
1912 }
1913 else
1914 thick = -thick;
1915
06a2c219
GM
1916 if (it->start_of_box_run_p)
1917 it->pixel_width += thick;
1918 if (it->end_of_box_run_p)
1919 it->pixel_width += thick;
1920 }
1921
1922 /* If face has an overline, add the height of the overline
1923 (1 pixel) and a 1 pixel margin to the character height. */
1924 if (face->overline_p)
1925 it->ascent += 2;
1926
1927 take_vertical_position_into_account (it);
1928
1929 /* If we have to actually produce glyphs, do it. */
1930 if (it->glyph_row)
1931 {
1932 if (stretched_p)
1933 {
1934 /* Translate a space with a `space-width' property
1935 into a stretch glyph. */
1936 double ascent = (double) font->ascent / FONT_HEIGHT (font);
1937 x_append_stretch_glyph (it, it->object, it->pixel_width,
1938 it->ascent + it->descent, ascent);
1939 }
1940 else
1941 x_append_glyph (it);
1942
1943 /* If characters with lbearing or rbearing are displayed
1944 in this line, record that fact in a flag of the
1945 glyph row. This is used to optimize X output code. */
1c7e22fd 1946 if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
06a2c219
GM
1947 it->glyph_row->contains_overlapping_glyphs_p = 1;
1948 }
1949 }
1950 else if (it->char_to_display == '\n')
1951 {
1952 /* A newline has no width but we need the height of the line. */
1953 it->pixel_width = 0;
1954 it->nglyphs = 0;
b4192550
KH
1955 it->ascent = it->phys_ascent = font->ascent + boff;
1956 it->descent = it->phys_descent = font->descent - boff;
06a2c219 1957
ea2ba0d4
KH
1958 if (face->box != FACE_NO_BOX
1959 && face->box_line_width > 0)
06a2c219 1960 {
ea2ba0d4
KH
1961 it->ascent += face->box_line_width;
1962 it->descent += face->box_line_width;
06a2c219
GM
1963 }
1964 }
1965 else if (it->char_to_display == '\t')
1966 {
1967 int tab_width = it->tab_width * CANON_X_UNIT (it->f);
d365f5bb 1968 int x = it->current_x + it->continuation_lines_width;
06a2c219 1969 int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
2a32b5ea
GM
1970
1971 /* If the distance from the current position to the next tab
1972 stop is less than a canonical character width, use the
1973 tab stop after that. */
1974 if (next_tab_x - x < CANON_X_UNIT (it->f))
1975 next_tab_x += tab_width;
06a2c219
GM
1976
1977 it->pixel_width = next_tab_x - x;
1978 it->nglyphs = 1;
b4192550
KH
1979 it->ascent = it->phys_ascent = font->ascent + boff;
1980 it->descent = it->phys_descent = font->descent - boff;
06a2c219
GM
1981
1982 if (it->glyph_row)
1983 {
1984 double ascent = (double) it->ascent / (it->ascent + it->descent);
1985 x_append_stretch_glyph (it, it->object, it->pixel_width,
1986 it->ascent + it->descent, ascent);
1987 }
1988 }
1989 else
1990 {
1991 /* A multi-byte character. Assume that the display width of the
1992 character is the width of the character multiplied by the
b4192550 1993 width of the font. */
06a2c219 1994
b4192550
KH
1995 /* If we found a font, this font should give us the right
1996 metrics. If we didn't find a font, use the frame's
1997 default font and calculate the width of the character
1998 from the charset width; this is what old redisplay code
1999 did. */
2000 pcm = x_per_char_metric (font, &char2b);
ee569018
KH
2001 if (font_not_found_p || !pcm)
2002 {
2003 int charset = CHAR_CHARSET (it->char_to_display);
2004
2005 it->glyph_not_available_p = 1;
2006 it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
2007 * CHARSET_WIDTH (charset));
2008 it->phys_ascent = font->ascent + boff;
2009 it->phys_descent = font->descent - boff;
2010 }
2011 else
2012 {
2013 it->pixel_width = pcm->width;
2014 it->phys_ascent = pcm->ascent + boff;
2015 it->phys_descent = pcm->descent - boff;
2016 if (it->glyph_row
2017 && (pcm->lbearing < 0
2018 || pcm->rbearing > pcm->width))
2019 it->glyph_row->contains_overlapping_glyphs_p = 1;
2020 }
b4192550
KH
2021 it->nglyphs = 1;
2022 it->ascent = font->ascent + boff;
2023 it->descent = font->descent - boff;
06a2c219
GM
2024 if (face->box != FACE_NO_BOX)
2025 {
2026 int thick = face->box_line_width;
ea2ba0d4
KH
2027
2028 if (thick > 0)
2029 {
2030 it->ascent += thick;
2031 it->descent += thick;
2032 }
2033 else
2034 thick = - thick;
06a2c219
GM
2035
2036 if (it->start_of_box_run_p)
2037 it->pixel_width += thick;
2038 if (it->end_of_box_run_p)
2039 it->pixel_width += thick;
2040 }
2041
2042 /* If face has an overline, add the height of the overline
2043 (1 pixel) and a 1 pixel margin to the character height. */
2044 if (face->overline_p)
2045 it->ascent += 2;
2046
2047 take_vertical_position_into_account (it);
2048
2049 if (it->glyph_row)
2050 x_append_glyph (it);
2051 }
a4249304 2052 it->multibyte_p = saved_multibyte_p;
06a2c219 2053 }
b4192550
KH
2054 else if (it->what == IT_COMPOSITION)
2055 {
2056 /* Note: A composition is represented as one glyph in the
2057 glyph matrix. There are no padding glyphs. */
2058 XChar2b char2b;
2059 XFontStruct *font;
ee569018 2060 struct face *face = FACE_FROM_ID (it->f, it->face_id);
b4192550
KH
2061 XCharStruct *pcm;
2062 int font_not_found_p;
2063 struct font_info *font_info;
2064 int boff; /* baseline offset */
2065 struct composition *cmp = composition_table[it->cmp_id];
2066
2067 /* Maybe translate single-byte characters to multibyte. */
2068 it->char_to_display = it->c;
2069 if (unibyte_display_via_language_environment
2070 && SINGLE_BYTE_CHAR_P (it->c)
2071 && (it->c >= 0240
2072 || (it->c >= 0200
2073 && !NILP (Vnonascii_translation_table))))
2074 {
2075 it->char_to_display = unibyte_char_to_multibyte (it->c);
b4192550
KH
2076 }
2077
2078 /* Get face and font to use. Encode IT->char_to_display. */
ee569018
KH
2079 it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
2080 face = FACE_FROM_ID (it->f, it->face_id);
2081 x_get_char_face_and_encoding (it->f, it->char_to_display,
2082 it->face_id, &char2b, it->multibyte_p);
b4192550
KH
2083 font = face->font;
2084
2085 /* When no suitable font found, use the default font. */
2086 font_not_found_p = font == NULL;
2087 if (font_not_found_p)
2088 {
2089 font = FRAME_FONT (it->f);
2090 boff = it->f->output_data.x->baseline_offset;
2091 font_info = NULL;
2092 }
2093 else
2094 {
2095 font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2096 boff = font_info->baseline_offset;
2097 if (font_info->vertical_centering)
2098 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2099 }
2100
2101 /* There are no padding glyphs, so there is only one glyph to
2102 produce for the composition. Important is that pixel_width,
2103 ascent and descent are the values of what is drawn by
2104 draw_glyphs (i.e. the values of the overall glyphs composed). */
2105 it->nglyphs = 1;
2106
2107 /* If we have not yet calculated pixel size data of glyphs of
2108 the composition for the current face font, calculate them
2109 now. Theoretically, we have to check all fonts for the
2110 glyphs, but that requires much time and memory space. So,
2111 here we check only the font of the first glyph. This leads
2112 to incorrect display very rarely, and C-l (recenter) can
2113 correct the display anyway. */
2114 if (cmp->font != (void *) font)
2115 {
2116 /* Ascent and descent of the font of the first character of
2117 this composition (adjusted by baseline offset). Ascent
2118 and descent of overall glyphs should not be less than
2119 them respectively. */
2120 int font_ascent = font->ascent + boff;
2121 int font_descent = font->descent - boff;
2122 /* Bounding box of the overall glyphs. */
2123 int leftmost, rightmost, lowest, highest;
329bed06 2124 int i, width, ascent, descent;
b4192550
KH
2125
2126 cmp->font = (void *) font;
2127
2128 /* Initialize the bounding box. */
1bdeec2e
KH
2129 if (font_info
2130 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2131 {
2132 width = pcm->width;
2133 ascent = pcm->ascent;
2134 descent = pcm->descent;
2135 }
2136 else
2137 {
2138 width = FONT_WIDTH (font);
2139 ascent = font->ascent;
2140 descent = font->descent;
2141 }
2142
2143 rightmost = width;
2144 lowest = - descent + boff;
2145 highest = ascent + boff;
b4192550 2146 leftmost = 0;
329bed06 2147
b4192550
KH
2148 if (font_info
2149 && font_info->default_ascent
2150 && CHAR_TABLE_P (Vuse_default_ascent)
2151 && !NILP (Faref (Vuse_default_ascent,
2152 make_number (it->char_to_display))))
2153 highest = font_info->default_ascent + boff;
2154
2155 /* Draw the first glyph at the normal position. It may be
2156 shifted to right later if some other glyphs are drawn at
2157 the left. */
2158 cmp->offsets[0] = 0;
2159 cmp->offsets[1] = boff;
2160
2161 /* Set cmp->offsets for the remaining glyphs. */
2162 for (i = 1; i < cmp->glyph_len; i++)
2163 {
2164 int left, right, btm, top;
2165 int ch = COMPOSITION_GLYPH (cmp, i);
ee569018
KH
2166 int face_id = FACE_FOR_CHAR (it->f, face, ch);
2167
2168 face = FACE_FROM_ID (it->f, face_id);
2169 x_get_char_face_and_encoding (it->f, ch, face->id, &char2b,
2170 it->multibyte_p);
b4192550
KH
2171 font = face->font;
2172 if (font == NULL)
2173 {
2174 font = FRAME_FONT (it->f);
2175 boff = it->f->output_data.x->baseline_offset;
2176 font_info = NULL;
2177 }
2178 else
2179 {
2180 font_info
2181 = FONT_INFO_FROM_ID (it->f, face->font_info_id);
2182 boff = font_info->baseline_offset;
2183 if (font_info->vertical_centering)
2184 boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
2185 }
2186
1bdeec2e
KH
2187 if (font_info
2188 && (pcm = x_per_char_metric (font, &char2b)))
329bed06
GM
2189 {
2190 width = pcm->width;
2191 ascent = pcm->ascent;
2192 descent = pcm->descent;
2193 }
2194 else
2195 {
2196 width = FONT_WIDTH (font);
1bdeec2e
KH
2197 ascent = 1;
2198 descent = 0;
329bed06 2199 }
b4192550
KH
2200
2201 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
2202 {
2203 /* Relative composition with or without
2204 alternate chars. */
329bed06
GM
2205 left = (leftmost + rightmost - width) / 2;
2206 btm = - descent + boff;
b4192550
KH
2207 if (font_info && font_info->relative_compose
2208 && (! CHAR_TABLE_P (Vignore_relative_composition)
2209 || NILP (Faref (Vignore_relative_composition,
2210 make_number (ch)))))
2211 {
2212
329bed06 2213 if (- descent >= font_info->relative_compose)
b4192550
KH
2214 /* One extra pixel between two glyphs. */
2215 btm = highest + 1;
329bed06 2216 else if (ascent <= 0)
b4192550 2217 /* One extra pixel between two glyphs. */
329bed06 2218 btm = lowest - 1 - ascent - descent;
b4192550
KH
2219 }
2220 }
2221 else
2222 {
2223 /* A composition rule is specified by an integer
2224 value that encodes global and new reference
2225 points (GREF and NREF). GREF and NREF are
2226 specified by numbers as below:
2227
2228 0---1---2 -- ascent
2229 | |
2230 | |
2231 | |
2232 9--10--11 -- center
2233 | |
2234 ---3---4---5--- baseline
2235 | |
2236 6---7---8 -- descent
2237 */
2238 int rule = COMPOSITION_RULE (cmp, i);
2239 int gref, nref, grefx, grefy, nrefx, nrefy;
2240
2241 COMPOSITION_DECODE_RULE (rule, gref, nref);
2242 grefx = gref % 3, nrefx = nref % 3;
2243 grefy = gref / 3, nrefy = nref / 3;
2244
2245 left = (leftmost
2246 + grefx * (rightmost - leftmost) / 2
329bed06 2247 - nrefx * width / 2);
b4192550
KH
2248 btm = ((grefy == 0 ? highest
2249 : grefy == 1 ? 0
2250 : grefy == 2 ? lowest
2251 : (highest + lowest) / 2)
329bed06
GM
2252 - (nrefy == 0 ? ascent + descent
2253 : nrefy == 1 ? descent - boff
b4192550 2254 : nrefy == 2 ? 0
329bed06 2255 : (ascent + descent) / 2));
b4192550
KH
2256 }
2257
2258 cmp->offsets[i * 2] = left;
329bed06 2259 cmp->offsets[i * 2 + 1] = btm + descent;
b4192550
KH
2260
2261 /* Update the bounding box of the overall glyphs. */
329bed06
GM
2262 right = left + width;
2263 top = btm + descent + ascent;
b4192550
KH
2264 if (left < leftmost)
2265 leftmost = left;
2266 if (right > rightmost)
2267 rightmost = right;
2268 if (top > highest)
2269 highest = top;
2270 if (btm < lowest)
2271 lowest = btm;
2272 }
2273
2274 /* If there are glyphs whose x-offsets are negative,
2275 shift all glyphs to the right and make all x-offsets
2276 non-negative. */
2277 if (leftmost < 0)
2278 {
2279 for (i = 0; i < cmp->glyph_len; i++)
2280 cmp->offsets[i * 2] -= leftmost;
2281 rightmost -= leftmost;
2282 }
2283
2284 cmp->pixel_width = rightmost;
2285 cmp->ascent = highest;
2286 cmp->descent = - lowest;
2287 if (cmp->ascent < font_ascent)
2288 cmp->ascent = font_ascent;
2289 if (cmp->descent < font_descent)
2290 cmp->descent = font_descent;
2291 }
2292
2293 it->pixel_width = cmp->pixel_width;
2294 it->ascent = it->phys_ascent = cmp->ascent;
2295 it->descent = it->phys_descent = cmp->descent;
2296
2297 if (face->box != FACE_NO_BOX)
2298 {
2299 int thick = face->box_line_width;
ea2ba0d4
KH
2300
2301 if (thick > 0)
2302 {
2303 it->ascent += thick;
2304 it->descent += thick;
2305 }
2306 else
2307 thick = - thick;
b4192550
KH
2308
2309 if (it->start_of_box_run_p)
2310 it->pixel_width += thick;
2311 if (it->end_of_box_run_p)
2312 it->pixel_width += thick;
2313 }
2314
2315 /* If face has an overline, add the height of the overline
2316 (1 pixel) and a 1 pixel margin to the character height. */
2317 if (face->overline_p)
2318 it->ascent += 2;
2319
2320 take_vertical_position_into_account (it);
2321
2322 if (it->glyph_row)
2323 x_append_composite_glyph (it);
2324 }
06a2c219
GM
2325 else if (it->what == IT_IMAGE)
2326 x_produce_image_glyph (it);
2327 else if (it->what == IT_STRETCH)
2328 x_produce_stretch_glyph (it);
2329
3017fdd1
GM
2330 /* Accumulate dimensions. Note: can't assume that it->descent > 0
2331 because this isn't true for images with `:ascent 100'. */
2332 xassert (it->ascent >= 0 && it->descent >= 0);
06a2c219
GM
2333 if (it->area == TEXT_AREA)
2334 it->current_x += it->pixel_width;
66ac4b0e 2335
d365f5bb
GM
2336 it->descent += it->extra_line_spacing;
2337
06a2c219
GM
2338 it->max_ascent = max (it->max_ascent, it->ascent);
2339 it->max_descent = max (it->max_descent, it->descent);
66ac4b0e
GM
2340 it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
2341 it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
06a2c219
GM
2342}
2343
2344
2345/* Estimate the pixel height of the mode or top line on frame F.
2346 FACE_ID specifies what line's height to estimate. */
2347
2348int
2349x_estimate_mode_line_height (f, face_id)
2350 struct frame *f;
2351 enum face_id face_id;
2352{
43281ee3 2353 int height = FONT_HEIGHT (FRAME_FONT (f));
06a2c219
GM
2354
2355 /* This function is called so early when Emacs starts that the face
2356 cache and mode line face are not yet initialized. */
2357 if (FRAME_FACE_CACHE (f))
2358 {
2359 struct face *face = FACE_FROM_ID (f, face_id);
2360 if (face)
43281ee3
GM
2361 {
2362 if (face->font)
2363 height = FONT_HEIGHT (face->font);
ea2ba0d4
KH
2364 if (face->box_line_width > 0)
2365 height += 2 * face->box_line_width;
43281ee3 2366 }
06a2c219
GM
2367 }
2368
2369 return height;
2370}
2371
2372\f
2373/***********************************************************************
2374 Glyph display
2375 ***********************************************************************/
2376
2377/* A sequence of glyphs to be drawn in the same face.
2378
2379 This data structure is not really completely X specific, so it
2380 could possibly, at least partially, be useful for other systems. It
2381 is currently not part of the external redisplay interface because
2382 it's not clear what other systems will need. */
2383
2384struct glyph_string
2385{
2386 /* X-origin of the string. */
2387 int x;
2388
2389 /* Y-origin and y-position of the base line of this string. */
2390 int y, ybase;
2391
2392 /* The width of the string, not including a face extension. */
2393 int width;
2394
2395 /* The width of the string, including a face extension. */
2396 int background_width;
2397
2398 /* The height of this string. This is the height of the line this
2399 string is drawn in, and can be different from the height of the
2400 font the string is drawn in. */
2401 int height;
2402
2403 /* Number of pixels this string overwrites in front of its x-origin.
2404 This number is zero if the string has an lbearing >= 0; it is
2405 -lbearing, if the string has an lbearing < 0. */
2406 int left_overhang;
2407
2408 /* Number of pixels this string overwrites past its right-most
2409 nominal x-position, i.e. x + width. Zero if the string's
2410 rbearing is <= its nominal width, rbearing - width otherwise. */
2411 int right_overhang;
2412
2413 /* The frame on which the glyph string is drawn. */
2414 struct frame *f;
2415
2416 /* The window on which the glyph string is drawn. */
2417 struct window *w;
2418
2419 /* X display and window for convenience. */
2420 Display *display;
2421 Window window;
2422
2423 /* The glyph row for which this string was built. It determines the
2424 y-origin and height of the string. */
2425 struct glyph_row *row;
2426
2427 /* The area within row. */
2428 enum glyph_row_area area;
2429
2430 /* Characters to be drawn, and number of characters. */
2431 XChar2b *char2b;
2432 int nchars;
2433
06a2c219
GM
2434 /* A face-override for drawing cursors, mouse face and similar. */
2435 enum draw_glyphs_face hl;
2436
2437 /* Face in which this string is to be drawn. */
2438 struct face *face;
2439
2440 /* Font in which this string is to be drawn. */
2441 XFontStruct *font;
2442
2443 /* Font info for this string. */
2444 struct font_info *font_info;
2445
b4192550
KH
2446 /* Non-null means this string describes (part of) a composition.
2447 All characters from char2b are drawn composed. */
2448 struct composition *cmp;
06a2c219
GM
2449
2450 /* Index of this glyph string's first character in the glyph
b4192550
KH
2451 definition of CMP. If this is zero, this glyph string describes
2452 the first character of a composition. */
06a2c219
GM
2453 int gidx;
2454
2455 /* 1 means this glyph strings face has to be drawn to the right end
2456 of the window's drawing area. */
2457 unsigned extends_to_end_of_line_p : 1;
2458
2459 /* 1 means the background of this string has been drawn. */
2460 unsigned background_filled_p : 1;
2461
2462 /* 1 means glyph string must be drawn with 16-bit functions. */
2463 unsigned two_byte_p : 1;
2464
2465 /* 1 means that the original font determined for drawing this glyph
2466 string could not be loaded. The member `font' has been set to
2467 the frame's default font in this case. */
2468 unsigned font_not_found_p : 1;
2469
2470 /* 1 means that the face in which this glyph string is drawn has a
2471 stipple pattern. */
2472 unsigned stippled_p : 1;
2473
66ac4b0e
GM
2474 /* 1 means only the foreground of this glyph string must be drawn,
2475 and we should use the physical height of the line this glyph
2476 string appears in as clip rect. */
2477 unsigned for_overlaps_p : 1;
2478
06a2c219
GM
2479 /* The GC to use for drawing this glyph string. */
2480 GC gc;
2481
2482 /* A pointer to the first glyph in the string. This glyph
2483 corresponds to char2b[0]. Needed to draw rectangles if
2484 font_not_found_p is 1. */
2485 struct glyph *first_glyph;
2486
2487 /* Image, if any. */
2488 struct image *img;
2489
2490 struct glyph_string *next, *prev;
2491};
2492
2493
57ac7c81 2494#if 1
06a2c219
GM
2495
2496static void
2497x_dump_glyph_string (s)
2498 struct glyph_string *s;
2499{
2500 fprintf (stderr, "glyph string\n");
2501 fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
2502 s->x, s->y, s->width, s->height);
2503 fprintf (stderr, " ybase = %d\n", s->ybase);
2504 fprintf (stderr, " hl = %d\n", s->hl);
2505 fprintf (stderr, " left overhang = %d, right = %d\n",
2506 s->left_overhang, s->right_overhang);
2507 fprintf (stderr, " nchars = %d\n", s->nchars);
2508 fprintf (stderr, " extends to end of line = %d\n",
2509 s->extends_to_end_of_line_p);
2510 fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
2511 fprintf (stderr, " bg width = %d\n", s->background_width);
2512}
2513
2514#endif /* GLYPH_DEBUG */
2515
2516
2517
2518static void x_append_glyph_string_lists P_ ((struct glyph_string **,
2519 struct glyph_string **,
2520 struct glyph_string *,
2521 struct glyph_string *));
2522static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
2523 struct glyph_string **,
2524 struct glyph_string *,
2525 struct glyph_string *));
2526static void x_append_glyph_string P_ ((struct glyph_string **,
2527 struct glyph_string **,
2528 struct glyph_string *));
2529static int x_left_overwritten P_ ((struct glyph_string *));
2530static int x_left_overwriting P_ ((struct glyph_string *));
2531static int x_right_overwritten P_ ((struct glyph_string *));
2532static int x_right_overwriting P_ ((struct glyph_string *));
66ac4b0e
GM
2533static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
2534 int));
06a2c219
GM
2535static void x_init_glyph_string P_ ((struct glyph_string *,
2536 XChar2b *, struct window *,
2537 struct glyph_row *,
2538 enum glyph_row_area, int,
2539 enum draw_glyphs_face));
2540static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
2541 enum glyph_row_area, int, int,
66ac4b0e 2542 enum draw_glyphs_face, int *, int *, int));
06a2c219
GM
2543static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
2544static void x_set_glyph_string_gc P_ ((struct glyph_string *));
2545static void x_draw_glyph_string_background P_ ((struct glyph_string *,
2546 int));
2547static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
b4192550 2548static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
06a2c219
GM
2549static void x_draw_glyph_string_box P_ ((struct glyph_string *));
2550static void x_draw_glyph_string P_ ((struct glyph_string *));
2551static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
2552static void x_set_cursor_gc P_ ((struct glyph_string *));
2553static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
2554static void x_set_mouse_face_gc P_ ((struct glyph_string *));
2555static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
2556 int *, int *));
2557static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
2558static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
68c45bf0 2559 unsigned long *, double, int));
06a2c219 2560static void x_setup_relief_color P_ ((struct frame *, struct relief *,
68c45bf0 2561 double, int, unsigned long));
06a2c219
GM
2562static void x_setup_relief_colors P_ ((struct glyph_string *));
2563static void x_draw_image_glyph_string P_ ((struct glyph_string *));
2564static void x_draw_image_relief P_ ((struct glyph_string *));
2565static void x_draw_image_foreground P_ ((struct glyph_string *));
2566static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
2567static void x_fill_image_glyph_string P_ ((struct glyph_string *));
2568static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
2569 int, int, int));
2570static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
2571 int, int, int, int, XRectangle *));
2572static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
2573 int, int, int, XRectangle *));
66ac4b0e
GM
2574static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
2575 enum glyph_row_area));
209f68d9
GM
2576static int x_fill_stretch_glyph_string P_ ((struct glyph_string *,
2577 struct glyph_row *,
2578 enum glyph_row_area, int, int));
06a2c219 2579
163dcff3
GM
2580#if GLYPH_DEBUG
2581static void x_check_font P_ ((struct frame *, XFontStruct *));
2582#endif
2583
06a2c219 2584
06a2c219
GM
2585/* Append the list of glyph strings with head H and tail T to the list
2586 with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
2587
2588static INLINE void
2589x_append_glyph_string_lists (head, tail, h, t)
2590 struct glyph_string **head, **tail;
2591 struct glyph_string *h, *t;
2592{
2593 if (h)
2594 {
2595 if (*head)
2596 (*tail)->next = h;
2597 else
2598 *head = h;
2599 h->prev = *tail;
2600 *tail = t;
2601 }
2602}
2603
2604
2605/* Prepend the list of glyph strings with head H and tail T to the
2606 list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
2607 result. */
2608
2609static INLINE void
2610x_prepend_glyph_string_lists (head, tail, h, t)
2611 struct glyph_string **head, **tail;
2612 struct glyph_string *h, *t;
2613{
2614 if (h)
2615 {
2616 if (*head)
2617 (*head)->prev = t;
2618 else
2619 *tail = t;
2620 t->next = *head;
2621 *head = h;
2622 }
2623}
2624
2625
2626/* Append glyph string S to the list with head *HEAD and tail *TAIL.
2627 Set *HEAD and *TAIL to the resulting list. */
2628
2629static INLINE void
2630x_append_glyph_string (head, tail, s)
2631 struct glyph_string **head, **tail;
2632 struct glyph_string *s;
2633{
2634 s->next = s->prev = NULL;
2635 x_append_glyph_string_lists (head, tail, s, s);
2636}
2637
2638
2639/* Set S->gc to a suitable GC for drawing glyph string S in cursor
2640 face. */
2641
2642static void
2643x_set_cursor_gc (s)
2644 struct glyph_string *s;
2645{
2646 if (s->font == FRAME_FONT (s->f)
2647 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
2648 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
b4192550 2649 && !s->cmp)
06a2c219
GM
2650 s->gc = s->f->output_data.x->cursor_gc;
2651 else
2652 {
2653 /* Cursor on non-default face: must merge. */
2654 XGCValues xgcv;
2655 unsigned long mask;
2656
2657 xgcv.background = s->f->output_data.x->cursor_pixel;
2658 xgcv.foreground = s->face->background;
2659
2660 /* If the glyph would be invisible, try a different foreground. */
2661 if (xgcv.foreground == xgcv.background)
2662 xgcv.foreground = s->face->foreground;
2663 if (xgcv.foreground == xgcv.background)
2664 xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
2665 if (xgcv.foreground == xgcv.background)
2666 xgcv.foreground = s->face->foreground;
2667
2668 /* Make sure the cursor is distinct from text in this face. */
2669 if (xgcv.background == s->face->background
2670 && xgcv.foreground == s->face->foreground)
2671 {
2672 xgcv.background = s->face->foreground;
2673 xgcv.foreground = s->face->background;
2674 }
2675
2676 IF_DEBUG (x_check_font (s->f, s->font));
2677 xgcv.font = s->font->fid;
2678 xgcv.graphics_exposures = False;
2679 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2680
2681 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2682 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2683 mask, &xgcv);
2684 else
2685 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2686 = XCreateGC (s->display, s->window, mask, &xgcv);
2687
2688 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2689 }
2690}
2691
2692
2693/* Set up S->gc of glyph string S for drawing text in mouse face. */
2694
2695static void
2696x_set_mouse_face_gc (s)
2697 struct glyph_string *s;
2698{
2699 int face_id;
ee569018 2700 struct face *face;
06a2c219 2701
e4ded23c 2702 /* What face has to be used last for the mouse face? */
06a2c219 2703 face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
ee569018 2704 face = FACE_FROM_ID (s->f, face_id);
e4ded23c
GM
2705 if (face == NULL)
2706 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2707
033e3e18
GM
2708 if (s->first_glyph->type == CHAR_GLYPH)
2709 face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
2710 else
2711 face_id = FACE_FOR_CHAR (s->f, face, 0);
06a2c219
GM
2712 s->face = FACE_FROM_ID (s->f, face_id);
2713 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2714
2715 /* If font in this face is same as S->font, use it. */
2716 if (s->font == s->face->font)
2717 s->gc = s->face->gc;
2718 else
2719 {
2720 /* Otherwise construct scratch_cursor_gc with values from FACE
2721 but font FONT. */
2722 XGCValues xgcv;
2723 unsigned long mask;
2724
2725 xgcv.background = s->face->background;
2726 xgcv.foreground = s->face->foreground;
2727 IF_DEBUG (x_check_font (s->f, s->font));
2728 xgcv.font = s->font->fid;
2729 xgcv.graphics_exposures = False;
2730 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
2731
2732 if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
2733 XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
2734 mask, &xgcv);
2735 else
2736 FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
2737 = XCreateGC (s->display, s->window, mask, &xgcv);
2738
2739 s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
2740 }
2741
2742 xassert (s->gc != 0);
2743}
2744
2745
2746/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
2747 Faces to use in the mode line have already been computed when the
2748 matrix was built, so there isn't much to do, here. */
2749
2750static INLINE void
2751x_set_mode_line_face_gc (s)
2752 struct glyph_string *s;
2753{
2754 s->gc = s->face->gc;
06a2c219
GM
2755}
2756
2757
2758/* Set S->gc of glyph string S for drawing that glyph string. Set
2759 S->stippled_p to a non-zero value if the face of S has a stipple
2760 pattern. */
2761
2762static INLINE void
2763x_set_glyph_string_gc (s)
2764 struct glyph_string *s;
2765{
209f68d9
GM
2766 PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
2767
06a2c219
GM
2768 if (s->hl == DRAW_NORMAL_TEXT)
2769 {
2770 s->gc = s->face->gc;
2771 s->stippled_p = s->face->stipple != 0;
2772 }
2773 else if (s->hl == DRAW_INVERSE_VIDEO)
2774 {
2775 x_set_mode_line_face_gc (s);
2776 s->stippled_p = s->face->stipple != 0;
2777 }
2778 else if (s->hl == DRAW_CURSOR)
2779 {
2780 x_set_cursor_gc (s);
2781 s->stippled_p = 0;
2782 }
2783 else if (s->hl == DRAW_MOUSE_FACE)
2784 {
2785 x_set_mouse_face_gc (s);
2786 s->stippled_p = s->face->stipple != 0;
2787 }
2788 else if (s->hl == DRAW_IMAGE_RAISED
2789 || s->hl == DRAW_IMAGE_SUNKEN)
2790 {
2791 s->gc = s->face->gc;
2792 s->stippled_p = s->face->stipple != 0;
2793 }
2794 else
2795 {
2796 s->gc = s->face->gc;
2797 s->stippled_p = s->face->stipple != 0;
2798 }
2799
2800 /* GC must have been set. */
2801 xassert (s->gc != 0);
2802}
2803
2804
2805/* Return in *R the clipping rectangle for glyph string S. */
2806
2807static void
2808x_get_glyph_string_clip_rect (s, r)
2809 struct glyph_string *s;
2810 XRectangle *r;
2811{
2812 if (s->row->full_width_p)
2813 {
2814 /* Draw full-width. X coordinates are relative to S->w->left. */
1da3fd71
GM
2815 int canon_x = CANON_X_UNIT (s->f);
2816
2817 r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
2818 r->width = XFASTINT (s->w->width) * canon_x;
06a2c219
GM
2819
2820 if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
2821 {
1da3fd71 2822 int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
06a2c219
GM
2823 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
2824 r->x -= width;
2825 }
2826
b9432a85 2827 r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
1da3fd71 2828
06a2c219
GM
2829 /* Unless displaying a mode or menu bar line, which are always
2830 fully visible, clip to the visible part of the row. */
2831 if (s->w->pseudo_window_p)
2832 r->height = s->row->visible_height;
2833 else
2834 r->height = s->height;
2835 }
2836 else
2837 {
2838 /* This is a text line that may be partially visible. */
2839 r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
2840 r->width = window_box_width (s->w, s->area);
2841 r->height = s->row->visible_height;
2842 }
2843
2844 /* Don't use S->y for clipping because it doesn't take partially
2845 visible lines into account. For example, it can be negative for
2846 partially visible lines at the top of a window. */
2847 if (!s->row->full_width_p
2848 && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
045dee35 2849 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
06a2c219
GM
2850 else
2851 r->y = max (0, s->row->y);
06a2c219 2852
9ea173e8 2853 /* If drawing a tool-bar window, draw it over the internal border
06a2c219 2854 at the top of the window. */
9ea173e8 2855 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219 2856 r->y -= s->f->output_data.x->internal_border_width;
66ac4b0e
GM
2857
2858 /* If S draws overlapping rows, it's sufficient to use the top and
2859 bottom of the window for clipping because this glyph string
2860 intentionally draws over other lines. */
2861 if (s->for_overlaps_p)
2862 {
045dee35 2863 r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
66ac4b0e
GM
2864 r->height = window_text_bottom_y (s->w) - r->y;
2865 }
2866
2867 r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
06a2c219
GM
2868}
2869
2870
2871/* Set clipping for output of glyph string S. S may be part of a mode
2872 line or menu if we don't have X toolkit support. */
2873
2874static INLINE void
2875x_set_glyph_string_clipping (s)
2876 struct glyph_string *s;
2877{
2878 XRectangle r;
2879 x_get_glyph_string_clip_rect (s, &r);
2880 XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
2881}
2882
2883
2884/* Compute left and right overhang of glyph string S. If S is a glyph
b4192550 2885 string for a composition, assume overhangs don't exist. */
06a2c219
GM
2886
2887static INLINE void
2888x_compute_glyph_string_overhangs (s)
2889 struct glyph_string *s;
2890{
b4192550 2891 if (s->cmp == NULL
06a2c219
GM
2892 && s->first_glyph->type == CHAR_GLYPH)
2893 {
2894 XCharStruct cs;
2895 int direction, font_ascent, font_descent;
2896 XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
2897 &font_ascent, &font_descent, &cs);
2898 s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
2899 s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
2900 }
2901}
2902
2903
2904/* Compute overhangs and x-positions for glyph string S and its
2905 predecessors, or successors. X is the starting x-position for S.
2906 BACKWARD_P non-zero means process predecessors. */
2907
2908static void
2909x_compute_overhangs_and_x (s, x, backward_p)
2910 struct glyph_string *s;
2911 int x;
2912 int backward_p;
2913{
2914 if (backward_p)
2915 {
2916 while (s)
2917 {
2918 x_compute_glyph_string_overhangs (s);
2919 x -= s->width;
2920 s->x = x;
2921 s = s->prev;
2922 }
2923 }
2924 else
2925 {
2926 while (s)
2927 {
2928 x_compute_glyph_string_overhangs (s);
2929 s->x = x;
2930 x += s->width;
2931 s = s->next;
2932 }
2933 }
2934}
2935
2936
2937/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
b4192550
KH
2938 frame F. Overhangs of glyphs other than type CHAR_GLYPH are
2939 assumed to be zero. */
06a2c219
GM
2940
2941static void
2942x_get_glyph_overhangs (glyph, f, left, right)
2943 struct glyph *glyph;
2944 struct frame *f;
2945 int *left, *right;
2946{
06a2c219
GM
2947 *left = *right = 0;
2948
b4192550 2949 if (glyph->type == CHAR_GLYPH)
06a2c219
GM
2950 {
2951 XFontStruct *font;
2952 struct face *face;
2953 struct font_info *font_info;
2954 XChar2b char2b;
ee569018
KH
2955 XCharStruct *pcm;
2956
2957 face = x_get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
06a2c219
GM
2958 font = face->font;
2959 font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
ee569018
KH
2960 if (font
2961 && (pcm = x_per_char_metric (font, &char2b)))
06a2c219 2962 {
06a2c219
GM
2963 if (pcm->rbearing > pcm->width)
2964 *right = pcm->rbearing - pcm->width;
2965 if (pcm->lbearing < 0)
2966 *left = -pcm->lbearing;
2967 }
2968 }
2969}
2970
2971
2972/* Return the index of the first glyph preceding glyph string S that
2973 is overwritten by S because of S's left overhang. Value is -1
2974 if no glyphs are overwritten. */
2975
2976static int
2977x_left_overwritten (s)
2978 struct glyph_string *s;
2979{
2980 int k;
2981
2982 if (s->left_overhang)
2983 {
2984 int x = 0, i;
2985 struct glyph *glyphs = s->row->glyphs[s->area];
2986 int first = s->first_glyph - glyphs;
2987
2988 for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
2989 x -= glyphs[i].pixel_width;
2990
2991 k = i + 1;
2992 }
2993 else
2994 k = -1;
2995
2996 return k;
2997}
2998
2999
3000/* Return the index of the first glyph preceding glyph string S that
3001 is overwriting S because of its right overhang. Value is -1 if no
3002 glyph in front of S overwrites S. */
3003
3004static int
3005x_left_overwriting (s)
3006 struct glyph_string *s;
3007{
3008 int i, k, x;
3009 struct glyph *glyphs = s->row->glyphs[s->area];
3010 int first = s->first_glyph - glyphs;
3011
3012 k = -1;
3013 x = 0;
3014 for (i = first - 1; i >= 0; --i)
3015 {
3016 int left, right;
3017 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3018 if (x + right > 0)
3019 k = i;
3020 x -= glyphs[i].pixel_width;
3021 }
3022
3023 return k;
3024}
3025
3026
3027/* Return the index of the last glyph following glyph string S that is
3028 not overwritten by S because of S's right overhang. Value is -1 if
3029 no such glyph is found. */
3030
3031static int
3032x_right_overwritten (s)
3033 struct glyph_string *s;
3034{
3035 int k = -1;
3036
3037 if (s->right_overhang)
3038 {
3039 int x = 0, i;
3040 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3041 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3042 int end = s->row->used[s->area];
3043
3044 for (i = first; i < end && s->right_overhang > x; ++i)
3045 x += glyphs[i].pixel_width;
3046
3047 k = i;
3048 }
3049
3050 return k;
3051}
3052
3053
3054/* Return the index of the last glyph following glyph string S that
3055 overwrites S because of its left overhang. Value is negative
3056 if no such glyph is found. */
3057
3058static int
3059x_right_overwriting (s)
3060 struct glyph_string *s;
3061{
3062 int i, k, x;
3063 int end = s->row->used[s->area];
3064 struct glyph *glyphs = s->row->glyphs[s->area];
b4192550 3065 int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
06a2c219
GM
3066
3067 k = -1;
3068 x = 0;
3069 for (i = first; i < end; ++i)
3070 {
3071 int left, right;
3072 x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
3073 if (x - left < 0)
3074 k = i;
3075 x += glyphs[i].pixel_width;
3076 }
3077
3078 return k;
3079}
3080
3081
3082/* Fill rectangle X, Y, W, H with background color of glyph string S. */
3083
3084static INLINE void
3085x_clear_glyph_string_rect (s, x, y, w, h)
3086 struct glyph_string *s;
3087 int x, y, w, h;
3088{
3089 XGCValues xgcv;
3090 XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
3091 XSetForeground (s->display, s->gc, xgcv.background);
3092 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
3093 XSetForeground (s->display, s->gc, xgcv.foreground);
3094}
3095
3096
3097/* Draw the background of glyph_string S. If S->background_filled_p
3098 is non-zero don't draw it. FORCE_P non-zero means draw the
3099 background even if it wouldn't be drawn normally. This is used
b4192550
KH
3100 when a string preceding S draws into the background of S, or S
3101 contains the first component of a composition. */
06a2c219
GM
3102
3103static void
3104x_draw_glyph_string_background (s, force_p)
3105 struct glyph_string *s;
3106 int force_p;
3107{
3108 /* Nothing to do if background has already been drawn or if it
3109 shouldn't be drawn in the first place. */
3110 if (!s->background_filled_p)
3111 {
ea2ba0d4
KH
3112 int box_line_width = max (s->face->box_line_width, 0);
3113
b4192550 3114 if (s->stippled_p)
06a2c219
GM
3115 {
3116 /* Fill background with a stipple pattern. */
3117 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
3118 XFillRectangle (s->display, s->window, s->gc, s->x,
ea2ba0d4 3119 s->y + box_line_width,
06a2c219 3120 s->background_width,
ea2ba0d4 3121 s->height - 2 * box_line_width);
06a2c219
GM
3122 XSetFillStyle (s->display, s->gc, FillSolid);
3123 s->background_filled_p = 1;
3124 }
ea2ba0d4 3125 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
06a2c219
GM
3126 || s->font_not_found_p
3127 || s->extends_to_end_of_line_p
06a2c219
GM
3128 || force_p)
3129 {
ea2ba0d4 3130 x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
06a2c219 3131 s->background_width,
ea2ba0d4 3132 s->height - 2 * box_line_width);
06a2c219
GM
3133 s->background_filled_p = 1;
3134 }
3135 }
3136}
3137
3138
3139/* Draw the foreground of glyph string S. */
3140
3141static void
3142x_draw_glyph_string_foreground (s)
3143 struct glyph_string *s;
3144{
3145 int i, x;
3146
3147 /* If first glyph of S has a left box line, start drawing the text
3148 of S to the right of that box line. */
3149 if (s->face->box != FACE_NO_BOX
3150 && s->first_glyph->left_box_line_p)
ea2ba0d4 3151 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
3152 else
3153 x = s->x;
3154
b4192550
KH
3155 /* Draw characters of S as rectangles if S's font could not be
3156 loaded. */
3157 if (s->font_not_found_p)
06a2c219 3158 {
b4192550 3159 for (i = 0; i < s->nchars; ++i)
06a2c219 3160 {
b4192550
KH
3161 struct glyph *g = s->first_glyph + i;
3162 XDrawRectangle (s->display, s->window,
3163 s->gc, x, s->y, g->pixel_width - 1,
3164 s->height - 1);
3165 x += g->pixel_width;
06a2c219
GM
3166 }
3167 }
3168 else
3169 {
b4192550
KH
3170 char *char1b = (char *) s->char2b;
3171 int boff = s->font_info->baseline_offset;
06a2c219 3172
b4192550
KH
3173 if (s->font_info->vertical_centering)
3174 boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
3175
3176 /* If we can use 8-bit functions, condense S->char2b. */
3177 if (!s->two_byte_p)
3178 for (i = 0; i < s->nchars; ++i)
3179 char1b[i] = s->char2b[i].byte2;
3180
3181 /* Draw text with XDrawString if background has already been
3182 filled. Otherwise, use XDrawImageString. (Note that
3183 XDrawImageString is usually faster than XDrawString.) Always
3184 use XDrawImageString when drawing the cursor so that there is
3185 no chance that characters under a box cursor are invisible. */
3186 if (s->for_overlaps_p
3187 || (s->background_filled_p && s->hl != DRAW_CURSOR))
3188 {
3189 /* Draw characters with 16-bit or 8-bit functions. */
3190 if (s->two_byte_p)
3191 XDrawString16 (s->display, s->window, s->gc, x,
3192 s->ybase - boff, s->char2b, s->nchars);
3193 else
3194 XDrawString (s->display, s->window, s->gc, x,
3195 s->ybase - boff, char1b, s->nchars);
3196 }
06a2c219
GM
3197 else
3198 {
b4192550
KH
3199 if (s->two_byte_p)
3200 XDrawImageString16 (s->display, s->window, s->gc, x,
3201 s->ybase - boff, s->char2b, s->nchars);
06a2c219 3202 else
b4192550
KH
3203 XDrawImageString (s->display, s->window, s->gc, x,
3204 s->ybase - boff, char1b, s->nchars);
3205 }
3206 }
3207}
06a2c219 3208
b4192550 3209/* Draw the foreground of composite glyph string S. */
06a2c219 3210
b4192550
KH
3211static void
3212x_draw_composite_glyph_string_foreground (s)
3213 struct glyph_string *s;
3214{
3215 int i, x;
06a2c219 3216
b4192550
KH
3217 /* If first glyph of S has a left box line, start drawing the text
3218 of S to the right of that box line. */
3219 if (s->face->box != FACE_NO_BOX
3220 && s->first_glyph->left_box_line_p)
ea2ba0d4 3221 x = s->x + abs (s->face->box_line_width);
b4192550
KH
3222 else
3223 x = s->x;
06a2c219 3224
b4192550
KH
3225 /* S is a glyph string for a composition. S->gidx is the index of
3226 the first character drawn for glyphs of this composition.
3227 S->gidx == 0 means we are drawing the very first character of
3228 this composition. */
06a2c219 3229
b4192550
KH
3230 /* Draw a rectangle for the composition if the font for the very
3231 first character of the composition could not be loaded. */
3232 if (s->font_not_found_p)
3233 {
3234 if (s->gidx == 0)
3235 XDrawRectangle (s->display, s->window, s->gc, x, s->y,
3236 s->width - 1, s->height - 1);
3237 }
3238 else
3239 {
3240 for (i = 0; i < s->nchars; i++, ++s->gidx)
3241 XDrawString16 (s->display, s->window, s->gc,
3242 x + s->cmp->offsets[s->gidx * 2],
3243 s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
3244 s->char2b + i, 1);
06a2c219
GM
3245 }
3246}
3247
3248
80c32bcc
GM
3249#ifdef USE_X_TOOLKIT
3250
3e71d8f2 3251static struct frame *x_frame_of_widget P_ ((Widget));
651f03b6
GM
3252static Boolean cvt_string_to_pixel P_ ((Display *, XrmValue *, Cardinal *,
3253 XrmValue *, XrmValue *, XtPointer *));
3254static void cvt_pixel_dtor P_ ((XtAppContext, XrmValue *, XtPointer,
3255 XrmValue *, Cardinal *));
80c32bcc 3256
3e71d8f2
GM
3257
3258/* Return the frame on which widget WIDGET is used.. Abort if frame
3259 cannot be determined. */
3260
e851c833 3261static struct frame *
3e71d8f2 3262x_frame_of_widget (widget)
80c32bcc 3263 Widget widget;
80c32bcc 3264{
80c32bcc 3265 struct x_display_info *dpyinfo;
5c187dee 3266 Lisp_Object tail;
3e71d8f2
GM
3267 struct frame *f;
3268
80c32bcc
GM
3269 dpyinfo = x_display_info_for_display (XtDisplay (widget));
3270
3271 /* Find the top-level shell of the widget. Note that this function
3272 can be called when the widget is not yet realized, so XtWindow
3273 (widget) == 0. That's the reason we can't simply use
3274 x_any_window_to_frame. */
3275 while (!XtIsTopLevelShell (widget))
3276 widget = XtParent (widget);
3277
3278 /* Look for a frame with that top-level widget. Allocate the color
3279 on that frame to get the right gamma correction value. */
3280 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
3281 if (GC_FRAMEP (XCAR (tail))
3282 && (f = XFRAME (XCAR (tail)),
3283 (f->output_data.nothing != 1
3284 && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
3285 && f->output_data.x->widget == widget)
3e71d8f2 3286 return f;
80c32bcc
GM
3287
3288 abort ();
3289}
3290
3e71d8f2
GM
3291
3292/* Allocate the color COLOR->pixel on the screen and display of
3293 widget WIDGET in colormap CMAP. If an exact match cannot be
3294 allocated, try the nearest color available. Value is non-zero
3295 if successful. This is called from lwlib. */
3296
3297int
3298x_alloc_nearest_color_for_widget (widget, cmap, color)
3299 Widget widget;
3300 Colormap cmap;
3301 XColor *color;
3302{
3303 struct frame *f = x_frame_of_widget (widget);
3304 return x_alloc_nearest_color (f, cmap, color);
3305}
3306
3307
46d516e5
MB
3308/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3309 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3310 If this produces the same color as PIXEL, try a color where all RGB
3311 values have DELTA added. Return the allocated color in *PIXEL.
3312 DISPLAY is the X display, CMAP is the colormap to operate on.
3313 Value is non-zero if successful. */
3314
3315int
3316x_alloc_lighter_color_for_widget (widget, display, cmap, pixel, factor, delta)
3317 Widget widget;
3318 Display *display;
3319 Colormap cmap;
3320 unsigned long *pixel;
3321 double factor;
3322 int delta;
3323{
3324 struct frame *f = x_frame_of_widget (widget);
3325 return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
3326}
3327
3328
651f03b6
GM
3329/* Structure specifying which arguments should be passed by Xt to
3330 cvt_string_to_pixel. We want the widget's screen and colormap. */
3331
3332static XtConvertArgRec cvt_string_to_pixel_args[] =
3333 {
3334 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.screen),
3335 sizeof (Screen *)},
3336 {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.colormap),
3337 sizeof (Colormap)}
3338 };
3339
3340
3341/* The address of this variable is returned by
3342 cvt_string_to_pixel. */
3343
3344static Pixel cvt_string_to_pixel_value;
3345
3346
3347/* Convert a color name to a pixel color.
3348
3349 DPY is the display we are working on.
3350
3351 ARGS is an array of *NARGS XrmValue structures holding additional
3352 information about the widget for which the conversion takes place.
3353 The contents of this array are determined by the specification
3354 in cvt_string_to_pixel_args.
3355
3356 FROM is a pointer to an XrmValue which points to the color name to
3357 convert. TO is an XrmValue in which to return the pixel color.
3358
3359 CLOSURE_RET is a pointer to user-data, in which we record if
3360 we allocated the color or not.
3361
3362 Value is True if successful, False otherwise. */
3363
3364static Boolean
3365cvt_string_to_pixel (dpy, args, nargs, from, to, closure_ret)
3366 Display *dpy;
3367 XrmValue *args;
3368 Cardinal *nargs;
3369 XrmValue *from, *to;
3370 XtPointer *closure_ret;
3371{
3372 Screen *screen;
3373 Colormap cmap;
3374 Pixel pixel;
3375 String color_name;
3376 XColor color;
3377
3378 if (*nargs != 2)
3379 {
3380 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3381 "wrongParameters", "cvt_string_to_pixel",
3382 "XtToolkitError",
3383 "Screen and colormap args required", NULL, NULL);
3384 return False;
3385 }
3386
3387 screen = *(Screen **) args[0].addr;
3388 cmap = *(Colormap *) args[1].addr;
3389 color_name = (String) from->addr;
3390
3391 if (strcmp (color_name, XtDefaultBackground) == 0)
3392 {
3393 *closure_ret = (XtPointer) False;
3394 pixel = WhitePixelOfScreen (screen);
3395 }
3396 else if (strcmp (color_name, XtDefaultForeground) == 0)
3397 {
3398 *closure_ret = (XtPointer) False;
3399 pixel = BlackPixelOfScreen (screen);
3400 }
3401 else if (XParseColor (dpy, cmap, color_name, &color)
3402 && x_alloc_nearest_color_1 (dpy, cmap, &color))
3403 {
3404 pixel = color.pixel;
3405 *closure_ret = (XtPointer) True;
3406 }
3407 else
3408 {
3409 String params[1];
3410 Cardinal nparams = 1;
3411
3412 params[0] = color_name;
3413 XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
3414 "badValue", "cvt_string_to_pixel",
3415 "XtToolkitError", "Invalid color `%s'",
3416 params, &nparams);
3417 return False;
3418 }
3419
3420 if (to->addr != NULL)
3421 {
3422 if (to->size < sizeof (Pixel))
3423 {
3424 to->size = sizeof (Pixel);
3425 return False;
3426 }
3427
3428 *(Pixel *) to->addr = pixel;
3429 }
3430 else
3431 {
3432 cvt_string_to_pixel_value = pixel;
3433 to->addr = (XtPointer) &cvt_string_to_pixel_value;
3434 }
3435
3436 to->size = sizeof (Pixel);
3437 return True;
3438}
3439
3440
3441/* Free a pixel color which was previously allocated via
3442 cvt_string_to_pixel. This is registered as the destructor
3443 for this type of resource via XtSetTypeConverter.
3444
3445 APP is the application context in which we work.
3446
3447 TO is a pointer to an XrmValue holding the color to free.
3448 CLOSURE is the value we stored in CLOSURE_RET for this color
3449 in cvt_string_to_pixel.
3450
3451 ARGS and NARGS are like for cvt_string_to_pixel. */
3452
3453static void
3454cvt_pixel_dtor (app, to, closure, args, nargs)
3455 XtAppContext app;
3456 XrmValuePtr to;
3457 XtPointer closure;
3458 XrmValuePtr args;
3459 Cardinal *nargs;
3460{
3461 if (*nargs != 2)
3462 {
3463 XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
3464 "XtToolkitError",
3465 "Screen and colormap arguments required",
3466 NULL, NULL);
3467 }
3468 else if (closure != NULL)
3469 {
3470 /* We did allocate the pixel, so free it. */
3471 Screen *screen = *(Screen **) args[0].addr;
3472 Colormap cmap = *(Colormap *) args[1].addr;
3473 x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
97762eb7 3474 (Pixel *) to->addr, 1);
651f03b6
GM
3475 }
3476}
3477
3478
80c32bcc
GM
3479#endif /* USE_X_TOOLKIT */
3480
3481
f04e1297 3482/* Value is an array of XColor structures for the contents of the
651f03b6 3483 color map of display DPY. Set *NCELLS to the size of the array.
f04e1297
GM
3484 Note that this probably shouldn't be called for large color maps,
3485 say a 24-bit TrueColor map. */
3486
3487static const XColor *
651f03b6
GM
3488x_color_cells (dpy, ncells)
3489 Display *dpy;
f04e1297
GM
3490 int *ncells;
3491{
651f03b6 3492 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
f04e1297
GM
3493
3494 if (dpyinfo->color_cells == NULL)
3495 {
651f03b6 3496 Screen *screen = dpyinfo->screen;
f04e1297
GM
3497 int i;
3498
3499 dpyinfo->ncolor_cells
651f03b6 3500 = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
f04e1297
GM
3501 dpyinfo->color_cells
3502 = (XColor *) xmalloc (dpyinfo->ncolor_cells
3503 * sizeof *dpyinfo->color_cells);
3504
3505 for (i = 0; i < dpyinfo->ncolor_cells; ++i)
3506 dpyinfo->color_cells[i].pixel = i;
3507
651f03b6 3508 XQueryColors (dpy, dpyinfo->cmap,
f04e1297
GM
3509 dpyinfo->color_cells, dpyinfo->ncolor_cells);
3510 }
3511
3512 *ncells = dpyinfo->ncolor_cells;
3513 return dpyinfo->color_cells;
3514}
3515
3516
3517/* On frame F, translate pixel colors to RGB values for the NCOLORS
3518 colors in COLORS. Use cached information, if available. */
3519
3520void
3521x_query_colors (f, colors, ncolors)
3522 struct frame *f;
3523 XColor *colors;
3524 int ncolors;
3525{
3526 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3527
3528 if (dpyinfo->color_cells)
3529 {
3530 int i;
3531 for (i = 0; i < ncolors; ++i)
3532 {
3533 unsigned long pixel = colors[i].pixel;
3534 xassert (pixel < dpyinfo->ncolor_cells);
3535 xassert (dpyinfo->color_cells[pixel].pixel == pixel);
3536 colors[i] = dpyinfo->color_cells[pixel];
3537 }
3538 }
3539 else
3540 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
3541}
3542
3543
3544/* On frame F, translate pixel color to RGB values for the color in
3545 COLOR. Use cached information, if available. */
3546
3547void
3548x_query_color (f, color)
3549 struct frame *f;
3550 XColor *color;
3551{
3552 x_query_colors (f, color, 1);
3553}
3554
3555
651f03b6
GM
3556/* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
3557 exact match can't be allocated, try the nearest color available.
3558 Value is non-zero if successful. Set *COLOR to the color
3559 allocated. */
06a2c219 3560
651f03b6
GM
3561static int
3562x_alloc_nearest_color_1 (dpy, cmap, color)
3563 Display *dpy;
06a2c219
GM
3564 Colormap cmap;
3565 XColor *color;
3566{
80c32bcc
GM
3567 int rc;
3568
651f03b6 3569 rc = XAllocColor (dpy, cmap, color);
06a2c219
GM
3570 if (rc == 0)
3571 {
3572 /* If we got to this point, the colormap is full, so we're going
3573 to try to get the next closest color. The algorithm used is
3574 a least-squares matching, which is what X uses for closest
3575 color matching with StaticColor visuals. */
3576 int nearest, i;
3577 unsigned long nearest_delta = ~0;
f04e1297 3578 int ncells;
651f03b6 3579 const XColor *cells = x_color_cells (dpy, &ncells);
06a2c219
GM
3580
3581 for (nearest = i = 0; i < ncells; ++i)
3582 {
3583 long dred = (color->red >> 8) - (cells[i].red >> 8);
3584 long dgreen = (color->green >> 8) - (cells[i].green >> 8);
3585 long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
3586 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
3587
3588 if (delta < nearest_delta)
3589 {
3590 nearest = i;
3591 nearest_delta = delta;
3592 }
3593 }
3594
3595 color->red = cells[nearest].red;
3596 color->green = cells[nearest].green;
3597 color->blue = cells[nearest].blue;
651f03b6 3598 rc = XAllocColor (dpy, cmap, color);
06a2c219 3599 }
35efe0a1
GM
3600 else
3601 {
3602 /* If allocation succeeded, and the allocated pixel color is not
3603 equal to a cached pixel color recorded earlier, there was a
3604 change in the colormap, so clear the color cache. */
651f03b6 3605 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
35efe0a1
GM
3606 XColor *cached_color;
3607
3608 if (dpyinfo->color_cells
3609 && (cached_color = &dpyinfo->color_cells[color->pixel],
cae71efe
GM
3610 (cached_color->red != color->red
3611 || cached_color->blue != color->blue
3612 || cached_color->green != color->green)))
35efe0a1
GM
3613 {
3614 xfree (dpyinfo->color_cells);
3615 dpyinfo->color_cells = NULL;
3616 dpyinfo->ncolor_cells = 0;
3617 }
3618 }
06a2c219 3619
d9c545da
GM
3620#ifdef DEBUG_X_COLORS
3621 if (rc)
3622 register_color (color->pixel);
3623#endif /* DEBUG_X_COLORS */
3624
06a2c219
GM
3625 return rc;
3626}
3627
3628
651f03b6
GM
3629/* Allocate the color COLOR->pixel on frame F, colormap CMAP. If an
3630 exact match can't be allocated, try the nearest color available.
3631 Value is non-zero if successful. Set *COLOR to the color
3632 allocated. */
3633
3634int
3635x_alloc_nearest_color (f, cmap, color)
3636 struct frame *f;
3637 Colormap cmap;
3638 XColor *color;
3639{
3640 gamma_correct (f, color);
3641 return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
3642}
3643
3644
d9c545da
GM
3645/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
3646 It's necessary to do this instead of just using PIXEL directly to
3647 get color reference counts right. */
3648
3649unsigned long
3650x_copy_color (f, pixel)
3651 struct frame *f;
3652 unsigned long pixel;
3653{
3654 XColor color;
3655
3656 color.pixel = pixel;
3657 BLOCK_INPUT;
f04e1297 3658 x_query_color (f, &color);
d9c545da
GM
3659 XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
3660 UNBLOCK_INPUT;
3661#ifdef DEBUG_X_COLORS
3662 register_color (pixel);
3663#endif
3664 return color.pixel;
3665}
3666
3667
3e71d8f2
GM
3668/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
3669 It's necessary to do this instead of just using PIXEL directly to
3670 get color reference counts right. */
3671
3672unsigned long
3673x_copy_dpy_color (dpy, cmap, pixel)
3674 Display *dpy;
3675 Colormap cmap;
3676 unsigned long pixel;
3677{
3678 XColor color;
3679
3680 color.pixel = pixel;
3681 BLOCK_INPUT;
3682 XQueryColor (dpy, cmap, &color);
3683 XAllocColor (dpy, cmap, &color);
3684 UNBLOCK_INPUT;
3685#ifdef DEBUG_X_COLORS
3686 register_color (pixel);
3687#endif
3688 return color.pixel;
3689}
3690
3691
6d8b0acd 3692/* Brightness beyond which a color won't have its highlight brightness
d7361edf 3693 boosted.
6d8b0acd 3694
d7361edf
MB
3695 Nominally, highlight colors for `3d' faces are calculated by
3696 brightening an object's color by a constant scale factor, but this
3697 doesn't yield good results for dark colors, so for colors who's
3698 brightness is less than this value (on a scale of 0-65535) have an
3699 use an additional additive factor.
6d8b0acd
MB
3700
3701 The value here is set so that the default menu-bar/mode-line color
3702 (grey75) will not have its highlights changed at all. */
3703#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
3704
3705
06a2c219
GM
3706/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
3707 or DELTA. Try a color with RGB values multiplied by FACTOR first.
3708 If this produces the same color as PIXEL, try a color where all RGB
3709 values have DELTA added. Return the allocated color in *PIXEL.
3710 DISPLAY is the X display, CMAP is the colormap to operate on.
3711 Value is non-zero if successful. */
3712
3713static int
3714x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
3715 struct frame *f;
3716 Display *display;
3717 Colormap cmap;
3718 unsigned long *pixel;
68c45bf0 3719 double factor;
06a2c219
GM
3720 int delta;
3721{
3722 XColor color, new;
6d8b0acd 3723 long bright;
06a2c219
GM
3724 int success_p;
3725
3726 /* Get RGB color values. */
3727 color.pixel = *pixel;
f04e1297 3728 x_query_color (f, &color);
06a2c219
GM
3729
3730 /* Change RGB values by specified FACTOR. Avoid overflow! */
3731 xassert (factor >= 0);
3732 new.red = min (0xffff, factor * color.red);
3733 new.green = min (0xffff, factor * color.green);
3734 new.blue = min (0xffff, factor * color.blue);
3735
d7361edf
MB
3736 /* Calculate brightness of COLOR. */
3737 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
6d8b0acd
MB
3738
3739 /* We only boost colors that are darker than
3740 HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
3741 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
3742 /* Make an additive adjustment to NEW, because it's dark enough so
3743 that scaling by FACTOR alone isn't enough. */
3744 {
3745 /* How far below the limit this color is (0 - 1, 1 being darker). */
3746 double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
3747 /* The additive adjustment. */
d7361edf 3748 int min_delta = delta * dimness * factor / 2;
6d8b0acd
MB
3749
3750 if (factor < 1)
3751 {
6d8b0acd
MB
3752 new.red = max (0, new.red - min_delta);
3753 new.green = max (0, new.green - min_delta);
3754 new.blue = max (0, new.blue - min_delta);
3755 }
3756 else
3757 {
3758 new.red = min (0xffff, min_delta + new.red);
3759 new.green = min (0xffff, min_delta + new.green);
3760 new.blue = min (0xffff, min_delta + new.blue);
3761 }
3762 }
3763
06a2c219 3764 /* Try to allocate the color. */
80c32bcc 3765 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3766 if (success_p)
3767 {
3768 if (new.pixel == *pixel)
3769 {
3770 /* If we end up with the same color as before, try adding
3771 delta to the RGB values. */
0d605c67 3772 x_free_colors (f, &new.pixel, 1);
06a2c219
GM
3773
3774 new.red = min (0xffff, delta + color.red);
3775 new.green = min (0xffff, delta + color.green);
3776 new.blue = min (0xffff, delta + color.blue);
80c32bcc 3777 success_p = x_alloc_nearest_color (f, cmap, &new);
06a2c219
GM
3778 }
3779 else
3780 success_p = 1;
3781 *pixel = new.pixel;
3782 }
3783
3784 return success_p;
3785}
3786
3787
3788/* Set up the foreground color for drawing relief lines of glyph
3789 string S. RELIEF is a pointer to a struct relief containing the GC
3790 with which lines will be drawn. Use a color that is FACTOR or
3791 DELTA lighter or darker than the relief's background which is found
3792 in S->f->output_data.x->relief_background. If such a color cannot
3793 be allocated, use DEFAULT_PIXEL, instead. */
3794
3795static void
3796x_setup_relief_color (f, relief, factor, delta, default_pixel)
3797 struct frame *f;
3798 struct relief *relief;
68c45bf0 3799 double factor;
06a2c219
GM
3800 int delta;
3801 unsigned long default_pixel;
3802{
3803 XGCValues xgcv;
3804 struct x_output *di = f->output_data.x;
3805 unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
3806 unsigned long pixel;
3807 unsigned long background = di->relief_background;
43bd1b2b 3808 Colormap cmap = FRAME_X_COLORMAP (f);
dcd08bfb
GM
3809 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
3810 Display *dpy = FRAME_X_DISPLAY (f);
06a2c219
GM
3811
3812 xgcv.graphics_exposures = False;
3813 xgcv.line_width = 1;
3814
3815 /* Free previously allocated color. The color cell will be reused
3816 when it has been freed as many times as it was allocated, so this
3817 doesn't affect faces using the same colors. */
3818 if (relief->gc
3819 && relief->allocated_p)
3820 {
0d605c67 3821 x_free_colors (f, &relief->pixel, 1);
06a2c219
GM
3822 relief->allocated_p = 0;
3823 }
3824
3825 /* Allocate new color. */
3826 xgcv.foreground = default_pixel;
3827 pixel = background;
dcd08bfb
GM
3828 if (dpyinfo->n_planes != 1
3829 && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
06a2c219
GM
3830 {
3831 relief->allocated_p = 1;
3832 xgcv.foreground = relief->pixel = pixel;
3833 }
3834
3835 if (relief->gc == 0)
3836 {
dcd08bfb 3837 xgcv.stipple = dpyinfo->gray;
06a2c219 3838 mask |= GCStipple;
dcd08bfb 3839 relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
06a2c219
GM
3840 }
3841 else
dcd08bfb 3842 XChangeGC (dpy, relief->gc, mask, &xgcv);
06a2c219
GM
3843}
3844
3845
3846/* Set up colors for the relief lines around glyph string S. */
3847
3848static void
3849x_setup_relief_colors (s)
3850 struct glyph_string *s;
3851{
3852 struct x_output *di = s->f->output_data.x;
3853 unsigned long color;
3854
3855 if (s->face->use_box_color_for_shadows_p)
3856 color = s->face->box_color;
3857 else
3858 {
3859 XGCValues xgcv;
3860
3861 /* Get the background color of the face. */
3862 XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
3863 color = xgcv.background;
3864 }
3865
3866 if (di->white_relief.gc == 0
3867 || color != di->relief_background)
3868 {
3869 di->relief_background = color;
3870 x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
3871 WHITE_PIX_DEFAULT (s->f));
3872 x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
3873 BLACK_PIX_DEFAULT (s->f));
3874 }
3875}
3876
3877
3878/* Draw a relief on frame F inside the rectangle given by LEFT_X,
3879 TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
3880 to draw, it must be >= 0. RAISED_P non-zero means draw a raised
3881 relief. LEFT_P non-zero means draw a relief on the left side of
3882 the rectangle. RIGHT_P non-zero means draw a relief on the right
3883 side of the rectangle. CLIP_RECT is the clipping rectangle to use
3884 when drawing. */
3885
3886static void
3887x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
3888 raised_p, left_p, right_p, clip_rect)
3889 struct frame *f;
3890 int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
3891 XRectangle *clip_rect;
3892{
3893 int i;
3894 GC gc;
3895
3896 if (raised_p)
3897 gc = f->output_data.x->white_relief.gc;
3898 else
3899 gc = f->output_data.x->black_relief.gc;
3900 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3901
3902 /* Top. */
3903 for (i = 0; i < width; ++i)
3904 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3905 left_x + i * left_p, top_y + i,
3906 right_x + 1 - i * right_p, top_y + i);
3907
3908 /* Left. */
3909 if (left_p)
3910 for (i = 0; i < width; ++i)
3911 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
44655e77 3912 left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
06a2c219
GM
3913
3914 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3915 if (raised_p)
3916 gc = f->output_data.x->black_relief.gc;
3917 else
3918 gc = f->output_data.x->white_relief.gc;
3919 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
3920
3921 /* Bottom. */
3922 for (i = 0; i < width; ++i)
3923 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
44655e77 3924 left_x + i * left_p + 1, bottom_y - i,
06a2c219
GM
3925 right_x + 1 - i * right_p, bottom_y - i);
3926
3927 /* Right. */
3928 if (right_p)
3929 for (i = 0; i < width; ++i)
3930 XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
3931 right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
3932
3933 XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
3934}
3935
3936
3937/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
3938 RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
3939 draw, it must be >= 0. LEFT_P non-zero means draw a line on the
3940 left side of the rectangle. RIGHT_P non-zero means draw a line
3941 on the right side of the rectangle. CLIP_RECT is the clipping
3942 rectangle to use when drawing. */
3943
3944static void
3945x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
3946 left_p, right_p, clip_rect)
3947 struct glyph_string *s;
3948 int left_x, top_y, right_x, bottom_y, left_p, right_p;
3949 XRectangle *clip_rect;
3950{
3951 XGCValues xgcv;
3952
3953 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
3954 XSetForeground (s->display, s->gc, s->face->box_color);
3955 XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
3956
3957 /* Top. */
3958 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3959 left_x, top_y, right_x - left_x + 1, width);
06a2c219
GM
3960
3961 /* Left. */
3962 if (left_p)
3963 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3964 left_x, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3965
3966 /* Bottom. */
3967 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3968 left_x, bottom_y - width + 1, right_x - left_x + 1, width);
06a2c219
GM
3969
3970 /* Right. */
3971 if (right_p)
3972 XFillRectangle (s->display, s->window, s->gc,
58e4fce8 3973 right_x - width + 1, top_y, width, bottom_y - top_y + 1);
06a2c219
GM
3974
3975 XSetForeground (s->display, s->gc, xgcv.foreground);
3976 XSetClipMask (s->display, s->gc, None);
3977}
3978
3979
3980/* Draw a box around glyph string S. */
3981
3982static void
3983x_draw_glyph_string_box (s)
3984 struct glyph_string *s;
3985{
3986 int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
3987 int left_p, right_p;
3988 struct glyph *last_glyph;
3989 XRectangle clip_rect;
3990
3991 last_x = window_box_right (s->w, s->area);
3992 if (s->row->full_width_p
3993 && !s->w->pseudo_window_p)
3994 {
110859fc 3995 last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
06a2c219
GM
3996 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
3997 last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
3998 }
3999
4000 /* The glyph that may have a right box line. */
b4192550 4001 last_glyph = (s->cmp || s->img
06a2c219
GM
4002 ? s->first_glyph
4003 : s->first_glyph + s->nchars - 1);
4004
ea2ba0d4 4005 width = abs (s->face->box_line_width);
06a2c219
GM
4006 raised_p = s->face->box == FACE_RAISED_BOX;
4007 left_x = s->x;
57ac7c81
GM
4008 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
4009 ? last_x - 1
4010 : min (last_x, s->x + s->background_width) - 1);
06a2c219
GM
4011 top_y = s->y;
4012 bottom_y = top_y + s->height - 1;
4013
4014 left_p = (s->first_glyph->left_box_line_p
4015 || (s->hl == DRAW_MOUSE_FACE
4016 && (s->prev == NULL
4017 || s->prev->hl != s->hl)));
4018 right_p = (last_glyph->right_box_line_p
4019 || (s->hl == DRAW_MOUSE_FACE
4020 && (s->next == NULL
4021 || s->next->hl != s->hl)));
4022
4023 x_get_glyph_string_clip_rect (s, &clip_rect);
4024
4025 if (s->face->box == FACE_SIMPLE_BOX)
4026 x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
4027 left_p, right_p, &clip_rect);
4028 else
4029 {
4030 x_setup_relief_colors (s);
4031 x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
4032 width, raised_p, left_p, right_p, &clip_rect);
4033 }
4034}
4035
4036
4037/* Draw foreground of image glyph string S. */
4038
4039static void
4040x_draw_image_foreground (s)
4041 struct glyph_string *s;
4042{
4043 int x;
95af8492 4044 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4045
4046 /* If first glyph of S has a left box line, start drawing it to the
4047 right of that line. */
4048 if (s->face->box != FACE_NO_BOX
4049 && s->first_glyph->left_box_line_p)
ea2ba0d4 4050 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4051 else
4052 x = s->x;
4053
4054 /* If there is a margin around the image, adjust x- and y-position
4055 by that margin. */
22d650b8
GM
4056 x += s->img->hmargin;
4057 y += s->img->vmargin;
06a2c219
GM
4058
4059 if (s->img->pixmap)
4060 {
4061 if (s->img->mask)
4062 {
4063 /* We can't set both a clip mask and use XSetClipRectangles
4064 because the latter also sets a clip mask. We also can't
4065 trust on the shape extension to be available
4066 (XShapeCombineRegion). So, compute the rectangle to draw
4067 manually. */
4068 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4069 | GCFunction);
4070 XGCValues xgcv;
4071 XRectangle clip_rect, image_rect, r;
4072
4073 xgcv.clip_mask = s->img->mask;
4074 xgcv.clip_x_origin = x;
4075 xgcv.clip_y_origin = y;
4076 xgcv.function = GXcopy;
4077 XChangeGC (s->display, s->gc, mask, &xgcv);
4078
4079 x_get_glyph_string_clip_rect (s, &clip_rect);
4080 image_rect.x = x;
4081 image_rect.y = y;
4082 image_rect.width = s->img->width;
4083 image_rect.height = s->img->height;
4084 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4085 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4086 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
4087 }
4088 else
4089 {
49ad1d99
GM
4090 unsigned long mask = GCClipXOrigin | GCClipYOrigin | GCFunction;
4091 XGCValues xgcv;
4092 XRectangle clip_rect, image_rect, r;
4093
4094 x_get_glyph_string_clip_rect (s, &clip_rect);
4095 image_rect.x = x;
4096 image_rect.y = y;
4097 image_rect.width = s->img->width;
4098 image_rect.height = s->img->height;
4099 if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
4100 XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
4101 r.x - x, r.y - y, r.width, r.height, r.x, r.y);
06a2c219
GM
4102
4103 /* When the image has a mask, we can expect that at
4104 least part of a mouse highlight or a block cursor will
4105 be visible. If the image doesn't have a mask, make
4106 a block cursor visible by drawing a rectangle around
4107 the image. I believe it's looking better if we do
4108 nothing here for mouse-face. */
4109 if (s->hl == DRAW_CURSOR)
4110 XDrawRectangle (s->display, s->window, s->gc, x, y,
4111 s->img->width - 1, s->img->height - 1);
4112 }
4113 }
4114 else
4115 /* Draw a rectangle if image could not be loaded. */
4116 XDrawRectangle (s->display, s->window, s->gc, x, y,
4117 s->img->width - 1, s->img->height - 1);
4118}
4119
4120
4121/* Draw a relief around the image glyph string S. */
4122
4123static void
4124x_draw_image_relief (s)
4125 struct glyph_string *s;
4126{
4127 int x0, y0, x1, y1, thick, raised_p;
4128 XRectangle r;
4129 int x;
95af8492 4130 int y = s->ybase - image_ascent (s->img, s->face);
06a2c219
GM
4131
4132 /* If first glyph of S has a left box line, start drawing it to the
4133 right of that line. */
4134 if (s->face->box != FACE_NO_BOX
4135 && s->first_glyph->left_box_line_p)
ea2ba0d4 4136 x = s->x + abs (s->face->box_line_width);
06a2c219
GM
4137 else
4138 x = s->x;
4139
4140 /* If there is a margin around the image, adjust x- and y-position
4141 by that margin. */
22d650b8
GM
4142 x += s->img->hmargin;
4143 y += s->img->vmargin;
06a2c219
GM
4144
4145 if (s->hl == DRAW_IMAGE_SUNKEN
4146 || s->hl == DRAW_IMAGE_RAISED)
4147 {
9ea173e8 4148 thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
06a2c219
GM
4149 raised_p = s->hl == DRAW_IMAGE_RAISED;
4150 }
4151 else
4152 {
4153 thick = abs (s->img->relief);
4154 raised_p = s->img->relief > 0;
4155 }
4156
4157 x0 = x - thick;
4158 y0 = y - thick;
4159 x1 = x + s->img->width + thick - 1;
4160 y1 = y + s->img->height + thick - 1;
4161
4162 x_setup_relief_colors (s);
4163 x_get_glyph_string_clip_rect (s, &r);
4164 x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
4165}
4166
4167
4168/* Draw the foreground of image glyph string S to PIXMAP. */
4169
4170static void
4171x_draw_image_foreground_1 (s, pixmap)
4172 struct glyph_string *s;
4173 Pixmap pixmap;
4174{
4175 int x;
95af8492 4176 int y = s->ybase - s->y - image_ascent (s->img, s->face);
06a2c219
GM
4177
4178 /* If first glyph of S has a left box line, start drawing it to the
4179 right of that line. */
4180 if (s->face->box != FACE_NO_BOX
4181 && s->first_glyph->left_box_line_p)
ea2ba0d4 4182 x = abs (s->face->box_line_width);
06a2c219
GM
4183 else
4184 x = 0;
4185
4186 /* If there is a margin around the image, adjust x- and y-position
4187 by that margin. */
22d650b8
GM
4188 x += s->img->hmargin;
4189 y += s->img->vmargin;
dc43ef94 4190
06a2c219
GM
4191 if (s->img->pixmap)
4192 {
4193 if (s->img->mask)
4194 {
4195 /* We can't set both a clip mask and use XSetClipRectangles
4196 because the latter also sets a clip mask. We also can't
4197 trust on the shape extension to be available
4198 (XShapeCombineRegion). So, compute the rectangle to draw
4199 manually. */
4200 unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
4201 | GCFunction);
4202 XGCValues xgcv;
4203
4204 xgcv.clip_mask = s->img->mask;
4205 xgcv.clip_x_origin = x;
4206 xgcv.clip_y_origin = y;
4207 xgcv.function = GXcopy;
4208 XChangeGC (s->display, s->gc, mask, &xgcv);
4209
4210 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4211 0, 0, s->img->width, s->img->height, x, y);
4212 XSetClipMask (s->display, s->gc, None);
4213 }
4214 else
4215 {
4216 XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
4217 0, 0, s->img->width, s->img->height, x, y);
4218
4219 /* When the image has a mask, we can expect that at
4220 least part of a mouse highlight or a block cursor will
4221 be visible. If the image doesn't have a mask, make
4222 a block cursor visible by drawing a rectangle around
4223 the image. I believe it's looking better if we do
4224 nothing here for mouse-face. */
4225 if (s->hl == DRAW_CURSOR)
4226 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4227 s->img->width - 1, s->img->height - 1);
4228 }
4229 }
4230 else
4231 /* Draw a rectangle if image could not be loaded. */
4232 XDrawRectangle (s->display, pixmap, s->gc, x, y,
4233 s->img->width - 1, s->img->height - 1);
4234}
dc43ef94 4235
990ba854 4236
06a2c219
GM
4237/* Draw part of the background of glyph string S. X, Y, W, and H
4238 give the rectangle to draw. */
a9a5b0a5 4239
06a2c219
GM
4240static void
4241x_draw_glyph_string_bg_rect (s, x, y, w, h)
4242 struct glyph_string *s;
4243 int x, y, w, h;
4244{
4245 if (s->stippled_p)
4246 {
4247 /* Fill background with a stipple pattern. */
4248 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4249 XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
4250 XSetFillStyle (s->display, s->gc, FillSolid);
4251 }
4252 else
4253 x_clear_glyph_string_rect (s, x, y, w, h);
4254}
07e34cb0 4255
b5210ea7 4256
06a2c219 4257/* Draw image glyph string S.
dc43ef94 4258
06a2c219
GM
4259 s->y
4260 s->x +-------------------------
4261 | s->face->box
4262 |
4263 | +-------------------------
4264 | | s->img->margin
4265 | |
4266 | | +-------------------
4267 | | | the image
dc43ef94 4268
06a2c219 4269 */
dc43ef94 4270
06a2c219
GM
4271static void
4272x_draw_image_glyph_string (s)
4273 struct glyph_string *s;
4274{
4275 int x, y;
ea2ba0d4
KH
4276 int box_line_hwidth = abs (s->face->box_line_width);
4277 int box_line_vwidth = max (s->face->box_line_width, 0);
06a2c219
GM
4278 int height;
4279 Pixmap pixmap = None;
4280
ea2ba0d4 4281 height = s->height - 2 * box_line_vwidth;
06a2c219
GM
4282
4283 /* Fill background with face under the image. Do it only if row is
4284 taller than image or if image has a clip mask to reduce
4285 flickering. */
4286 s->stippled_p = s->face->stipple != 0;
4287 if (height > s->img->height
22d650b8
GM
4288 || s->img->hmargin
4289 || s->img->vmargin
06a2c219
GM
4290 || s->img->mask
4291 || s->img->pixmap == 0
4292 || s->width != s->background_width)
4293 {
ea2ba0d4
KH
4294 if (box_line_hwidth && s->first_glyph->left_box_line_p)
4295 x = s->x + box_line_hwidth;
06a2c219
GM
4296 else
4297 x = s->x;
4298
ea2ba0d4 4299 y = s->y + box_line_vwidth;
06a2c219
GM
4300
4301 if (s->img->mask)
4302 {
f9b5db02
GM
4303 /* Create a pixmap as large as the glyph string. Fill it
4304 with the background color. Copy the image to it, using
4305 its mask. Copy the temporary pixmap to the display. */
06a2c219
GM
4306 Screen *screen = FRAME_X_SCREEN (s->f);
4307 int depth = DefaultDepthOfScreen (screen);
4308
4309 /* Create a pixmap as large as the glyph string. */
4310 pixmap = XCreatePixmap (s->display, s->window,
4311 s->background_width,
4312 s->height, depth);
4313
4314 /* Don't clip in the following because we're working on the
4315 pixmap. */
4316 XSetClipMask (s->display, s->gc, None);
4317
4318 /* Fill the pixmap with the background color/stipple. */
4319 if (s->stippled_p)
4320 {
4321 /* Fill background with a stipple pattern. */
4322 XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
4323 XFillRectangle (s->display, pixmap, s->gc,
4324 0, 0, s->background_width, s->height);
4325 XSetFillStyle (s->display, s->gc, FillSolid);
4326 }
4327 else
4328 {
4329 XGCValues xgcv;
4330 XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
4331 &xgcv);
4332 XSetForeground (s->display, s->gc, xgcv.background);
4333 XFillRectangle (s->display, pixmap, s->gc,
4334 0, 0, s->background_width, s->height);
4335 XSetForeground (s->display, s->gc, xgcv.foreground);
4336 }
4337 }
4338 else
06a2c219
GM
4339 x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
4340
4341 s->background_filled_p = 1;
4342 }
dc43ef94 4343
06a2c219
GM
4344 /* Draw the foreground. */
4345 if (pixmap != None)
4346 {
4347 x_draw_image_foreground_1 (s, pixmap);
4348 x_set_glyph_string_clipping (s);
4349 XCopyArea (s->display, pixmap, s->window, s->gc,
4350 0, 0, s->background_width, s->height, s->x, s->y);
4351 XFreePixmap (s->display, pixmap);
4352 }
4353 else
4354 x_draw_image_foreground (s);
b5210ea7 4355
06a2c219
GM
4356 /* If we must draw a relief around the image, do it. */
4357 if (s->img->relief
4358 || s->hl == DRAW_IMAGE_RAISED
4359 || s->hl == DRAW_IMAGE_SUNKEN)
4360 x_draw_image_relief (s);
4361}
8c1a6a84 4362
990ba854 4363
06a2c219 4364/* Draw stretch glyph string S. */
dc43ef94 4365
06a2c219
GM
4366static void
4367x_draw_stretch_glyph_string (s)
4368 struct glyph_string *s;
4369{
4370 xassert (s->first_glyph->type == STRETCH_GLYPH);
4371 s->stippled_p = s->face->stipple != 0;
990ba854 4372
06a2c219
GM
4373 if (s->hl == DRAW_CURSOR
4374 && !x_stretch_cursor_p)
4375 {
4376 /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
4377 as wide as the stretch glyph. */
4378 int width = min (CANON_X_UNIT (s->f), s->background_width);
990ba854 4379
06a2c219
GM
4380 /* Draw cursor. */
4381 x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
0cdd0c9f 4382
06a2c219
GM
4383 /* Clear rest using the GC of the original non-cursor face. */
4384 if (width < s->background_width)
4385 {
06a2c219
GM
4386 int x = s->x + width, y = s->y;
4387 int w = s->background_width - width, h = s->height;
4388 XRectangle r;
b7f83f9e 4389 GC gc;
dc43ef94 4390
b7f83f9e
GM
4391 if (s->row->mouse_face_p
4392 && cursor_in_mouse_face_p (s->w))
4393 {
4394 x_set_mouse_face_gc (s);
4395 gc = s->gc;
4396 }
4397 else
4398 gc = s->face->gc;
4399
06a2c219
GM
4400 x_get_glyph_string_clip_rect (s, &r);
4401 XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
b7f83f9e 4402
06a2c219
GM
4403 if (s->face->stipple)
4404 {
4405 /* Fill background with a stipple pattern. */
4406 XSetFillStyle (s->display, gc, FillOpaqueStippled);
4407 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4408 XSetFillStyle (s->display, gc, FillSolid);
4409 }
4410 else
4411 {
4412 XGCValues xgcv;
4413 XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
4414 XSetForeground (s->display, gc, xgcv.background);
4415 XFillRectangle (s->display, s->window, gc, x, y, w, h);
4416 XSetForeground (s->display, gc, xgcv.foreground);
4417 }
4418 }
4419 }
61e9f9f3 4420 else if (!s->background_filled_p)
06a2c219
GM
4421 x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
4422 s->height);
4423
4424 s->background_filled_p = 1;
4425}
4426
4427
4428/* Draw glyph string S. */
4429
4430static void
4431x_draw_glyph_string (s)
4432 struct glyph_string *s;
4433{
4458cf11
KH
4434 int relief_drawn_p = 0;
4435
06a2c219
GM
4436 /* If S draws into the background of its successor, draw the
4437 background of the successor first so that S can draw into it.
4438 This makes S->next use XDrawString instead of XDrawImageString. */
66ac4b0e 4439 if (s->next && s->right_overhang && !s->for_overlaps_p)
06a2c219
GM
4440 {
4441 xassert (s->next->img == NULL);
4442 x_set_glyph_string_gc (s->next);
4443 x_set_glyph_string_clipping (s->next);
4444 x_draw_glyph_string_background (s->next, 1);
4445 }
97210f4e 4446
06a2c219
GM
4447 /* Set up S->gc, set clipping and draw S. */
4448 x_set_glyph_string_gc (s);
4449 x_set_glyph_string_clipping (s);
4450
4458cf11
KH
4451 /* Draw relief (if any) in advance for char/composition so that the
4452 glyph string can be drawn over it. */
4453 if (!s->for_overlaps_p
4454 && s->face->box != FACE_NO_BOX
4455 && (s->first_glyph->type == CHAR_GLYPH
4456 || s->first_glyph->type == COMPOSITE_GLYPH))
4457
4458 {
4459 x_draw_glyph_string_background (s, 1);
4460 x_draw_glyph_string_box (s);
4461 relief_drawn_p = 1;
4462 }
4463
06a2c219
GM
4464 switch (s->first_glyph->type)
4465 {
4466 case IMAGE_GLYPH:
4467 x_draw_image_glyph_string (s);
4468 break;
4469
4470 case STRETCH_GLYPH:
4471 x_draw_stretch_glyph_string (s);
4472 break;
4473
4474 case CHAR_GLYPH:
66ac4b0e
GM
4475 if (s->for_overlaps_p)
4476 s->background_filled_p = 1;
4477 else
4478 x_draw_glyph_string_background (s, 0);
06a2c219
GM
4479 x_draw_glyph_string_foreground (s);
4480 break;
4481
b4192550
KH
4482 case COMPOSITE_GLYPH:
4483 if (s->for_overlaps_p || s->gidx > 0)
4484 s->background_filled_p = 1;
4485 else
4486 x_draw_glyph_string_background (s, 1);
4487 x_draw_composite_glyph_string_foreground (s);
4488 break;
4489
06a2c219
GM
4490 default:
4491 abort ();
4492 }
4493
66ac4b0e 4494 if (!s->for_overlaps_p)
06a2c219 4495 {
66ac4b0e
GM
4496 /* Draw underline. */
4497 if (s->face->underline_p)
4498 {
e24e84cc
GM
4499 unsigned long tem, h;
4500 int y;
06a2c219 4501
e24e84cc 4502 /* Get the underline thickness. Default is 1 pixel. */
66ac4b0e
GM
4503 if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
4504 h = 1;
e24e84cc
GM
4505
4506 /* Get the underline position. This is the recommended
4507 vertical offset in pixels from the baseline to the top of
4508 the underline. This is a signed value according to the
4509 specs, and its default is
4510
4511 ROUND ((maximum descent) / 2), with
4512 ROUND(x) = floor (x + 0.5) */
4513
a72d5ce5
GM
4514 if (x_use_underline_position_properties
4515 && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
e24e84cc
GM
4516 y = s->ybase + (long) tem;
4517 else if (s->face->font)
4518 y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
4519 else
a02f1be0 4520 y = s->y + s->height - h;
06a2c219 4521
66ac4b0e 4522 if (s->face->underline_defaulted_p)
e24e84cc
GM
4523 XFillRectangle (s->display, s->window, s->gc,
4524 s->x, y, s->width, h);
66ac4b0e
GM
4525 else
4526 {
4527 XGCValues xgcv;
4528 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4529 XSetForeground (s->display, s->gc, s->face->underline_color);
e24e84cc
GM
4530 XFillRectangle (s->display, s->window, s->gc,
4531 s->x, y, s->width, h);
66ac4b0e
GM
4532 XSetForeground (s->display, s->gc, xgcv.foreground);
4533 }
dc6f92b8 4534 }
07e34cb0 4535
66ac4b0e
GM
4536 /* Draw overline. */
4537 if (s->face->overline_p)
06a2c219 4538 {
66ac4b0e
GM
4539 unsigned long dy = 0, h = 1;
4540
4541 if (s->face->overline_color_defaulted_p)
4542 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4543 s->width, h);
4544 else
4545 {
4546 XGCValues xgcv;
4547 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4548 XSetForeground (s->display, s->gc, s->face->overline_color);
4549 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4550 s->width, h);
4551 XSetForeground (s->display, s->gc, xgcv.foreground);
4552 }
06a2c219 4553 }
06a2c219 4554
66ac4b0e
GM
4555 /* Draw strike-through. */
4556 if (s->face->strike_through_p)
06a2c219 4557 {
66ac4b0e
GM
4558 unsigned long h = 1;
4559 unsigned long dy = (s->height - h) / 2;
4560
4561 if (s->face->strike_through_color_defaulted_p)
4562 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4563 s->width, h);
4564 else
4565 {
4566 XGCValues xgcv;
4567 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
4568 XSetForeground (s->display, s->gc, s->face->strike_through_color);
4569 XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
4570 s->width, h);
4571 XSetForeground (s->display, s->gc, xgcv.foreground);
4572 }
06a2c219 4573 }
06a2c219 4574
4458cf11
KH
4575 /* Draw relief if not yet drawn. */
4576 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
66ac4b0e
GM
4577 x_draw_glyph_string_box (s);
4578 }
06a2c219
GM
4579
4580 /* Reset clipping. */
4581 XSetClipMask (s->display, s->gc, None);
dc6f92b8 4582}
07e34cb0 4583
06a2c219 4584
b4192550
KH
4585static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
4586 struct face **, int));
06a2c219 4587
06a2c219 4588
209f68d9
GM
4589/* Fill glyph string S with composition components specified by S->cmp.
4590
b4192550
KH
4591 FACES is an array of faces for all components of this composition.
4592 S->gidx is the index of the first component for S.
4593 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4594 use its physical height for clipping.
06a2c219 4595
b4192550 4596 Value is the index of a component not in S. */
07e34cb0 4597
b4192550
KH
4598static int
4599x_fill_composite_glyph_string (s, faces, overlaps_p)
06a2c219 4600 struct glyph_string *s;
b4192550 4601 struct face **faces;
66ac4b0e 4602 int overlaps_p;
07e34cb0 4603{
b4192550 4604 int i;
06a2c219 4605
b4192550 4606 xassert (s);
06a2c219 4607
b4192550 4608 s->for_overlaps_p = overlaps_p;
06a2c219 4609
b4192550
KH
4610 s->face = faces[s->gidx];
4611 s->font = s->face->font;
4612 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
06a2c219 4613
b4192550
KH
4614 /* For all glyphs of this composition, starting at the offset
4615 S->gidx, until we reach the end of the definition or encounter a
4616 glyph that requires the different face, add it to S. */
4617 ++s->nchars;
4618 for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
4619 ++s->nchars;
06a2c219 4620
b4192550
KH
4621 /* All glyph strings for the same composition has the same width,
4622 i.e. the width set for the first component of the composition. */
06a2c219 4623
06a2c219
GM
4624 s->width = s->first_glyph->pixel_width;
4625
4626 /* If the specified font could not be loaded, use the frame's
4627 default font, but record the fact that we couldn't load it in
4628 the glyph string so that we can draw rectangles for the
4629 characters of the glyph string. */
4630 if (s->font == NULL)
4631 {
4632 s->font_not_found_p = 1;
4633 s->font = FRAME_FONT (s->f);
4634 }
4635
4636 /* Adjust base line for subscript/superscript text. */
4637 s->ybase += s->first_glyph->voffset;
4638
4639 xassert (s->face && s->face->gc);
4640
4641 /* This glyph string must always be drawn with 16-bit functions. */
4642 s->two_byte_p = 1;
b4192550
KH
4643
4644 return s->gidx + s->nchars;
06a2c219
GM
4645}
4646
4647
209f68d9
GM
4648/* Fill glyph string S from a sequence of character glyphs.
4649
06a2c219 4650 FACE_ID is the face id of the string. START is the index of the
66ac4b0e
GM
4651 first glyph to consider, END is the index of the last + 1.
4652 OVERLAPS_P non-zero means S should draw the foreground only, and
209f68d9 4653 use its physical height for clipping.
66ac4b0e
GM
4654
4655 Value is the index of the first glyph not in S. */
06a2c219
GM
4656
4657static int
66ac4b0e 4658x_fill_glyph_string (s, face_id, start, end, overlaps_p)
06a2c219
GM
4659 struct glyph_string *s;
4660 int face_id;
66ac4b0e 4661 int start, end, overlaps_p;
06a2c219
GM
4662{
4663 struct glyph *glyph, *last;
4664 int voffset;
ee569018 4665 int glyph_not_available_p;
06a2c219 4666
06a2c219
GM
4667 xassert (s->f == XFRAME (s->w->frame));
4668 xassert (s->nchars == 0);
4669 xassert (start >= 0 && end > start);
4670
66ac4b0e 4671 s->for_overlaps_p = overlaps_p,
06a2c219
GM
4672 glyph = s->row->glyphs[s->area] + start;
4673 last = s->row->glyphs[s->area] + end;
4674 voffset = glyph->voffset;
4675
ee569018
KH
4676 glyph_not_available_p = glyph->glyph_not_available_p;
4677
06a2c219
GM
4678 while (glyph < last
4679 && glyph->type == CHAR_GLYPH
4680 && glyph->voffset == voffset
ee569018
KH
4681 /* Same face id implies same font, nowadays. */
4682 && glyph->face_id == face_id
4683 && glyph->glyph_not_available_p == glyph_not_available_p)
06a2c219 4684 {
ee569018
KH
4685 int two_byte_p;
4686
06a2c219 4687 s->face = x_get_glyph_face_and_encoding (s->f, glyph,
ee569018
KH
4688 s->char2b + s->nchars,
4689 &two_byte_p);
4690 s->two_byte_p = two_byte_p;
06a2c219
GM
4691 ++s->nchars;
4692 xassert (s->nchars <= end - start);
4693 s->width += glyph->pixel_width;
4694 ++glyph;
4695 }
4696
4697 s->font = s->face->font;
4698 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4699
4700 /* If the specified font could not be loaded, use the frame's font,
4701 but record the fact that we couldn't load it in
4702 S->font_not_found_p so that we can draw rectangles for the
4703 characters of the glyph string. */
ee569018 4704 if (s->font == NULL || glyph_not_available_p)
06a2c219
GM
4705 {
4706 s->font_not_found_p = 1;
4707 s->font = FRAME_FONT (s->f);
4708 }
4709
4710 /* Adjust base line for subscript/superscript text. */
4711 s->ybase += voffset;
66ac4b0e 4712
06a2c219
GM
4713 xassert (s->face && s->face->gc);
4714 return glyph - s->row->glyphs[s->area];
07e34cb0 4715}
dc6f92b8 4716
06a2c219
GM
4717
4718/* Fill glyph string S from image glyph S->first_glyph. */
dc6f92b8 4719
dfcf069d 4720static void
06a2c219
GM
4721x_fill_image_glyph_string (s)
4722 struct glyph_string *s;
4723{
4724 xassert (s->first_glyph->type == IMAGE_GLYPH);
43d120d8 4725 s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
06a2c219 4726 xassert (s->img);
43d120d8 4727 s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
06a2c219
GM
4728 s->font = s->face->font;
4729 s->width = s->first_glyph->pixel_width;
4730
4731 /* Adjust base line for subscript/superscript text. */
4732 s->ybase += s->first_glyph->voffset;
4733}
4734
4735
209f68d9 4736/* Fill glyph string S from a sequence of stretch glyphs.
06a2c219 4737
209f68d9
GM
4738 ROW is the glyph row in which the glyphs are found, AREA is the
4739 area within the row. START is the index of the first glyph to
4740 consider, END is the index of the last + 1.
4741
4742 Value is the index of the first glyph not in S. */
4743
4744static int
4745x_fill_stretch_glyph_string (s, row, area, start, end)
06a2c219 4746 struct glyph_string *s;
209f68d9
GM
4747 struct glyph_row *row;
4748 enum glyph_row_area area;
4749 int start, end;
06a2c219 4750{
209f68d9
GM
4751 struct glyph *glyph, *last;
4752 int voffset, face_id;
4753
06a2c219 4754 xassert (s->first_glyph->type == STRETCH_GLYPH);
209f68d9
GM
4755
4756 glyph = s->row->glyphs[s->area] + start;
4757 last = s->row->glyphs[s->area] + end;
4758 face_id = glyph->face_id;
4759 s->face = FACE_FROM_ID (s->f, face_id);
06a2c219 4760 s->font = s->face->font;
209f68d9
GM
4761 s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
4762 s->width = glyph->pixel_width;
4763 voffset = glyph->voffset;
4764
4765 for (++glyph;
4766 (glyph < last
4767 && glyph->type == STRETCH_GLYPH
4768 && glyph->voffset == voffset
4769 && glyph->face_id == face_id);
4770 ++glyph)
4771 s->width += glyph->pixel_width;
06a2c219
GM
4772
4773 /* Adjust base line for subscript/superscript text. */
209f68d9
GM
4774 s->ybase += voffset;
4775
c296fc01
GM
4776 /* The case that face->gc == 0 is handled when drawing the glyph
4777 string by calling PREPARE_FACE_FOR_DISPLAY. */
4778 xassert (s->face);
209f68d9 4779 return glyph - s->row->glyphs[s->area];
06a2c219
GM
4780}
4781
4782
4783/* Initialize glyph string S. CHAR2B is a suitably allocated vector
4784 of XChar2b structures for S; it can't be allocated in
4785 x_init_glyph_string because it must be allocated via `alloca'. W
4786 is the window on which S is drawn. ROW and AREA are the glyph row
4787 and area within the row from which S is constructed. START is the
4788 index of the first glyph structure covered by S. HL is a
4789 face-override for drawing S. */
4790
4791static void
4792x_init_glyph_string (s, char2b, w, row, area, start, hl)
4793 struct glyph_string *s;
4794 XChar2b *char2b;
4795 struct window *w;
4796 struct glyph_row *row;
4797 enum glyph_row_area area;
4798 int start;
4799 enum draw_glyphs_face hl;
4800{
4801 bzero (s, sizeof *s);
4802 s->w = w;
4803 s->f = XFRAME (w->frame);
4804 s->display = FRAME_X_DISPLAY (s->f);
4805 s->window = FRAME_X_WINDOW (s->f);
4806 s->char2b = char2b;
4807 s->hl = hl;
4808 s->row = row;
4809 s->area = area;
4810 s->first_glyph = row->glyphs[area] + start;
4811 s->height = row->height;
4812 s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
4813
9ea173e8
GM
4814 /* Display the internal border below the tool-bar window. */
4815 if (s->w == XWINDOW (s->f->tool_bar_window))
06a2c219
GM
4816 s->y -= s->f->output_data.x->internal_border_width;
4817
4818 s->ybase = s->y + row->ascent;
4819}
4820
4821
4822/* Set background width of glyph string S. START is the index of the
4823 first glyph following S. LAST_X is the right-most x-position + 1
4824 in the drawing area. */
4825
4826static INLINE void
4827x_set_glyph_string_background_width (s, start, last_x)
4828 struct glyph_string *s;
4829 int start;
4830 int last_x;
4831{
4832 /* If the face of this glyph string has to be drawn to the end of
4833 the drawing area, set S->extends_to_end_of_line_p. */
4834 struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
4835
4836 if (start == s->row->used[s->area]
4837 && s->hl == DRAW_NORMAL_TEXT
eb79f5cc
GM
4838 && s->area == TEXT_AREA
4839 && (s->row->fill_line_p
06a2c219
GM
4840 || s->face->background != default_face->background
4841 || s->face->stipple != default_face->stipple))
4842 s->extends_to_end_of_line_p = 1;
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;
dc6f92b8 5817
06a2c219 5818 TRACE ((stderr, "expose_frame "));
dc6f92b8 5819
06a2c219
GM
5820 /* No need to redraw if frame will be redrawn soon. */
5821 if (FRAME_GARBAGED_P (f))
dc6f92b8 5822 {
06a2c219
GM
5823 TRACE ((stderr, " garbaged\n"));
5824 return;
5825 }
5826
5827 /* If basic faces haven't been realized yet, there is no point in
5828 trying to redraw anything. This can happen when we get an expose
5829 event while Emacs is starting, e.g. by moving another window. */
5830 if (FRAME_FACE_CACHE (f) == NULL
5831 || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
5832 {
5833 TRACE ((stderr, " no faces\n"));
5834 return;
58769bee 5835 }
06a2c219
GM
5836
5837 if (w == 0 || h == 0)
58769bee 5838 {
06a2c219
GM
5839 r.x = r.y = 0;
5840 r.width = CANON_X_UNIT (f) * f->width;
5841 r.height = CANON_Y_UNIT (f) * f->height;
dc6f92b8
JB
5842 }
5843 else
5844 {
06a2c219
GM
5845 r.x = x;
5846 r.y = y;
5847 r.width = w;
5848 r.height = h;
5849 }
5850
5851 TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
5852 expose_window_tree (XWINDOW (f->root_window), &r);
5853
9ea173e8 5854 if (WINDOWP (f->tool_bar_window))
a02f1be0 5855 expose_window (XWINDOW (f->tool_bar_window), &r);
06a2c219
GM
5856
5857#ifndef USE_X_TOOLKIT
5858 if (WINDOWP (f->menu_bar_window))
a02f1be0 5859 expose_window (XWINDOW (f->menu_bar_window), &r);
06a2c219 5860#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
5861}
5862
06a2c219
GM
5863
5864/* Redraw (parts) of all windows in the window tree rooted at W that
5865 intersect R. R contains frame pixel coordinates. */
5866
58769bee 5867static void
06a2c219
GM
5868expose_window_tree (w, r)
5869 struct window *w;
5870 XRectangle *r;
dc6f92b8 5871{
06a2c219
GM
5872 while (w)
5873 {
5874 if (!NILP (w->hchild))
5875 expose_window_tree (XWINDOW (w->hchild), r);
5876 else if (!NILP (w->vchild))
5877 expose_window_tree (XWINDOW (w->vchild), r);
a39202f6
GM
5878 else if (expose_window (w, r) == 0)
5879 break;
a02f1be0 5880 w = NILP (w->next) ? NULL : XWINDOW (w->next);
06a2c219
GM
5881 }
5882}
58769bee 5883
dc6f92b8 5884
06a2c219
GM
5885/* Redraw the part of glyph row area AREA of glyph row ROW on window W
5886 which intersects rectangle R. R is in window-relative coordinates. */
5887
5888static void
5889expose_area (w, row, r, area)
5890 struct window *w;
5891 struct glyph_row *row;
5892 XRectangle *r;
5893 enum glyph_row_area area;
5894{
06a2c219
GM
5895 struct glyph *first = row->glyphs[area];
5896 struct glyph *end = row->glyphs[area] + row->used[area];
5897 struct glyph *last;
4bc6dcc7 5898 int first_x, start_x, x;
06a2c219 5899
6fb13182
GM
5900 if (area == TEXT_AREA && row->fill_line_p)
5901 /* If row extends face to end of line write the whole line. */
4bc6dcc7 5902 x_draw_glyphs (w, 0, row, area,
6fb13182 5903 0, row->used[area],
06a2c219 5904 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5905 NULL, NULL, 0);
6fb13182
GM
5906 else
5907 {
4bc6dcc7
GM
5908 /* Set START_X to the window-relative start position for drawing glyphs of
5909 AREA. The first glyph of the text area can be partially visible.
5910 The first glyphs of other areas cannot. */
5911 if (area == LEFT_MARGIN_AREA)
5912 start_x = 0;
5913 else if (area == TEXT_AREA)
5914 start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
5915 else
5916 start_x = (window_box_width (w, LEFT_MARGIN_AREA)
5917 + window_box_width (w, TEXT_AREA));
5918 x = start_x;
5919
6fb13182
GM
5920 /* Find the first glyph that must be redrawn. */
5921 while (first < end
5922 && x + first->pixel_width < r->x)
5923 {
5924 x += first->pixel_width;
5925 ++first;
5926 }
5927
5928 /* Find the last one. */
5929 last = first;
5930 first_x = x;
5931 while (last < end
5932 && x < r->x + r->width)
5933 {
5934 x += last->pixel_width;
5935 ++last;
5936 }
5937
5938 /* Repaint. */
5939 if (last > first)
4bc6dcc7 5940 x_draw_glyphs (w, first_x - start_x, row, area,
6fb13182
GM
5941 first - row->glyphs[area],
5942 last - row->glyphs[area],
5943 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
5944 NULL, NULL, 0);
5945 }
06a2c219
GM
5946}
5947
58769bee 5948
06a2c219
GM
5949/* Redraw the parts of the glyph row ROW on window W intersecting
5950 rectangle R. R is in window-relative coordinates. */
dc6f92b8 5951
06a2c219
GM
5952static void
5953expose_line (w, row, r)
5954 struct window *w;
5955 struct glyph_row *row;
5956 XRectangle *r;
5957{
5958 xassert (row->enabled_p);
5959
5960 if (row->mode_line_p || w->pseudo_window_p)
5961 x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
5962 row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
66ac4b0e 5963 NULL, NULL, 0);
06a2c219
GM
5964 else
5965 {
5966 if (row->used[LEFT_MARGIN_AREA])
5967 expose_area (w, row, r, LEFT_MARGIN_AREA);
5968 if (row->used[TEXT_AREA])
5969 expose_area (w, row, r, TEXT_AREA);
5970 if (row->used[RIGHT_MARGIN_AREA])
5971 expose_area (w, row, r, RIGHT_MARGIN_AREA);
5972 x_draw_row_bitmaps (w, row);
5973 }
5974}
dc6f92b8 5975
58769bee 5976
06a2c219
GM
5977/* Return non-zero if W's cursor intersects rectangle R. */
5978
5979static int
5980x_phys_cursor_in_rect_p (w, r)
5981 struct window *w;
5982 XRectangle *r;
5983{
5984 XRectangle cr, result;
5985 struct glyph *cursor_glyph;
5986
5987 cursor_glyph = get_phys_cursor_glyph (w);
5988 if (cursor_glyph)
5989 {
5990 cr.x = w->phys_cursor.x;
5991 cr.y = w->phys_cursor.y;
5992 cr.width = cursor_glyph->pixel_width;
5993 cr.height = w->phys_cursor_height;
5994 return x_intersect_rectangles (&cr, r, &result);
5995 }
5996 else
5997 return 0;
dc6f92b8 5998}
dc6f92b8 5999
06a2c219 6000
a02f1be0
GM
6001/* Redraw the part of window W intersection rectangle FR. Pixel
6002 coordinates in FR are frame-relative. Call this function with
6003 input blocked. */
dc6f92b8 6004
a39202f6 6005static int
a02f1be0 6006expose_window (w, fr)
06a2c219 6007 struct window *w;
a02f1be0 6008 XRectangle *fr;
dc6f92b8 6009{
a02f1be0 6010 struct frame *f = XFRAME (w->frame);
a02f1be0 6011 XRectangle wr, r;
dc6f92b8 6012
80c32bcc
GM
6013 /* If window is not yet fully initialized, do nothing. This can
6014 happen when toolkit scroll bars are used and a window is split.
6015 Reconfiguring the scroll bar will generate an expose for a newly
6016 created window. */
a39202f6
GM
6017 if (w->current_matrix == NULL)
6018 return 1;
6019
6020 /* When we're currently updating the window, display and current
6021 matrix usually don't agree. Arrange for a thorough display
6022 later. */
6023 if (w == updated_window)
6024 {
6025 SET_FRAME_GARBAGED (f);
6026 return 0;
6027 }
80c32bcc 6028
a39202f6 6029 /* Frame-relative pixel rectangle of W. */
a02f1be0
GM
6030 wr.x = XFASTINT (w->left) * CANON_X_UNIT (f);
6031 wr.y = XFASTINT (w->top) * CANON_Y_UNIT (f);
6032 wr.width = XFASTINT (w->width) * CANON_X_UNIT (f);
6033 wr.height = XFASTINT (w->height) * CANON_Y_UNIT (f);
6034
a39202f6
GM
6035 if (x_intersect_rectangles (fr, &wr, &r))
6036 {
6037 int yb = window_text_bottom_y (w);
6038 struct glyph_row *row;
6039 int cursor_cleared_p;
a02f1be0 6040
a39202f6
GM
6041 TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
6042 r.x, r.y, r.width, r.height));
dc6f92b8 6043
a39202f6
GM
6044 /* Convert to window coordinates. */
6045 r.x = FRAME_TO_WINDOW_PIXEL_X (w, r.x);
6046 r.y = FRAME_TO_WINDOW_PIXEL_Y (w, r.y);
dc6f92b8 6047
a39202f6
GM
6048 /* Turn off the cursor. */
6049 if (!w->pseudo_window_p
6050 && x_phys_cursor_in_rect_p (w, &r))
6051 {
6052 x_clear_cursor (w);
6053 cursor_cleared_p = 1;
6054 }
6055 else
6056 cursor_cleared_p = 0;
06a2c219 6057
a39202f6
GM
6058 /* Find the first row intersecting the rectangle R. */
6059 for (row = w->current_matrix->rows;
6060 row->enabled_p;
6061 ++row)
6062 {
6063 int y0 = row->y;
6064 int y1 = MATRIX_ROW_BOTTOM_Y (row);
6065
6066 if ((y0 >= r.y && y0 < r.y + r.height)
6067 || (y1 > r.y && y1 < r.y + r.height)
6068 || (r.y >= y0 && r.y < y1)
6069 || (r.y + r.height > y0 && r.y + r.height < y1))
6070 expose_line (w, row, &r);
6071
6072 if (y1 >= yb)
6073 break;
6074 }
dc6f92b8 6075
a39202f6
GM
6076 /* Display the mode line if there is one. */
6077 if (WINDOW_WANTS_MODELINE_P (w)
6078 && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
6079 row->enabled_p)
6080 && row->y < r.y + r.height)
6081 expose_line (w, row, &r);
6082
6083 if (!w->pseudo_window_p)
6084 {
6085 /* Draw border between windows. */
6086 x_draw_vertical_border (w);
06a2c219 6087
a39202f6
GM
6088 /* Turn the cursor on again. */
6089 if (cursor_cleared_p)
6090 x_update_window_cursor (w, 1);
6091 }
06a2c219 6092 }
a39202f6
GM
6093
6094 return 1;
06a2c219 6095}
dc6f92b8 6096
dc6f92b8 6097
06a2c219
GM
6098/* Determine the intersection of two rectangles R1 and R2. Return
6099 the intersection in *RESULT. Value is non-zero if RESULT is not
6100 empty. */
6101
6102static int
6103x_intersect_rectangles (r1, r2, result)
6104 XRectangle *r1, *r2, *result;
6105{
6106 XRectangle *left, *right;
6107 XRectangle *upper, *lower;
6108 int intersection_p = 0;
6109
6110 /* Rearrange so that R1 is the left-most rectangle. */
6111 if (r1->x < r2->x)
6112 left = r1, right = r2;
6113 else
6114 left = r2, right = r1;
6115
6116 /* X0 of the intersection is right.x0, if this is inside R1,
6117 otherwise there is no intersection. */
6118 if (right->x <= left->x + left->width)
6119 {
6120 result->x = right->x;
6121
6122 /* The right end of the intersection is the minimum of the
6123 the right ends of left and right. */
6124 result->width = (min (left->x + left->width, right->x + right->width)
6125 - result->x);
6126
6127 /* Same game for Y. */
6128 if (r1->y < r2->y)
6129 upper = r1, lower = r2;
6130 else
6131 upper = r2, lower = r1;
6132
6133 /* The upper end of the intersection is lower.y0, if this is inside
6134 of upper. Otherwise, there is no intersection. */
6135 if (lower->y <= upper->y + upper->height)
dc43ef94 6136 {
06a2c219
GM
6137 result->y = lower->y;
6138
6139 /* The lower end of the intersection is the minimum of the lower
6140 ends of upper and lower. */
6141 result->height = (min (lower->y + lower->height,
6142 upper->y + upper->height)
6143 - result->y);
6144 intersection_p = 1;
dc43ef94 6145 }
dc6f92b8
JB
6146 }
6147
06a2c219 6148 return intersection_p;
dc6f92b8 6149}
06a2c219
GM
6150
6151
6152
6153
dc6f92b8 6154\f
dc6f92b8 6155static void
334208b7
RS
6156frame_highlight (f)
6157 struct frame *f;
dc6f92b8 6158{
b3e1e05c
JB
6159 /* We used to only do this if Vx_no_window_manager was non-nil, but
6160 the ICCCM (section 4.1.6) says that the window's border pixmap
6161 and border pixel are window attributes which are "private to the
6162 client", so we can always change it to whatever we want. */
6163 BLOCK_INPUT;
334208b7 6164 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6165 f->output_data.x->border_pixel);
b3e1e05c 6166 UNBLOCK_INPUT;
5d46f928 6167 x_update_cursor (f, 1);
dc6f92b8
JB
6168}
6169
6170static void
334208b7
RS
6171frame_unhighlight (f)
6172 struct frame *f;
dc6f92b8 6173{
b3e1e05c
JB
6174 /* We used to only do this if Vx_no_window_manager was non-nil, but
6175 the ICCCM (section 4.1.6) says that the window's border pixmap
6176 and border pixel are window attributes which are "private to the
6177 client", so we can always change it to whatever we want. */
6178 BLOCK_INPUT;
334208b7 6179 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 6180 f->output_data.x->border_tile);
b3e1e05c 6181 UNBLOCK_INPUT;
5d46f928 6182 x_update_cursor (f, 1);
dc6f92b8 6183}
dc6f92b8 6184
f676886a
JB
6185/* The focus has changed. Update the frames as necessary to reflect
6186 the new situation. Note that we can't change the selected frame
c5acd733 6187 here, because the Lisp code we are interrupting might become confused.
eb8c3be9 6188 Each event gets marked with the frame in which it occurred, so the
c5acd733 6189 Lisp code can tell when the switch took place by examining the events. */
dc6f92b8 6190
6d4238f3 6191static void
0f941935
KH
6192x_new_focus_frame (dpyinfo, frame)
6193 struct x_display_info *dpyinfo;
f676886a 6194 struct frame *frame;
dc6f92b8 6195{
0f941935 6196 struct frame *old_focus = dpyinfo->x_focus_frame;
dc6f92b8 6197
0f941935 6198 if (frame != dpyinfo->x_focus_frame)
dc6f92b8 6199 {
58769bee 6200 /* Set this before calling other routines, so that they see
f676886a 6201 the correct value of x_focus_frame. */
0f941935 6202 dpyinfo->x_focus_frame = frame;
6d4238f3
JB
6203
6204 if (old_focus && old_focus->auto_lower)
f676886a 6205 x_lower_frame (old_focus);
dc6f92b8
JB
6206
6207#if 0
f676886a 6208 selected_frame = frame;
e0c1aef2
KH
6209 XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
6210 selected_frame);
f676886a
JB
6211 Fselect_window (selected_frame->selected_window);
6212 choose_minibuf_frame ();
c118dd06 6213#endif /* ! 0 */
dc6f92b8 6214
0f941935
KH
6215 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
6216 pending_autoraise_frame = dpyinfo->x_focus_frame;
0134a210
RS
6217 else
6218 pending_autoraise_frame = 0;
6d4238f3 6219 }
dc6f92b8 6220
0f941935 6221 x_frame_rehighlight (dpyinfo);
6d4238f3
JB
6222}
6223
37c2c98b
RS
6224/* Handle an event saying the mouse has moved out of an Emacs frame. */
6225
6226void
0f941935
KH
6227x_mouse_leave (dpyinfo)
6228 struct x_display_info *dpyinfo;
37c2c98b 6229{
0f941935 6230 x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
37c2c98b 6231}
6d4238f3 6232
f451eb13
JB
6233/* The focus has changed, or we have redirected a frame's focus to
6234 another frame (this happens when a frame uses a surrogate
06a2c219 6235 mini-buffer frame). Shift the highlight as appropriate.
0f941935
KH
6236
6237 The FRAME argument doesn't necessarily have anything to do with which
06a2c219 6238 frame is being highlighted or un-highlighted; we only use it to find
0f941935 6239 the appropriate X display info. */
06a2c219 6240
6d4238f3 6241static void
0f941935
KH
6242XTframe_rehighlight (frame)
6243 struct frame *frame;
6d4238f3 6244{
0f941935
KH
6245 x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
6246}
6d4238f3 6247
0f941935
KH
6248static void
6249x_frame_rehighlight (dpyinfo)
6250 struct x_display_info *dpyinfo;
6251{
6252 struct frame *old_highlight = dpyinfo->x_highlight_frame;
6253
6254 if (dpyinfo->x_focus_frame)
6d4238f3 6255 {
0f941935
KH
6256 dpyinfo->x_highlight_frame
6257 = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
6258 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
6259 : dpyinfo->x_focus_frame);
6260 if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
f451eb13 6261 {
0f941935
KH
6262 FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
6263 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
f451eb13 6264 }
dc6f92b8 6265 }
6d4238f3 6266 else
0f941935 6267 dpyinfo->x_highlight_frame = 0;
dc6f92b8 6268
0f941935 6269 if (dpyinfo->x_highlight_frame != old_highlight)
6d4238f3
JB
6270 {
6271 if (old_highlight)
f676886a 6272 frame_unhighlight (old_highlight);
0f941935
KH
6273 if (dpyinfo->x_highlight_frame)
6274 frame_highlight (dpyinfo->x_highlight_frame);
6d4238f3 6275 }
dc6f92b8 6276}
06a2c219
GM
6277
6278
dc6f92b8 6279\f
06a2c219 6280/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
dc6f92b8 6281
28430d3c
JB
6282/* Initialize mode_switch_bit and modifier_meaning. */
6283static void
334208b7
RS
6284x_find_modifier_meanings (dpyinfo)
6285 struct x_display_info *dpyinfo;
28430d3c 6286{
f689eb05 6287 int min_code, max_code;
28430d3c
JB
6288 KeySym *syms;
6289 int syms_per_code;
6290 XModifierKeymap *mods;
6291
334208b7
RS
6292 dpyinfo->meta_mod_mask = 0;
6293 dpyinfo->shift_lock_mask = 0;
6294 dpyinfo->alt_mod_mask = 0;
6295 dpyinfo->super_mod_mask = 0;
6296 dpyinfo->hyper_mod_mask = 0;
58769bee 6297
9658a521 6298#ifdef HAVE_X11R4
334208b7 6299 XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
9658a521 6300#else
4a60f8c5
RS
6301 min_code = dpyinfo->display->min_keycode;
6302 max_code = dpyinfo->display->max_keycode;
9658a521
JB
6303#endif
6304
334208b7 6305 syms = XGetKeyboardMapping (dpyinfo->display,
28430d3c
JB
6306 min_code, max_code - min_code + 1,
6307 &syms_per_code);
334208b7 6308 mods = XGetModifierMapping (dpyinfo->display);
28430d3c 6309
58769bee 6310 /* Scan the modifier table to see which modifier bits the Meta and
11edeb03 6311 Alt keysyms are on. */
28430d3c 6312 {
06a2c219 6313 int row, col; /* The row and column in the modifier table. */
28430d3c
JB
6314
6315 for (row = 3; row < 8; row++)
6316 for (col = 0; col < mods->max_keypermod; col++)
6317 {
0299d313
RS
6318 KeyCode code
6319 = mods->modifiermap[(row * mods->max_keypermod) + col];
28430d3c 6320
af92970c
KH
6321 /* Zeroes are used for filler. Skip them. */
6322 if (code == 0)
6323 continue;
6324
28430d3c
JB
6325 /* Are any of this keycode's keysyms a meta key? */
6326 {
6327 int code_col;
6328
6329 for (code_col = 0; code_col < syms_per_code; code_col++)
6330 {
f689eb05 6331 int sym = syms[((code - min_code) * syms_per_code) + code_col];
28430d3c 6332
f689eb05 6333 switch (sym)
28430d3c 6334 {
f689eb05
JB
6335 case XK_Meta_L:
6336 case XK_Meta_R:
334208b7 6337 dpyinfo->meta_mod_mask |= (1 << row);
28430d3c 6338 break;
f689eb05
JB
6339
6340 case XK_Alt_L:
6341 case XK_Alt_R:
334208b7 6342 dpyinfo->alt_mod_mask |= (1 << row);
a3c44b14
RS
6343 break;
6344
6345 case XK_Hyper_L:
6346 case XK_Hyper_R:
334208b7 6347 dpyinfo->hyper_mod_mask |= (1 << row);
a3c44b14
RS
6348 break;
6349
6350 case XK_Super_L:
6351 case XK_Super_R:
334208b7 6352 dpyinfo->super_mod_mask |= (1 << row);
f689eb05 6353 break;
11edeb03
JB
6354
6355 case XK_Shift_Lock:
6356 /* Ignore this if it's not on the lock modifier. */
6357 if ((1 << row) == LockMask)
334208b7 6358 dpyinfo->shift_lock_mask = LockMask;
11edeb03 6359 break;
28430d3c
JB
6360 }
6361 }
6362 }
6363 }
6364 }
6365
f689eb05 6366 /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
334208b7 6367 if (! dpyinfo->meta_mod_mask)
a3c44b14 6368 {
334208b7
RS
6369 dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
6370 dpyinfo->alt_mod_mask = 0;
a3c44b14 6371 }
f689eb05 6372
148c4b70
RS
6373 /* If some keys are both alt and meta,
6374 make them just meta, not alt. */
334208b7 6375 if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
148c4b70 6376 {
334208b7 6377 dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
148c4b70 6378 }
58769bee 6379
28430d3c 6380 XFree ((char *) syms);
f689eb05 6381 XFreeModifiermap (mods);
28430d3c
JB
6382}
6383
dfeccd2d
JB
6384/* Convert between the modifier bits X uses and the modifier bits
6385 Emacs uses. */
06a2c219 6386
7c5283e4 6387static unsigned int
334208b7
RS
6388x_x_to_emacs_modifiers (dpyinfo, state)
6389 struct x_display_info *dpyinfo;
dc6f92b8
JB
6390 unsigned int state;
6391{
334208b7
RS
6392 return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0)
6393 | ((state & ControlMask) ? ctrl_modifier : 0)
6394 | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0)
6395 | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0)
6396 | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0)
6397 | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0));
dc6f92b8
JB
6398}
6399
dfeccd2d 6400static unsigned int
334208b7
RS
6401x_emacs_to_x_modifiers (dpyinfo, state)
6402 struct x_display_info *dpyinfo;
dfeccd2d
JB
6403 unsigned int state;
6404{
334208b7
RS
6405 return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0)
6406 | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0)
6407 | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0)
6408 | ((state & shift_modifier) ? ShiftMask : 0)
6409 | ((state & ctrl_modifier) ? ControlMask : 0)
6410 | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0));
dfeccd2d 6411}
d047c4eb
KH
6412
6413/* Convert a keysym to its name. */
6414
6415char *
6416x_get_keysym_name (keysym)
6417 KeySym keysym;
6418{
6419 char *value;
6420
6421 BLOCK_INPUT;
6422 value = XKeysymToString (keysym);
6423 UNBLOCK_INPUT;
6424
6425 return value;
6426}
06a2c219
GM
6427
6428
e4571a43
JB
6429\f
6430/* Mouse clicks and mouse movement. Rah. */
e4571a43 6431
06a2c219
GM
6432/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
6433 co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
6434 glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
6435 not force the value into range. */
69388238 6436
c8dba240 6437void
69388238 6438pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
e4571a43 6439 FRAME_PTR f;
69388238 6440 register int pix_x, pix_y;
e4571a43
JB
6441 register int *x, *y;
6442 XRectangle *bounds;
69388238 6443 int noclip;
e4571a43 6444{
06a2c219 6445 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
69388238
RS
6446 even for negative values. */
6447 if (pix_x < 0)
7556890b 6448 pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
69388238 6449 if (pix_y < 0)
7556890b 6450 pix_y -= (f)->output_data.x->line_height - 1;
69388238 6451
e4571a43
JB
6452 pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
6453 pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
6454
6455 if (bounds)
6456 {
7556890b
RS
6457 bounds->width = FONT_WIDTH (f->output_data.x->font);
6458 bounds->height = f->output_data.x->line_height;
e4571a43
JB
6459 bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
6460 bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
6461 }
6462
69388238
RS
6463 if (!noclip)
6464 {
6465 if (pix_x < 0)
6466 pix_x = 0;
3cbd2e0b
RS
6467 else if (pix_x > FRAME_WINDOW_WIDTH (f))
6468 pix_x = FRAME_WINDOW_WIDTH (f);
69388238
RS
6469
6470 if (pix_y < 0)
6471 pix_y = 0;
6472 else if (pix_y > f->height)
6473 pix_y = f->height;
6474 }
e4571a43
JB
6475
6476 *x = pix_x;
6477 *y = pix_y;
6478}
6479
06a2c219
GM
6480
6481/* Given HPOS/VPOS in the current matrix of W, return corresponding
6482 frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
6483 can't tell the positions because W's display is not up to date,
6484 return 0. */
6485
6486int
6487glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
6488 struct window *w;
6489 int hpos, vpos;
6490 int *frame_x, *frame_y;
2b5c9e71 6491{
06a2c219
GM
6492 int success_p;
6493
6494 xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
6495 xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
6496
6497 if (display_completed)
6498 {
6499 struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
6500 struct glyph *glyph = row->glyphs[TEXT_AREA];
6501 struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
6502
6503 *frame_y = row->y;
6504 *frame_x = row->x;
6505 while (glyph < end)
6506 {
6507 *frame_x += glyph->pixel_width;
6508 ++glyph;
6509 }
6510
6511 success_p = 1;
6512 }
6513 else
6514 {
6515 *frame_y = *frame_x = 0;
6516 success_p = 0;
6517 }
6518
6519 *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
6520 *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
6521 return success_p;
2b5c9e71
RS
6522}
6523
06a2c219 6524
dc6f92b8
JB
6525/* Prepare a mouse-event in *RESULT for placement in the input queue.
6526
6527 If the event is a button press, then note that we have grabbed
f451eb13 6528 the mouse. */
dc6f92b8
JB
6529
6530static Lisp_Object
f451eb13 6531construct_mouse_click (result, event, f)
dc6f92b8
JB
6532 struct input_event *result;
6533 XButtonEvent *event;
f676886a 6534 struct frame *f;
dc6f92b8 6535{
f451eb13 6536 /* Make the event type no_event; we'll change that when we decide
dc6f92b8 6537 otherwise. */
f451eb13 6538 result->kind = mouse_click;
69388238 6539 result->code = event->button - Button1;
1113d9db 6540 result->timestamp = event->time;
334208b7
RS
6541 result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
6542 event->state)
f689eb05 6543 | (event->type == ButtonRelease
58769bee 6544 ? up_modifier
f689eb05 6545 : down_modifier));
dc6f92b8 6546
06a2c219
GM
6547 XSETINT (result->x, event->x);
6548 XSETINT (result->y, event->y);
6549 XSETFRAME (result->frame_or_window, f);
0f8aabe9 6550 result->arg = Qnil;
06a2c219 6551 return Qnil;
dc6f92b8 6552}
b849c413 6553
69388238 6554\f
90e65f07
JB
6555/* Function to report a mouse movement to the mainstream Emacs code.
6556 The input handler calls this.
6557
6558 We have received a mouse movement event, which is given in *event.
6559 If the mouse is over a different glyph than it was last time, tell
6560 the mainstream emacs code by setting mouse_moved. If not, ask for
6561 another motion event, so we can check again the next time it moves. */
b8009dd1 6562
06a2c219
GM
6563static XMotionEvent last_mouse_motion_event;
6564static Lisp_Object last_mouse_motion_frame;
6565
90e65f07 6566static void
12ba150f 6567note_mouse_movement (frame, event)
f676886a 6568 FRAME_PTR frame;
90e65f07 6569 XMotionEvent *event;
90e65f07 6570{
e5d77022 6571 last_mouse_movement_time = event->time;
06a2c219
GM
6572 last_mouse_motion_event = *event;
6573 XSETFRAME (last_mouse_motion_frame, frame);
e5d77022 6574
27f338af
RS
6575 if (event->window != FRAME_X_WINDOW (frame))
6576 {
39d8bb4d 6577 frame->mouse_moved = 1;
27f338af 6578 last_mouse_scroll_bar = Qnil;
27f338af 6579 note_mouse_highlight (frame, -1, -1);
27f338af
RS
6580 }
6581
90e65f07 6582 /* Has the mouse moved off the glyph it was on at the last sighting? */
27f338af
RS
6583 else if (event->x < last_mouse_glyph.x
6584 || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
6585 || event->y < last_mouse_glyph.y
6586 || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
12ba150f 6587 {
39d8bb4d 6588 frame->mouse_moved = 1;
ab648270 6589 last_mouse_scroll_bar = Qnil;
b8009dd1 6590 note_mouse_highlight (frame, event->x, event->y);
90e65f07
JB
6591 }
6592}
6593
bf1c0ba1 6594/* This is used for debugging, to turn off note_mouse_highlight. */
bf1c0ba1 6595
06a2c219
GM
6596 int disable_mouse_highlight;
6597
6598
6599\f
6600/************************************************************************
6601 Mouse Face
6602 ************************************************************************/
6603
6604/* Find the glyph under window-relative coordinates X/Y in window W.
6605 Consider only glyphs from buffer text, i.e. no glyphs from overlay
6606 strings. Return in *HPOS and *VPOS the row and column number of
6607 the glyph found. Return in *AREA the glyph area containing X.
6608 Value is a pointer to the glyph found or null if X/Y is not on
6609 text, or we can't tell because W's current matrix is not up to
6610 date. */
6611
6612static struct glyph *
f9db2310 6613x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
06a2c219
GM
6614 struct window *w;
6615 int x, y;
6616 int *hpos, *vpos, *area;
f9db2310 6617 int buffer_only_p;
06a2c219
GM
6618{
6619 struct glyph *glyph, *end;
3e71d8f2 6620 struct glyph_row *row = NULL;
06a2c219
GM
6621 int x0, i, left_area_width;
6622
6623 /* Find row containing Y. Give up if some row is not enabled. */
6624 for (i = 0; i < w->current_matrix->nrows; ++i)
6625 {
6626 row = MATRIX_ROW (w->current_matrix, i);
6627 if (!row->enabled_p)
6628 return NULL;
6629 if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
6630 break;
6631 }
6632
6633 *vpos = i;
6634 *hpos = 0;
6635
6636 /* Give up if Y is not in the window. */
6637 if (i == w->current_matrix->nrows)
6638 return NULL;
6639
6640 /* Get the glyph area containing X. */
6641 if (w->pseudo_window_p)
6642 {
6643 *area = TEXT_AREA;
6644 x0 = 0;
6645 }
6646 else
6647 {
6648 left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
6649 if (x < left_area_width)
6650 {
6651 *area = LEFT_MARGIN_AREA;
6652 x0 = 0;
6653 }
6654 else if (x < left_area_width + window_box_width (w, TEXT_AREA))
6655 {
6656 *area = TEXT_AREA;
6657 x0 = row->x + left_area_width;
6658 }
6659 else
6660 {
6661 *area = RIGHT_MARGIN_AREA;
6662 x0 = left_area_width + window_box_width (w, TEXT_AREA);
6663 }
6664 }
6665
6666 /* Find glyph containing X. */
6667 glyph = row->glyphs[*area];
6668 end = glyph + row->used[*area];
6669 while (glyph < end)
6670 {
6671 if (x < x0 + glyph->pixel_width)
6672 {
6673 if (w->pseudo_window_p)
6674 break;
f9db2310 6675 else if (!buffer_only_p || BUFFERP (glyph->object))
06a2c219
GM
6676 break;
6677 }
6678
6679 x0 += glyph->pixel_width;
6680 ++glyph;
6681 }
6682
6683 if (glyph == end)
6684 return NULL;
6685
6686 *hpos = glyph - row->glyphs[*area];
6687 return glyph;
6688}
6689
6690
6691/* Convert frame-relative x/y to coordinates relative to window W.
6692 Takes pseudo-windows into account. */
6693
6694static void
6695frame_to_window_pixel_xy (w, x, y)
6696 struct window *w;
6697 int *x, *y;
6698{
6699 if (w->pseudo_window_p)
6700 {
6701 /* A pseudo-window is always full-width, and starts at the
6702 left edge of the frame, plus a frame border. */
6703 struct frame *f = XFRAME (w->frame);
6704 *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
6705 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6706 }
6707 else
6708 {
6709 *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
6710 *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
6711 }
6712}
6713
6714
e371a781 6715/* Take proper action when mouse has moved to the mode or header line of
06a2c219
GM
6716 window W, x-position X. MODE_LINE_P non-zero means mouse is on the
6717 mode line. X is relative to the start of the text display area of
6718 W, so the width of bitmap areas and scroll bars must be subtracted
6719 to get a position relative to the start of the mode line. */
6720
6721static void
6722note_mode_line_highlight (w, x, mode_line_p)
6723 struct window *w;
6724 int x, mode_line_p;
6725{
6726 struct frame *f = XFRAME (w->frame);
6727 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6728 Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
6729 struct glyph_row *row;
6730
6731 if (mode_line_p)
6732 row = MATRIX_MODE_LINE_ROW (w->current_matrix);
6733 else
045dee35 6734 row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
e371a781 6735
06a2c219
GM
6736 if (row->enabled_p)
6737 {
6738 struct glyph *glyph, *end;
6739 Lisp_Object help, map;
6740 int x0;
6741
6742 /* Find the glyph under X. */
6743 glyph = row->glyphs[TEXT_AREA];
6744 end = glyph + row->used[TEXT_AREA];
6745 x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
110859fc 6746 + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
e371a781 6747
06a2c219
GM
6748 while (glyph < end
6749 && x >= x0 + glyph->pixel_width)
6750 {
6751 x0 += glyph->pixel_width;
6752 ++glyph;
6753 }
6754
6755 if (glyph < end
6756 && STRINGP (glyph->object)
6757 && XSTRING (glyph->object)->intervals
6758 && glyph->charpos >= 0
6759 && glyph->charpos < XSTRING (glyph->object)->size)
6760 {
6761 /* If we're on a string with `help-echo' text property,
6762 arrange for the help to be displayed. This is done by
6763 setting the global variable help_echo to the help string. */
6764 help = Fget_text_property (make_number (glyph->charpos),
6765 Qhelp_echo, glyph->object);
b7e80413 6766 if (!NILP (help))
be010514
GM
6767 {
6768 help_echo = help;
7cea38bc 6769 XSETWINDOW (help_echo_window, w);
be010514
GM
6770 help_echo_object = glyph->object;
6771 help_echo_pos = glyph->charpos;
6772 }
06a2c219
GM
6773
6774 /* Change the mouse pointer according to what is under X/Y. */
6775 map = Fget_text_property (make_number (glyph->charpos),
6776 Qlocal_map, glyph->object);
02067692 6777 if (KEYMAPP (map))
06a2c219 6778 cursor = f->output_data.x->nontext_cursor;
be010514
GM
6779 else
6780 {
6781 map = Fget_text_property (make_number (glyph->charpos),
6782 Qkeymap, glyph->object);
02067692 6783 if (KEYMAPP (map))
be010514
GM
6784 cursor = f->output_data.x->nontext_cursor;
6785 }
06a2c219
GM
6786 }
6787 }
6788
6789 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
6790}
6791
6792
6793/* Take proper action when the mouse has moved to position X, Y on
6794 frame F as regards highlighting characters that have mouse-face
6795 properties. Also de-highlighting chars where the mouse was before.
27f338af 6796 X and Y can be negative or out of range. */
b8009dd1
RS
6797
6798static void
6799note_mouse_highlight (f, x, y)
06a2c219 6800 struct frame *f;
c32cdd9a 6801 int x, y;
b8009dd1 6802{
06a2c219
GM
6803 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
6804 int portion;
b8009dd1
RS
6805 Lisp_Object window;
6806 struct window *w;
0d487c52
GM
6807 Cursor cursor = None;
6808 struct buffer *b;
b8009dd1 6809
06a2c219
GM
6810 /* When a menu is active, don't highlight because this looks odd. */
6811#ifdef USE_X_TOOLKIT
6812 if (popup_activated ())
6813 return;
6814#endif
6815
04fff9c0
GM
6816 if (disable_mouse_highlight
6817 || !f->glyphs_initialized_p)
bf1c0ba1
RS
6818 return;
6819
06a2c219
GM
6820 dpyinfo->mouse_face_mouse_x = x;
6821 dpyinfo->mouse_face_mouse_y = y;
6822 dpyinfo->mouse_face_mouse_frame = f;
b8009dd1 6823
06a2c219 6824 if (dpyinfo->mouse_face_defer)
b8009dd1
RS
6825 return;
6826
514e4681
RS
6827 if (gc_in_progress)
6828 {
06a2c219 6829 dpyinfo->mouse_face_deferred_gc = 1;
514e4681
RS
6830 return;
6831 }
6832
b8009dd1 6833 /* Which window is that in? */
06a2c219 6834 window = window_from_coordinates (f, x, y, &portion, 1);
b8009dd1
RS
6835
6836 /* If we were displaying active text in another window, clear that. */
06a2c219
GM
6837 if (! EQ (window, dpyinfo->mouse_face_window))
6838 clear_mouse_face (dpyinfo);
6839
6840 /* Not on a window -> return. */
6841 if (!WINDOWP (window))
6842 return;
6843
6844 /* Convert to window-relative pixel coordinates. */
6845 w = XWINDOW (window);
6846 frame_to_window_pixel_xy (w, &x, &y);
6847
9ea173e8 6848 /* Handle tool-bar window differently since it doesn't display a
06a2c219 6849 buffer. */
9ea173e8 6850 if (EQ (window, f->tool_bar_window))
06a2c219 6851 {
9ea173e8 6852 note_tool_bar_highlight (f, x, y);
06a2c219
GM
6853 return;
6854 }
6855
0d487c52 6856 /* Mouse is on the mode or header line? */
06a2c219
GM
6857 if (portion == 1 || portion == 3)
6858 {
06a2c219
GM
6859 note_mode_line_highlight (w, x, portion == 1);
6860 return;
6861 }
0d487c52
GM
6862
6863 if (portion == 2)
6864 cursor = f->output_data.x->horizontal_drag_cursor;
06a2c219 6865 else
0d487c52 6866 cursor = f->output_data.x->text_cursor;
b8009dd1 6867
0cdd0c9f
RS
6868 /* Are we in a window whose display is up to date?
6869 And verify the buffer's text has not changed. */
0d487c52 6870 b = XBUFFER (w->buffer);
06a2c219
GM
6871 if (/* Within text portion of the window. */
6872 portion == 0
0cdd0c9f 6873 && EQ (w->window_end_valid, w->buffer)
0d487c52
GM
6874 && XFASTINT (w->last_modified) == BUF_MODIFF (b)
6875 && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
b8009dd1 6876 {
06a2c219
GM
6877 int hpos, vpos, pos, i, area;
6878 struct glyph *glyph;
f9db2310 6879 Lisp_Object object;
0d487c52
GM
6880 Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
6881 Lisp_Object *overlay_vec = NULL;
6882 int len, noverlays;
6883 struct buffer *obuf;
6884 int obegv, ozv, same_region;
b8009dd1 6885
06a2c219 6886 /* Find the glyph under X/Y. */
f9db2310 6887 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
06a2c219
GM
6888
6889 /* Clear mouse face if X/Y not over text. */
6890 if (glyph == NULL
6891 || area != TEXT_AREA
6892 || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
b8009dd1 6893 {
fa262c07
GM
6894 if (clear_mouse_face (dpyinfo))
6895 cursor = None;
6896 goto set_cursor;
06a2c219
GM
6897 }
6898
6899 pos = glyph->charpos;
f9db2310
GM
6900 object = glyph->object;
6901 if (!STRINGP (object) && !BUFFERP (object))
fa262c07 6902 goto set_cursor;
06a2c219 6903
0d487c52
GM
6904 /* If we get an out-of-range value, return now; avoid an error. */
6905 if (BUFFERP (object) && pos > BUF_Z (b))
fa262c07 6906 goto set_cursor;
06a2c219 6907
0d487c52
GM
6908 /* Make the window's buffer temporarily current for
6909 overlays_at and compute_char_face. */
6910 obuf = current_buffer;
6911 current_buffer = b;
6912 obegv = BEGV;
6913 ozv = ZV;
6914 BEGV = BEG;
6915 ZV = Z;
06a2c219 6916
0d487c52
GM
6917 /* Is this char mouse-active or does it have help-echo? */
6918 position = make_number (pos);
f9db2310 6919
0d487c52
GM
6920 if (BUFFERP (object))
6921 {
6922 /* Put all the overlays we want in a vector in overlay_vec.
6923 Store the length in len. If there are more than 10, make
6924 enough space for all, and try again. */
6925 len = 10;
6926 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6927 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
6928 if (noverlays > len)
6929 {
6930 len = noverlays;
6931 overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
6932 noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
6933 }
f8349001 6934
0d487c52
GM
6935 /* Sort overlays into increasing priority order. */
6936 noverlays = sort_overlays (overlay_vec, noverlays, w);
6937 }
6938 else
6939 noverlays = 0;
6940
6941 same_region = (EQ (window, dpyinfo->mouse_face_window)
6942 && vpos >= dpyinfo->mouse_face_beg_row
6943 && vpos <= dpyinfo->mouse_face_end_row
6944 && (vpos > dpyinfo->mouse_face_beg_row
6945 || hpos >= dpyinfo->mouse_face_beg_col)
6946 && (vpos < dpyinfo->mouse_face_end_row
6947 || hpos < dpyinfo->mouse_face_end_col
6948 || dpyinfo->mouse_face_past_end));
6949
6950 if (same_region)
6951 cursor = None;
6952
6953 /* Check mouse-face highlighting. */
6954 if (! same_region
6955 /* If there exists an overlay with mouse-face overlapping
6956 the one we are currently highlighting, we have to
6957 check if we enter the overlapping overlay, and then
6958 highlight only that. */
6959 || (OVERLAYP (dpyinfo->mouse_face_overlay)
6960 && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
6961 {
0d487c52
GM
6962 /* Find the highest priority overlay that has a mouse-face
6963 property. */
6964 overlay = Qnil;
6965 for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
6966 {
6967 mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
6968 if (!NILP (mouse_face))
6969 overlay = overlay_vec[i];
6970 }
8bd189fb
GM
6971
6972 /* If we're actually highlighting the same overlay as
6973 before, there's no need to do that again. */
6974 if (!NILP (overlay)
6975 && EQ (overlay, dpyinfo->mouse_face_overlay))
6976 goto check_help_echo;
f9db2310 6977
8bd189fb
GM
6978 dpyinfo->mouse_face_overlay = overlay;
6979
6980 /* Clear the display of the old active region, if any. */
6981 if (clear_mouse_face (dpyinfo))
6982 cursor = None;
6983
0d487c52
GM
6984 /* If no overlay applies, get a text property. */
6985 if (NILP (overlay))
6986 mouse_face = Fget_text_property (position, Qmouse_face, object);
06a2c219 6987
0d487c52
GM
6988 /* Handle the overlay case. */
6989 if (!NILP (overlay))
6990 {
6991 /* Find the range of text around this char that
6992 should be active. */
6993 Lisp_Object before, after;
6994 int ignore;
6995
6996 before = Foverlay_start (overlay);
6997 after = Foverlay_end (overlay);
6998 /* Record this as the current active region. */
6999 fast_find_position (w, XFASTINT (before),
7000 &dpyinfo->mouse_face_beg_col,
7001 &dpyinfo->mouse_face_beg_row,
7002 &dpyinfo->mouse_face_beg_x,
7003 &dpyinfo->mouse_face_beg_y);
7004 dpyinfo->mouse_face_past_end
7005 = !fast_find_position (w, XFASTINT (after),
7006 &dpyinfo->mouse_face_end_col,
7007 &dpyinfo->mouse_face_end_row,
7008 &dpyinfo->mouse_face_end_x,
7009 &dpyinfo->mouse_face_end_y);
7010 dpyinfo->mouse_face_window = window;
7011 dpyinfo->mouse_face_face_id
7012 = face_at_buffer_position (w, pos, 0, 0,
7013 &ignore, pos + 1, 1);
7014
7015 /* Display it as active. */
7016 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7017 cursor = None;
0d487c52
GM
7018 }
7019 /* Handle the text property case. */
7020 else if (!NILP (mouse_face) && BUFFERP (object))
7021 {
7022 /* Find the range of text around this char that
7023 should be active. */
7024 Lisp_Object before, after, beginning, end;
7025 int ignore;
7026
7027 beginning = Fmarker_position (w->start);
7028 end = make_number (BUF_Z (XBUFFER (object))
7029 - XFASTINT (w->window_end_pos));
7030 before
7031 = Fprevious_single_property_change (make_number (pos + 1),
7032 Qmouse_face,
7033 object, beginning);
7034 after
7035 = Fnext_single_property_change (position, Qmouse_face,
7036 object, end);
7037
7038 /* Record this as the current active region. */
7039 fast_find_position (w, XFASTINT (before),
7040 &dpyinfo->mouse_face_beg_col,
7041 &dpyinfo->mouse_face_beg_row,
7042 &dpyinfo->mouse_face_beg_x,
7043 &dpyinfo->mouse_face_beg_y);
7044 dpyinfo->mouse_face_past_end
7045 = !fast_find_position (w, XFASTINT (after),
7046 &dpyinfo->mouse_face_end_col,
7047 &dpyinfo->mouse_face_end_row,
7048 &dpyinfo->mouse_face_end_x,
7049 &dpyinfo->mouse_face_end_y);
7050 dpyinfo->mouse_face_window = window;
7051
7052 if (BUFFERP (object))
06a2c219
GM
7053 dpyinfo->mouse_face_face_id
7054 = face_at_buffer_position (w, pos, 0, 0,
7055 &ignore, pos + 1, 1);
7056
0d487c52
GM
7057 /* Display it as active. */
7058 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7059 cursor = None;
0d487c52
GM
7060 }
7061 else if (!NILP (mouse_face) && STRINGP (object))
7062 {
7063 Lisp_Object b, e;
7064 int ignore;
f9db2310 7065
0d487c52
GM
7066 b = Fprevious_single_property_change (make_number (pos + 1),
7067 Qmouse_face,
7068 object, Qnil);
7069 e = Fnext_single_property_change (position, Qmouse_face,
7070 object, Qnil);
7071 if (NILP (b))
7072 b = make_number (0);
7073 if (NILP (e))
7074 e = make_number (XSTRING (object)->size - 1);
7075 fast_find_string_pos (w, XINT (b), object,
06a2c219
GM
7076 &dpyinfo->mouse_face_beg_col,
7077 &dpyinfo->mouse_face_beg_row,
7078 &dpyinfo->mouse_face_beg_x,
0d487c52
GM
7079 &dpyinfo->mouse_face_beg_y, 0);
7080 fast_find_string_pos (w, XINT (e), object,
7081 &dpyinfo->mouse_face_end_col,
7082 &dpyinfo->mouse_face_end_row,
7083 &dpyinfo->mouse_face_end_x,
7084 &dpyinfo->mouse_face_end_y, 1);
7085 dpyinfo->mouse_face_past_end = 0;
7086 dpyinfo->mouse_face_window = window;
7087 dpyinfo->mouse_face_face_id
7088 = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
7089 glyph->face_id, 1);
7090 show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
58e5af83 7091 cursor = None;
0d487c52
GM
7092 }
7093 }
06a2c219 7094
8bd189fb
GM
7095 check_help_echo:
7096
0d487c52
GM
7097 /* Look for a `help-echo' property. */
7098 {
7099 Lisp_Object help, overlay;
06a2c219 7100
0d487c52
GM
7101 /* Check overlays first. */
7102 help = overlay = Qnil;
7103 for (i = noverlays - 1; i >= 0 && NILP (help); --i)
7104 {
7105 overlay = overlay_vec[i];
7106 help = Foverlay_get (overlay, Qhelp_echo);
7107 }
be010514 7108
0d487c52
GM
7109 if (!NILP (help))
7110 {
7111 help_echo = help;
7112 help_echo_window = window;
7113 help_echo_object = overlay;
7114 help_echo_pos = pos;
7115 }
7116 else
7117 {
7118 Lisp_Object object = glyph->object;
7119 int charpos = glyph->charpos;
7177d86b 7120
0d487c52
GM
7121 /* Try text properties. */
7122 if (STRINGP (object)
7123 && charpos >= 0
7124 && charpos < XSTRING (object)->size)
7125 {
7126 help = Fget_text_property (make_number (charpos),
7127 Qhelp_echo, object);
7128 if (NILP (help))
7129 {
7130 /* If the string itself doesn't specify a help-echo,
7131 see if the buffer text ``under'' it does. */
7132 struct glyph_row *r
7133 = MATRIX_ROW (w->current_matrix, vpos);
7134 int start = MATRIX_ROW_START_CHARPOS (r);
7135 int pos = string_buffer_position (w, object, start);
7136 if (pos > 0)
7137 {
7138 help = Fget_text_property (make_number (pos),
7139 Qhelp_echo, w->buffer);
7140 if (!NILP (help))
7141 {
7142 charpos = pos;
7143 object = w->buffer;
7144 }
7145 }
7146 }
7147 }
7148 else if (BUFFERP (object)
7149 && charpos >= BEGV
7150 && charpos < ZV)
7151 help = Fget_text_property (make_number (charpos), Qhelp_echo,
7152 object);
06a2c219 7153
0d487c52
GM
7154 if (!NILP (help))
7155 {
7156 help_echo = help;
7157 help_echo_window = window;
7158 help_echo_object = object;
7159 help_echo_pos = charpos;
7160 }
7161 }
06a2c219 7162 }
0d487c52
GM
7163
7164 BEGV = obegv;
7165 ZV = ozv;
7166 current_buffer = obuf;
06a2c219 7167 }
0d487c52 7168
fa262c07
GM
7169 set_cursor:
7170
0d487c52
GM
7171 if (cursor != None)
7172 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
06a2c219
GM
7173}
7174
7175static void
7176redo_mouse_highlight ()
7177{
7178 if (!NILP (last_mouse_motion_frame)
7179 && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
7180 note_mouse_highlight (XFRAME (last_mouse_motion_frame),
7181 last_mouse_motion_event.x,
7182 last_mouse_motion_event.y);
7183}
7184
7185
7186\f
7187/***********************************************************************
9ea173e8 7188 Tool-bars
06a2c219
GM
7189 ***********************************************************************/
7190
9ea173e8
GM
7191static int x_tool_bar_item P_ ((struct frame *, int, int,
7192 struct glyph **, int *, int *, int *));
06a2c219 7193
9ea173e8 7194/* Tool-bar item index of the item on which a mouse button was pressed
06a2c219
GM
7195 or -1. */
7196
9ea173e8 7197static int last_tool_bar_item;
06a2c219
GM
7198
7199
9ea173e8
GM
7200/* Get information about the tool-bar item at position X/Y on frame F.
7201 Return in *GLYPH a pointer to the glyph of the tool-bar item in
7202 the current matrix of the tool-bar window of F, or NULL if not
7203 on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
8daf1204 7204 item in F->tool_bar_items. Value is
06a2c219 7205
9ea173e8 7206 -1 if X/Y is not on a tool-bar item
06a2c219
GM
7207 0 if X/Y is on the same item that was highlighted before.
7208 1 otherwise. */
7209
7210static int
9ea173e8 7211x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
06a2c219
GM
7212 struct frame *f;
7213 int x, y;
7214 struct glyph **glyph;
7215 int *hpos, *vpos, *prop_idx;
7216{
7217 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7218 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7219 int area;
7220
7221 /* Find the glyph under X/Y. */
f9db2310 7222 *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
06a2c219
GM
7223 if (*glyph == NULL)
7224 return -1;
7225
9ea173e8 7226 /* Get the start of this tool-bar item's properties in
8daf1204 7227 f->tool_bar_items. */
9ea173e8 7228 if (!tool_bar_item_info (f, *glyph, prop_idx))
06a2c219
GM
7229 return -1;
7230
7231 /* Is mouse on the highlighted item? */
9ea173e8 7232 if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
06a2c219
GM
7233 && *vpos >= dpyinfo->mouse_face_beg_row
7234 && *vpos <= dpyinfo->mouse_face_end_row
7235 && (*vpos > dpyinfo->mouse_face_beg_row
7236 || *hpos >= dpyinfo->mouse_face_beg_col)
7237 && (*vpos < dpyinfo->mouse_face_end_row
7238 || *hpos < dpyinfo->mouse_face_end_col
7239 || dpyinfo->mouse_face_past_end))
7240 return 0;
7241
7242 return 1;
7243}
7244
7245
9ea173e8 7246/* Handle mouse button event on the tool-bar of frame F, at
06a2c219
GM
7247 frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress
7248 or ButtonRelase. */
7249
7250static void
9ea173e8 7251x_handle_tool_bar_click (f, button_event)
06a2c219
GM
7252 struct frame *f;
7253 XButtonEvent *button_event;
7254{
7255 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
9ea173e8 7256 struct window *w = XWINDOW (f->tool_bar_window);
06a2c219
GM
7257 int hpos, vpos, prop_idx;
7258 struct glyph *glyph;
7259 Lisp_Object enabled_p;
7260 int x = button_event->x;
7261 int y = button_event->y;
7262
9ea173e8 7263 /* If not on the highlighted tool-bar item, return. */
06a2c219 7264 frame_to_window_pixel_xy (w, &x, &y);
9ea173e8 7265 if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
06a2c219
GM
7266 return;
7267
7268 /* If item is disabled, do nothing. */
8daf1204 7269 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7270 if (NILP (enabled_p))
7271 return;
7272
7273 if (button_event->type == ButtonPress)
7274 {
7275 /* Show item in pressed state. */
7276 show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
7277 dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
9ea173e8 7278 last_tool_bar_item = prop_idx;
06a2c219
GM
7279 }
7280 else
7281 {
7282 Lisp_Object key, frame;
7283 struct input_event event;
7284
7285 /* Show item in released state. */
7286 show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
7287 dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
7288
8daf1204 7289 key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
06a2c219
GM
7290
7291 XSETFRAME (frame, f);
9ea173e8 7292 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7293 event.frame_or_window = frame;
7294 event.arg = frame;
06a2c219
GM
7295 kbd_buffer_store_event (&event);
7296
9ea173e8 7297 event.kind = TOOL_BAR_EVENT;
0f1a9b23
GM
7298 event.frame_or_window = frame;
7299 event.arg = key;
06a2c219
GM
7300 event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
7301 button_event->state);
7302 kbd_buffer_store_event (&event);
9ea173e8 7303 last_tool_bar_item = -1;
06a2c219
GM
7304 }
7305}
7306
7307
9ea173e8
GM
7308/* Possibly highlight a tool-bar item on frame F when mouse moves to
7309 tool-bar window-relative coordinates X/Y. Called from
06a2c219
GM
7310 note_mouse_highlight. */
7311
7312static void
9ea173e8 7313note_tool_bar_highlight (f, x, y)
06a2c219
GM
7314 struct frame *f;
7315 int x, y;
7316{
9ea173e8 7317 Lisp_Object window = f->tool_bar_window;
06a2c219
GM
7318 struct window *w = XWINDOW (window);
7319 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7320 int hpos, vpos;
7321 struct glyph *glyph;
7322 struct glyph_row *row;
5c187dee 7323 int i;
06a2c219
GM
7324 Lisp_Object enabled_p;
7325 int prop_idx;
140330de 7326 enum draw_glyphs_face draw;
5c187dee 7327 int mouse_down_p, rc;
06a2c219
GM
7328
7329 /* Function note_mouse_highlight is called with negative x(y
7330 values when mouse moves outside of the frame. */
7331 if (x <= 0 || y <= 0)
7332 {
7333 clear_mouse_face (dpyinfo);
7334 return;
7335 }
7336
9ea173e8 7337 rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
06a2c219
GM
7338 if (rc < 0)
7339 {
9ea173e8 7340 /* Not on tool-bar item. */
06a2c219
GM
7341 clear_mouse_face (dpyinfo);
7342 return;
7343 }
7344 else if (rc == 0)
06a2c219 7345 goto set_help_echo;
b8009dd1 7346
06a2c219
GM
7347 clear_mouse_face (dpyinfo);
7348
9ea173e8 7349 /* Mouse is down, but on different tool-bar item? */
06a2c219
GM
7350 mouse_down_p = (dpyinfo->grabbed
7351 && f == last_mouse_frame
7352 && FRAME_LIVE_P (f));
7353 if (mouse_down_p
9ea173e8 7354 && last_tool_bar_item != prop_idx)
06a2c219
GM
7355 return;
7356
7357 dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
7358 draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
7359
9ea173e8 7360 /* If tool-bar item is not enabled, don't highlight it. */
8daf1204 7361 enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
06a2c219
GM
7362 if (!NILP (enabled_p))
7363 {
7364 /* Compute the x-position of the glyph. In front and past the
7365 image is a space. We include this is the highlighted area. */
7366 row = MATRIX_ROW (w->current_matrix, vpos);
7367 for (i = x = 0; i < hpos; ++i)
7368 x += row->glyphs[TEXT_AREA][i].pixel_width;
7369
7370 /* Record this as the current active region. */
7371 dpyinfo->mouse_face_beg_col = hpos;
7372 dpyinfo->mouse_face_beg_row = vpos;
7373 dpyinfo->mouse_face_beg_x = x;
7374 dpyinfo->mouse_face_beg_y = row->y;
7375 dpyinfo->mouse_face_past_end = 0;
7376
7377 dpyinfo->mouse_face_end_col = hpos + 1;
7378 dpyinfo->mouse_face_end_row = vpos;
7379 dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
7380 dpyinfo->mouse_face_end_y = row->y;
7381 dpyinfo->mouse_face_window = window;
9ea173e8 7382 dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
06a2c219
GM
7383
7384 /* Display it as active. */
7385 show_mouse_face (dpyinfo, draw);
7386 dpyinfo->mouse_face_image_state = draw;
b8009dd1 7387 }
06a2c219
GM
7388
7389 set_help_echo:
7390
9ea173e8 7391 /* Set help_echo to a help string.to display for this tool-bar item.
06a2c219 7392 XTread_socket does the rest. */
7cea38bc 7393 help_echo_object = help_echo_window = Qnil;
be010514 7394 help_echo_pos = -1;
8daf1204 7395 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
b7e80413 7396 if (NILP (help_echo))
8daf1204 7397 help_echo = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
b8009dd1 7398}
4d73d038 7399
06a2c219
GM
7400
7401\f
7402/* Find the glyph matrix position of buffer position POS in window W.
7403 *HPOS, *VPOS, *X, and *Y are set to the positions found. W's
7404 current glyphs must be up to date. If POS is above window start
7405 return (0, 0, 0, 0). If POS is after end of W, return end of
7406 last line in W. */
b8009dd1
RS
7407
7408static int
06a2c219
GM
7409fast_find_position (w, pos, hpos, vpos, x, y)
7410 struct window *w;
b8009dd1 7411 int pos;
06a2c219 7412 int *hpos, *vpos, *x, *y;
b8009dd1 7413{
b8009dd1 7414 int i;
bf1c0ba1 7415 int lastcol;
06a2c219
GM
7416 int maybe_next_line_p = 0;
7417 int line_start_position;
7418 int yb = window_text_bottom_y (w);
03d1a189
GM
7419 struct glyph_row *row, *best_row;
7420 int row_vpos, best_row_vpos;
06a2c219
GM
7421 int current_x;
7422
03d1a189
GM
7423 row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7424 row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
7425
06a2c219 7426 while (row->y < yb)
b8009dd1 7427 {
06a2c219
GM
7428 if (row->used[TEXT_AREA])
7429 line_start_position = row->glyphs[TEXT_AREA]->charpos;
7430 else
7431 line_start_position = 0;
7432
7433 if (line_start_position > pos)
b8009dd1 7434 break;
77b68646
RS
7435 /* If the position sought is the end of the buffer,
7436 don't include the blank lines at the bottom of the window. */
06a2c219
GM
7437 else if (line_start_position == pos
7438 && pos == BUF_ZV (XBUFFER (w->buffer)))
77b68646 7439 {
06a2c219 7440 maybe_next_line_p = 1;
77b68646
RS
7441 break;
7442 }
06a2c219
GM
7443 else if (line_start_position > 0)
7444 {
7445 best_row = row;
7446 best_row_vpos = row_vpos;
7447 }
4b0bb6f3
GM
7448
7449 if (row->y + row->height >= yb)
7450 break;
06a2c219
GM
7451
7452 ++row;
7453 ++row_vpos;
b8009dd1 7454 }
06a2c219
GM
7455
7456 /* Find the right column within BEST_ROW. */
7457 lastcol = 0;
7458 current_x = best_row->x;
7459 for (i = 0; i < best_row->used[TEXT_AREA]; i++)
bf1c0ba1 7460 {
06a2c219
GM
7461 struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
7462 int charpos;
7463
7464 charpos = glyph->charpos;
7465 if (charpos == pos)
bf1c0ba1 7466 {
06a2c219
GM
7467 *hpos = i;
7468 *vpos = best_row_vpos;
7469 *x = current_x;
7470 *y = best_row->y;
bf1c0ba1
RS
7471 return 1;
7472 }
06a2c219 7473 else if (charpos > pos)
4d73d038 7474 break;
06a2c219
GM
7475 else if (charpos > 0)
7476 lastcol = i;
7477
7478 current_x += glyph->pixel_width;
bf1c0ba1 7479 }
b8009dd1 7480
77b68646
RS
7481 /* If we're looking for the end of the buffer,
7482 and we didn't find it in the line we scanned,
7483 use the start of the following line. */
06a2c219 7484 if (maybe_next_line_p)
77b68646 7485 {
06a2c219
GM
7486 ++best_row;
7487 ++best_row_vpos;
7488 lastcol = 0;
7489 current_x = best_row->x;
77b68646
RS
7490 }
7491
06a2c219
GM
7492 *vpos = best_row_vpos;
7493 *hpos = lastcol + 1;
7494 *x = current_x;
7495 *y = best_row->y;
b8009dd1
RS
7496 return 0;
7497}
7498
06a2c219 7499
f9db2310
GM
7500/* Find the position of the the glyph for position POS in OBJECT in
7501 window W's current matrix, and return in *X/*Y the pixel
7502 coordinates, and return in *HPOS/*VPOS the column/row of the glyph.
7503
7504 RIGHT_P non-zero means return the position of the right edge of the
7505 glyph, RIGHT_P zero means return the left edge position.
7506
7507 If no glyph for POS exists in the matrix, return the position of
7508 the glyph with the next smaller position that is in the matrix, if
7509 RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS
7510 exists in the matrix, return the position of the glyph with the
7511 next larger position in OBJECT.
7512
7513 Value is non-zero if a glyph was found. */
7514
7515static int
7516fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
7517 struct window *w;
7518 int pos;
7519 Lisp_Object object;
7520 int *hpos, *vpos, *x, *y;
7521 int right_p;
7522{
7523 int yb = window_text_bottom_y (w);
7524 struct glyph_row *r;
7525 struct glyph *best_glyph = NULL;
7526 struct glyph_row *best_row = NULL;
7527 int best_x = 0;
7528
7529 for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7530 r->enabled_p && r->y < yb;
7531 ++r)
7532 {
7533 struct glyph *g = r->glyphs[TEXT_AREA];
7534 struct glyph *e = g + r->used[TEXT_AREA];
7535 int gx;
7536
7537 for (gx = r->x; g < e; gx += g->pixel_width, ++g)
7538 if (EQ (g->object, object))
7539 {
7540 if (g->charpos == pos)
7541 {
7542 best_glyph = g;
7543 best_x = gx;
7544 best_row = r;
7545 goto found;
7546 }
7547 else if (best_glyph == NULL
7548 || ((abs (g->charpos - pos)
7549 < abs (best_glyph->charpos - pos))
7550 && (right_p
7551 ? g->charpos < pos
7552 : g->charpos > pos)))
7553 {
7554 best_glyph = g;
7555 best_x = gx;
7556 best_row = r;
7557 }
7558 }
7559 }
7560
7561 found:
7562
7563 if (best_glyph)
7564 {
7565 *x = best_x;
7566 *hpos = best_glyph - best_row->glyphs[TEXT_AREA];
7567
7568 if (right_p)
7569 {
7570 *x += best_glyph->pixel_width;
7571 ++*hpos;
7572 }
7573
7574 *y = best_row->y;
7575 *vpos = best_row - w->current_matrix->rows;
7576 }
7577
7578 return best_glyph != NULL;
7579}
7580
7581
b8009dd1
RS
7582/* Display the active region described by mouse_face_*
7583 in its mouse-face if HL > 0, in its normal face if HL = 0. */
7584
7585static void
06a2c219 7586show_mouse_face (dpyinfo, draw)
7a13e894 7587 struct x_display_info *dpyinfo;
06a2c219 7588 enum draw_glyphs_face draw;
b8009dd1 7589{
7a13e894 7590 struct window *w = XWINDOW (dpyinfo->mouse_face_window);
06a2c219 7591 struct frame *f = XFRAME (WINDOW_FRAME (w));
b8009dd1 7592 int i;
06a2c219
GM
7593 int cursor_off_p = 0;
7594 struct cursor_pos saved_cursor;
7595
7596 saved_cursor = output_cursor;
7597
7598 /* If window is in the process of being destroyed, don't bother
7599 to do anything. */
7600 if (w->current_matrix == NULL)
7601 goto set_x_cursor;
7602
7603 /* Recognize when we are called to operate on rows that don't exist
7604 anymore. This can happen when a window is split. */
7605 if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
7606 goto set_x_cursor;
7607
7608 set_output_cursor (&w->phys_cursor);
7609
7610 /* Note that mouse_face_beg_row etc. are window relative. */
7611 for (i = dpyinfo->mouse_face_beg_row;
7612 i <= dpyinfo->mouse_face_end_row;
7613 i++)
7614 {
7615 int start_hpos, end_hpos, start_x;
7616 struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
7617
7618 /* Don't do anything if row doesn't have valid contents. */
7619 if (!row->enabled_p)
7620 continue;
7621
7622 /* For all but the first row, the highlight starts at column 0. */
7623 if (i == dpyinfo->mouse_face_beg_row)
7624 {
7625 start_hpos = dpyinfo->mouse_face_beg_col;
7626 start_x = dpyinfo->mouse_face_beg_x;
7627 }
7628 else
7629 {
7630 start_hpos = 0;
7631 start_x = 0;
7632 }
7633
7634 if (i == dpyinfo->mouse_face_end_row)
7635 end_hpos = dpyinfo->mouse_face_end_col;
7636 else
7637 end_hpos = row->used[TEXT_AREA];
7638
7639 /* If the cursor's in the text we are about to rewrite, turn the
7640 cursor off. */
7641 if (!w->pseudo_window_p
7642 && i == output_cursor.vpos
7643 && output_cursor.hpos >= start_hpos - 1
7644 && output_cursor.hpos <= end_hpos)
514e4681 7645 {
06a2c219
GM
7646 x_update_window_cursor (w, 0);
7647 cursor_off_p = 1;
514e4681 7648 }
b8009dd1 7649
06a2c219 7650 if (end_hpos > start_hpos)
64f26cf5 7651 {
140330de 7652 row->mouse_face_p = draw == DRAW_MOUSE_FACE || DRAW_IMAGE_RAISED;
64f26cf5
GM
7653 x_draw_glyphs (w, start_x, row, TEXT_AREA,
7654 start_hpos, end_hpos, draw, NULL, NULL, 0);
7655 }
b8009dd1
RS
7656 }
7657
514e4681 7658 /* If we turned the cursor off, turn it back on. */
06a2c219
GM
7659 if (cursor_off_p)
7660 x_display_cursor (w, 1,
7661 output_cursor.hpos, output_cursor.vpos,
7662 output_cursor.x, output_cursor.y);
2729a2b5 7663
06a2c219 7664 output_cursor = saved_cursor;
fb3b7de5 7665
06a2c219
GM
7666 set_x_cursor:
7667
7668 /* Change the mouse cursor. */
7669 if (draw == DRAW_NORMAL_TEXT)
7670 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7671 f->output_data.x->text_cursor);
7672 else if (draw == DRAW_MOUSE_FACE)
334208b7 7673 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
7556890b 7674 f->output_data.x->cross_cursor);
27ead1d5 7675 else
334208b7 7676 XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
06a2c219 7677 f->output_data.x->nontext_cursor);
b8009dd1
RS
7678}
7679
7680/* Clear out the mouse-highlighted active region.
fa262c07
GM
7681 Redraw it un-highlighted first. Value is non-zero if mouse
7682 face was actually drawn unhighlighted. */
b8009dd1 7683
fa262c07 7684static int
7a13e894
RS
7685clear_mouse_face (dpyinfo)
7686 struct x_display_info *dpyinfo;
b8009dd1 7687{
fa262c07 7688 int cleared = 0;
06a2c219 7689
fa262c07
GM
7690 if (!NILP (dpyinfo->mouse_face_window))
7691 {
7692 show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
7693 cleared = 1;
7694 }
b8009dd1 7695
7a13e894
RS
7696 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7697 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7698 dpyinfo->mouse_face_window = Qnil;
1b85dc1c 7699 dpyinfo->mouse_face_overlay = Qnil;
fa262c07 7700 return cleared;
b8009dd1 7701}
e687d06e 7702
71b8321e
GM
7703
7704/* Clear any mouse-face on window W. This function is part of the
7705 redisplay interface, and is called from try_window_id and similar
7706 functions to ensure the mouse-highlight is off. */
7707
7708static void
7709x_clear_mouse_face (w)
7710 struct window *w;
7711{
7712 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
7713 Lisp_Object window;
7714
2e636f9d 7715 BLOCK_INPUT;
71b8321e
GM
7716 XSETWINDOW (window, w);
7717 if (EQ (window, dpyinfo->mouse_face_window))
7718 clear_mouse_face (dpyinfo);
2e636f9d 7719 UNBLOCK_INPUT;
71b8321e
GM
7720}
7721
7722
e687d06e
RS
7723/* Just discard the mouse face information for frame F, if any.
7724 This is used when the size of F is changed. */
7725
dfcf069d 7726void
e687d06e
RS
7727cancel_mouse_face (f)
7728 FRAME_PTR f;
7729{
7730 Lisp_Object window;
7731 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
7732
7733 window = dpyinfo->mouse_face_window;
7734 if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
7735 {
7736 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
7737 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
7738 dpyinfo->mouse_face_window = Qnil;
7739 }
7740}
b52b65bd 7741
b8009dd1 7742\f
b52b65bd
GM
7743static int glyph_rect P_ ((struct frame *f, int, int, XRectangle *));
7744
7745
7746/* Try to determine frame pixel position and size of the glyph under
7747 frame pixel coordinates X/Y on frame F . Return the position and
7748 size in *RECT. Value is non-zero if we could compute these
7749 values. */
7750
7751static int
7752glyph_rect (f, x, y, rect)
7753 struct frame *f;
7754 int x, y;
7755 XRectangle *rect;
7756{
7757 Lisp_Object window;
7758 int part, found = 0;
7759
7760 window = window_from_coordinates (f, x, y, &part, 0);
7761 if (!NILP (window))
7762 {
7763 struct window *w = XWINDOW (window);
7764 struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
7765 struct glyph_row *end = r + w->current_matrix->nrows - 1;
7766 int area;
7767
7768 frame_to_window_pixel_xy (w, &x, &y);
7769
7770 for (; !found && r < end && r->enabled_p; ++r)
7771 if (r->y >= y)
7772 {
7773 struct glyph *g = r->glyphs[TEXT_AREA];
7774 struct glyph *end = g + r->used[TEXT_AREA];
7775 int gx;
7776
7777 for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
7778 if (gx >= x)
7779 {
7780 rect->width = g->pixel_width;
7781 rect->height = r->height;
7782 rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
7783 rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
7784 found = 1;
7785 }
7786 }
7787 }
7788
7789 return found;
7790}
7791
12ba150f 7792
90e65f07 7793/* Return the current position of the mouse.
b52b65bd 7794 *FP should be a frame which indicates which display to ask about.
90e65f07 7795
b52b65bd
GM
7796 If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
7797 and *PART to the frame, window, and scroll bar part that the mouse
7798 is over. Set *X and *Y to the portion and whole of the mouse's
ab648270 7799 position on the scroll bar.
12ba150f 7800
b52b65bd
GM
7801 If the mouse movement started elsewhere, set *FP to the frame the
7802 mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
12ba150f
JB
7803 the mouse is over.
7804
b52b65bd 7805 Set *TIME to the server time-stamp for the time at which the mouse
12ba150f
JB
7806 was at this position.
7807
a135645a
RS
7808 Don't store anything if we don't have a valid set of values to report.
7809
90e65f07 7810 This clears the mouse_moved flag, so we can wait for the next mouse
f5bb65ec 7811 movement. */
90e65f07
JB
7812
7813static void
1cf412ec 7814XTmouse_position (fp, insist, bar_window, part, x, y, time)
334208b7 7815 FRAME_PTR *fp;
1cf412ec 7816 int insist;
12ba150f 7817 Lisp_Object *bar_window;
ab648270 7818 enum scroll_bar_part *part;
90e65f07 7819 Lisp_Object *x, *y;
e5d77022 7820 unsigned long *time;
90e65f07 7821{
a135645a
RS
7822 FRAME_PTR f1;
7823
90e65f07
JB
7824 BLOCK_INPUT;
7825
8bcee03e 7826 if (! NILP (last_mouse_scroll_bar) && insist == 0)
334208b7 7827 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
90e65f07
JB
7828 else
7829 {
12ba150f
JB
7830 Window root;
7831 int root_x, root_y;
90e65f07 7832
12ba150f
JB
7833 Window dummy_window;
7834 int dummy;
7835
39d8bb4d
KH
7836 Lisp_Object frame, tail;
7837
7838 /* Clear the mouse-moved flag for every frame on this display. */
7839 FOR_EACH_FRAME (tail, frame)
7840 if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
7841 XFRAME (frame)->mouse_moved = 0;
7842
ab648270 7843 last_mouse_scroll_bar = Qnil;
12ba150f
JB
7844
7845 /* Figure out which root window we're on. */
334208b7
RS
7846 XQueryPointer (FRAME_X_DISPLAY (*fp),
7847 DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
12ba150f
JB
7848
7849 /* The root window which contains the pointer. */
7850 &root,
7851
7852 /* Trash which we can't trust if the pointer is on
7853 a different screen. */
7854 &dummy_window,
7855
7856 /* The position on that root window. */
58769bee 7857 &root_x, &root_y,
12ba150f
JB
7858
7859 /* More trash we can't trust. */
7860 &dummy, &dummy,
7861
7862 /* Modifier keys and pointer buttons, about which
7863 we don't care. */
7864 (unsigned int *) &dummy);
7865
7866 /* Now we have a position on the root; find the innermost window
7867 containing the pointer. */
7868 {
7869 Window win, child;
7870 int win_x, win_y;
06a2c219 7871 int parent_x = 0, parent_y = 0;
e99db5a1 7872 int count;
12ba150f
JB
7873
7874 win = root;
69388238 7875
2d7fc7e8
RS
7876 /* XTranslateCoordinates can get errors if the window
7877 structure is changing at the same time this function
7878 is running. So at least we must not crash from them. */
7879
e99db5a1 7880 count = x_catch_errors (FRAME_X_DISPLAY (*fp));
2d7fc7e8 7881
334208b7 7882 if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
23faf38f 7883 && FRAME_LIVE_P (last_mouse_frame))
12ba150f 7884 {
69388238
RS
7885 /* If mouse was grabbed on a frame, give coords for that frame
7886 even if the mouse is now outside it. */
334208b7 7887 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
69388238 7888
12ba150f 7889 /* From-window, to-window. */
69388238 7890 root, FRAME_X_WINDOW (last_mouse_frame),
12ba150f
JB
7891
7892 /* From-position, to-position. */
7893 root_x, root_y, &win_x, &win_y,
7894
7895 /* Child of win. */
7896 &child);
69388238
RS
7897 f1 = last_mouse_frame;
7898 }
7899 else
7900 {
7901 while (1)
7902 {
334208b7 7903 XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
12ba150f 7904
69388238
RS
7905 /* From-window, to-window. */
7906 root, win,
12ba150f 7907
69388238
RS
7908 /* From-position, to-position. */
7909 root_x, root_y, &win_x, &win_y,
7910
7911 /* Child of win. */
7912 &child);
7913
9af3143a 7914 if (child == None || child == win)
69388238
RS
7915 break;
7916
7917 win = child;
7918 parent_x = win_x;
7919 parent_y = win_y;
7920 }
12ba150f 7921
69388238
RS
7922 /* Now we know that:
7923 win is the innermost window containing the pointer
7924 (XTC says it has no child containing the pointer),
7925 win_x and win_y are the pointer's position in it
7926 (XTC did this the last time through), and
7927 parent_x and parent_y are the pointer's position in win's parent.
7928 (They are what win_x and win_y were when win was child.
7929 If win is the root window, it has no parent, and
7930 parent_{x,y} are invalid, but that's okay, because we'll
7931 never use them in that case.) */
7932
7933 /* Is win one of our frames? */
19126e11 7934 f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
aad0f6ab
GM
7935
7936#ifdef USE_X_TOOLKIT
7937 /* If we end up with the menu bar window, say it's not
7938 on the frame. */
7939 if (f1 != NULL
7940 && f1->output_data.x->menubar_widget
7941 && win == XtWindow (f1->output_data.x->menubar_widget))
7942 f1 = NULL;
7943#endif /* USE_X_TOOLKIT */
69388238 7944 }
58769bee 7945
2d7fc7e8
RS
7946 if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
7947 f1 = 0;
7948
e99db5a1 7949 x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
2d7fc7e8 7950
ab648270 7951 /* If not, is it one of our scroll bars? */
a135645a 7952 if (! f1)
12ba150f 7953 {
ab648270 7954 struct scroll_bar *bar = x_window_to_scroll_bar (win);
12ba150f
JB
7955
7956 if (bar)
7957 {
a135645a 7958 f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
7959 win_x = parent_x;
7960 win_y = parent_y;
7961 }
7962 }
90e65f07 7963
8bcee03e 7964 if (f1 == 0 && insist > 0)
b86bd3dd 7965 f1 = SELECTED_FRAME ();
1cf412ec 7966
a135645a 7967 if (f1)
12ba150f 7968 {
06a2c219
GM
7969 /* Ok, we found a frame. Store all the values.
7970 last_mouse_glyph is a rectangle used to reduce the
7971 generation of mouse events. To not miss any motion
7972 events, we must divide the frame into rectangles of the
7973 size of the smallest character that could be displayed
7974 on it, i.e. into the same rectangles that matrices on
7975 the frame are divided into. */
7976
b52b65bd
GM
7977 int width, height, gx, gy;
7978 XRectangle rect;
7979
7980 if (glyph_rect (f1, win_x, win_y, &rect))
7981 last_mouse_glyph = rect;
7982 else
7983 {
7984 width = FRAME_SMALLEST_CHAR_WIDTH (f1);
7985 height = FRAME_SMALLEST_FONT_HEIGHT (f1);
7986 gx = win_x;
7987 gy = win_y;
06a2c219 7988
b52b65bd
GM
7989 /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
7990 round down even for negative values. */
7991 if (gx < 0)
7992 gx -= width - 1;
4f00e84d 7993 if (gy < 0)
b52b65bd
GM
7994 gy -= height - 1;
7995 gx = (gx + width - 1) / width * width;
7996 gy = (gy + height - 1) / height * height;
7997
7998 last_mouse_glyph.width = width;
7999 last_mouse_glyph.height = height;
8000 last_mouse_glyph.x = gx;
8001 last_mouse_glyph.y = gy;
8002 }
12ba150f
JB
8003
8004 *bar_window = Qnil;
8005 *part = 0;
334208b7 8006 *fp = f1;
e0c1aef2
KH
8007 XSETINT (*x, win_x);
8008 XSETINT (*y, win_y);
12ba150f
JB
8009 *time = last_mouse_movement_time;
8010 }
8011 }
8012 }
90e65f07
JB
8013
8014 UNBLOCK_INPUT;
8015}
f451eb13 8016
06a2c219 8017
06a2c219 8018#ifdef USE_X_TOOLKIT
bffcfca9
GM
8019
8020/* Atimer callback function for TIMER. Called every 0.1s to process
8021 Xt timeouts, if needed. We must avoid calling XtAppPending as
8022 much as possible because that function does an implicit XFlush
8023 that slows us down. */
8024
8025static void
8026x_process_timeouts (timer)
8027 struct atimer *timer;
8028{
8029 if (toolkit_scroll_bar_interaction || popup_activated_flag)
8030 {
8031 BLOCK_INPUT;
8032 while (XtAppPending (Xt_app_con) & XtIMTimer)
8033 XtAppProcessEvent (Xt_app_con, XtIMTimer);
8034 UNBLOCK_INPUT;
8035 }
06a2c219
GM
8036}
8037
bffcfca9 8038#endif /* USE_X_TOOLKIT */
06a2c219
GM
8039
8040\f
8041/* Scroll bar support. */
8042
8043/* Given an X window ID, find the struct scroll_bar which manages it.
8044 This can be called in GC, so we have to make sure to strip off mark
8045 bits. */
bffcfca9 8046
06a2c219
GM
8047static struct scroll_bar *
8048x_window_to_scroll_bar (window_id)
8049 Window window_id;
8050{
8051 Lisp_Object tail;
8052
8053 for (tail = Vframe_list;
8054 XGCTYPE (tail) == Lisp_Cons;
8e713be6 8055 tail = XCDR (tail))
06a2c219
GM
8056 {
8057 Lisp_Object frame, bar, condemned;
8058
8e713be6 8059 frame = XCAR (tail);
06a2c219
GM
8060 /* All elements of Vframe_list should be frames. */
8061 if (! GC_FRAMEP (frame))
8062 abort ();
8063
8064 /* Scan this frame's scroll bar list for a scroll bar with the
8065 right window ID. */
8066 condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
8067 for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
8068 /* This trick allows us to search both the ordinary and
8069 condemned scroll bar lists with one loop. */
8070 ! GC_NILP (bar) || (bar = condemned,
8071 condemned = Qnil,
8072 ! GC_NILP (bar));
8073 bar = XSCROLL_BAR (bar)->next)
8074 if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
8075 return XSCROLL_BAR (bar);
8076 }
8077
8078 return 0;
8079}
8080
8081
c95fc5f1
GM
8082#if defined USE_X_TOOLKIT && defined USE_LUCID
8083
8084/* Return the Lucid menu bar WINDOW is part of. Return null
8085 if WINDOW is not part of a menu bar. */
8086
8087static Widget
8088x_window_to_menu_bar (window)
8089 Window window;
8090{
8091 Lisp_Object tail;
8092
8093 for (tail = Vframe_list;
8094 XGCTYPE (tail) == Lisp_Cons;
8095 tail = XCDR (tail))
8096 {
8097 Lisp_Object frame = XCAR (tail);
8098 Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
8099
8100 if (menu_bar && xlwmenu_window_p (menu_bar, window))
8101 return menu_bar;
8102 }
8103
8104 return NULL;
8105}
8106
8107#endif /* USE_X_TOOLKIT && USE_LUCID */
8108
06a2c219
GM
8109\f
8110/************************************************************************
8111 Toolkit scroll bars
8112 ************************************************************************/
8113
eccc05db 8114#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8115
8116static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
8117static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
8118static void x_create_toolkit_scroll_bar P_ ((struct frame *,
8119 struct scroll_bar *));
8120static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
8121 int, int, int));
8122
8123
8124/* Id of action hook installed for scroll bars. */
8125
8126static XtActionHookId action_hook_id;
8127
8128/* Lisp window being scrolled. Set when starting to interact with
8129 a toolkit scroll bar, reset to nil when ending the interaction. */
8130
8131static Lisp_Object window_being_scrolled;
8132
8133/* Last scroll bar part sent in xm_scroll_callback. */
8134
8135static int last_scroll_bar_part;
8136
ec18280f
SM
8137/* Whether this is an Xaw with arrow-scrollbars. This should imply
8138 that movements of 1/20 of the screen size are mapped to up/down. */
8139
8140static Boolean xaw3d_arrow_scroll;
8141
8142/* Whether the drag scrolling maintains the mouse at the top of the
8143 thumb. If not, resizing the thumb needs to be done more carefully
8144 to avoid jerkyness. */
8145
8146static Boolean xaw3d_pick_top;
8147
06a2c219
GM
8148
8149/* Action hook installed via XtAppAddActionHook when toolkit scroll
ec18280f 8150 bars are used.. The hook is responsible for detecting when
06a2c219
GM
8151 the user ends an interaction with the scroll bar, and generates
8152 a `end-scroll' scroll_bar_click' event if so. */
8153
8154static void
8155xt_action_hook (widget, client_data, action_name, event, params,
8156 num_params)
8157 Widget widget;
8158 XtPointer client_data;
8159 String action_name;
8160 XEvent *event;
8161 String *params;
8162 Cardinal *num_params;
8163{
8164 int scroll_bar_p;
8165 char *end_action;
8166
8167#ifdef USE_MOTIF
8168 scroll_bar_p = XmIsScrollBar (widget);
8169 end_action = "Release";
ec18280f 8170#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8171 scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
8172 end_action = "EndScroll";
ec18280f 8173#endif /* USE_MOTIF */
06a2c219 8174
06a2c219
GM
8175 if (scroll_bar_p
8176 && strcmp (action_name, end_action) == 0
8177 && WINDOWP (window_being_scrolled))
8178 {
8179 struct window *w;
8180
8181 x_send_scroll_bar_event (window_being_scrolled,
8182 scroll_bar_end_scroll, 0, 0);
8183 w = XWINDOW (window_being_scrolled);
8184 XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
8185 window_being_scrolled = Qnil;
8186 last_scroll_bar_part = -1;
bffcfca9
GM
8187
8188 /* Xt timeouts no longer needed. */
8189 toolkit_scroll_bar_interaction = 0;
06a2c219
GM
8190 }
8191}
8192
07b3d16e
GM
8193/* A vector of windows used for communication between
8194 x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
8195
8196static struct window **scroll_bar_windows;
8197static int scroll_bar_windows_size;
8198
06a2c219
GM
8199
8200/* Send a client message with message type Xatom_Scrollbar for a
8201 scroll action to the frame of WINDOW. PART is a value identifying
8202 the part of the scroll bar that was clicked on. PORTION is the
8203 amount to scroll of a whole of WHOLE. */
8204
8205static void
8206x_send_scroll_bar_event (window, part, portion, whole)
8207 Lisp_Object window;
8208 int part, portion, whole;
8209{
8210 XEvent event;
8211 XClientMessageEvent *ev = (XClientMessageEvent *) &event;
07b3d16e
GM
8212 struct window *w = XWINDOW (window);
8213 struct frame *f = XFRAME (w->frame);
8214 int i;
06a2c219 8215
07b3d16e
GM
8216 BLOCK_INPUT;
8217
06a2c219
GM
8218 /* Construct a ClientMessage event to send to the frame. */
8219 ev->type = ClientMessage;
8220 ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
8221 ev->display = FRAME_X_DISPLAY (f);
8222 ev->window = FRAME_X_WINDOW (f);
8223 ev->format = 32;
07b3d16e
GM
8224
8225 /* We can only transfer 32 bits in the XClientMessageEvent, which is
8226 not enough to store a pointer or Lisp_Object on a 64 bit system.
8227 So, store the window in scroll_bar_windows and pass the index
8228 into that array in the event. */
8229 for (i = 0; i < scroll_bar_windows_size; ++i)
8230 if (scroll_bar_windows[i] == NULL)
8231 break;
8232
8233 if (i == scroll_bar_windows_size)
8234 {
8235 int new_size = max (10, 2 * scroll_bar_windows_size);
8236 size_t nbytes = new_size * sizeof *scroll_bar_windows;
8237 size_t old_nbytes = scroll_bar_windows_size * sizeof *scroll_bar_windows;
8238
8239 scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
8240 nbytes);
8241 bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
8242 scroll_bar_windows_size = new_size;
8243 }
8244
8245 scroll_bar_windows[i] = w;
8246 ev->data.l[0] = (long) i;
06a2c219
GM
8247 ev->data.l[1] = (long) part;
8248 ev->data.l[2] = (long) 0;
8249 ev->data.l[3] = (long) portion;
8250 ev->data.l[4] = (long) whole;
8251
bffcfca9
GM
8252 /* Make Xt timeouts work while the scroll bar is active. */
8253 toolkit_scroll_bar_interaction = 1;
8254
06a2c219
GM
8255 /* Setting the event mask to zero means that the message will
8256 be sent to the client that created the window, and if that
8257 window no longer exists, no event will be sent. */
06a2c219
GM
8258 XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
8259 UNBLOCK_INPUT;
8260}
8261
8262
8263/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
8264 in *IEVENT. */
8265
8266static void
8267x_scroll_bar_to_input_event (event, ievent)
8268 XEvent *event;
8269 struct input_event *ievent;
8270{
8271 XClientMessageEvent *ev = (XClientMessageEvent *) event;
52e386c2
KR
8272 Lisp_Object window;
8273 struct frame *f;
07b3d16e
GM
8274 struct window *w;
8275
8276 w = scroll_bar_windows[ev->data.l[0]];
8277 scroll_bar_windows[ev->data.l[0]] = NULL;
52e386c2 8278
07b3d16e
GM
8279 XSETWINDOW (window, w);
8280 f = XFRAME (w->frame);
06a2c219
GM
8281
8282 ievent->kind = scroll_bar_click;
8283 ievent->frame_or_window = window;
0f8aabe9 8284 ievent->arg = Qnil;
06a2c219
GM
8285 ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
8286 ievent->part = ev->data.l[1];
8287 ievent->code = ev->data.l[2];
8288 ievent->x = make_number ((int) ev->data.l[3]);
8289 ievent->y = make_number ((int) ev->data.l[4]);
8290 ievent->modifiers = 0;
8291}
8292
8293
8294#ifdef USE_MOTIF
8295
8296/* Minimum and maximum values used for Motif scroll bars. */
8297
8298#define XM_SB_MIN 1
8299#define XM_SB_MAX 10000000
8300#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
8301
8302
8303/* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
8304 bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
8305 CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */
8306
8307static void
8308xm_scroll_callback (widget, client_data, call_data)
8309 Widget widget;
8310 XtPointer client_data, call_data;
8311{
8312 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8313 XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
8314 double percent;
8315 int part = -1, whole = 0, portion = 0;
8316
8317 switch (cs->reason)
8318 {
8319 case XmCR_DECREMENT:
8320 bar->dragging = Qnil;
8321 part = scroll_bar_up_arrow;
8322 break;
8323
8324 case XmCR_INCREMENT:
8325 bar->dragging = Qnil;
8326 part = scroll_bar_down_arrow;
8327 break;
8328
8329 case XmCR_PAGE_DECREMENT:
8330 bar->dragging = Qnil;
8331 part = scroll_bar_above_handle;
8332 break;
8333
8334 case XmCR_PAGE_INCREMENT:
8335 bar->dragging = Qnil;
8336 part = scroll_bar_below_handle;
8337 break;
8338
8339 case XmCR_TO_TOP:
8340 bar->dragging = Qnil;
8341 part = scroll_bar_to_top;
8342 break;
8343
8344 case XmCR_TO_BOTTOM:
8345 bar->dragging = Qnil;
8346 part = scroll_bar_to_bottom;
8347 break;
8348
8349 case XmCR_DRAG:
8350 {
8351 int slider_size;
8352 int dragging_down_p = (INTEGERP (bar->dragging)
8353 && XINT (bar->dragging) <= cs->value);
8354
8355 /* Get the slider size. */
8356 BLOCK_INPUT;
8357 XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
8358 UNBLOCK_INPUT;
8359
8360 /* At the max position of the scroll bar, do a line-wise
23442ae4
GM
8361 movement. Without doing anything, we would be called with
8362 the same cs->value again and again. If we want to make
8363 sure that we can reach the end of the buffer, we have to do
8364 something.
06a2c219
GM
8365
8366 Implementation note: setting bar->dragging always to
8367 cs->value gives a smoother movement at the max position.
8368 Setting it to nil when doing line-wise movement gives
8369 a better slider behavior. */
8370
8371 if (cs->value + slider_size == XM_SB_MAX
8372 || (dragging_down_p
8373 && last_scroll_bar_part == scroll_bar_down_arrow))
8374 {
8375 part = scroll_bar_down_arrow;
8376 bar->dragging = Qnil;
8377 }
8378 else
8379 {
8380 whole = XM_SB_RANGE;
8381 portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
8382 part = scroll_bar_handle;
8383 bar->dragging = make_number (cs->value);
8384 }
8385 }
8386 break;
8387
8388 case XmCR_VALUE_CHANGED:
8389 break;
8390 };
8391
8392 if (part >= 0)
8393 {
8394 window_being_scrolled = bar->window;
8395 last_scroll_bar_part = part;
8396 x_send_scroll_bar_event (bar->window, part, portion, whole);
8397 }
8398}
8399
8400
ec18280f 8401#else /* !USE_MOTIF, i.e. Xaw. */
06a2c219
GM
8402
8403
ec18280f 8404/* Xaw scroll bar callback. Invoked when the thumb is dragged.
06a2c219
GM
8405 WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
8406 scroll bar struct. CALL_DATA is a pointer to a float saying where
8407 the thumb is. */
8408
8409static void
ec18280f 8410xaw_jump_callback (widget, client_data, call_data)
06a2c219
GM
8411 Widget widget;
8412 XtPointer client_data, call_data;
8413{
8414 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8415 float top = *(float *) call_data;
8416 float shown;
ec18280f
SM
8417 int whole, portion, height;
8418 int part;
06a2c219
GM
8419
8420 /* Get the size of the thumb, a value between 0 and 1. */
8421 BLOCK_INPUT;
ec18280f 8422 XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
06a2c219
GM
8423 UNBLOCK_INPUT;
8424
8425 whole = 10000000;
8426 portion = shown < 1 ? top * whole : 0;
06a2c219 8427
ec18280f
SM
8428 if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
8429 /* Some derivatives of Xaw refuse to shrink the thumb when you reach
8430 the bottom, so we force the scrolling whenever we see that we're
8431 too close to the bottom (in x_set_toolkit_scroll_bar_thumb
8432 we try to ensure that we always stay two pixels away from the
8433 bottom). */
06a2c219
GM
8434 part = scroll_bar_down_arrow;
8435 else
8436 part = scroll_bar_handle;
8437
8438 window_being_scrolled = bar->window;
8439 bar->dragging = make_number (portion);
8440 last_scroll_bar_part = part;
8441 x_send_scroll_bar_event (bar->window, part, portion, whole);
8442}
8443
8444
ec18280f
SM
8445/* Xaw scroll bar callback. Invoked for incremental scrolling.,
8446 i.e. line or page up or down. WIDGET is the Xaw scroll bar
06a2c219
GM
8447 widget. CLIENT_DATA is a pointer to the scroll_bar structure for
8448 the scroll bar. CALL_DATA is an integer specifying the action that
8449 has taken place. It's magnitude is in the range 0..height of the
8450 scroll bar. Negative values mean scroll towards buffer start.
8451 Values < height of scroll bar mean line-wise movement. */
8452
8453static void
ec18280f 8454xaw_scroll_callback (widget, client_data, call_data)
06a2c219
GM
8455 Widget widget;
8456 XtPointer client_data, call_data;
8457{
8458 struct scroll_bar *bar = (struct scroll_bar *) client_data;
8459 int position = (int) call_data;
8460 Dimension height;
8461 int part;
8462
8463 /* Get the height of the scroll bar. */
8464 BLOCK_INPUT;
8465 XtVaGetValues (widget, XtNheight, &height, NULL);
8466 UNBLOCK_INPUT;
8467
ec18280f
SM
8468 if (abs (position) >= height)
8469 part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
8470
8471 /* If Xaw3d was compiled with ARROW_SCROLLBAR,
8472 it maps line-movement to call_data = max(5, height/20). */
8473 else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
8474 part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
06a2c219 8475 else
ec18280f 8476 part = scroll_bar_move_ratio;
06a2c219
GM
8477
8478 window_being_scrolled = bar->window;
8479 bar->dragging = Qnil;
8480 last_scroll_bar_part = part;
ec18280f 8481 x_send_scroll_bar_event (bar->window, part, position, height);
06a2c219
GM
8482}
8483
8484
8485#endif /* not USE_MOTIF */
8486
8487
8488/* Create the widget for scroll bar BAR on frame F. Record the widget
8489 and X window of the scroll bar in BAR. */
8490
8491static void
8492x_create_toolkit_scroll_bar (f, bar)
8493 struct frame *f;
8494 struct scroll_bar *bar;
8495{
8496 Window xwindow;
8497 Widget widget;
8498 Arg av[20];
8499 int ac = 0;
8500 char *scroll_bar_name = "verticalScrollBar";
8501 unsigned long pixel;
8502
8503 BLOCK_INPUT;
8504
8505#ifdef USE_MOTIF
06a2c219
GM
8506 /* Set resources. Create the widget. */
8507 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8508 XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
8509 XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
8510 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
8511 XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
8512 XtSetArg (av[ac], XmNincrement, 1); ++ac;
8513 XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
8514
8515 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8516 if (pixel != -1)
8517 {
8518 XtSetArg (av[ac], XmNforeground, pixel);
8519 ++ac;
8520 }
8521
8522 pixel = f->output_data.x->scroll_bar_background_pixel;
8523 if (pixel != -1)
8524 {
8525 XtSetArg (av[ac], XmNbackground, pixel);
8526 ++ac;
8527 }
8528
8529 widget = XmCreateScrollBar (f->output_data.x->edit_widget,
8530 scroll_bar_name, av, ac);
8531
8532 /* Add one callback for everything that can happen. */
8533 XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
8534 (XtPointer) bar);
8535 XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
8536 (XtPointer) bar);
8537 XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
8538 (XtPointer) bar);
8539 XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
8540 (XtPointer) bar);
8541 XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
8542 (XtPointer) bar);
8543 XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
8544 (XtPointer) bar);
8545 XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
8546 (XtPointer) bar);
8547
8548 /* Realize the widget. Only after that is the X window created. */
8549 XtRealizeWidget (widget);
8550
8551 /* Set the cursor to an arrow. I didn't find a resource to do that.
8552 And I'm wondering why it hasn't an arrow cursor by default. */
8553 XDefineCursor (XtDisplay (widget), XtWindow (widget),
8554 f->output_data.x->nontext_cursor);
8555
ec18280f 8556#else /* !USE_MOTIF i.e. use Xaw */
06a2c219
GM
8557
8558 /* Set resources. Create the widget. The background of the
8559 Xaw3d scroll bar widget is a little bit light for my taste.
8560 We don't alter it here to let users change it according
8561 to their taste with `emacs*verticalScrollBar.background: xxx'. */
8562 XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
8563 XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
ec18280f
SM
8564 /* For smoother scrolling with Xaw3d -sm */
8565 /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
8566 /* XtSetArg (av[ac], XtNbeNiceToColormap, True); ++ac; */
06a2c219
GM
8567
8568 pixel = f->output_data.x->scroll_bar_foreground_pixel;
8569 if (pixel != -1)
8570 {
8571 XtSetArg (av[ac], XtNforeground, pixel);
8572 ++ac;
8573 }
8574
8575 pixel = f->output_data.x->scroll_bar_background_pixel;
8576 if (pixel != -1)
8577 {
8578 XtSetArg (av[ac], XtNbackground, pixel);
8579 ++ac;
8580 }
8581
8582 widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
8583 f->output_data.x->edit_widget, av, ac);
ec18280f
SM
8584
8585 {
8586 char *initial = "";
8587 char *val = initial;
8588 XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
8589 XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
8590 if (val == initial)
8591 { /* ARROW_SCROLL */
8592 xaw3d_arrow_scroll = True;
8593 /* Isn't that just a personal preference ? -sm */
8594 XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
8595 }
8596 }
06a2c219
GM
8597
8598 /* Define callbacks. */
ec18280f
SM
8599 XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
8600 XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
06a2c219
GM
8601 (XtPointer) bar);
8602
8603 /* Realize the widget. Only after that is the X window created. */
8604 XtRealizeWidget (widget);
8605
ec18280f 8606#endif /* !USE_MOTIF */
06a2c219
GM
8607
8608 /* Install an action hook that let's us detect when the user
8609 finishes interacting with a scroll bar. */
8610 if (action_hook_id == 0)
8611 action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
8612
8613 /* Remember X window and widget in the scroll bar vector. */
8614 SET_SCROLL_BAR_X_WIDGET (bar, widget);
8615 xwindow = XtWindow (widget);
8616 SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
8617
8618 UNBLOCK_INPUT;
8619}
8620
8621
8622/* Set the thumb size and position of scroll bar BAR. We are currently
8623 displaying PORTION out of a whole WHOLE, and our position POSITION. */
8624
8625static void
8626x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
8627 struct scroll_bar *bar;
8628 int portion, position, whole;
f451eb13 8629{
e83dc917
GM
8630 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
8631 Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
06a2c219 8632 float top, shown;
f451eb13 8633
06a2c219
GM
8634 if (whole == 0)
8635 top = 0, shown = 1;
8636 else
f451eb13 8637 {
06a2c219
GM
8638 top = (float) position / whole;
8639 shown = (float) portion / whole;
8640 }
f451eb13 8641
06a2c219 8642 BLOCK_INPUT;
f451eb13 8643
06a2c219
GM
8644#ifdef USE_MOTIF
8645 {
8646 int size, value;
06a2c219
GM
8647 XmScrollBarWidget sb;
8648
ec18280f 8649 /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
06a2c219
GM
8650 is the scroll bar's maximum and MIN is the scroll bar's minimum
8651 value. */
8652 size = shown * XM_SB_RANGE;
8653 size = min (size, XM_SB_RANGE);
8654 size = max (size, 1);
8655
8656 /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
8657 value = top * XM_SB_RANGE;
8658 value = min (value, XM_SB_MAX - size);
8659 value = max (value, XM_SB_MIN);
8660
06a2c219
GM
8661 if (NILP (bar->dragging))
8662 XmScrollBarSetValues (widget, value, size, 0, 0, False);
8663 else if (last_scroll_bar_part == scroll_bar_down_arrow)
8664 /* This has the negative side effect that the slider value is
ec18280f 8665 not what it would be if we scrolled here using line-wise or
06a2c219
GM
8666 page-wise movement. */
8667 XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
8668 else
8669 {
8670 /* If currently dragging, only update the slider size.
8671 This reduces flicker effects. */
8672 int old_value, old_size, increment, page_increment;
8673
8674 XmScrollBarGetValues (widget, &old_value, &old_size,
8675 &increment, &page_increment);
8676 XmScrollBarSetValues (widget, old_value,
8677 min (size, XM_SB_RANGE - old_value),
8678 0, 0, False);
8679 }
06a2c219 8680 }
ec18280f 8681#else /* !USE_MOTIF i.e. use Xaw */
06a2c219 8682 {
ec18280f
SM
8683 float old_top, old_shown;
8684 Dimension height;
8685 XtVaGetValues (widget,
8686 XtNtopOfThumb, &old_top,
8687 XtNshown, &old_shown,
8688 XtNheight, &height,
8689 NULL);
8690
8691 /* Massage the top+shown values. */
8692 if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
8693 top = max (0, min (1, top));
8694 else
8695 top = old_top;
8696 /* Keep two pixels available for moving the thumb down. */
8697 shown = max (0, min (1 - top - (2.0 / height), shown));
06a2c219
GM
8698
8699 /* If the call to XawScrollbarSetThumb below doesn't seem to work,
8700 check that your system's configuration file contains a define
8701 for `NARROWPROTO'. See s/freebsd.h for an example. */
ec18280f 8702 if (top != old_top || shown != old_shown)
eb393530 8703 {
ec18280f 8704 if (NILP (bar->dragging))
eb393530 8705 XawScrollbarSetThumb (widget, top, shown);
06a2c219
GM
8706 else
8707 {
ec18280f
SM
8708#ifdef HAVE_XAW3D
8709 ScrollbarWidget sb = (ScrollbarWidget) widget;
3e71d8f2 8710 int scroll_mode = 0;
ec18280f
SM
8711
8712 /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
8713 if (xaw3d_arrow_scroll)
8714 {
8715 /* Xaw3d stupidly ignores resize requests while dragging
8716 so we have to make it believe it's not in dragging mode. */
8717 scroll_mode = sb->scrollbar.scroll_mode;
8718 if (scroll_mode == 2)
8719 sb->scrollbar.scroll_mode = 0;
8720 }
8721#endif
8722 /* Try to make the scrolling a tad smoother. */
8723 if (!xaw3d_pick_top)
8724 shown = min (shown, old_shown);
8725
8726 XawScrollbarSetThumb (widget, top, shown);
8727
8728#ifdef HAVE_XAW3D
8729 if (xaw3d_arrow_scroll && scroll_mode == 2)
8730 sb->scrollbar.scroll_mode = scroll_mode;
8731#endif
06a2c219 8732 }
06a2c219
GM
8733 }
8734 }
ec18280f 8735#endif /* !USE_MOTIF */
06a2c219
GM
8736
8737 UNBLOCK_INPUT;
f451eb13
JB
8738}
8739
06a2c219
GM
8740#endif /* USE_TOOLKIT_SCROLL_BARS */
8741
8742
8743\f
8744/************************************************************************
8745 Scroll bars, general
8746 ************************************************************************/
8747
8748/* Create a scroll bar and return the scroll bar vector for it. W is
8749 the Emacs window on which to create the scroll bar. TOP, LEFT,
8750 WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
8751 scroll bar. */
8752
ab648270 8753static struct scroll_bar *
06a2c219
GM
8754x_scroll_bar_create (w, top, left, width, height)
8755 struct window *w;
f451eb13
JB
8756 int top, left, width, height;
8757{
06a2c219 8758 struct frame *f = XFRAME (w->frame);
334208b7
RS
8759 struct scroll_bar *bar
8760 = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
f451eb13
JB
8761
8762 BLOCK_INPUT;
8763
eccc05db 8764#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
8765 x_create_toolkit_scroll_bar (f, bar);
8766#else /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8767 {
8768 XSetWindowAttributes a;
8769 unsigned long mask;
5c187dee 8770 Window window;
06a2c219
GM
8771
8772 a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
8773 if (a.background_pixel == -1)
8774 a.background_pixel = f->output_data.x->background_pixel;
8775
12ba150f 8776 a.event_mask = (ButtonPressMask | ButtonReleaseMask
9a572e2a 8777 | ButtonMotionMask | PointerMotionHintMask
12ba150f 8778 | ExposureMask);
7a13e894 8779 a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
f451eb13 8780
dbc4e1c1 8781 mask = (CWBackPixel | CWEventMask | CWCursor);
f451eb13 8782
06a2c219
GM
8783 /* Clear the area of W that will serve as a scroll bar. This is
8784 for the case that a window has been split horizontally. In
8785 this case, no clear_frame is generated to reduce flickering. */
c5e6e06b
GM
8786 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8787 left, top, width,
8788 window_box_height (w), False);
06a2c219
GM
8789
8790 window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
8791 /* Position and size of scroll bar. */
8792 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8793 top,
8794 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8795 height,
8796 /* Border width, depth, class, and visual. */
8797 0,
8798 CopyFromParent,
8799 CopyFromParent,
8800 CopyFromParent,
8801 /* Attributes. */
8802 mask, &a);
8803 SET_SCROLL_BAR_X_WINDOW (bar, window);
f451eb13 8804 }
06a2c219 8805#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 8806
06a2c219 8807 XSETWINDOW (bar->window, w);
e0c1aef2
KH
8808 XSETINT (bar->top, top);
8809 XSETINT (bar->left, left);
8810 XSETINT (bar->width, width);
8811 XSETINT (bar->height, height);
8812 XSETINT (bar->start, 0);
8813 XSETINT (bar->end, 0);
12ba150f 8814 bar->dragging = Qnil;
f451eb13
JB
8815
8816 /* Add bar to its frame's list of scroll bars. */
334208b7 8817 bar->next = FRAME_SCROLL_BARS (f);
12ba150f 8818 bar->prev = Qnil;
334208b7 8819 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
06a2c219 8820 if (!NILP (bar->next))
e0c1aef2 8821 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13 8822
06a2c219 8823 /* Map the window/widget. */
eccc05db 8824#ifdef USE_TOOLKIT_SCROLL_BARS
f964b4d7
GM
8825 {
8826 Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
8827 XtConfigureWidget (scroll_bar,
8828 left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
8829 top,
8830 width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
8831 max (height, 1), 0);
8832 XtMapWidget (scroll_bar);
8833 }
06a2c219 8834#else /* not USE_TOOLKIT_SCROLL_BARS */
7f9c7f94 8835 XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
06a2c219 8836#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
8837
8838 UNBLOCK_INPUT;
12ba150f 8839 return bar;
f451eb13
JB
8840}
8841
06a2c219 8842
12ba150f 8843/* Draw BAR's handle in the proper position.
06a2c219 8844
12ba150f
JB
8845 If the handle is already drawn from START to END, don't bother
8846 redrawing it, unless REBUILD is non-zero; in that case, always
8847 redraw it. (REBUILD is handy for drawing the handle after expose
58769bee 8848 events.)
12ba150f
JB
8849
8850 Normally, we want to constrain the start and end of the handle to
06a2c219
GM
8851 fit inside its rectangle, but if the user is dragging the scroll
8852 bar handle, we want to let them drag it down all the way, so that
8853 the bar's top is as far down as it goes; otherwise, there's no way
8854 to move to the very end of the buffer. */
8855
5c187dee
GM
8856#ifndef USE_TOOLKIT_SCROLL_BARS
8857
f451eb13 8858static void
ab648270
JB
8859x_scroll_bar_set_handle (bar, start, end, rebuild)
8860 struct scroll_bar *bar;
f451eb13 8861 int start, end;
12ba150f 8862 int rebuild;
f451eb13 8863{
12ba150f 8864 int dragging = ! NILP (bar->dragging);
ab648270 8865 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 8866 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 8867 GC gc = f->output_data.x->normal_gc;
12ba150f
JB
8868
8869 /* If the display is already accurate, do nothing. */
8870 if (! rebuild
8871 && start == XINT (bar->start)
8872 && end == XINT (bar->end))
8873 return;
8874
f451eb13
JB
8875 BLOCK_INPUT;
8876
8877 {
d9cdbb3d
RS
8878 int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT (bar->width));
8879 int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
8880 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
f451eb13
JB
8881
8882 /* Make sure the values are reasonable, and try to preserve
8883 the distance between start and end. */
12ba150f
JB
8884 {
8885 int length = end - start;
8886
8887 if (start < 0)
8888 start = 0;
8889 else if (start > top_range)
8890 start = top_range;
8891 end = start + length;
8892
8893 if (end < start)
8894 end = start;
8895 else if (end > top_range && ! dragging)
8896 end = top_range;
8897 }
f451eb13 8898
ab648270 8899 /* Store the adjusted setting in the scroll bar. */
e0c1aef2
KH
8900 XSETINT (bar->start, start);
8901 XSETINT (bar->end, end);
f451eb13 8902
12ba150f
JB
8903 /* Clip the end position, just for display. */
8904 if (end > top_range)
8905 end = top_range;
f451eb13 8906
ab648270 8907 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
12ba150f
JB
8908 below top positions, to make sure the handle is always at least
8909 that many pixels tall. */
ab648270 8910 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
f451eb13 8911
12ba150f
JB
8912 /* Draw the empty space above the handle. Note that we can't clear
8913 zero-height areas; that means "clear to end of window." */
8914 if (0 < start)
c5e6e06b
GM
8915 x_clear_area (FRAME_X_DISPLAY (f), w,
8916 /* x, y, width, height, and exposures. */
8917 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8918 VERTICAL_SCROLL_BAR_TOP_BORDER,
8919 inside_width, start,
8920 False);
f451eb13 8921
06a2c219
GM
8922 /* Change to proper foreground color if one is specified. */
8923 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8924 XSetForeground (FRAME_X_DISPLAY (f), gc,
8925 f->output_data.x->scroll_bar_foreground_pixel);
8926
12ba150f 8927 /* Draw the handle itself. */
334208b7 8928 XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
12ba150f 8929 /* x, y, width, height */
ab648270
JB
8930 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8931 VERTICAL_SCROLL_BAR_TOP_BORDER + start,
12ba150f 8932 inside_width, end - start);
f451eb13 8933
06a2c219
GM
8934 /* Restore the foreground color of the GC if we changed it above. */
8935 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
8936 XSetForeground (FRAME_X_DISPLAY (f), gc,
8937 f->output_data.x->foreground_pixel);
f451eb13 8938
12ba150f
JB
8939 /* Draw the empty space below the handle. Note that we can't
8940 clear zero-height areas; that means "clear to end of window." */
8941 if (end < inside_height)
c5e6e06b
GM
8942 x_clear_area (FRAME_X_DISPLAY (f), w,
8943 /* x, y, width, height, and exposures. */
8944 VERTICAL_SCROLL_BAR_LEFT_BORDER,
8945 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
8946 inside_width, inside_height - end,
8947 False);
f451eb13 8948
f451eb13
JB
8949 }
8950
f451eb13
JB
8951 UNBLOCK_INPUT;
8952}
8953
5c187dee 8954#endif /* !USE_TOOLKIT_SCROLL_BARS */
f451eb13 8955
06a2c219
GM
8956/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
8957 nil. */
58769bee 8958
12ba150f 8959static void
ab648270
JB
8960x_scroll_bar_remove (bar)
8961 struct scroll_bar *bar;
12ba150f 8962{
e83dc917 8963 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f
JB
8964 BLOCK_INPUT;
8965
eccc05db 8966#ifdef USE_TOOLKIT_SCROLL_BARS
e83dc917
GM
8967 XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
8968#else
8969 XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
8970#endif
06a2c219 8971
ab648270
JB
8972 /* Disassociate this scroll bar from its window. */
8973 XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
12ba150f
JB
8974
8975 UNBLOCK_INPUT;
8976}
8977
06a2c219 8978
12ba150f
JB
8979/* Set the handle of the vertical scroll bar for WINDOW to indicate
8980 that we are displaying PORTION characters out of a total of WHOLE
ab648270 8981 characters, starting at POSITION. If WINDOW has no scroll bar,
12ba150f 8982 create one. */
06a2c219 8983
12ba150f 8984static void
06a2c219
GM
8985XTset_vertical_scroll_bar (w, portion, whole, position)
8986 struct window *w;
f451eb13
JB
8987 int portion, whole, position;
8988{
06a2c219 8989 struct frame *f = XFRAME (w->frame);
ab648270 8990 struct scroll_bar *bar;
3c6ede7b 8991 int top, height, left, sb_left, width, sb_width;
06a2c219 8992 int window_x, window_y, window_width, window_height;
06a2c219 8993
3c6ede7b 8994 /* Get window dimensions. */
06a2c219 8995 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
3c6ede7b
GM
8996 top = window_y;
8997 width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
8998 height = window_height;
06a2c219 8999
3c6ede7b 9000 /* Compute the left edge of the scroll bar area. */
06a2c219 9001 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
3c6ede7b
GM
9002 left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
9003 else
9004 left = XFASTINT (w->left);
9005 left *= CANON_X_UNIT (f);
9006 left += FRAME_INTERNAL_BORDER_WIDTH (f);
9007
9008 /* Compute the width of the scroll bar which might be less than
9009 the width of the area reserved for the scroll bar. */
9010 if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
9011 sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
06a2c219 9012 else
3c6ede7b 9013 sb_width = width;
12ba150f 9014
3c6ede7b
GM
9015 /* Compute the left edge of the scroll bar. */
9016#ifdef USE_TOOLKIT_SCROLL_BARS
9017 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9018 sb_left = left + width - sb_width - (width - sb_width) / 2;
9019 else
9020 sb_left = left + (width - sb_width) / 2;
9021#else
9022 if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
9023 sb_left = left + width - sb_width;
9024 else
9025 sb_left = left;
9026#endif
9027
ab648270 9028 /* Does the scroll bar exist yet? */
06a2c219 9029 if (NILP (w->vertical_scroll_bar))
3c6ede7b 9030 {
80c32bcc 9031 BLOCK_INPUT;
f964b4d7
GM
9032 if (width && height)
9033 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9034 left, top, width, height, False);
80c32bcc 9035 UNBLOCK_INPUT;
3c6ede7b
GM
9036 bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
9037 }
f451eb13 9038 else
12ba150f
JB
9039 {
9040 /* It may just need to be moved and resized. */
06a2c219
GM
9041 unsigned int mask = 0;
9042
9043 bar = XSCROLL_BAR (w->vertical_scroll_bar);
9044
9045 BLOCK_INPUT;
9046
3c6ede7b 9047 if (sb_left != XINT (bar->left))
06a2c219 9048 mask |= CWX;
3c6ede7b 9049 if (top != XINT (bar->top))
06a2c219 9050 mask |= CWY;
3c6ede7b 9051 if (sb_width != XINT (bar->width))
06a2c219 9052 mask |= CWWidth;
3c6ede7b 9053 if (height != XINT (bar->height))
06a2c219
GM
9054 mask |= CWHeight;
9055
9056#ifdef USE_TOOLKIT_SCROLL_BARS
fe6f39d9
GM
9057
9058 /* Since toolkit scroll bars are smaller than the space reserved
9059 for them on the frame, we have to clear "under" them. */
f964b4d7
GM
9060 if (width && height)
9061 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9062 left, top, width, height, False);
06a2c219
GM
9063
9064 /* Move/size the scroll bar widget. */
9065 if (mask)
e83dc917 9066 XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
3c6ede7b
GM
9067 sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9068 top,
9069 sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
f964b4d7 9070 max (height, 1), 0);
06a2c219
GM
9071
9072#else /* not USE_TOOLKIT_SCROLL_BARS */
9073
357e7376
GM
9074 /* Clear areas not covered by the scroll bar because of
9075 VERTICAL_SCROLL_BAR_WIDTH_TRIM. */
e1f6572f
RS
9076 if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
9077 {
c5e6e06b
GM
9078 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9079 left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9080 height, False);
9081 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9082 left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9083 top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
9084 height, False);
e1f6572f 9085 }
357e7376
GM
9086
9087 /* Clear areas not covered by the scroll bar because it's not as
9088 wide as the area reserved for it . This makes sure a
9089 previous mode line display is cleared after C-x 2 C-x 1, for
9090 example. */
9091 {
9092 int area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
9093 int rest = area_width - sb_width;
9094 if (rest > 0)
9095 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9096 left + area_width - rest, 0,
9097 rest, max (height, 1), False);
9098 }
06a2c219
GM
9099
9100 /* Move/size the scroll bar window. */
9101 if (mask)
9102 {
9103 XWindowChanges wc;
9104
3c6ede7b
GM
9105 wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
9106 wc.y = top;
9107 wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
9108 wc.height = height;
06a2c219
GM
9109 XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
9110 mask, &wc);
9111 }
9112
9113#endif /* not USE_TOOLKIT_SCROLL_BARS */
9114
9115 /* Remember new settings. */
3c6ede7b
GM
9116 XSETINT (bar->left, sb_left);
9117 XSETINT (bar->top, top);
9118 XSETINT (bar->width, sb_width);
9119 XSETINT (bar->height, height);
06a2c219
GM
9120
9121 UNBLOCK_INPUT;
12ba150f 9122 }
f451eb13 9123
eccc05db 9124#ifdef USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
9125 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
9126#else /* not USE_TOOLKIT_SCROLL_BARS */
ab648270 9127 /* Set the scroll bar's current state, unless we're currently being
f451eb13 9128 dragged. */
12ba150f 9129 if (NILP (bar->dragging))
f451eb13 9130 {
92857db0 9131 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
f451eb13 9132
12ba150f 9133 if (whole == 0)
ab648270 9134 x_scroll_bar_set_handle (bar, 0, top_range, 0);
12ba150f
JB
9135 else
9136 {
43f868f5
JB
9137 int start = ((double) position * top_range) / whole;
9138 int end = ((double) (position + portion) * top_range) / whole;
ab648270 9139 x_scroll_bar_set_handle (bar, start, end, 0);
12ba150f 9140 }
f451eb13 9141 }
06a2c219 9142#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13 9143
06a2c219 9144 XSETVECTOR (w->vertical_scroll_bar, bar);
f451eb13
JB
9145}
9146
12ba150f 9147
f451eb13 9148/* The following three hooks are used when we're doing a thorough
ab648270 9149 redisplay of the frame. We don't explicitly know which scroll bars
f451eb13 9150 are going to be deleted, because keeping track of when windows go
12ba150f
JB
9151 away is a real pain - "Can you say set-window-configuration, boys
9152 and girls?" Instead, we just assert at the beginning of redisplay
ab648270 9153 that *all* scroll bars are to be removed, and then save a scroll bar
12ba150f 9154 from the fiery pit when we actually redisplay its window. */
f451eb13 9155
ab648270
JB
9156/* Arrange for all scroll bars on FRAME to be removed at the next call
9157 to `*judge_scroll_bars_hook'. A scroll bar may be spared if
06a2c219
GM
9158 `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
9159
58769bee 9160static void
ab648270 9161XTcondemn_scroll_bars (frame)
f451eb13
JB
9162 FRAME_PTR frame;
9163{
f9e24cb9
RS
9164 /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
9165 while (! NILP (FRAME_SCROLL_BARS (frame)))
9166 {
9167 Lisp_Object bar;
9168 bar = FRAME_SCROLL_BARS (frame);
9169 FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
9170 XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
9171 XSCROLL_BAR (bar)->prev = Qnil;
9172 if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
9173 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
9174 FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
9175 }
f451eb13
JB
9176}
9177
fa2dfc30 9178
06a2c219 9179/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
12ba150f 9180 Note that WINDOW isn't necessarily condemned at all. */
fa2dfc30 9181
f451eb13 9182static void
ab648270 9183XTredeem_scroll_bar (window)
12ba150f 9184 struct window *window;
f451eb13 9185{
ab648270 9186 struct scroll_bar *bar;
fa2dfc30 9187 struct frame *f;
12ba150f 9188
ab648270
JB
9189 /* We can't redeem this window's scroll bar if it doesn't have one. */
9190 if (NILP (window->vertical_scroll_bar))
12ba150f
JB
9191 abort ();
9192
ab648270 9193 bar = XSCROLL_BAR (window->vertical_scroll_bar);
12ba150f
JB
9194
9195 /* Unlink it from the condemned list. */
fa2dfc30
GM
9196 f = XFRAME (WINDOW_FRAME (window));
9197 if (NILP (bar->prev))
9198 {
9199 /* If the prev pointer is nil, it must be the first in one of
9200 the lists. */
9201 if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
9202 /* It's not condemned. Everything's fine. */
9203 return;
9204 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
9205 window->vertical_scroll_bar))
9206 FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
9207 else
9208 /* If its prev pointer is nil, it must be at the front of
9209 one or the other! */
9210 abort ();
9211 }
9212 else
9213 XSCROLL_BAR (bar->prev)->next = bar->next;
12ba150f 9214
fa2dfc30
GM
9215 if (! NILP (bar->next))
9216 XSCROLL_BAR (bar->next)->prev = bar->prev;
12ba150f 9217
fa2dfc30
GM
9218 bar->next = FRAME_SCROLL_BARS (f);
9219 bar->prev = Qnil;
9220 XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
9221 if (! NILP (bar->next))
9222 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
f451eb13
JB
9223}
9224
ab648270
JB
9225/* Remove all scroll bars on FRAME that haven't been saved since the
9226 last call to `*condemn_scroll_bars_hook'. */
06a2c219 9227
f451eb13 9228static void
ab648270 9229XTjudge_scroll_bars (f)
12ba150f 9230 FRAME_PTR f;
f451eb13 9231{
12ba150f 9232 Lisp_Object bar, next;
f451eb13 9233
ab648270 9234 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
cf7cb199
JB
9235
9236 /* Clear out the condemned list now so we won't try to process any
ab648270
JB
9237 more events on the hapless scroll bars. */
9238 FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
cf7cb199
JB
9239
9240 for (; ! NILP (bar); bar = next)
f451eb13 9241 {
ab648270 9242 struct scroll_bar *b = XSCROLL_BAR (bar);
12ba150f 9243
ab648270 9244 x_scroll_bar_remove (b);
12ba150f
JB
9245
9246 next = b->next;
9247 b->next = b->prev = Qnil;
f451eb13 9248 }
12ba150f 9249
ab648270 9250 /* Now there should be no references to the condemned scroll bars,
12ba150f 9251 and they should get garbage-collected. */
f451eb13
JB
9252}
9253
9254
06a2c219
GM
9255/* Handle an Expose or GraphicsExpose event on a scroll bar. This
9256 is a no-op when using toolkit scroll bars.
ab648270
JB
9257
9258 This may be called from a signal handler, so we have to ignore GC
9259 mark bits. */
06a2c219 9260
f451eb13 9261static void
ab648270
JB
9262x_scroll_bar_expose (bar, event)
9263 struct scroll_bar *bar;
f451eb13
JB
9264 XEvent *event;
9265{
06a2c219
GM
9266#ifndef USE_TOOLKIT_SCROLL_BARS
9267
ab648270 9268 Window w = SCROLL_BAR_X_WINDOW (bar);
334208b7 9269 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
7556890b 9270 GC gc = f->output_data.x->normal_gc;
3cbd2e0b 9271 int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
12ba150f 9272
f451eb13
JB
9273 BLOCK_INPUT;
9274
ab648270 9275 x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
f451eb13 9276
06a2c219 9277 /* Draw a one-pixel border just inside the edges of the scroll bar. */
334208b7 9278 XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
f451eb13
JB
9279
9280 /* x, y, width, height */
d9cdbb3d 9281 0, 0,
3cbd2e0b 9282 XINT (bar->width) - 1 - width_trim - width_trim,
d9cdbb3d
RS
9283 XINT (bar->height) - 1);
9284
f451eb13 9285 UNBLOCK_INPUT;
06a2c219
GM
9286
9287#endif /* not USE_TOOLKIT_SCROLL_BARS */
f451eb13
JB
9288}
9289
ab648270
JB
9290/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
9291 is set to something other than no_event, it is enqueued.
9292
9293 This may be called from a signal handler, so we have to ignore GC
9294 mark bits. */
06a2c219 9295
5c187dee
GM
9296#ifndef USE_TOOLKIT_SCROLL_BARS
9297
f451eb13 9298static void
ab648270
JB
9299x_scroll_bar_handle_click (bar, event, emacs_event)
9300 struct scroll_bar *bar;
f451eb13
JB
9301 XEvent *event;
9302 struct input_event *emacs_event;
9303{
0299d313 9304 if (! GC_WINDOWP (bar->window))
12ba150f
JB
9305 abort ();
9306
ab648270 9307 emacs_event->kind = scroll_bar_click;
69388238 9308 emacs_event->code = event->xbutton.button - Button1;
0299d313
RS
9309 emacs_event->modifiers
9310 = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
9311 (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
9312 event->xbutton.state)
9313 | (event->type == ButtonRelease
9314 ? up_modifier
9315 : down_modifier));
12ba150f 9316 emacs_event->frame_or_window = bar->window;
0f8aabe9 9317 emacs_event->arg = Qnil;
f451eb13 9318 emacs_event->timestamp = event->xbutton.time;
12ba150f 9319 {
06a2c219 9320#if 0
d9cdbb3d 9321 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
0299d313 9322 int internal_height
d9cdbb3d 9323 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9324#endif
0299d313 9325 int top_range
d9cdbb3d 9326 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
ab648270 9327 int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
12ba150f
JB
9328
9329 if (y < 0) y = 0;
9330 if (y > top_range) y = top_range;
9331
9332 if (y < XINT (bar->start))
ab648270
JB
9333 emacs_event->part = scroll_bar_above_handle;
9334 else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9335 emacs_event->part = scroll_bar_handle;
12ba150f 9336 else
ab648270 9337 emacs_event->part = scroll_bar_below_handle;
929787e1
JB
9338
9339 /* Just because the user has clicked on the handle doesn't mean
5116f055
JB
9340 they want to drag it. Lisp code needs to be able to decide
9341 whether or not we're dragging. */
929787e1 9342#if 0
12ba150f
JB
9343 /* If the user has just clicked on the handle, record where they're
9344 holding it. */
9345 if (event->type == ButtonPress
ab648270 9346 && emacs_event->part == scroll_bar_handle)
e0c1aef2 9347 XSETINT (bar->dragging, y - XINT (bar->start));
929787e1 9348#endif
12ba150f
JB
9349
9350 /* If the user has released the handle, set it to its final position. */
9351 if (event->type == ButtonRelease
9352 && ! NILP (bar->dragging))
9353 {
9354 int new_start = y - XINT (bar->dragging);
9355 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
f451eb13 9356
ab648270 9357 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
12ba150f
JB
9358 bar->dragging = Qnil;
9359 }
f451eb13 9360
5116f055
JB
9361 /* Same deal here as the other #if 0. */
9362#if 0
58769bee 9363 /* Clicks on the handle are always reported as occurring at the top of
12ba150f 9364 the handle. */
ab648270 9365 if (emacs_event->part == scroll_bar_handle)
12ba150f
JB
9366 emacs_event->x = bar->start;
9367 else
e0c1aef2 9368 XSETINT (emacs_event->x, y);
5116f055 9369#else
e0c1aef2 9370 XSETINT (emacs_event->x, y);
5116f055 9371#endif
f451eb13 9372
e0c1aef2 9373 XSETINT (emacs_event->y, top_range);
12ba150f
JB
9374 }
9375}
f451eb13 9376
ab648270
JB
9377/* Handle some mouse motion while someone is dragging the scroll bar.
9378
9379 This may be called from a signal handler, so we have to ignore GC
9380 mark bits. */
06a2c219 9381
f451eb13 9382static void
ab648270
JB
9383x_scroll_bar_note_movement (bar, event)
9384 struct scroll_bar *bar;
f451eb13
JB
9385 XEvent *event;
9386{
39d8bb4d
KH
9387 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
9388
f451eb13
JB
9389 last_mouse_movement_time = event->xmotion.time;
9390
39d8bb4d 9391 f->mouse_moved = 1;
e0c1aef2 9392 XSETVECTOR (last_mouse_scroll_bar, bar);
f451eb13
JB
9393
9394 /* If we're dragging the bar, display it. */
ab648270 9395 if (! GC_NILP (bar->dragging))
f451eb13
JB
9396 {
9397 /* Where should the handle be now? */
12ba150f 9398 int new_start = event->xmotion.y - XINT (bar->dragging);
f451eb13 9399
12ba150f 9400 if (new_start != XINT (bar->start))
f451eb13 9401 {
12ba150f 9402 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
58769bee 9403
ab648270 9404 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
f451eb13
JB
9405 }
9406 }
f451eb13
JB
9407}
9408
5c187dee
GM
9409#endif /* !USE_TOOLKIT_SCROLL_BARS */
9410
12ba150f 9411/* Return information to the user about the current position of the mouse
ab648270 9412 on the scroll bar. */
06a2c219 9413
12ba150f 9414static void
334208b7
RS
9415x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
9416 FRAME_PTR *fp;
12ba150f 9417 Lisp_Object *bar_window;
ab648270 9418 enum scroll_bar_part *part;
12ba150f
JB
9419 Lisp_Object *x, *y;
9420 unsigned long *time;
9421{
ab648270 9422 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
334208b7
RS
9423 Window w = SCROLL_BAR_X_WINDOW (bar);
9424 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
12ba150f 9425 int win_x, win_y;
559cb2fb
JB
9426 Window dummy_window;
9427 int dummy_coord;
9428 unsigned int dummy_mask;
12ba150f 9429
cf7cb199
JB
9430 BLOCK_INPUT;
9431
ab648270 9432 /* Get the mouse's position relative to the scroll bar window, and
12ba150f 9433 report that. */
334208b7 9434 if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
12ba150f 9435
559cb2fb
JB
9436 /* Root, child, root x and root y. */
9437 &dummy_window, &dummy_window,
9438 &dummy_coord, &dummy_coord,
12ba150f 9439
559cb2fb
JB
9440 /* Position relative to scroll bar. */
9441 &win_x, &win_y,
12ba150f 9442
559cb2fb
JB
9443 /* Mouse buttons and modifier keys. */
9444 &dummy_mask))
7a13e894 9445 ;
559cb2fb
JB
9446 else
9447 {
06a2c219 9448#if 0
559cb2fb 9449 int inside_height
d9cdbb3d 9450 = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
06a2c219 9451#endif
559cb2fb 9452 int top_range
d9cdbb3d 9453 = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
559cb2fb
JB
9454
9455 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
9456
9457 if (! NILP (bar->dragging))
9458 win_y -= XINT (bar->dragging);
9459
9460 if (win_y < 0)
9461 win_y = 0;
9462 if (win_y > top_range)
9463 win_y = top_range;
9464
334208b7 9465 *fp = f;
7a13e894 9466 *bar_window = bar->window;
559cb2fb
JB
9467
9468 if (! NILP (bar->dragging))
9469 *part = scroll_bar_handle;
9470 else if (win_y < XINT (bar->start))
9471 *part = scroll_bar_above_handle;
9472 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
9473 *part = scroll_bar_handle;
9474 else
9475 *part = scroll_bar_below_handle;
12ba150f 9476
e0c1aef2
KH
9477 XSETINT (*x, win_y);
9478 XSETINT (*y, top_range);
12ba150f 9479
39d8bb4d 9480 f->mouse_moved = 0;
559cb2fb
JB
9481 last_mouse_scroll_bar = Qnil;
9482 }
12ba150f 9483
559cb2fb 9484 *time = last_mouse_movement_time;
cf7cb199 9485
cf7cb199 9486 UNBLOCK_INPUT;
12ba150f
JB
9487}
9488
f451eb13 9489
dbc4e1c1 9490/* The screen has been cleared so we may have changed foreground or
ab648270
JB
9491 background colors, and the scroll bars may need to be redrawn.
9492 Clear out the scroll bars, and ask for expose events, so we can
dbc4e1c1
JB
9493 redraw them. */
9494
dfcf069d 9495void
ab648270 9496x_scroll_bar_clear (f)
dbc4e1c1
JB
9497 FRAME_PTR f;
9498{
06a2c219 9499#ifndef USE_TOOLKIT_SCROLL_BARS
dbc4e1c1
JB
9500 Lisp_Object bar;
9501
b80c363e
RS
9502 /* We can have scroll bars even if this is 0,
9503 if we just turned off scroll bar mode.
9504 But in that case we should not clear them. */
9505 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
9506 for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
9507 bar = XSCROLL_BAR (bar)->next)
c5e6e06b
GM
9508 XClearArea (FRAME_X_DISPLAY (f),
9509 SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
b80c363e 9510 0, 0, 0, 0, True);
06a2c219 9511#endif /* not USE_TOOLKIT_SCROLL_BARS */
dbc4e1c1
JB
9512}
9513
06a2c219 9514/* This processes Expose events from the menu-bar specific X event
19126e11 9515 loop in xmenu.c. This allows to redisplay the frame if necessary
06a2c219 9516 when handling menu-bar or pop-up items. */
3afe33e7 9517
06a2c219 9518int
3afe33e7
RS
9519process_expose_from_menu (event)
9520 XEvent event;
9521{
9522 FRAME_PTR f;
19126e11 9523 struct x_display_info *dpyinfo;
06a2c219 9524 int frame_exposed_p = 0;
3afe33e7 9525
f94397b5
KH
9526 BLOCK_INPUT;
9527
19126e11
KH
9528 dpyinfo = x_display_info_for_display (event.xexpose.display);
9529 f = x_window_to_frame (dpyinfo, event.xexpose.window);
3afe33e7
RS
9530 if (f)
9531 {
9532 if (f->async_visible == 0)
9533 {
9534 f->async_visible = 1;
9535 f->async_iconified = 0;
06c488fd 9536 f->output_data.x->has_been_visible = 1;
3afe33e7
RS
9537 SET_FRAME_GARBAGED (f);
9538 }
9539 else
9540 {
06a2c219
GM
9541 expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
9542 event.xexpose.x, event.xexpose.y,
9543 event.xexpose.width, event.xexpose.height);
9544 frame_exposed_p = 1;
3afe33e7
RS
9545 }
9546 }
9547 else
9548 {
9549 struct scroll_bar *bar
9550 = x_window_to_scroll_bar (event.xexpose.window);
58769bee 9551
3afe33e7
RS
9552 if (bar)
9553 x_scroll_bar_expose (bar, &event);
9554 }
f94397b5
KH
9555
9556 UNBLOCK_INPUT;
06a2c219 9557 return frame_exposed_p;
3afe33e7 9558}
09756a85
RS
9559\f
9560/* Define a queue to save up SelectionRequest events for later handling. */
9561
9562struct selection_event_queue
9563 {
9564 XEvent event;
9565 struct selection_event_queue *next;
9566 };
9567
9568static struct selection_event_queue *queue;
9569
9570/* Nonzero means queue up certain events--don't process them yet. */
06a2c219 9571
09756a85
RS
9572static int x_queue_selection_requests;
9573
9574/* Queue up an X event *EVENT, to be processed later. */
dbc4e1c1 9575
09756a85 9576static void
334208b7
RS
9577x_queue_event (f, event)
9578 FRAME_PTR f;
09756a85
RS
9579 XEvent *event;
9580{
9581 struct selection_event_queue *queue_tmp
06a2c219 9582 = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
09756a85 9583
58769bee 9584 if (queue_tmp != NULL)
09756a85
RS
9585 {
9586 queue_tmp->event = *event;
9587 queue_tmp->next = queue;
9588 queue = queue_tmp;
9589 }
9590}
9591
9592/* Take all the queued events and put them back
9593 so that they get processed afresh. */
9594
9595static void
db3906fd
RS
9596x_unqueue_events (display)
9597 Display *display;
09756a85 9598{
58769bee 9599 while (queue != NULL)
09756a85
RS
9600 {
9601 struct selection_event_queue *queue_tmp = queue;
db3906fd 9602 XPutBackEvent (display, &queue_tmp->event);
09756a85 9603 queue = queue_tmp->next;
06a2c219 9604 xfree ((char *)queue_tmp);
09756a85
RS
9605 }
9606}
9607
9608/* Start queuing SelectionRequest events. */
9609
9610void
db3906fd
RS
9611x_start_queuing_selection_requests (display)
9612 Display *display;
09756a85
RS
9613{
9614 x_queue_selection_requests++;
9615}
9616
9617/* Stop queuing SelectionRequest events. */
9618
9619void
db3906fd
RS
9620x_stop_queuing_selection_requests (display)
9621 Display *display;
09756a85
RS
9622{
9623 x_queue_selection_requests--;
db3906fd 9624 x_unqueue_events (display);
09756a85 9625}
f451eb13
JB
9626\f
9627/* The main X event-reading loop - XTread_socket. */
dc6f92b8 9628
06a2c219 9629/* Time stamp of enter window event. This is only used by XTread_socket,
dc6f92b8
JB
9630 but we have to put it out here, since static variables within functions
9631 sometimes don't work. */
06a2c219 9632
dc6f92b8
JB
9633static Time enter_timestamp;
9634
11edeb03 9635/* This holds the state XLookupString needs to implement dead keys
58769bee 9636 and other tricks known as "compose processing". _X Window System_
11edeb03
JB
9637 says that a portable program can't use this, but Stephen Gildea assures
9638 me that letting the compiler initialize it to zeros will work okay.
9639
9640 This must be defined outside of XTread_socket, for the same reasons
06a2c219
GM
9641 given for enter_time stamp, above. */
9642
11edeb03
JB
9643static XComposeStatus compose_status;
9644
10e6549c
RS
9645/* Record the last 100 characters stored
9646 to help debug the loss-of-chars-during-GC problem. */
06a2c219 9647
2224b905
RS
9648static int temp_index;
9649static short temp_buffer[100];
10e6549c 9650
7a13e894
RS
9651/* Set this to nonzero to fake an "X I/O error"
9652 on a particular display. */
06a2c219 9653
7a13e894
RS
9654struct x_display_info *XTread_socket_fake_io_error;
9655
2224b905
RS
9656/* When we find no input here, we occasionally do a no-op command
9657 to verify that the X server is still running and we can still talk with it.
9658 We try all the open displays, one by one.
9659 This variable is used for cycling thru the displays. */
06a2c219 9660
2224b905
RS
9661static struct x_display_info *next_noop_dpyinfo;
9662
06a2c219
GM
9663#define SET_SAVED_MENU_EVENT(size) \
9664 do \
9665 { \
9666 if (f->output_data.x->saved_menu_event == 0) \
9667 f->output_data.x->saved_menu_event \
9668 = (XEvent *) xmalloc (sizeof (XEvent)); \
9669 bcopy (&event, f->output_data.x->saved_menu_event, size); \
9670 if (numchars >= 1) \
9671 { \
9672 bufp->kind = menu_bar_activate_event; \
9673 XSETFRAME (bufp->frame_or_window, f); \
0f8aabe9 9674 bufp->arg = Qnil; \
06a2c219
GM
9675 bufp++; \
9676 count++; \
9677 numchars--; \
9678 } \
9679 } \
9680 while (0)
9681
8805890a 9682#define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
06a2c219 9683#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
8805890a 9684
dc6f92b8
JB
9685/* Read events coming from the X server.
9686 This routine is called by the SIGIO handler.
9687 We return as soon as there are no more events to be read.
9688
9689 Events representing keys are stored in buffer BUFP,
9690 which can hold up to NUMCHARS characters.
9691 We return the number of characters stored into the buffer,
9692 thus pretending to be `read'.
9693
dc6f92b8
JB
9694 EXPECTED is nonzero if the caller knows input is available. */
9695
7c5283e4 9696int
f66868ba 9697XTread_socket (sd, bufp, numchars, expected)
dc6f92b8 9698 register int sd;
8805890a
KH
9699 /* register */ struct input_event *bufp;
9700 /* register */ int numchars;
dc6f92b8
JB
9701 int expected;
9702{
9703 int count = 0;
9704 int nbytes = 0;
dc6f92b8 9705 XEvent event;
f676886a 9706 struct frame *f;
66f55a9d 9707 int event_found = 0;
334208b7 9708 struct x_display_info *dpyinfo;
379b5ac0 9709 struct coding_system coding;
dc6f92b8 9710
9ac0d9e0 9711 if (interrupt_input_blocked)
dc6f92b8 9712 {
9ac0d9e0 9713 interrupt_input_pending = 1;
dc6f92b8
JB
9714 return -1;
9715 }
9716
9ac0d9e0 9717 interrupt_input_pending = 0;
dc6f92b8 9718 BLOCK_INPUT;
c0a04927
RS
9719
9720 /* So people can tell when we have read the available input. */
9721 input_signal_count++;
9722
dc6f92b8 9723 if (numchars <= 0)
06a2c219 9724 abort (); /* Don't think this happens. */
dc6f92b8 9725
bde5503b
GM
9726 ++handling_signal;
9727
379b5ac0
KH
9728 /* The input should be decoded if it is from XIM. Currently the
9729 locale of XIM is the same as that of the system. So, we can use
9730 Vlocale_coding_system which is initialized properly at Emacs
9731 startup time. */
9732 setup_coding_system (Vlocale_coding_system, &coding);
9733 coding.src_multibyte = 0;
9734 coding.dst_multibyte = 1;
9735 /* The input is converted to events, thus we can't handle
9736 composition. Anyway, there's no XIM that gives us composition
9737 information. */
9738 coding.composing = COMPOSITION_DISABLED;
9739
7a13e894
RS
9740 /* Find the display we are supposed to read input for.
9741 It's the one communicating on descriptor SD. */
9742 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
9743 {
9744#if 0 /* This ought to be unnecessary; let's verify it. */
dc6f92b8 9745#ifdef FIOSNBIO
7a13e894
RS
9746 /* If available, Xlib uses FIOSNBIO to make the socket
9747 non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set,
e6cbea31 9748 FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
06a2c219 9749 a read returns 0, which Xlib interprets as equivalent to EPIPE. */
7a13e894 9750 fcntl (dpyinfo->connection, F_SETFL, 0);
c118dd06 9751#endif /* ! defined (FIOSNBIO) */
7a13e894 9752#endif
dc6f92b8 9753
7a13e894
RS
9754#if 0 /* This code can't be made to work, with multiple displays,
9755 and appears not to be used on any system any more.
9756 Also keyboard.c doesn't turn O_NDELAY on and off
9757 for X connections. */
dc6f92b8
JB
9758#ifndef SIGIO
9759#ifndef HAVE_SELECT
7a13e894
RS
9760 if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
9761 {
9762 extern int read_alarm_should_throw;
9763 read_alarm_should_throw = 1;
9764 XPeekEvent (dpyinfo->display, &event);
9765 read_alarm_should_throw = 0;
9766 }
c118dd06
JB
9767#endif /* HAVE_SELECT */
9768#endif /* SIGIO */
7a13e894 9769#endif
dc6f92b8 9770
7a13e894
RS
9771 /* For debugging, this gives a way to fake an I/O error. */
9772 if (dpyinfo == XTread_socket_fake_io_error)
9773 {
9774 XTread_socket_fake_io_error = 0;
9775 x_io_error_quitter (dpyinfo->display);
9776 }
dc6f92b8 9777
06a2c219 9778 while (XPending (dpyinfo->display))
dc6f92b8 9779 {
7a13e894 9780 XNextEvent (dpyinfo->display, &event);
06a2c219 9781
531483fb 9782#ifdef HAVE_X_I18N
d1bc4182 9783 {
f2be1146
GM
9784 /* Filter events for the current X input method.
9785 XFilterEvent returns non-zero if the input method has
9786 consumed the event. We pass the frame's X window to
9787 XFilterEvent because that's the one for which the IC
9788 was created. */
f5d11644
GM
9789 struct frame *f1 = x_any_window_to_frame (dpyinfo,
9790 event.xclient.window);
9791 if (XFilterEvent (&event, f1 ? FRAME_X_WINDOW (f1) : None))
d1bc4182
RS
9792 break;
9793 }
0cd6403b 9794#endif
7a13e894
RS
9795 event_found = 1;
9796
9797 switch (event.type)
9798 {
9799 case ClientMessage:
c047688c 9800 {
7a13e894
RS
9801 if (event.xclient.message_type
9802 == dpyinfo->Xatom_wm_protocols
9803 && event.xclient.format == 32)
c047688c 9804 {
7a13e894
RS
9805 if (event.xclient.data.l[0]
9806 == dpyinfo->Xatom_wm_take_focus)
c047688c 9807 {
8c1a6a84
RS
9808 /* Use x_any_window_to_frame because this
9809 could be the shell widget window
9810 if the frame has no title bar. */
9811 f = x_any_window_to_frame (dpyinfo, event.xclient.window);
6c183ba5
RS
9812#ifdef HAVE_X_I18N
9813 /* Not quite sure this is needed -pd */
8c1a6a84 9814 if (f && FRAME_XIC (f))
6c183ba5
RS
9815 XSetICFocus (FRAME_XIC (f));
9816#endif
f1da8f06
GM
9817#if 0 /* Emacs sets WM hints whose `input' field is `true'. This
9818 instructs the WM to set the input focus automatically for
9819 Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
9820 tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
9821 it has set the focus. So, XSetInputFocus below is not
9822 needed.
9823
9824 The call to XSetInputFocus below has also caused trouble. In
9825 cases where the XSetInputFocus done by the WM and the one
9826 below are temporally close (on a fast machine), the call
9827 below can generate additional FocusIn events which confuse
9828 Emacs. */
9829
bf7253f4
RS
9830 /* Since we set WM_TAKE_FOCUS, we must call
9831 XSetInputFocus explicitly. But not if f is null,
9832 since that might be an event for a deleted frame. */
7a13e894 9833 if (f)
bf7253f4
RS
9834 {
9835 Display *d = event.xclient.display;
9836 /* Catch and ignore errors, in case window has been
9837 iconified by a window manager such as GWM. */
9838 int count = x_catch_errors (d);
9839 XSetInputFocus (d, event.xclient.window,
e1f6572f
RS
9840 /* The ICCCM says this is
9841 the only valid choice. */
9842 RevertToParent,
bf7253f4
RS
9843 event.xclient.data.l[1]);
9844 /* This is needed to detect the error
9845 if there is an error. */
9846 XSync (d, False);
9847 x_uncatch_errors (d, count);
9848 }
7a13e894 9849 /* Not certain about handling scroll bars here */
f1da8f06 9850#endif /* 0 */
c047688c 9851 }
7a13e894
RS
9852 else if (event.xclient.data.l[0]
9853 == dpyinfo->Xatom_wm_save_yourself)
9854 {
9855 /* Save state modify the WM_COMMAND property to
06a2c219 9856 something which can reinstate us. This notifies
7a13e894
RS
9857 the session manager, who's looking for such a
9858 PropertyNotify. Can restart processing when
06a2c219 9859 a keyboard or mouse event arrives. */
7a13e894
RS
9860 if (numchars > 0)
9861 {
19126e11
KH
9862 f = x_top_window_to_frame (dpyinfo,
9863 event.xclient.window);
7a13e894
RS
9864
9865 /* This is just so we only give real data once
9866 for a single Emacs process. */
b86bd3dd 9867 if (f == SELECTED_FRAME ())
7a13e894
RS
9868 XSetCommand (FRAME_X_DISPLAY (f),
9869 event.xclient.window,
9870 initial_argv, initial_argc);
f000f5c5 9871 else if (f)
7a13e894
RS
9872 XSetCommand (FRAME_X_DISPLAY (f),
9873 event.xclient.window,
9874 0, 0);
9875 }
9876 }
9877 else if (event.xclient.data.l[0]
9878 == dpyinfo->Xatom_wm_delete_window)
1fb20991 9879 {
19126e11
KH
9880 struct frame *f
9881 = x_any_window_to_frame (dpyinfo,
9882 event.xclient.window);
1fb20991 9883
7a13e894
RS
9884 if (f)
9885 {
9886 if (numchars == 0)
9887 abort ();
1fb20991 9888
7a13e894
RS
9889 bufp->kind = delete_window_event;
9890 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 9891 bufp->arg = Qnil;
7a13e894
RS
9892 bufp++;
9893
9894 count += 1;
9895 numchars -= 1;
9896 }
1fb20991 9897 }
c047688c 9898 }
7a13e894
RS
9899 else if (event.xclient.message_type
9900 == dpyinfo->Xatom_wm_configure_denied)
9901 {
9902 }
9903 else if (event.xclient.message_type
9904 == dpyinfo->Xatom_wm_window_moved)
9905 {
9906 int new_x, new_y;
19126e11
KH
9907 struct frame *f
9908 = x_window_to_frame (dpyinfo, event.xclient.window);
58769bee 9909
7a13e894
RS
9910 new_x = event.xclient.data.s[0];
9911 new_y = event.xclient.data.s[1];
1fb20991 9912
7a13e894
RS
9913 if (f)
9914 {
7556890b
RS
9915 f->output_data.x->left_pos = new_x;
9916 f->output_data.x->top_pos = new_y;
7a13e894 9917 }
1fb20991 9918 }
0fdff6bb 9919#ifdef HACK_EDITRES
7a13e894
RS
9920 else if (event.xclient.message_type
9921 == dpyinfo->Xatom_editres)
9922 {
19126e11
KH
9923 struct frame *f
9924 = x_any_window_to_frame (dpyinfo, event.xclient.window);
7556890b 9925 _XEditResCheckMessages (f->output_data.x->widget, NULL,
19126e11 9926 &event, NULL);
7a13e894 9927 }
0fdff6bb 9928#endif /* HACK_EDITRES */
06a2c219
GM
9929 else if ((event.xclient.message_type
9930 == dpyinfo->Xatom_DONE)
9931 || (event.xclient.message_type
9932 == dpyinfo->Xatom_PAGE))
9933 {
9934 /* Ghostview job completed. Kill it. We could
9935 reply with "Next" if we received "Page", but we
9936 currently never do because we are interested in
9937 images, only, which should have 1 page. */
06a2c219
GM
9938 Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
9939 struct frame *f
9940 = x_window_to_frame (dpyinfo, event.xclient.window);
9941 x_kill_gs_process (pixmap, f);
9942 expose_frame (f, 0, 0, 0, 0);
9943 }
9944#ifdef USE_TOOLKIT_SCROLL_BARS
9945 /* Scroll bar callbacks send a ClientMessage from which
9946 we construct an input_event. */
9947 else if (event.xclient.message_type
9948 == dpyinfo->Xatom_Scrollbar)
9949 {
9950 x_scroll_bar_to_input_event (&event, bufp);
9951 ++bufp, ++count, --numchars;
9952 goto out;
9953 }
9954#endif /* USE_TOOLKIT_SCROLL_BARS */
9955 else
9956 goto OTHER;
7a13e894
RS
9957 }
9958 break;
dc6f92b8 9959
7a13e894 9960 case SelectionNotify:
3afe33e7 9961#ifdef USE_X_TOOLKIT
19126e11 9962 if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
7a13e894 9963 goto OTHER;
3afe33e7 9964#endif /* not USE_X_TOOLKIT */
dfcf069d 9965 x_handle_selection_notify (&event.xselection);
7a13e894 9966 break;
d56a553a 9967
06a2c219 9968 case SelectionClear: /* Someone has grabbed ownership. */
3afe33e7 9969#ifdef USE_X_TOOLKIT
19126e11 9970 if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
7a13e894 9971 goto OTHER;
3afe33e7 9972#endif /* USE_X_TOOLKIT */
7a13e894
RS
9973 {
9974 XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
d56a553a 9975
7a13e894
RS
9976 if (numchars == 0)
9977 abort ();
d56a553a 9978
7a13e894
RS
9979 bufp->kind = selection_clear_event;
9980 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
9981 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
9982 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 9983 bufp->frame_or_window = Qnil;
0f8aabe9 9984 bufp->arg = Qnil;
7a13e894 9985 bufp++;
d56a553a 9986
7a13e894
RS
9987 count += 1;
9988 numchars -= 1;
9989 }
9990 break;
dc6f92b8 9991
06a2c219 9992 case SelectionRequest: /* Someone wants our selection. */
3afe33e7 9993#ifdef USE_X_TOOLKIT
19126e11 9994 if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
7a13e894 9995 goto OTHER;
3afe33e7 9996#endif /* USE_X_TOOLKIT */
7a13e894 9997 if (x_queue_selection_requests)
19126e11 9998 x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner),
7a13e894
RS
9999 &event);
10000 else
10001 {
1d2b2268
GM
10002 XSelectionRequestEvent *eventp
10003 = (XSelectionRequestEvent *) &event;
dc6f92b8 10004
7a13e894
RS
10005 if (numchars == 0)
10006 abort ();
10007
10008 bufp->kind = selection_request_event;
10009 SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
10010 SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
10011 SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
10012 SELECTION_EVENT_TARGET (bufp) = eventp->target;
10013 SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
10014 SELECTION_EVENT_TIME (bufp) = eventp->time;
e6cbea31 10015 bufp->frame_or_window = Qnil;
0f8aabe9 10016 bufp->arg = Qnil;
7a13e894
RS
10017 bufp++;
10018
10019 count += 1;
10020 numchars -= 1;
10021 }
10022 break;
10023
10024 case PropertyNotify:
1d2b2268
GM
10025#if 0 /* This is plain wrong. In the case that we are waiting for a
10026 PropertyNotify used as an ACK in incremental selection
10027 transfer, the property will be on the receiver's window. */
10028#if defined USE_X_TOOLKIT
19126e11 10029 if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
7a13e894 10030 goto OTHER;
1d2b2268
GM
10031#endif
10032#endif
dfcf069d 10033 x_handle_property_notify (&event.xproperty);
1d2b2268 10034 goto OTHER;
dc6f92b8 10035
7a13e894 10036 case ReparentNotify:
19126e11 10037 f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
7a13e894
RS
10038 if (f)
10039 {
10040 int x, y;
7556890b 10041 f->output_data.x->parent_desc = event.xreparent.parent;
7a13e894 10042 x_real_positions (f, &x, &y);
7556890b
RS
10043 f->output_data.x->left_pos = x;
10044 f->output_data.x->top_pos = y;
7a13e894
RS
10045 }
10046 break;
3bd330d4 10047
7a13e894 10048 case Expose:
19126e11 10049 f = x_window_to_frame (dpyinfo, event.xexpose.window);
7a13e894 10050 if (f)
dc6f92b8 10051 {
7a13e894
RS
10052 if (f->async_visible == 0)
10053 {
10054 f->async_visible = 1;
10055 f->async_iconified = 0;
06c488fd 10056 f->output_data.x->has_been_visible = 1;
7a13e894
RS
10057 SET_FRAME_GARBAGED (f);
10058 }
10059 else
06a2c219
GM
10060 expose_frame (x_window_to_frame (dpyinfo,
10061 event.xexpose.window),
10062 event.xexpose.x, event.xexpose.y,
10063 event.xexpose.width, event.xexpose.height);
dc6f92b8
JB
10064 }
10065 else
7a13e894 10066 {
12949a7f
EZ
10067#ifndef USE_TOOLKIT_SCROLL_BARS
10068 struct scroll_bar *bar;
10069#endif
c95fc5f1
GM
10070#if defined USE_X_TOOLKIT && defined USE_LUCID
10071 /* Submenus of the Lucid menu bar aren't widgets
10072 themselves, so there's no way to dispatch events
10073 to them. Recognize this case separately. */
10074 {
10075 Widget widget
10076 = x_window_to_menu_bar (event.xexpose.window);
10077 if (widget)
10078 xlwmenu_redisplay (widget);
10079 }
10080#endif /* USE_X_TOOLKIT && USE_LUCID */
10081
06a2c219
GM
10082#ifdef USE_TOOLKIT_SCROLL_BARS
10083 /* Dispatch event to the widget. */
10084 goto OTHER;
10085#else /* not USE_TOOLKIT_SCROLL_BARS */
12949a7f 10086 bar = x_window_to_scroll_bar (event.xexpose.window);
58769bee 10087
7a13e894
RS
10088 if (bar)
10089 x_scroll_bar_expose (bar, &event);
3afe33e7 10090#ifdef USE_X_TOOLKIT
7a13e894
RS
10091 else
10092 goto OTHER;
3afe33e7 10093#endif /* USE_X_TOOLKIT */
06a2c219 10094#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10095 }
10096 break;
dc6f92b8 10097
7a13e894
RS
10098 case GraphicsExpose: /* This occurs when an XCopyArea's
10099 source area was obscured or not
10100 available.*/
19126e11 10101 f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
7a13e894
RS
10102 if (f)
10103 {
06a2c219
GM
10104 expose_frame (f,
10105 event.xgraphicsexpose.x, event.xgraphicsexpose.y,
10106 event.xgraphicsexpose.width,
10107 event.xgraphicsexpose.height);
7a13e894 10108 }
3afe33e7 10109#ifdef USE_X_TOOLKIT
7a13e894
RS
10110 else
10111 goto OTHER;
3afe33e7 10112#endif /* USE_X_TOOLKIT */
7a13e894 10113 break;
dc6f92b8 10114
7a13e894 10115 case NoExpose: /* This occurs when an XCopyArea's
06a2c219
GM
10116 source area was completely
10117 available */
7a13e894 10118 break;
dc6f92b8 10119
7a13e894 10120 case UnmapNotify:
06a2c219
GM
10121 /* Redo the mouse-highlight after the tooltip has gone. */
10122 if (event.xmap.window == tip_window)
10123 {
10124 tip_window = 0;
10125 redo_mouse_highlight ();
10126 }
10127
91ea2a7a 10128 f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
7a13e894
RS
10129 if (f) /* F may no longer exist if
10130 the frame was deleted. */
10131 {
10132 /* While a frame is unmapped, display generation is
10133 disabled; you don't want to spend time updating a
10134 display that won't ever be seen. */
10135 f->async_visible = 0;
10136 /* We can't distinguish, from the event, whether the window
10137 has become iconified or invisible. So assume, if it
10138 was previously visible, than now it is iconified.
1aa6072f
RS
10139 But x_make_frame_invisible clears both
10140 the visible flag and the iconified flag;
10141 and that way, we know the window is not iconified now. */
7a13e894 10142 if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
1aa6072f
RS
10143 {
10144 f->async_iconified = 1;
bddd097c 10145
1aa6072f
RS
10146 bufp->kind = iconify_event;
10147 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10148 bufp->arg = Qnil;
1aa6072f
RS
10149 bufp++;
10150 count++;
10151 numchars--;
10152 }
7a13e894 10153 }
7a13e894 10154 goto OTHER;
dc6f92b8 10155
7a13e894 10156 case MapNotify:
06a2c219
GM
10157 if (event.xmap.window == tip_window)
10158 /* The tooltip has been drawn already. Avoid
10159 the SET_FRAME_GARBAGED below. */
10160 goto OTHER;
10161
10162 /* We use x_top_window_to_frame because map events can
10163 come for sub-windows and they don't mean that the
10164 frame is visible. */
19126e11 10165 f = x_top_window_to_frame (dpyinfo, event.xmap.window);
7a13e894
RS
10166 if (f)
10167 {
10168 f->async_visible = 1;
10169 f->async_iconified = 0;
06c488fd 10170 f->output_data.x->has_been_visible = 1;
dc6f92b8 10171
7a13e894
RS
10172 /* wait_reading_process_input will notice this and update
10173 the frame's display structures. */
10174 SET_FRAME_GARBAGED (f);
bddd097c 10175
d806e720
RS
10176 if (f->iconified)
10177 {
10178 bufp->kind = deiconify_event;
10179 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10180 bufp->arg = Qnil;
d806e720
RS
10181 bufp++;
10182 count++;
10183 numchars--;
10184 }
e73ec6fa 10185 else if (! NILP (Vframe_list)
8e713be6 10186 && ! NILP (XCDR (Vframe_list)))
78aa2ba5
KH
10187 /* Force a redisplay sooner or later
10188 to update the frame titles
10189 in case this is the second frame. */
10190 record_asynch_buffer_change ();
7a13e894 10191 }
7a13e894 10192 goto OTHER;
dc6f92b8 10193
7a13e894 10194 case KeyPress:
19126e11 10195 f = x_any_window_to_frame (dpyinfo, event.xkey.window);
f451eb13 10196
eccc05db 10197#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
06a2c219
GM
10198 if (f == 0)
10199 {
2564ea1b
GM
10200 /* Scroll bars consume key events, but we want
10201 the keys to go to the scroll bar's frame. */
06a2c219
GM
10202 Widget widget = XtWindowToWidget (dpyinfo->display,
10203 event.xkey.window);
10204 if (widget && XmIsScrollBar (widget))
10205 {
10206 widget = XtParent (widget);
10207 f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
10208 }
10209 }
eccc05db 10210#endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
06a2c219 10211
7a13e894
RS
10212 if (f != 0)
10213 {
10214 KeySym keysym, orig_keysym;
379b5ac0
KH
10215 /* al%imercury@uunet.uu.net says that making this 81
10216 instead of 80 fixed a bug whereby meta chars made
10217 his Emacs hang.
10218
10219 It seems that some version of XmbLookupString has
10220 a bug of not returning XBufferOverflow in
10221 status_return even if the input is too long to
10222 fit in 81 bytes. So, we must prepare sufficient
10223 bytes for copy_buffer. 513 bytes (256 chars for
10224 two-byte character set) seems to be a faily good
10225 approximation. -- 2000.8.10 handa@etl.go.jp */
10226 unsigned char copy_buffer[513];
10227 unsigned char *copy_bufptr = copy_buffer;
10228 int copy_bufsiz = sizeof (copy_buffer);
7a13e894 10229 int modifiers;
64bb1782 10230
7a13e894
RS
10231 event.xkey.state
10232 |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
10233 extra_keyboard_modifiers);
10234 modifiers = event.xkey.state;
3a2712f9 10235
7a13e894 10236 /* This will have to go some day... */
752a043f 10237
7a13e894
RS
10238 /* make_lispy_event turns chars into control chars.
10239 Don't do it here because XLookupString is too eager. */
10240 event.xkey.state &= ~ControlMask;
5d46f928
RS
10241 event.xkey.state &= ~(dpyinfo->meta_mod_mask
10242 | dpyinfo->super_mod_mask
10243 | dpyinfo->hyper_mod_mask
10244 | dpyinfo->alt_mod_mask);
10245
1cf4a0d1
RS
10246 /* In case Meta is ComposeCharacter,
10247 clear its status. According to Markus Ehrnsperger
10248 Markus.Ehrnsperger@lehrstuhl-bross.physik.uni-muenchen.de
10249 this enables ComposeCharacter to work whether or
10250 not it is combined with Meta. */
10251 if (modifiers & dpyinfo->meta_mod_mask)
10252 bzero (&compose_status, sizeof (compose_status));
10253
6c183ba5
RS
10254#ifdef HAVE_X_I18N
10255 if (FRAME_XIC (f))
10256 {
f5d11644
GM
10257 Status status_return;
10258
6c183ba5 10259 nbytes = XmbLookupString (FRAME_XIC (f),
f5d11644
GM
10260 &event.xkey, copy_bufptr,
10261 copy_bufsiz, &keysym,
6c183ba5 10262 &status_return);
f5d11644
GM
10263 if (status_return == XBufferOverflow)
10264 {
10265 copy_bufsiz = nbytes + 1;
10266 copy_bufptr = (char *) alloca (copy_bufsiz);
10267 nbytes = XmbLookupString (FRAME_XIC (f),
10268 &event.xkey, copy_bufptr,
10269 copy_bufsiz, &keysym,
10270 &status_return);
10271 }
10272
1decb680
PE
10273 if (status_return == XLookupNone)
10274 break;
10275 else if (status_return == XLookupChars)
fdd9d55e
GM
10276 {
10277 keysym = NoSymbol;
10278 modifiers = 0;
10279 }
1decb680
PE
10280 else if (status_return != XLookupKeySym
10281 && status_return != XLookupBoth)
10282 abort ();
6c183ba5
RS
10283 }
10284 else
379b5ac0
KH
10285 nbytes = XLookupString (&event.xkey, copy_bufptr,
10286 copy_bufsiz, &keysym,
10287 &compose_status);
6c183ba5 10288#else
379b5ac0
KH
10289 nbytes = XLookupString (&event.xkey, copy_bufptr,
10290 copy_bufsiz, &keysym,
10291 &compose_status);
6c183ba5 10292#endif
dc6f92b8 10293
7a13e894 10294 orig_keysym = keysym;
55123275 10295
7a13e894
RS
10296 if (numchars > 1)
10297 {
10298 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
10299 || keysym == XK_Delete
1097aea0 10300#ifdef XK_ISO_Left_Tab
441affdb 10301 || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
1097aea0 10302#endif
852bff8f 10303 || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
7a13e894
RS
10304 || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
10305 || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
c34790e0 10306#ifdef HPUX
7a13e894
RS
10307 /* This recognizes the "extended function keys".
10308 It seems there's no cleaner way.
10309 Test IsModifierKey to avoid handling mode_switch
10310 incorrectly. */
10311 || ((unsigned) (keysym) >= XK_Select
10312 && (unsigned)(keysym) < XK_KP_Space)
69388238
RS
10313#endif
10314#ifdef XK_dead_circumflex
7a13e894 10315 || orig_keysym == XK_dead_circumflex
69388238
RS
10316#endif
10317#ifdef XK_dead_grave
7a13e894 10318 || orig_keysym == XK_dead_grave
69388238
RS
10319#endif
10320#ifdef XK_dead_tilde
7a13e894 10321 || orig_keysym == XK_dead_tilde
69388238
RS
10322#endif
10323#ifdef XK_dead_diaeresis
7a13e894 10324 || orig_keysym == XK_dead_diaeresis
69388238
RS
10325#endif
10326#ifdef XK_dead_macron
7a13e894 10327 || orig_keysym == XK_dead_macron
69388238
RS
10328#endif
10329#ifdef XK_dead_degree
7a13e894 10330 || orig_keysym == XK_dead_degree
69388238
RS
10331#endif
10332#ifdef XK_dead_acute
7a13e894 10333 || orig_keysym == XK_dead_acute
69388238
RS
10334#endif
10335#ifdef XK_dead_cedilla
7a13e894 10336 || orig_keysym == XK_dead_cedilla
69388238
RS
10337#endif
10338#ifdef XK_dead_breve
7a13e894 10339 || orig_keysym == XK_dead_breve
69388238
RS
10340#endif
10341#ifdef XK_dead_ogonek
7a13e894 10342 || orig_keysym == XK_dead_ogonek
69388238
RS
10343#endif
10344#ifdef XK_dead_caron
7a13e894 10345 || orig_keysym == XK_dead_caron
69388238
RS
10346#endif
10347#ifdef XK_dead_doubleacute
7a13e894 10348 || orig_keysym == XK_dead_doubleacute
69388238
RS
10349#endif
10350#ifdef XK_dead_abovedot
7a13e894 10351 || orig_keysym == XK_dead_abovedot
c34790e0 10352#endif
7a13e894
RS
10353 || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
10354 || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
10355 /* Any "vendor-specific" key is ok. */
10356 || (orig_keysym & (1 << 28)))
10357 && ! (IsModifierKey (orig_keysym)
7719aa06
RS
10358#ifndef HAVE_X11R5
10359#ifdef XK_Mode_switch
7a13e894 10360 || ((unsigned)(orig_keysym) == XK_Mode_switch)
7719aa06
RS
10361#endif
10362#ifdef XK_Num_Lock
7a13e894 10363 || ((unsigned)(orig_keysym) == XK_Num_Lock)
7719aa06
RS
10364#endif
10365#endif /* not HAVE_X11R5 */
7a13e894 10366 ))
dc6f92b8 10367 {
10e6549c
RS
10368 if (temp_index == sizeof temp_buffer / sizeof (short))
10369 temp_index = 0;
7a13e894
RS
10370 temp_buffer[temp_index++] = keysym;
10371 bufp->kind = non_ascii_keystroke;
10372 bufp->code = keysym;
e0c1aef2 10373 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10374 bufp->arg = Qnil;
334208b7
RS
10375 bufp->modifiers
10376 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10377 modifiers);
1113d9db 10378 bufp->timestamp = event.xkey.time;
dc6f92b8 10379 bufp++;
7a13e894
RS
10380 count++;
10381 numchars--;
dc6f92b8 10382 }
7a13e894
RS
10383 else if (numchars > nbytes)
10384 {
10385 register int i;
379b5ac0 10386 register int c;
379b5ac0 10387 int nchars, len;
7a13e894
RS
10388
10389 for (i = 0; i < nbytes; i++)
10390 {
379b5ac0
KH
10391 if (temp_index == (sizeof temp_buffer
10392 / sizeof (short)))
7a13e894 10393 temp_index = 0;
379b5ac0
KH
10394 temp_buffer[temp_index++] = copy_bufptr[i];
10395 }
10396
10397 if (/* If the event is not from XIM, */
10398 event.xkey.keycode != 0
10399 /* or the current locale doesn't request
10400 decoding of the intup data, ... */
10401 || coding.type == coding_type_raw_text
10402 || coding.type == coding_type_no_conversion)
10403 {
10404 /* ... we can use the input data as is. */
10405 nchars = nbytes;
10406 }
10407 else
10408 {
10409 /* We have to decode the input data. */
10410 int require;
10411 unsigned char *p;
10412
10413 require = decoding_buffer_size (&coding, nbytes);
10414 p = (unsigned char *) alloca (require);
10415 coding.mode |= CODING_MODE_LAST_BLOCK;
10416 decode_coding (&coding, copy_bufptr, p,
10417 nbytes, require);
10418 nbytes = coding.produced;
10419 nchars = coding.produced_char;
10420 copy_bufptr = p;
10421 }
10422
10423 /* Convert the input data to a sequence of
10424 character events. */
10425 for (i = 0; i < nbytes; i += len)
10426 {
10427 c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
10428 nbytes - i, len);
10429 bufp->kind = (SINGLE_BYTE_CHAR_P (c)
10430 ? ascii_keystroke
10431 : multibyte_char_keystroke);
10432 bufp->code = c;
7a13e894 10433 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10434 bufp->arg = Qnil;
7a13e894
RS
10435 bufp->modifiers
10436 = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
10437 modifiers);
10438 bufp->timestamp = event.xkey.time;
10439 bufp++;
10440 }
10441
379b5ac0
KH
10442 count += nchars;
10443 numchars -= nchars;
1decb680
PE
10444
10445 if (keysym == NoSymbol)
10446 break;
7a13e894
RS
10447 }
10448 else
10449 abort ();
dc6f92b8 10450 }
10e6549c
RS
10451 else
10452 abort ();
dc6f92b8 10453 }
59ddecde
GM
10454#ifdef HAVE_X_I18N
10455 /* Don't dispatch this event since XtDispatchEvent calls
10456 XFilterEvent, and two calls in a row may freeze the
10457 client. */
10458 break;
10459#else
717ca130 10460 goto OTHER;
59ddecde 10461#endif
f451eb13 10462
f5d11644 10463 case KeyRelease:
59ddecde
GM
10464#ifdef HAVE_X_I18N
10465 /* Don't dispatch this event since XtDispatchEvent calls
10466 XFilterEvent, and two calls in a row may freeze the
10467 client. */
10468 break;
10469#else
f5d11644 10470 goto OTHER;
59ddecde 10471#endif
f5d11644 10472
7a13e894 10473 /* Here's a possible interpretation of the whole
06a2c219
GM
10474 FocusIn-EnterNotify FocusOut-LeaveNotify mess. If
10475 you get a FocusIn event, you have to get a FocusOut
10476 event before you relinquish the focus. If you
10477 haven't received a FocusIn event, then a mere
10478 LeaveNotify is enough to free you. */
f451eb13 10479
7a13e894 10480 case EnterNotify:
06a2c219 10481 {
06a2c219
GM
10482 f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
10483
582c60f8 10484 if (event.xcrossing.focus)
06a2c219
GM
10485 {
10486 /* Avoid nasty pop/raise loops. */
10487 if (f && (!(f->auto_raise)
10488 || !(f->auto_lower)
10489 || (event.xcrossing.time - enter_timestamp) > 500))
10490 {
10491 x_new_focus_frame (dpyinfo, f);
10492 enter_timestamp = event.xcrossing.time;
10493 }
10494 }
10495 else if (f == dpyinfo->x_focus_frame)
10496 x_new_focus_frame (dpyinfo, 0);
10497
10498 /* EnterNotify counts as mouse movement,
10499 so update things that depend on mouse position. */
2533c408 10500 if (f && !f->output_data.x->hourglass_p)
06a2c219
GM
10501 note_mouse_movement (f, &event.xmotion);
10502 goto OTHER;
10503 }
dc6f92b8 10504
7a13e894 10505 case FocusIn:
19126e11 10506 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10507 if (event.xfocus.detail != NotifyPointer)
0f941935 10508 dpyinfo->x_focus_event_frame = f;
7a13e894 10509 if (f)
eb72635f
GM
10510 {
10511 x_new_focus_frame (dpyinfo, f);
10512
10513 /* Don't stop displaying the initial startup message
10514 for a switch-frame event we don't need. */
10515 if (GC_NILP (Vterminal_frame)
10516 && GC_CONSP (Vframe_list)
10517 && !GC_NILP (XCDR (Vframe_list)))
10518 {
10519 bufp->kind = FOCUS_IN_EVENT;
10520 XSETFRAME (bufp->frame_or_window, f);
0f8aabe9 10521 bufp->arg = Qnil;
eb72635f
GM
10522 ++bufp, ++count, --numchars;
10523 }
10524 }
f9e24cb9 10525
6c183ba5
RS
10526#ifdef HAVE_X_I18N
10527 if (f && FRAME_XIC (f))
10528 XSetICFocus (FRAME_XIC (f));
10529#endif
10530
7a13e894 10531 goto OTHER;
10c5e63d 10532
7a13e894 10533 case LeaveNotify:
19126e11 10534 f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
7a13e894 10535 if (f)
10c5e63d 10536 {
7a13e894 10537 if (f == dpyinfo->mouse_face_mouse_frame)
06a2c219
GM
10538 {
10539 /* If we move outside the frame, then we're
10540 certainly no longer on any text in the frame. */
10541 clear_mouse_face (dpyinfo);
10542 dpyinfo->mouse_face_mouse_frame = 0;
10543 }
10544
10545 /* Generate a nil HELP_EVENT to cancel a help-echo.
10546 Do it only if there's something to cancel.
10547 Otherwise, the startup message is cleared when
10548 the mouse leaves the frame. */
10549 if (any_help_event_p)
10550 {
be010514
GM
10551 Lisp_Object frame;
10552 int n;
10553
06a2c219 10554 XSETFRAME (frame, f);
82c5d67a 10555 help_echo = Qnil;
5ab2570d
GM
10556 n = gen_help_event (bufp, numchars,
10557 Qnil, frame, Qnil, Qnil, 0);
be010514 10558 bufp += n, count += n, numchars -= n;
06a2c219 10559 }
7a13e894 10560
582c60f8 10561 if (event.xcrossing.focus)
0f941935 10562 x_mouse_leave (dpyinfo);
10c5e63d 10563 else
7a13e894 10564 {
0f941935
KH
10565 if (f == dpyinfo->x_focus_event_frame)
10566 dpyinfo->x_focus_event_frame = 0;
10567 if (f == dpyinfo->x_focus_frame)
10568 x_new_focus_frame (dpyinfo, 0);
7a13e894 10569 }
10c5e63d 10570 }
7a13e894 10571 goto OTHER;
dc6f92b8 10572
7a13e894 10573 case FocusOut:
19126e11 10574 f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
7a13e894 10575 if (event.xfocus.detail != NotifyPointer
0f941935
KH
10576 && f == dpyinfo->x_focus_event_frame)
10577 dpyinfo->x_focus_event_frame = 0;
10578 if (f && f == dpyinfo->x_focus_frame)
10579 x_new_focus_frame (dpyinfo, 0);
f9e24cb9 10580
6c183ba5
RS
10581#ifdef HAVE_X_I18N
10582 if (f && FRAME_XIC (f))
10583 XUnsetICFocus (FRAME_XIC (f));
10584#endif
10585
7a13e894 10586 goto OTHER;
dc6f92b8 10587
7a13e894 10588 case MotionNotify:
dc6f92b8 10589 {
06a2c219 10590 previous_help_echo = help_echo;
7cea38bc 10591 help_echo = help_echo_object = help_echo_window = Qnil;
be010514 10592 help_echo_pos = -1;
06a2c219 10593
7a13e894
RS
10594 if (dpyinfo->grabbed && last_mouse_frame
10595 && FRAME_LIVE_P (last_mouse_frame))
10596 f = last_mouse_frame;
10597 else
19126e11 10598 f = x_window_to_frame (dpyinfo, event.xmotion.window);
06a2c219 10599
7a13e894
RS
10600 if (f)
10601 note_mouse_movement (f, &event.xmotion);
10602 else
10603 {
e88b3c50 10604#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10605 struct scroll_bar *bar
10606 = x_window_to_scroll_bar (event.xmotion.window);
f451eb13 10607
7a13e894
RS
10608 if (bar)
10609 x_scroll_bar_note_movement (bar, &event);
e88b3c50 10610#endif /* USE_TOOLKIT_SCROLL_BARS */
b8009dd1 10611
06a2c219
GM
10612 /* If we move outside the frame, then we're
10613 certainly no longer on any text in the frame. */
7a13e894
RS
10614 clear_mouse_face (dpyinfo);
10615 }
06a2c219
GM
10616
10617 /* If the contents of the global variable help_echo
10618 has changed, generate a HELP_EVENT. */
b7e80413
SM
10619 if (!NILP (help_echo)
10620 || !NILP (previous_help_echo))
06a2c219
GM
10621 {
10622 Lisp_Object frame;
be010514 10623 int n;
06a2c219
GM
10624
10625 if (f)
10626 XSETFRAME (frame, f);
10627 else
10628 frame = Qnil;
10629
10630 any_help_event_p = 1;
5ab2570d 10631 n = gen_help_event (bufp, numchars, help_echo, frame,
7cea38bc
GM
10632 help_echo_window, help_echo_object,
10633 help_echo_pos);
be010514 10634 bufp += n, count += n, numchars -= n;
06a2c219
GM
10635 }
10636
10637 goto OTHER;
dc6f92b8 10638 }
dc6f92b8 10639
7a13e894 10640 case ConfigureNotify:
9829ddba
RS
10641 f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
10642 if (f)
af395ec1 10643 {
5c187dee 10644#ifndef USE_X_TOOLKIT
bf1b7b30
KH
10645 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
10646 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
5c187dee 10647
2d7fc7e8
RS
10648 /* In the toolkit version, change_frame_size
10649 is called by the code that handles resizing
10650 of the EmacsFrame widget. */
7a13e894 10651
7a13e894
RS
10652 /* Even if the number of character rows and columns has
10653 not changed, the font size may have changed, so we need
10654 to check the pixel dimensions as well. */
10655 if (columns != f->width
10656 || rows != f->height
7556890b
RS
10657 || event.xconfigure.width != f->output_data.x->pixel_width
10658 || event.xconfigure.height != f->output_data.x->pixel_height)
7a13e894 10659 {
7d1e984f 10660 change_frame_size (f, rows, columns, 0, 1, 0);
7a13e894 10661 SET_FRAME_GARBAGED (f);
e687d06e 10662 cancel_mouse_face (f);
7a13e894 10663 }
2d7fc7e8 10664#endif
af395ec1 10665
7556890b
RS
10666 f->output_data.x->pixel_width = event.xconfigure.width;
10667 f->output_data.x->pixel_height = event.xconfigure.height;
7a13e894
RS
10668
10669 /* What we have now is the position of Emacs's own window.
10670 Convert that to the position of the window manager window. */
dcb07ae9
RS
10671 x_real_positions (f, &f->output_data.x->left_pos,
10672 &f->output_data.x->top_pos);
10673
f5d11644
GM
10674#ifdef HAVE_X_I18N
10675 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
10676 xic_set_statusarea (f);
10677#endif
10678
dcb07ae9
RS
10679 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
10680 {
10681 /* Since the WM decorations come below top_pos now,
10682 we must put them below top_pos in the future. */
10683 f->output_data.x->win_gravity = NorthWestGravity;
10684 x_wm_set_size_hint (f, (long) 0, 0);
10685 }
8f08dc93
KH
10686#ifdef USE_MOTIF
10687 /* Some window managers pass (0,0) as the location of
10688 the window, and the Motif event handler stores it
10689 in the emacs widget, which messes up Motif menus. */
10690 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
10691 {
10692 event.xconfigure.x = f->output_data.x->widget->core.x;
10693 event.xconfigure.y = f->output_data.x->widget->core.y;
10694 }
06a2c219 10695#endif /* USE_MOTIF */
7a13e894 10696 }
2d7fc7e8 10697 goto OTHER;
dc6f92b8 10698
7a13e894
RS
10699 case ButtonPress:
10700 case ButtonRelease:
10701 {
10702 /* If we decide we want to generate an event to be seen
10703 by the rest of Emacs, we put it here. */
10704 struct input_event emacs_event;
9ea173e8 10705 int tool_bar_p = 0;
06a2c219 10706
7a13e894 10707 emacs_event.kind = no_event;
7a13e894 10708 bzero (&compose_status, sizeof (compose_status));
9b07615b 10709
06a2c219
GM
10710 if (dpyinfo->grabbed
10711 && last_mouse_frame
9f67f20b
RS
10712 && FRAME_LIVE_P (last_mouse_frame))
10713 f = last_mouse_frame;
10714 else
2224b905 10715 f = x_window_to_frame (dpyinfo, event.xbutton.window);
9f67f20b 10716
06a2c219
GM
10717 if (f)
10718 {
9ea173e8
GM
10719 /* Is this in the tool-bar? */
10720 if (WINDOWP (f->tool_bar_window)
10721 && XFASTINT (XWINDOW (f->tool_bar_window)->height))
06a2c219
GM
10722 {
10723 Lisp_Object window;
10724 int p, x, y;
10725
10726 x = event.xbutton.x;
10727 y = event.xbutton.y;
10728
10729 /* Set x and y. */
10730 window = window_from_coordinates (f, x, y, &p, 1);
9ea173e8 10731 if (EQ (window, f->tool_bar_window))
06a2c219 10732 {
9ea173e8
GM
10733 x_handle_tool_bar_click (f, &event.xbutton);
10734 tool_bar_p = 1;
06a2c219
GM
10735 }
10736 }
10737
9ea173e8 10738 if (!tool_bar_p)
06a2c219
GM
10739 if (!dpyinfo->x_focus_frame
10740 || f == dpyinfo->x_focus_frame)
10741 construct_mouse_click (&emacs_event, &event, f);
7a13e894
RS
10742 }
10743 else
10744 {
06a2c219 10745#ifndef USE_TOOLKIT_SCROLL_BARS
7a13e894
RS
10746 struct scroll_bar *bar
10747 = x_window_to_scroll_bar (event.xbutton.window);
f451eb13 10748
7a13e894
RS
10749 if (bar)
10750 x_scroll_bar_handle_click (bar, &event, &emacs_event);
06a2c219 10751#endif /* not USE_TOOLKIT_SCROLL_BARS */
7a13e894
RS
10752 }
10753
10754 if (event.type == ButtonPress)
10755 {
10756 dpyinfo->grabbed |= (1 << event.xbutton.button);
10757 last_mouse_frame = f;
edad46f6
KH
10758 /* Ignore any mouse motion that happened
10759 before this event; any subsequent mouse-movement
10760 Emacs events should reflect only motion after
10761 the ButtonPress. */
a00e91cd
KH
10762 if (f != 0)
10763 f->mouse_moved = 0;
06a2c219 10764
9ea173e8
GM
10765 if (!tool_bar_p)
10766 last_tool_bar_item = -1;
7a13e894 10767 }
3afe33e7
RS
10768 else
10769 {
7a13e894 10770 dpyinfo->grabbed &= ~(1 << event.xbutton.button);
3afe33e7 10771 }
23faf38f 10772
7a13e894
RS
10773 if (numchars >= 1 && emacs_event.kind != no_event)
10774 {
10775 bcopy (&emacs_event, bufp, sizeof (struct input_event));
10776 bufp++;
10777 count++;
10778 numchars--;
10779 }
3afe33e7
RS
10780
10781#ifdef USE_X_TOOLKIT
2224b905
RS
10782 f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
10783 /* For a down-event in the menu bar,
10784 don't pass it to Xt right now.
10785 Instead, save it away
10786 and we will pass it to Xt from kbd_buffer_get_event.
10787 That way, we can run some Lisp code first. */
91375f8f
RS
10788 if (f && event.type == ButtonPress
10789 /* Verify the event is really within the menu bar
10790 and not just sent to it due to grabbing. */
10791 && event.xbutton.x >= 0
10792 && event.xbutton.x < f->output_data.x->pixel_width
10793 && event.xbutton.y >= 0
10794 && event.xbutton.y < f->output_data.x->menubar_height
10795 && event.xbutton.same_screen)
2224b905 10796 {
8805890a 10797 SET_SAVED_BUTTON_EVENT;
2237cac9
RS
10798 XSETFRAME (last_mouse_press_frame, f);
10799 }
10800 else if (event.type == ButtonPress)
10801 {
10802 last_mouse_press_frame = Qnil;
30e671c3 10803 goto OTHER;
ce89ef46 10804 }
06a2c219 10805
2237cac9
RS
10806#ifdef USE_MOTIF /* This should do not harm for Lucid,
10807 but I am trying to be cautious. */
ce89ef46
RS
10808 else if (event.type == ButtonRelease)
10809 {
2237cac9 10810 if (!NILP (last_mouse_press_frame))
f10ded1c 10811 {
2237cac9
RS
10812 f = XFRAME (last_mouse_press_frame);
10813 if (f->output_data.x)
06a2c219 10814 SET_SAVED_BUTTON_EVENT;
f10ded1c 10815 }
06a2c219 10816 else
30e671c3 10817 goto OTHER;
2224b905 10818 }
2237cac9 10819#endif /* USE_MOTIF */
2224b905
RS
10820 else
10821 goto OTHER;
3afe33e7 10822#endif /* USE_X_TOOLKIT */
7a13e894
RS
10823 }
10824 break;
dc6f92b8 10825
7a13e894 10826 case CirculateNotify:
06a2c219
GM
10827 goto OTHER;
10828
7a13e894 10829 case CirculateRequest:
06a2c219
GM
10830 goto OTHER;
10831
10832 case VisibilityNotify:
10833 goto OTHER;
dc6f92b8 10834
7a13e894
RS
10835 case MappingNotify:
10836 /* Someone has changed the keyboard mapping - update the
10837 local cache. */
10838 switch (event.xmapping.request)
10839 {
10840 case MappingModifier:
10841 x_find_modifier_meanings (dpyinfo);
10842 /* This is meant to fall through. */
10843 case MappingKeyboard:
10844 XRefreshKeyboardMapping (&event.xmapping);
10845 }
7a13e894 10846 goto OTHER;
dc6f92b8 10847
7a13e894 10848 default:
7a13e894 10849 OTHER:
717ca130 10850#ifdef USE_X_TOOLKIT
7a13e894
RS
10851 BLOCK_INPUT;
10852 XtDispatchEvent (&event);
10853 UNBLOCK_INPUT;
3afe33e7 10854#endif /* USE_X_TOOLKIT */
7a13e894
RS
10855 break;
10856 }
dc6f92b8
JB
10857 }
10858 }
10859
06a2c219
GM
10860 out:;
10861
9a5196d0
RS
10862 /* On some systems, an X bug causes Emacs to get no more events
10863 when the window is destroyed. Detect that. (1994.) */
58769bee 10864 if (! event_found)
ef2a22d0 10865 {
ef2a22d0
RS
10866 /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
10867 One XNOOP in 100 loops will make Emacs terminate.
10868 B. Bretthauer, 1994 */
10869 x_noop_count++;
58769bee 10870 if (x_noop_count >= 100)
ef2a22d0
RS
10871 {
10872 x_noop_count=0;
2224b905
RS
10873
10874 if (next_noop_dpyinfo == 0)
10875 next_noop_dpyinfo = x_display_list;
10876
10877 XNoOp (next_noop_dpyinfo->display);
10878
10879 /* Each time we get here, cycle through the displays now open. */
10880 next_noop_dpyinfo = next_noop_dpyinfo->next;
ef2a22d0
RS
10881 }
10882 }
502add23 10883
06a2c219 10884 /* If the focus was just given to an auto-raising frame,
0134a210 10885 raise it now. */
7a13e894 10886 /* ??? This ought to be able to handle more than one such frame. */
0134a210
RS
10887 if (pending_autoraise_frame)
10888 {
10889 x_raise_frame (pending_autoraise_frame);
10890 pending_autoraise_frame = 0;
10891 }
0134a210 10892
dc6f92b8 10893 UNBLOCK_INPUT;
bde5503b 10894 --handling_signal;
dc6f92b8
JB
10895 return count;
10896}
06a2c219
GM
10897
10898
10899
dc6f92b8 10900\f
06a2c219
GM
10901/***********************************************************************
10902 Text Cursor
10903 ***********************************************************************/
10904
10905/* Note if the text cursor of window W has been overwritten by a
10906 drawing operation that outputs N glyphs starting at HPOS in the
10907 line given by output_cursor.vpos. N < 0 means all the rest of the
10908 line after HPOS has been written. */
10909
10910static void
10911note_overwritten_text_cursor (w, hpos, n)
10912 struct window *w;
10913 int hpos, n;
10914{
10915 if (updated_area == TEXT_AREA
10916 && output_cursor.vpos == w->phys_cursor.vpos
10917 && hpos <= w->phys_cursor.hpos
10918 && (n < 0
10919 || hpos + n > w->phys_cursor.hpos))
10920 w->phys_cursor_on_p = 0;
10921}
f451eb13
JB
10922
10923
06a2c219
GM
10924/* Set clipping for output in glyph row ROW. W is the window in which
10925 we operate. GC is the graphics context to set clipping in.
10926 WHOLE_LINE_P non-zero means include the areas used for truncation
10927 mark display and alike in the clipping rectangle.
10928
10929 ROW may be a text row or, e.g., a mode line. Text rows must be
10930 clipped to the interior of the window dedicated to text display,
10931 mode lines must be clipped to the whole window. */
dc6f92b8
JB
10932
10933static void
06a2c219
GM
10934x_clip_to_row (w, row, gc, whole_line_p)
10935 struct window *w;
10936 struct glyph_row *row;
10937 GC gc;
10938 int whole_line_p;
dc6f92b8 10939{
06a2c219
GM
10940 struct frame *f = XFRAME (WINDOW_FRAME (w));
10941 XRectangle clip_rect;
10942 int window_x, window_y, window_width, window_height;
dc6f92b8 10943
06a2c219 10944 window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
5c1aae96 10945
06a2c219
GM
10946 clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
10947 clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
10948 clip_rect.y = max (clip_rect.y, window_y);
10949 clip_rect.width = window_width;
10950 clip_rect.height = row->visible_height;
5c1aae96 10951
06a2c219
GM
10952 /* If clipping to the whole line, including trunc marks, extend
10953 the rectangle to the left and increase its width. */
10954 if (whole_line_p)
10955 {
110859fc
GM
10956 clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
10957 clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
06a2c219 10958 }
5c1aae96 10959
06a2c219 10960 XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
dc6f92b8
JB
10961}
10962
06a2c219
GM
10963
10964/* Draw a hollow box cursor on window W in glyph row ROW. */
dc6f92b8
JB
10965
10966static void
06a2c219
GM
10967x_draw_hollow_cursor (w, row)
10968 struct window *w;
10969 struct glyph_row *row;
dc6f92b8 10970{
06a2c219
GM
10971 struct frame *f = XFRAME (WINDOW_FRAME (w));
10972 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10973 Display *dpy = FRAME_X_DISPLAY (f);
10974 int x, y, wd, h;
10975 XGCValues xgcv;
10976 struct glyph *cursor_glyph;
10977 GC gc;
10978
10979 /* Compute frame-relative coordinates from window-relative
10980 coordinates. */
10981 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
10982 y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
10983 + row->ascent - w->phys_cursor_ascent);
10984 h = row->height - 1;
10985
10986 /* Get the glyph the cursor is on. If we can't tell because
10987 the current matrix is invalid or such, give up. */
10988 cursor_glyph = get_phys_cursor_glyph (w);
10989 if (cursor_glyph == NULL)
dc6f92b8
JB
10990 return;
10991
06a2c219
GM
10992 /* Compute the width of the rectangle to draw. If on a stretch
10993 glyph, and `x-stretch-block-cursor' is nil, don't draw a
10994 rectangle as wide as the glyph, but use a canonical character
10995 width instead. */
10996 wd = cursor_glyph->pixel_width - 1;
10997 if (cursor_glyph->type == STRETCH_GLYPH
10998 && !x_stretch_cursor_p)
10999 wd = min (CANON_X_UNIT (f), wd);
11000
11001 /* The foreground of cursor_gc is typically the same as the normal
11002 background color, which can cause the cursor box to be invisible. */
11003 xgcv.foreground = f->output_data.x->cursor_pixel;
11004 if (dpyinfo->scratch_cursor_gc)
11005 XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
11006 else
11007 dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
11008 GCForeground, &xgcv);
11009 gc = dpyinfo->scratch_cursor_gc;
11010
11011 /* Set clipping, draw the rectangle, and reset clipping again. */
11012 x_clip_to_row (w, row, gc, 0);
11013 XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
11014 XSetClipMask (dpy, gc, None);
dc6f92b8
JB
11015}
11016
06a2c219
GM
11017
11018/* Draw a bar cursor on window W in glyph row ROW.
11019
11020 Implementation note: One would like to draw a bar cursor with an
11021 angle equal to the one given by the font property XA_ITALIC_ANGLE.
11022 Unfortunately, I didn't find a font yet that has this property set.
11023 --gerd. */
dc6f92b8
JB
11024
11025static void
f02d8aa0 11026x_draw_bar_cursor (w, row, width)
06a2c219
GM
11027 struct window *w;
11028 struct glyph_row *row;
f02d8aa0 11029 int width;
dc6f92b8 11030{
92f424df
GM
11031 struct frame *f = XFRAME (w->frame);
11032 struct glyph *cursor_glyph;
11033 GC gc;
11034 int x;
11035 unsigned long mask;
11036 XGCValues xgcv;
11037 Display *dpy;
11038 Window window;
06a2c219 11039
92f424df
GM
11040 /* If cursor is out of bounds, don't draw garbage. This can happen
11041 in mini-buffer windows when switching between echo area glyphs
11042 and mini-buffer. */
11043 cursor_glyph = get_phys_cursor_glyph (w);
11044 if (cursor_glyph == NULL)
11045 return;
06a2c219 11046
92f424df
GM
11047 /* If on an image, draw like a normal cursor. That's usually better
11048 visible than drawing a bar, esp. if the image is large so that
11049 the bar might not be in the window. */
11050 if (cursor_glyph->type == IMAGE_GLYPH)
11051 {
11052 struct glyph_row *row;
11053 row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
11054 x_draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
11055 }
11056 else
11057 {
06a2c219
GM
11058 xgcv.background = f->output_data.x->cursor_pixel;
11059 xgcv.foreground = f->output_data.x->cursor_pixel;
11060 xgcv.graphics_exposures = 0;
11061 mask = GCForeground | GCBackground | GCGraphicsExposures;
11062 dpy = FRAME_X_DISPLAY (f);
11063 window = FRAME_X_WINDOW (f);
11064 gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
92f424df 11065
06a2c219
GM
11066 if (gc)
11067 XChangeGC (dpy, gc, mask, &xgcv);
11068 else
11069 {
11070 gc = XCreateGC (dpy, window, mask, &xgcv);
11071 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
11072 }
92f424df 11073
f02d8aa0
GM
11074 if (width < 0)
11075 width = f->output_data.x->cursor_width;
92f424df 11076
06a2c219
GM
11077 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
11078 x_clip_to_row (w, row, gc, 0);
11079 XFillRectangle (dpy, window, gc,
11080 x,
11081 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
f02d8aa0 11082 min (cursor_glyph->pixel_width, width),
06a2c219
GM
11083 row->height);
11084 XSetClipMask (dpy, gc, None);
11085 }
dc6f92b8
JB
11086}
11087
06a2c219
GM
11088
11089/* Clear the cursor of window W to background color, and mark the
11090 cursor as not shown. This is used when the text where the cursor
11091 is is about to be rewritten. */
11092
dc6f92b8 11093static void
06a2c219
GM
11094x_clear_cursor (w)
11095 struct window *w;
dc6f92b8 11096{
06a2c219
GM
11097 if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
11098 x_update_window_cursor (w, 0);
11099}
90e65f07 11100
dbc4e1c1 11101
06a2c219
GM
11102/* Draw the cursor glyph of window W in glyph row ROW. See the
11103 comment of x_draw_glyphs for the meaning of HL. */
dbc4e1c1 11104
06a2c219
GM
11105static void
11106x_draw_phys_cursor_glyph (w, row, hl)
11107 struct window *w;
11108 struct glyph_row *row;
11109 enum draw_glyphs_face hl;
11110{
11111 /* If cursor hpos is out of bounds, don't draw garbage. This can
11112 happen in mini-buffer windows when switching between echo area
11113 glyphs and mini-buffer. */
11114 if (w->phys_cursor.hpos < row->used[TEXT_AREA])
66ac4b0e
GM
11115 {
11116 x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
11117 w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
11118 hl, 0, 0, 0);
11119
11120 /* When we erase the cursor, and ROW is overlapped by other
11121 rows, make sure that these overlapping parts of other rows
11122 are redrawn. */
11123 if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
11124 {
11125 if (row > w->current_matrix->rows
11126 && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
11127 x_fix_overlapping_area (w, row - 1, TEXT_AREA);
11128
11129 if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
11130 && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
11131 x_fix_overlapping_area (w, row + 1, TEXT_AREA);
11132 }
11133 }
06a2c219 11134}
dbc4e1c1 11135
eea6af04 11136
06a2c219 11137/* Erase the image of a cursor of window W from the screen. */
eea6af04 11138
06a2c219
GM
11139static void
11140x_erase_phys_cursor (w)
11141 struct window *w;
11142{
11143 struct frame *f = XFRAME (w->frame);
11144 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
11145 int hpos = w->phys_cursor.hpos;
11146 int vpos = w->phys_cursor.vpos;
11147 int mouse_face_here_p = 0;
11148 struct glyph_matrix *active_glyphs = w->current_matrix;
11149 struct glyph_row *cursor_row;
11150 struct glyph *cursor_glyph;
11151 enum draw_glyphs_face hl;
11152
11153 /* No cursor displayed or row invalidated => nothing to do on the
11154 screen. */
11155 if (w->phys_cursor_type == NO_CURSOR)
11156 goto mark_cursor_off;
11157
11158 /* VPOS >= active_glyphs->nrows means that window has been resized.
11159 Don't bother to erase the cursor. */
11160 if (vpos >= active_glyphs->nrows)
11161 goto mark_cursor_off;
11162
11163 /* If row containing cursor is marked invalid, there is nothing we
11164 can do. */
11165 cursor_row = MATRIX_ROW (active_glyphs, vpos);
11166 if (!cursor_row->enabled_p)
11167 goto mark_cursor_off;
11168
11169 /* This can happen when the new row is shorter than the old one.
11170 In this case, either x_draw_glyphs or clear_end_of_line
11171 should have cleared the cursor. Note that we wouldn't be
11172 able to erase the cursor in this case because we don't have a
11173 cursor glyph at hand. */
11174 if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
11175 goto mark_cursor_off;
11176
11177 /* If the cursor is in the mouse face area, redisplay that when
11178 we clear the cursor. */
8801a864
KR
11179 if (! NILP (dpyinfo->mouse_face_window)
11180 && w == XWINDOW (dpyinfo->mouse_face_window)
06a2c219
GM
11181 && (vpos > dpyinfo->mouse_face_beg_row
11182 || (vpos == dpyinfo->mouse_face_beg_row
11183 && hpos >= dpyinfo->mouse_face_beg_col))
11184 && (vpos < dpyinfo->mouse_face_end_row
11185 || (vpos == dpyinfo->mouse_face_end_row
11186 && hpos < dpyinfo->mouse_face_end_col))
11187 /* Don't redraw the cursor's spot in mouse face if it is at the
11188 end of a line (on a newline). The cursor appears there, but
11189 mouse highlighting does not. */
11190 && cursor_row->used[TEXT_AREA] > hpos)
11191 mouse_face_here_p = 1;
11192
11193 /* Maybe clear the display under the cursor. */
11194 if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
11195 {
11196 int x;
045dee35 11197 int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
dbc4e1c1 11198
06a2c219
GM
11199 cursor_glyph = get_phys_cursor_glyph (w);
11200 if (cursor_glyph == NULL)
11201 goto mark_cursor_off;
dbc4e1c1 11202
e0300d33 11203 x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
06a2c219 11204
c5e6e06b
GM
11205 x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
11206 x,
11207 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
11208 cursor_row->y)),
11209 cursor_glyph->pixel_width,
11210 cursor_row->visible_height,
11211 False);
dbc4e1c1 11212 }
06a2c219
GM
11213
11214 /* Erase the cursor by redrawing the character underneath it. */
11215 if (mouse_face_here_p)
11216 hl = DRAW_MOUSE_FACE;
11217 else if (cursor_row->inverse_p)
11218 hl = DRAW_INVERSE_VIDEO;
11219 else
11220 hl = DRAW_NORMAL_TEXT;
11221 x_draw_phys_cursor_glyph (w, cursor_row, hl);
dbc4e1c1 11222
06a2c219
GM
11223 mark_cursor_off:
11224 w->phys_cursor_on_p = 0;
11225 w->phys_cursor_type = NO_CURSOR;
dbc4e1c1
JB
11226}
11227
11228
b7f83f9e
GM
11229/* Non-zero if physical cursor of window W is within mouse face. */
11230
11231static int
11232cursor_in_mouse_face_p (w)
11233 struct window *w;
11234{
11235 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
11236 int in_mouse_face = 0;
11237
11238 if (WINDOWP (dpyinfo->mouse_face_window)
11239 && XWINDOW (dpyinfo->mouse_face_window) == w)
11240 {
11241 int hpos = w->phys_cursor.hpos;
11242 int vpos = w->phys_cursor.vpos;
11243
11244 if (vpos >= dpyinfo->mouse_face_beg_row
11245 && vpos <= dpyinfo->mouse_face_end_row
11246 && (vpos > dpyinfo->mouse_face_beg_row
11247 || hpos >= dpyinfo->mouse_face_beg_col)
11248 && (vpos < dpyinfo->mouse_face_end_row
11249 || hpos < dpyinfo->mouse_face_end_col
11250 || dpyinfo->mouse_face_past_end))
11251 in_mouse_face = 1;
11252 }
11253
11254 return in_mouse_face;
11255}
11256
11257
06a2c219
GM
11258/* Display or clear cursor of window W. If ON is zero, clear the
11259 cursor. If it is non-zero, display the cursor. If ON is nonzero,
11260 where to put the cursor is specified by HPOS, VPOS, X and Y. */
dbc4e1c1 11261
06a2c219
GM
11262void
11263x_display_and_set_cursor (w, on, hpos, vpos, x, y)
11264 struct window *w;
11265 int on, hpos, vpos, x, y;
dbc4e1c1 11266{
06a2c219
GM
11267 struct frame *f = XFRAME (w->frame);
11268 int new_cursor_type;
f02d8aa0 11269 int new_cursor_width;
06a2c219
GM
11270 struct glyph_matrix *current_glyphs;
11271 struct glyph_row *glyph_row;
11272 struct glyph *glyph;
dbc4e1c1 11273
49d838ea 11274 /* This is pointless on invisible frames, and dangerous on garbaged
06a2c219
GM
11275 windows and frames; in the latter case, the frame or window may
11276 be in the midst of changing its size, and x and y may be off the
11277 window. */
11278 if (! FRAME_VISIBLE_P (f)
11279 || FRAME_GARBAGED_P (f)
11280 || vpos >= w->current_matrix->nrows
11281 || hpos >= w->current_matrix->matrix_w)
dc6f92b8
JB
11282 return;
11283
11284 /* If cursor is off and we want it off, return quickly. */
06a2c219 11285 if (!on && !w->phys_cursor_on_p)
dc6f92b8
JB
11286 return;
11287
06a2c219
GM
11288 current_glyphs = w->current_matrix;
11289 glyph_row = MATRIX_ROW (current_glyphs, vpos);
11290 glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
11291
11292 /* If cursor row is not enabled, we don't really know where to
11293 display the cursor. */
11294 if (!glyph_row->enabled_p)
11295 {
11296 w->phys_cursor_on_p = 0;
11297 return;
11298 }
11299
11300 xassert (interrupt_input_blocked);
11301
11302 /* Set new_cursor_type to the cursor we want to be displayed. In a
11303 mini-buffer window, we want the cursor only to appear if we are
11304 reading input from this window. For the selected window, we want
11305 the cursor type given by the frame parameter. If explicitly
11306 marked off, draw no cursor. In all other cases, we want a hollow
11307 box cursor. */
f02d8aa0 11308 new_cursor_width = -1;
9b4a7047
GM
11309 if (cursor_in_echo_area
11310 && FRAME_HAS_MINIBUF_P (f)
11311 && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
06a2c219 11312 {
9b4a7047
GM
11313 if (w == XWINDOW (echo_area_window))
11314 new_cursor_type = FRAME_DESIRED_CURSOR (f);
06a2c219
GM
11315 else
11316 new_cursor_type = HOLLOW_BOX_CURSOR;
11317 }
06a2c219 11318 else
9b4a7047 11319 {
7a58ab59
GM
11320 if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
11321 || w != XWINDOW (f->selected_window))
9b4a7047 11322 {
e55a0b79
GM
11323 extern int cursor_in_non_selected_windows;
11324
5cefa566
GM
11325 if (MINI_WINDOW_P (w)
11326 || !cursor_in_non_selected_windows
11327 || NILP (XBUFFER (w->buffer)->cursor_type))
9b4a7047
GM
11328 new_cursor_type = NO_CURSOR;
11329 else
11330 new_cursor_type = HOLLOW_BOX_CURSOR;
11331 }
11332 else if (w->cursor_off_p)
11333 new_cursor_type = NO_CURSOR;
11334 else
f02d8aa0
GM
11335 {
11336 struct buffer *b = XBUFFER (w->buffer);
11337
11338 if (EQ (b->cursor_type, Qt))
11339 new_cursor_type = FRAME_DESIRED_CURSOR (f);
11340 else
11341 new_cursor_type = x_specified_cursor_type (b->cursor_type,
11342 &new_cursor_width);
11343 }
9b4a7047 11344 }
06a2c219
GM
11345
11346 /* If cursor is currently being shown and we don't want it to be or
11347 it is in the wrong place, or the cursor type is not what we want,
dc6f92b8 11348 erase it. */
06a2c219 11349 if (w->phys_cursor_on_p
dc6f92b8 11350 && (!on
06a2c219
GM
11351 || w->phys_cursor.x != x
11352 || w->phys_cursor.y != y
11353 || new_cursor_type != w->phys_cursor_type))
11354 x_erase_phys_cursor (w);
11355
11356 /* If the cursor is now invisible and we want it to be visible,
11357 display it. */
11358 if (on && !w->phys_cursor_on_p)
11359 {
11360 w->phys_cursor_ascent = glyph_row->ascent;
11361 w->phys_cursor_height = glyph_row->height;
11362
11363 /* Set phys_cursor_.* before x_draw_.* is called because some
11364 of them may need the information. */
11365 w->phys_cursor.x = x;
11366 w->phys_cursor.y = glyph_row->y;
11367 w->phys_cursor.hpos = hpos;
11368 w->phys_cursor.vpos = vpos;
11369 w->phys_cursor_type = new_cursor_type;
11370 w->phys_cursor_on_p = 1;
11371
11372 switch (new_cursor_type)
dc6f92b8 11373 {
06a2c219
GM
11374 case HOLLOW_BOX_CURSOR:
11375 x_draw_hollow_cursor (w, glyph_row);
11376 break;
11377
11378 case FILLED_BOX_CURSOR:
11379 x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
11380 break;
11381
11382 case BAR_CURSOR:
f02d8aa0 11383 x_draw_bar_cursor (w, glyph_row, new_cursor_width);
06a2c219
GM
11384 break;
11385
11386 case NO_CURSOR:
11387 break;
dc6f92b8 11388
06a2c219
GM
11389 default:
11390 abort ();
11391 }
59ddecde
GM
11392
11393#ifdef HAVE_X_I18N
11394 if (w == XWINDOW (f->selected_window))
11395 if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
11396 xic_set_preeditarea (w, x, y);
11397#endif
dc6f92b8
JB
11398 }
11399
06a2c219 11400#ifndef XFlush
f676886a 11401 if (updating_frame != f)
334208b7 11402 XFlush (FRAME_X_DISPLAY (f));
06a2c219 11403#endif
dc6f92b8
JB
11404}
11405
06a2c219
GM
11406
11407/* Display the cursor on window W, or clear it. X and Y are window
11408 relative pixel coordinates. HPOS and VPOS are glyph matrix
11409 positions. If W is not the selected window, display a hollow
11410 cursor. ON non-zero means display the cursor at X, Y which
11411 correspond to HPOS, VPOS, otherwise it is cleared. */
5d46f928 11412
dfcf069d 11413void
06a2c219
GM
11414x_display_cursor (w, on, hpos, vpos, x, y)
11415 struct window *w;
11416 int on, hpos, vpos, x, y;
dc6f92b8 11417{
f94397b5 11418 BLOCK_INPUT;
06a2c219 11419 x_display_and_set_cursor (w, on, hpos, vpos, x, y);
5d46f928
RS
11420 UNBLOCK_INPUT;
11421}
11422
06a2c219
GM
11423
11424/* Display the cursor on window W, or clear it, according to ON_P.
5d46f928
RS
11425 Don't change the cursor's position. */
11426
dfcf069d 11427void
06a2c219 11428x_update_cursor (f, on_p)
5d46f928 11429 struct frame *f;
5d46f928 11430{
06a2c219
GM
11431 x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
11432}
11433
11434
11435/* Call x_update_window_cursor with parameter ON_P on all leaf windows
11436 in the window tree rooted at W. */
11437
11438static void
11439x_update_cursor_in_window_tree (w, on_p)
11440 struct window *w;
11441 int on_p;
11442{
11443 while (w)
11444 {
11445 if (!NILP (w->hchild))
11446 x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
11447 else if (!NILP (w->vchild))
11448 x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
11449 else
11450 x_update_window_cursor (w, on_p);
11451
11452 w = NILP (w->next) ? 0 : XWINDOW (w->next);
11453 }
11454}
5d46f928 11455
f94397b5 11456
06a2c219
GM
11457/* Switch the display of W's cursor on or off, according to the value
11458 of ON. */
11459
11460static void
11461x_update_window_cursor (w, on)
11462 struct window *w;
11463 int on;
11464{
16b5d424
GM
11465 /* Don't update cursor in windows whose frame is in the process
11466 of being deleted. */
11467 if (w->current_matrix)
11468 {
11469 BLOCK_INPUT;
11470 x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
11471 w->phys_cursor.x, w->phys_cursor.y);
11472 UNBLOCK_INPUT;
11473 }
dc6f92b8 11474}
06a2c219
GM
11475
11476
11477
dc6f92b8
JB
11478\f
11479/* Icons. */
11480
f676886a 11481/* Refresh bitmap kitchen sink icon for frame F
06a2c219 11482 when we get an expose event for it. */
dc6f92b8 11483
dfcf069d 11484void
f676886a
JB
11485refreshicon (f)
11486 struct frame *f;
dc6f92b8 11487{
06a2c219 11488 /* Normally, the window manager handles this function. */
dc6f92b8
JB
11489}
11490
dbc4e1c1 11491/* Make the x-window of frame F use the gnu icon bitmap. */
dc6f92b8
JB
11492
11493int
990ba854 11494x_bitmap_icon (f, file)
f676886a 11495 struct frame *f;
990ba854 11496 Lisp_Object file;
dc6f92b8 11497{
06a2c219 11498 int bitmap_id;
dc6f92b8 11499
c118dd06 11500 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11501 return 1;
11502
990ba854 11503 /* Free up our existing icon bitmap if any. */
7556890b
RS
11504 if (f->output_data.x->icon_bitmap > 0)
11505 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11506 f->output_data.x->icon_bitmap = 0;
990ba854
RS
11507
11508 if (STRINGP (file))
7f2ae036
RS
11509 bitmap_id = x_create_bitmap_from_file (f, file);
11510 else
11511 {
990ba854 11512 /* Create the GNU bitmap if necessary. */
5bf01b68 11513 if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
334208b7
RS
11514 FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
11515 = x_create_bitmap_from_data (f, gnu_bits,
11516 gnu_width, gnu_height);
990ba854
RS
11517
11518 /* The first time we create the GNU bitmap,
06a2c219 11519 this increments the ref-count one extra time.
990ba854
RS
11520 As a result, the GNU bitmap is never freed.
11521 That way, we don't have to worry about allocating it again. */
334208b7 11522 x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
990ba854 11523
334208b7 11524 bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
7f2ae036
RS
11525 }
11526
11527 x_wm_set_icon_pixmap (f, bitmap_id);
7556890b 11528 f->output_data.x->icon_bitmap = bitmap_id;
dc6f92b8
JB
11529
11530 return 0;
11531}
11532
11533
1be2d067
KH
11534/* Make the x-window of frame F use a rectangle with text.
11535 Use ICON_NAME as the text. */
dc6f92b8
JB
11536
11537int
f676886a
JB
11538x_text_icon (f, icon_name)
11539 struct frame *f;
dc6f92b8
JB
11540 char *icon_name;
11541{
c118dd06 11542 if (FRAME_X_WINDOW (f) == 0)
dc6f92b8
JB
11543 return 1;
11544
1be2d067
KH
11545#ifdef HAVE_X11R4
11546 {
11547 XTextProperty text;
11548 text.value = (unsigned char *) icon_name;
11549 text.encoding = XA_STRING;
11550 text.format = 8;
11551 text.nitems = strlen (icon_name);
11552#ifdef USE_X_TOOLKIT
7556890b 11553 XSetWMIconName (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
1be2d067
KH
11554 &text);
11555#else /* not USE_X_TOOLKIT */
11556 XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
11557#endif /* not USE_X_TOOLKIT */
11558 }
11559#else /* not HAVE_X11R4 */
11560 XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), icon_name);
11561#endif /* not HAVE_X11R4 */
58769bee 11562
7556890b
RS
11563 if (f->output_data.x->icon_bitmap > 0)
11564 x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
11565 f->output_data.x->icon_bitmap = 0;
b1c884c3 11566 x_wm_set_icon_pixmap (f, 0);
dc6f92b8
JB
11567
11568 return 0;
11569}
11570\f
e99db5a1
RS
11571#define X_ERROR_MESSAGE_SIZE 200
11572
11573/* If non-nil, this should be a string.
11574 It means catch X errors and store the error message in this string. */
11575
11576static Lisp_Object x_error_message_string;
11577
11578/* An X error handler which stores the error message in
11579 x_error_message_string. This is called from x_error_handler if
11580 x_catch_errors is in effect. */
11581
06a2c219 11582static void
e99db5a1
RS
11583x_error_catcher (display, error)
11584 Display *display;
11585 XErrorEvent *error;
11586{
11587 XGetErrorText (display, error->error_code,
11588 XSTRING (x_error_message_string)->data,
11589 X_ERROR_MESSAGE_SIZE);
11590}
11591
11592/* Begin trapping X errors for display DPY. Actually we trap X errors
11593 for all displays, but DPY should be the display you are actually
11594 operating on.
11595
11596 After calling this function, X protocol errors no longer cause
11597 Emacs to exit; instead, they are recorded in the string
11598 stored in x_error_message_string.
11599
11600 Calling x_check_errors signals an Emacs error if an X error has
11601 occurred since the last call to x_catch_errors or x_check_errors.
11602
11603 Calling x_uncatch_errors resumes the normal error handling. */
11604
11605void x_check_errors ();
11606static Lisp_Object x_catch_errors_unwind ();
11607
11608int
11609x_catch_errors (dpy)
11610 Display *dpy;
11611{
11612 int count = specpdl_ptr - specpdl;
11613
11614 /* Make sure any errors from previous requests have been dealt with. */
11615 XSync (dpy, False);
11616
11617 record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
11618
11619 x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
11620 XSTRING (x_error_message_string)->data[0] = 0;
11621
11622 return count;
11623}
11624
11625/* Unbind the binding that we made to check for X errors. */
11626
11627static Lisp_Object
11628x_catch_errors_unwind (old_val)
11629 Lisp_Object old_val;
11630{
11631 x_error_message_string = old_val;
11632 return Qnil;
11633}
11634
11635/* If any X protocol errors have arrived since the last call to
11636 x_catch_errors or x_check_errors, signal an Emacs error using
11637 sprintf (a buffer, FORMAT, the x error message text) as the text. */
11638
11639void
11640x_check_errors (dpy, format)
11641 Display *dpy;
11642 char *format;
11643{
11644 /* Make sure to catch any errors incurred so far. */
11645 XSync (dpy, False);
11646
11647 if (XSTRING (x_error_message_string)->data[0])
11648 error (format, XSTRING (x_error_message_string)->data);
11649}
11650
9829ddba
RS
11651/* Nonzero if we had any X protocol errors
11652 since we did x_catch_errors on DPY. */
e99db5a1
RS
11653
11654int
11655x_had_errors_p (dpy)
11656 Display *dpy;
11657{
11658 /* Make sure to catch any errors incurred so far. */
11659 XSync (dpy, False);
11660
11661 return XSTRING (x_error_message_string)->data[0] != 0;
11662}
11663
9829ddba
RS
11664/* Forget about any errors we have had, since we did x_catch_errors on DPY. */
11665
06a2c219 11666void
9829ddba
RS
11667x_clear_errors (dpy)
11668 Display *dpy;
11669{
11670 XSTRING (x_error_message_string)->data[0] = 0;
11671}
11672
e99db5a1
RS
11673/* Stop catching X protocol errors and let them make Emacs die.
11674 DPY should be the display that was passed to x_catch_errors.
11675 COUNT should be the value that was returned by
11676 the corresponding call to x_catch_errors. */
11677
11678void
11679x_uncatch_errors (dpy, count)
11680 Display *dpy;
11681 int count;
11682{
11683 unbind_to (count, Qnil);
11684}
11685
11686#if 0
11687static unsigned int x_wire_count;
11688x_trace_wire ()
11689{
11690 fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
11691}
11692#endif /* ! 0 */
11693
11694\f
11695/* Handle SIGPIPE, which can happen when the connection to a server
11696 simply goes away. SIGPIPE is handled by x_connection_signal.
11697 Don't need to do anything, because the write which caused the
11698 SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
06a2c219 11699 which will do the appropriate cleanup for us. */
e99db5a1
RS
11700
11701static SIGTYPE
11702x_connection_signal (signalnum) /* If we don't have an argument, */
06a2c219 11703 int signalnum; /* some compilers complain in signal calls. */
e99db5a1
RS
11704{
11705#ifdef USG
11706 /* USG systems forget handlers when they are used;
11707 must reestablish each time */
11708 signal (signalnum, x_connection_signal);
11709#endif /* USG */
11710}
0da1ab50 11711
e99db5a1 11712\f
0da1ab50
GM
11713/************************************************************************
11714 Handling X errors
11715 ************************************************************************/
4746118a 11716
0da1ab50
GM
11717/* Handle the loss of connection to display DPY. ERROR_MESSAGE is
11718 the text of an error message that lead to the connection loss. */
16bd92ea 11719
4746118a 11720static SIGTYPE
5978125e
GM
11721x_connection_closed (dpy, error_message)
11722 Display *dpy;
7a13e894 11723 char *error_message;
4746118a 11724{
5978125e 11725 struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
7a13e894 11726 Lisp_Object frame, tail;
0da1ab50
GM
11727 int count;
11728 char *msg;
11729
11730 msg = (char *) alloca (strlen (error_message) + 1);
11731 strcpy (msg, error_message);
1a532e54
GM
11732 handling_signal = 0;
11733
0da1ab50
GM
11734 /* Prevent being called recursively because of an error condition
11735 below. Otherwise, we might end up with printing ``can't find per
11736 display information'' in the recursive call instead of printing
11737 the original message here. */
11738 count = x_catch_errors (dpy);
11739
8a4f36cc
GM
11740 /* We have to close the display to inform Xt that it doesn't
11741 exist anymore. If we don't, Xt will continue to wait for
11742 events from the display. As a consequence, a sequence of
11743
11744 M-x make-frame-on-display RET :1 RET
11745 ...kill the new frame, so that we get an IO error...
11746 M-x make-frame-on-display RET :1 RET
11747
11748 will indefinitely wait in Xt for events for display `:1', opened
11749 in the first class to make-frame-on-display.
6186a4a0 11750
8a4f36cc
GM
11751 Closing the display is reported to lead to a bus error on
11752 OpenWindows in certain situations. I suspect that is a bug
11753 in OpenWindows. I don't know how to cicumvent it here. */
11754
f613a4c8 11755#ifdef USE_X_TOOLKIT
ae24cb3b
GM
11756 /* If DPYINFO is null, this means we didn't open the display
11757 in the first place, so don't try to close it. */
11758 if (dpyinfo)
11759 XtCloseDisplay (dpy);
f613a4c8 11760#endif
adabc3a9 11761
8a4f36cc 11762 /* Indicate that this display is dead. */
9e80b57d
KR
11763 if (dpyinfo)
11764 dpyinfo->display = 0;
6186a4a0 11765
06a2c219 11766 /* First delete frames whose mini-buffers are on frames
7a13e894
RS
11767 that are on the dead display. */
11768 FOR_EACH_FRAME (tail, frame)
11769 {
11770 Lisp_Object minibuf_frame;
11771 minibuf_frame
11772 = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
f48f33ca
RS
11773 if (FRAME_X_P (XFRAME (frame))
11774 && FRAME_X_P (XFRAME (minibuf_frame))
11775 && ! EQ (frame, minibuf_frame)
11776 && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
7a13e894
RS
11777 Fdelete_frame (frame, Qt);
11778 }
11779
11780 /* Now delete all remaining frames on the dead display.
06a2c219 11781 We are now sure none of these is used as the mini-buffer
7a13e894
RS
11782 for another frame that we need to delete. */
11783 FOR_EACH_FRAME (tail, frame)
f48f33ca
RS
11784 if (FRAME_X_P (XFRAME (frame))
11785 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
07a7096a
KH
11786 {
11787 /* Set this to t so that Fdelete_frame won't get confused
11788 trying to find a replacement. */
11789 FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
11790 Fdelete_frame (frame, Qt);
11791 }
7a13e894 11792
482a1bd2
KH
11793 if (dpyinfo)
11794 x_delete_display (dpyinfo);
7a13e894 11795
0da1ab50
GM
11796 x_uncatch_errors (dpy, count);
11797
7a13e894
RS
11798 if (x_display_list == 0)
11799 {
0da1ab50 11800 fprintf (stderr, "%s\n", msg);
7a13e894
RS
11801 shut_down_emacs (0, 0, Qnil);
11802 exit (70);
11803 }
12ba150f 11804
7a13e894
RS
11805 /* Ordinary stack unwind doesn't deal with these. */
11806#ifdef SIGIO
11807 sigunblock (sigmask (SIGIO));
11808#endif
11809 sigunblock (sigmask (SIGALRM));
11810 TOTALLY_UNBLOCK_INPUT;
11811
aa4d9a9e 11812 clear_waiting_for_input ();
0da1ab50 11813 error ("%s", msg);
4746118a
JB
11814}
11815
0da1ab50 11816
7a13e894
RS
11817/* This is the usual handler for X protocol errors.
11818 It kills all frames on the display that we got the error for.
11819 If that was the only one, it prints an error message and kills Emacs. */
11820
06a2c219 11821static void
c118dd06
JB
11822x_error_quitter (display, error)
11823 Display *display;
11824 XErrorEvent *error;
11825{
7a13e894 11826 char buf[256], buf1[356];
dc6f92b8 11827
58769bee 11828 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 11829 original error handler. */
dc6f92b8 11830
c118dd06 11831 XGetErrorText (display, error->error_code, buf, sizeof (buf));
0a0fdc70 11832 sprintf (buf1, "X protocol error: %s on protocol request %d",
c118dd06 11833 buf, error->request_code);
7a13e894 11834 x_connection_closed (display, buf1);
dc6f92b8
JB
11835}
11836
0da1ab50 11837
e99db5a1
RS
11838/* This is the first-level handler for X protocol errors.
11839 It calls x_error_quitter or x_error_catcher. */
7a13e894 11840
8922af5f 11841static int
e99db5a1 11842x_error_handler (display, error)
8922af5f 11843 Display *display;
e99db5a1 11844 XErrorEvent *error;
8922af5f 11845{
e99db5a1
RS
11846 if (! NILP (x_error_message_string))
11847 x_error_catcher (display, error);
11848 else
11849 x_error_quitter (display, error);
06a2c219 11850 return 0;
f9e24cb9 11851}
c118dd06 11852
e99db5a1
RS
11853/* This is the handler for X IO errors, always.
11854 It kills all frames on the display that we lost touch with.
11855 If that was the only one, it prints an error message and kills Emacs. */
7a13e894 11856
c118dd06 11857static int
e99db5a1 11858x_io_error_quitter (display)
c118dd06 11859 Display *display;
c118dd06 11860{
e99db5a1 11861 char buf[256];
dc6f92b8 11862
e99db5a1
RS
11863 sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
11864 x_connection_closed (display, buf);
06a2c219 11865 return 0;
dc6f92b8 11866}
dc6f92b8 11867\f
f451eb13
JB
11868/* Changing the font of the frame. */
11869
76bcdf39
RS
11870/* Give frame F the font named FONTNAME as its default font, and
11871 return the full name of that font. FONTNAME may be a wildcard
11872 pattern; in that case, we choose some font that fits the pattern.
11873 The return value shows which font we chose. */
11874
b5cf7a0e 11875Lisp_Object
f676886a
JB
11876x_new_font (f, fontname)
11877 struct frame *f;
dc6f92b8
JB
11878 register char *fontname;
11879{
dc43ef94 11880 struct font_info *fontp
ee569018 11881 = FS_LOAD_FONT (f, 0, fontname, -1);
dc6f92b8 11882
dc43ef94
KH
11883 if (!fontp)
11884 return Qnil;
2224a5fc 11885
dc43ef94 11886 f->output_data.x->font = (XFontStruct *) (fontp->font);
b4192550 11887 f->output_data.x->baseline_offset = fontp->baseline_offset;
dc43ef94
KH
11888 f->output_data.x->fontset = -1;
11889
b2cad826
KH
11890 /* Compute the scroll bar width in character columns. */
11891 if (f->scroll_bar_pixel_width > 0)
11892 {
7556890b 11893 int wid = FONT_WIDTH (f->output_data.x->font);
b2cad826
KH
11894 f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
11895 }
11896 else
4e61bddf
RS
11897 {
11898 int wid = FONT_WIDTH (f->output_data.x->font);
11899 f->scroll_bar_cols = (14 + wid - 1) / wid;
11900 }
b2cad826 11901
f676886a 11902 /* Now make the frame display the given font. */
c118dd06 11903 if (FRAME_X_WINDOW (f) != 0)
dc6f92b8 11904 {
7556890b
RS
11905 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
11906 f->output_data.x->font->fid);
11907 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
11908 f->output_data.x->font->fid);
11909 XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
11910 f->output_data.x->font->fid);
f676886a 11911
a27f9f86 11912 frame_update_line_height (f);
3497f73e
GM
11913
11914 /* Don't change the size of a tip frame; there's no point in
11915 doing it because it's done in Fx_show_tip, and it leads to
11916 problems because the tip frame has no widget. */
11917 if (NILP (tip_frame) || XFRAME (tip_frame) != f)
11918 x_set_window_size (f, 0, f->width, f->height);
dc6f92b8 11919 }
a27f9f86
RS
11920 else
11921 /* If we are setting a new frame's font for the first time,
11922 there are no faces yet, so this font's height is the line height. */
7556890b 11923 f->output_data.x->line_height = FONT_HEIGHT (f->output_data.x->font);
dc6f92b8 11924
dc43ef94
KH
11925 return build_string (fontp->full_name);
11926}
11927
11928/* Give frame F the fontset named FONTSETNAME as its default font, and
11929 return the full name of that fontset. FONTSETNAME may be a wildcard
b5210ea7
KH
11930 pattern; in that case, we choose some fontset that fits the pattern.
11931 The return value shows which fontset we chose. */
b5cf7a0e 11932
dc43ef94
KH
11933Lisp_Object
11934x_new_fontset (f, fontsetname)
11935 struct frame *f;
11936 char *fontsetname;
11937{
ee569018 11938 int fontset = fs_query_fontset (build_string (fontsetname), 0);
dc43ef94 11939 Lisp_Object result;
b5cf7a0e 11940
dc43ef94
KH
11941 if (fontset < 0)
11942 return Qnil;
b5cf7a0e 11943
2da424f1
KH
11944 if (f->output_data.x->fontset == fontset)
11945 /* This fontset is already set in frame F. There's nothing more
11946 to do. */
ee569018 11947 return fontset_name (fontset);
dc43ef94 11948
ee569018 11949 result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
dc43ef94
KH
11950
11951 if (!STRINGP (result))
11952 /* Can't load ASCII font. */
11953 return Qnil;
11954
11955 /* Since x_new_font doesn't update any fontset information, do it now. */
11956 f->output_data.x->fontset = fontset;
dc43ef94 11957
f5d11644
GM
11958#ifdef HAVE_X_I18N
11959 if (FRAME_XIC (f)
11960 && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
ee569018 11961 xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
f5d11644
GM
11962#endif
11963
dc43ef94 11964 return build_string (fontsetname);
dc6f92b8 11965}
f5d11644
GM
11966
11967\f
11968/***********************************************************************
11969 X Input Methods
11970 ***********************************************************************/
11971
11972#ifdef HAVE_X_I18N
11973
11974#ifdef HAVE_X11R6
11975
11976/* XIM destroy callback function, which is called whenever the
11977 connection to input method XIM dies. CLIENT_DATA contains a
11978 pointer to the x_display_info structure corresponding to XIM. */
11979
11980static void
11981xim_destroy_callback (xim, client_data, call_data)
11982 XIM xim;
11983 XPointer client_data;
11984 XPointer call_data;
11985{
11986 struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
11987 Lisp_Object frame, tail;
11988
11989 BLOCK_INPUT;
11990
11991 /* No need to call XDestroyIC.. */
11992 FOR_EACH_FRAME (tail, frame)
11993 {
11994 struct frame *f = XFRAME (frame);
11995 if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
11996 {
11997 FRAME_XIC (f) = NULL;
11998 if (FRAME_XIC_FONTSET (f))
11999 {
12000 XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
12001 FRAME_XIC_FONTSET (f) = NULL;
12002 }
12003 }
12004 }
12005
12006 /* No need to call XCloseIM. */
12007 dpyinfo->xim = NULL;
12008 XFree (dpyinfo->xim_styles);
12009 UNBLOCK_INPUT;
12010}
12011
12012#endif /* HAVE_X11R6 */
12013
12014/* Open the connection to the XIM server on display DPYINFO.
12015 RESOURCE_NAME is the resource name Emacs uses. */
12016
12017static void
12018xim_open_dpy (dpyinfo, resource_name)
12019 struct x_display_info *dpyinfo;
12020 char *resource_name;
12021{
287f7dd6 12022#ifdef USE_XIM
f5d11644
GM
12023 XIM xim;
12024
12025 xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name, EMACS_CLASS);
12026 dpyinfo->xim = xim;
12027
12028 if (xim)
12029 {
f5d11644
GM
12030#ifdef HAVE_X11R6
12031 XIMCallback destroy;
12032#endif
12033
12034 /* Get supported styles and XIM values. */
12035 XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
12036
12037#ifdef HAVE_X11R6
12038 destroy.callback = xim_destroy_callback;
12039 destroy.client_data = (XPointer)dpyinfo;
cea2ad76 12040 /* This isn't prototyped in OSF 5.0. */
f5d11644
GM
12041 XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
12042#endif
12043 }
287f7dd6
GM
12044
12045#else /* not USE_XIM */
12046 dpyinfo->xim = NULL;
12047#endif /* not USE_XIM */
f5d11644
GM
12048}
12049
12050
b9de836c 12051#ifdef HAVE_X11R6_XIM
f5d11644
GM
12052
12053struct xim_inst_t
12054{
12055 struct x_display_info *dpyinfo;
12056 char *resource_name;
12057};
12058
12059/* XIM instantiate callback function, which is called whenever an XIM
12060 server is available. DISPLAY is teh display of the XIM.
12061 CLIENT_DATA contains a pointer to an xim_inst_t structure created
12062 when the callback was registered. */
12063
12064static void
12065xim_instantiate_callback (display, client_data, call_data)
12066 Display *display;
12067 XPointer client_data;
12068 XPointer call_data;
12069{
12070 struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
12071 struct x_display_info *dpyinfo = xim_inst->dpyinfo;
12072
12073 /* We don't support multiple XIM connections. */
12074 if (dpyinfo->xim)
12075 return;
12076
12077 xim_open_dpy (dpyinfo, xim_inst->resource_name);
12078
12079 /* Create XIC for the existing frames on the same display, as long
12080 as they have no XIC. */
12081 if (dpyinfo->xim && dpyinfo->reference_count > 0)
12082 {
12083 Lisp_Object tail, frame;
12084
12085 BLOCK_INPUT;
12086 FOR_EACH_FRAME (tail, frame)
12087 {
12088 struct frame *f = XFRAME (frame);
12089
12090 if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
12091 if (FRAME_XIC (f) == NULL)
12092 {
12093 create_frame_xic (f);
12094 if (FRAME_XIC_STYLE (f) & XIMStatusArea)
12095 xic_set_statusarea (f);
12096 if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
12097 {
12098 struct window *w = XWINDOW (f->selected_window);
12099 xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
12100 }
12101 }
12102 }
12103
12104 UNBLOCK_INPUT;
12105 }
12106}
12107
b9de836c 12108#endif /* HAVE_X11R6_XIM */
f5d11644
GM
12109
12110
12111/* Open a connection to the XIM server on display DPYINFO.
12112 RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
12113 connection only at the first time. On X11R6, open the connection
12114 in the XIM instantiate callback function. */
12115
12116static void
12117xim_initialize (dpyinfo, resource_name)
12118 struct x_display_info *dpyinfo;
12119 char *resource_name;
12120{
287f7dd6 12121#ifdef USE_XIM
b9de836c 12122#ifdef HAVE_X11R6_XIM
f5d11644
GM
12123 struct xim_inst_t *xim_inst;
12124 int len;
12125
12126 dpyinfo->xim = NULL;
12127 xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
12128 xim_inst->dpyinfo = dpyinfo;
12129 len = strlen (resource_name);
12130 xim_inst->resource_name = (char *) xmalloc (len + 1);
12131 bcopy (resource_name, xim_inst->resource_name, len + 1);
12132 XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12133 resource_name, EMACS_CLASS,
12134 xim_instantiate_callback,
2ebb2f8b
DL
12135 /* Fixme: This is XPointer in
12136 XFree86 but (XPointer *) on
12137 Tru64, at least. */
12138 (XPointer) xim_inst);
b9de836c 12139#else /* not HAVE_X11R6_XIM */
f5d11644
GM
12140 dpyinfo->xim = NULL;
12141 xim_open_dpy (dpyinfo, resource_name);
b9de836c 12142#endif /* not HAVE_X11R6_XIM */
287f7dd6
GM
12143
12144#else /* not USE_XIM */
12145 dpyinfo->xim = NULL;
12146#endif /* not USE_XIM */
f5d11644
GM
12147}
12148
12149
12150/* Close the connection to the XIM server on display DPYINFO. */
12151
12152static void
12153xim_close_dpy (dpyinfo)
12154 struct x_display_info *dpyinfo;
12155{
287f7dd6 12156#ifdef USE_XIM
b9de836c 12157#ifdef HAVE_X11R6_XIM
8a4f36cc
GM
12158 if (dpyinfo->display)
12159 XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
12160 NULL, EMACS_CLASS,
12161 xim_instantiate_callback, NULL);
b9de836c 12162#endif /* not HAVE_X11R6_XIM */
8a4f36cc
GM
12163 if (dpyinfo->display)
12164 XCloseIM (dpyinfo->xim);
f5d11644
GM
12165 dpyinfo->xim = NULL;
12166 XFree (dpyinfo->xim_styles);
287f7dd6 12167#endif /* USE_XIM */
f5d11644
GM
12168}
12169
b9de836c 12170#endif /* not HAVE_X11R6_XIM */
f5d11644
GM
12171
12172
dc6f92b8 12173\f
2e365682
RS
12174/* Calculate the absolute position in frame F
12175 from its current recorded position values and gravity. */
12176
dfcf069d 12177void
43bca5d5 12178x_calc_absolute_position (f)
f676886a 12179 struct frame *f;
dc6f92b8 12180{
06a2c219 12181 Window child;
6dba1858 12182 int win_x = 0, win_y = 0;
7556890b 12183 int flags = f->output_data.x->size_hint_flags;
c81412a0
KH
12184 int this_window;
12185
9829ddba
RS
12186 /* We have nothing to do if the current position
12187 is already for the top-left corner. */
12188 if (! ((flags & XNegative) || (flags & YNegative)))
12189 return;
12190
c81412a0 12191#ifdef USE_X_TOOLKIT
7556890b 12192 this_window = XtWindow (f->output_data.x->widget);
c81412a0
KH
12193#else
12194 this_window = FRAME_X_WINDOW (f);
12195#endif
6dba1858
RS
12196
12197 /* Find the position of the outside upper-left corner of
9829ddba
RS
12198 the inner window, with respect to the outer window.
12199 But do this only if we will need the results. */
7556890b 12200 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
6dba1858 12201 {
9829ddba
RS
12202 int count;
12203
6dba1858 12204 BLOCK_INPUT;
9829ddba
RS
12205 count = x_catch_errors (FRAME_X_DISPLAY (f));
12206 while (1)
12207 {
12208 x_clear_errors (FRAME_X_DISPLAY (f));
12209 XTranslateCoordinates (FRAME_X_DISPLAY (f),
12210
12211 /* From-window, to-window. */
12212 this_window,
12213 f->output_data.x->parent_desc,
12214
12215 /* From-position, to-position. */
12216 0, 0, &win_x, &win_y,
12217
12218 /* Child of win. */
12219 &child);
12220 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
12221 {
12222 Window newroot, newparent = 0xdeadbeef;
12223 Window *newchildren;
2ebb2f8b 12224 unsigned int nchildren;
9829ddba
RS
12225
12226 if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
12227 &newparent, &newchildren, &nchildren))
12228 break;
58769bee 12229
7c3c78a3 12230 XFree ((char *) newchildren);
6dba1858 12231
9829ddba
RS
12232 f->output_data.x->parent_desc = newparent;
12233 }
12234 else
12235 break;
12236 }
6dba1858 12237
9829ddba 12238 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
6dba1858
RS
12239 UNBLOCK_INPUT;
12240 }
12241
12242 /* Treat negative positions as relative to the leftmost bottommost
12243 position that fits on the screen. */
20f55f9a 12244 if (flags & XNegative)
7556890b 12245 f->output_data.x->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
2e365682
RS
12246 - 2 * f->output_data.x->border_width - win_x
12247 - PIXEL_WIDTH (f)
12248 + f->output_data.x->left_pos);
dc6f92b8 12249
7708ced0
GM
12250 {
12251 int height = PIXEL_HEIGHT (f);
06a2c219 12252
7708ced0
GM
12253#if defined USE_X_TOOLKIT && defined USE_MOTIF
12254 /* Something is fishy here. When using Motif, starting Emacs with
12255 `-g -0-0', the frame appears too low by a few pixels.
12256
12257 This seems to be so because initially, while Emacs is starting,
12258 the column widget's height and the frame's pixel height are
12259 different. The column widget's height is the right one. In
12260 later invocations, when Emacs is up, the frame's pixel height
12261 is right, though.
12262
12263 It's not obvious where the initial small difference comes from.
12264 2000-12-01, gerd. */
12265
12266 XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
06a2c219 12267#endif
2e365682 12268
7708ced0
GM
12269 if (flags & YNegative)
12270 f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
12271 - 2 * f->output_data.x->border_width
12272 - win_y
12273 - height
12274 + f->output_data.x->top_pos);
12275 }
12276
3a35ab44
RS
12277 /* The left_pos and top_pos
12278 are now relative to the top and left screen edges,
12279 so the flags should correspond. */
7556890b 12280 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
dc6f92b8
JB
12281}
12282
3a35ab44
RS
12283/* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
12284 to really change the position, and 0 when calling from
12285 x_make_frame_visible (in that case, XOFF and YOFF are the current
aa3ff7c9
KH
12286 position values). It is -1 when calling from x_set_frame_parameters,
12287 which means, do adjust for borders but don't change the gravity. */
3a35ab44 12288
dfcf069d 12289void
dc05a16b 12290x_set_offset (f, xoff, yoff, change_gravity)
f676886a 12291 struct frame *f;
dc6f92b8 12292 register int xoff, yoff;
dc05a16b 12293 int change_gravity;
dc6f92b8 12294{
4a4cbdd5
KH
12295 int modified_top, modified_left;
12296
aa3ff7c9 12297 if (change_gravity > 0)
3a35ab44 12298 {
7556890b
RS
12299 f->output_data.x->top_pos = yoff;
12300 f->output_data.x->left_pos = xoff;
12301 f->output_data.x->size_hint_flags &= ~ (XNegative | YNegative);
3a35ab44 12302 if (xoff < 0)
7556890b 12303 f->output_data.x->size_hint_flags |= XNegative;
3a35ab44 12304 if (yoff < 0)
7556890b
RS
12305 f->output_data.x->size_hint_flags |= YNegative;
12306 f->output_data.x->win_gravity = NorthWestGravity;
3a35ab44 12307 }
43bca5d5 12308 x_calc_absolute_position (f);
dc6f92b8
JB
12309
12310 BLOCK_INPUT;
c32cdd9a 12311 x_wm_set_size_hint (f, (long) 0, 0);
3a35ab44 12312
7556890b
RS
12313 modified_left = f->output_data.x->left_pos;
12314 modified_top = f->output_data.x->top_pos;
e73ec6fa
RS
12315#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
12316 this seems to be unnecessary and incorrect. rms, 4/17/97. */
12317 /* It is a mystery why we need to add the border_width here
12318 when the frame is already visible, but experiment says we do. */
aa3ff7c9 12319 if (change_gravity != 0)
4a4cbdd5 12320 {
7556890b
RS
12321 modified_left += f->output_data.x->border_width;
12322 modified_top += f->output_data.x->border_width;
4a4cbdd5 12323 }
e73ec6fa 12324#endif
4a4cbdd5 12325
3afe33e7 12326#ifdef USE_X_TOOLKIT
7556890b 12327 XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
4a4cbdd5 12328 modified_left, modified_top);
3afe33e7 12329#else /* not USE_X_TOOLKIT */
334208b7 12330 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4a4cbdd5 12331 modified_left, modified_top);
3afe33e7 12332#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
12333 UNBLOCK_INPUT;
12334}
12335
dc6f92b8 12336
499b1844
GM
12337/* Change the size of frame F's X window to COLS/ROWS in the case F
12338 doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
12339 top-left-corner window gravity for this size change and subsequent
12340 size changes. Otherwise we leave the window gravity unchanged. */
12341
12342static void
12343x_set_window_size_1 (f, change_gravity, cols, rows)
f676886a 12344 struct frame *f;
bc20ebbf 12345 int change_gravity;
b1c884c3 12346 int cols, rows;
dc6f92b8
JB
12347{
12348 int pixelwidth, pixelheight;
80fd1fe2 12349
b1c884c3 12350 check_frame_size (f, &rows, &cols);
7556890b 12351 f->output_data.x->vertical_scroll_bar_extra
b2cad826
KH
12352 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
12353 ? 0
12354 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
480407eb 12355 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
7556890b 12356 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
06a2c219 12357 f->output_data.x->flags_areas_extra
110859fc 12358 = FRAME_FLAGS_AREA_WIDTH (f);
f451eb13
JB
12359 pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
12360 pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
dc6f92b8 12361
7556890b 12362 f->output_data.x->win_gravity = NorthWestGravity;
c32cdd9a 12363 x_wm_set_size_hint (f, (long) 0, 0);
6ccf47d1 12364
334208b7
RS
12365 XSync (FRAME_X_DISPLAY (f), False);
12366 XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
12367 pixelwidth, pixelheight);
b1c884c3
JB
12368
12369 /* Now, strictly speaking, we can't be sure that this is accurate,
12370 but the window manager will get around to dealing with the size
12371 change request eventually, and we'll hear how it went when the
dbc4e1c1
JB
12372 ConfigureNotify event gets here.
12373
12374 We could just not bother storing any of this information here,
12375 and let the ConfigureNotify event set everything up, but that
fddd5ceb 12376 might be kind of confusing to the Lisp code, since size changes
dbc4e1c1 12377 wouldn't be reported in the frame parameters until some random
fddd5ceb
RS
12378 point in the future when the ConfigureNotify event arrives.
12379
12380 We pass 1 for DELAY since we can't run Lisp code inside of
12381 a BLOCK_INPUT. */
7d1e984f 12382 change_frame_size (f, rows, cols, 0, 1, 0);
b1c884c3
JB
12383 PIXEL_WIDTH (f) = pixelwidth;
12384 PIXEL_HEIGHT (f) = pixelheight;
12385
aee9a898
RS
12386 /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
12387 receive in the ConfigureNotify event; if we get what we asked
12388 for, then the event won't cause the screen to become garbaged, so
12389 we have to make sure to do it here. */
12390 SET_FRAME_GARBAGED (f);
12391
12392 XFlush (FRAME_X_DISPLAY (f));
499b1844
GM
12393}
12394
12395
12396/* Call this to change the size of frame F's x-window.
12397 If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
12398 for this size change and subsequent size changes.
12399 Otherwise we leave the window gravity unchanged. */
aee9a898 12400
499b1844
GM
12401void
12402x_set_window_size (f, change_gravity, cols, rows)
12403 struct frame *f;
12404 int change_gravity;
12405 int cols, rows;
12406{
12407 BLOCK_INPUT;
12408
12409#ifdef USE_X_TOOLKIT
12410
f1f4d345 12411 if (f->output_data.x->widget != NULL)
499b1844
GM
12412 {
12413 /* The x and y position of the widget is clobbered by the
12414 call to XtSetValues within EmacsFrameSetCharSize.
12415 This is a real kludge, but I don't understand Xt so I can't
12416 figure out a correct fix. Can anyone else tell me? -- rms. */
12417 int xpos = f->output_data.x->widget->core.x;
12418 int ypos = f->output_data.x->widget->core.y;
12419 EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
12420 f->output_data.x->widget->core.x = xpos;
12421 f->output_data.x->widget->core.y = ypos;
12422 }
12423 else
12424 x_set_window_size_1 (f, change_gravity, cols, rows);
12425
12426#else /* not USE_X_TOOLKIT */
12427
12428 x_set_window_size_1 (f, change_gravity, cols, rows);
12429
aee9a898
RS
12430#endif /* not USE_X_TOOLKIT */
12431
4d73d038 12432 /* If cursor was outside the new size, mark it as off. */
06a2c219 12433 mark_window_cursors_off (XWINDOW (f->root_window));
4d73d038 12434
aee9a898
RS
12435 /* Clear out any recollection of where the mouse highlighting was,
12436 since it might be in a place that's outside the new frame size.
12437 Actually checking whether it is outside is a pain in the neck,
12438 so don't try--just let the highlighting be done afresh with new size. */
e687d06e 12439 cancel_mouse_face (f);
dbc4e1c1 12440
dc6f92b8
JB
12441 UNBLOCK_INPUT;
12442}
dc6f92b8 12443\f
d047c4eb 12444/* Mouse warping. */
dc6f92b8 12445
9b378208 12446void
f676886a
JB
12447x_set_mouse_position (f, x, y)
12448 struct frame *f;
dc6f92b8
JB
12449 int x, y;
12450{
12451 int pix_x, pix_y;
12452
7556890b
RS
12453 pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->output_data.x->font) / 2;
12454 pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->output_data.x->line_height / 2;
f451eb13
JB
12455
12456 if (pix_x < 0) pix_x = 0;
12457 if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
12458
12459 if (pix_y < 0) pix_y = 0;
12460 if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
dc6f92b8
JB
12461
12462 BLOCK_INPUT;
dc6f92b8 12463
334208b7
RS
12464 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12465 0, 0, 0, 0, pix_x, pix_y);
dc6f92b8
JB
12466 UNBLOCK_INPUT;
12467}
12468
9b378208
RS
12469/* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
12470
12471void
12472x_set_mouse_pixel_position (f, pix_x, pix_y)
12473 struct frame *f;
12474 int pix_x, pix_y;
12475{
12476 BLOCK_INPUT;
12477
334208b7
RS
12478 XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
12479 0, 0, 0, 0, pix_x, pix_y);
9b378208
RS
12480 UNBLOCK_INPUT;
12481}
d047c4eb
KH
12482\f
12483/* focus shifting, raising and lowering. */
9b378208 12484
dfcf069d 12485void
f676886a
JB
12486x_focus_on_frame (f)
12487 struct frame *f;
dc6f92b8 12488{
1fb20991 12489#if 0 /* This proves to be unpleasant. */
f676886a 12490 x_raise_frame (f);
1fb20991 12491#endif
6d4238f3
JB
12492#if 0
12493 /* I don't think that the ICCCM allows programs to do things like this
12494 without the interaction of the window manager. Whatever you end up
f676886a 12495 doing with this code, do it to x_unfocus_frame too. */
334208b7 12496 XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
dc6f92b8 12497 RevertToPointerRoot, CurrentTime);
c118dd06 12498#endif /* ! 0 */
dc6f92b8
JB
12499}
12500
dfcf069d 12501void
f676886a
JB
12502x_unfocus_frame (f)
12503 struct frame *f;
dc6f92b8 12504{
6d4238f3 12505#if 0
f676886a 12506 /* Look at the remarks in x_focus_on_frame. */
0f941935 12507 if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
334208b7 12508 XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
dc6f92b8 12509 RevertToPointerRoot, CurrentTime);
c118dd06 12510#endif /* ! 0 */
dc6f92b8
JB
12511}
12512
f676886a 12513/* Raise frame F. */
dc6f92b8 12514
dfcf069d 12515void
f676886a
JB
12516x_raise_frame (f)
12517 struct frame *f;
dc6f92b8 12518{
3a88c238 12519 if (f->async_visible)
dc6f92b8
JB
12520 {
12521 BLOCK_INPUT;
3afe33e7 12522#ifdef USE_X_TOOLKIT
7556890b 12523 XRaiseWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12524#else /* not USE_X_TOOLKIT */
334208b7 12525 XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12526#endif /* not USE_X_TOOLKIT */
334208b7 12527 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12528 UNBLOCK_INPUT;
12529 }
12530}
12531
f676886a 12532/* Lower frame F. */
dc6f92b8 12533
dfcf069d 12534void
f676886a
JB
12535x_lower_frame (f)
12536 struct frame *f;
dc6f92b8 12537{
3a88c238 12538 if (f->async_visible)
dc6f92b8
JB
12539 {
12540 BLOCK_INPUT;
3afe33e7 12541#ifdef USE_X_TOOLKIT
7556890b 12542 XLowerWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget));
3afe33e7 12543#else /* not USE_X_TOOLKIT */
334208b7 12544 XLowerWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12545#endif /* not USE_X_TOOLKIT */
334208b7 12546 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8
JB
12547 UNBLOCK_INPUT;
12548 }
12549}
12550
dbc4e1c1 12551static void
6b0442dc 12552XTframe_raise_lower (f, raise_flag)
dbc4e1c1 12553 FRAME_PTR f;
6b0442dc 12554 int raise_flag;
dbc4e1c1 12555{
6b0442dc 12556 if (raise_flag)
dbc4e1c1
JB
12557 x_raise_frame (f);
12558 else
12559 x_lower_frame (f);
12560}
d047c4eb
KH
12561\f
12562/* Change of visibility. */
dc6f92b8 12563
9382638d
KH
12564/* This tries to wait until the frame is really visible.
12565 However, if the window manager asks the user where to position
12566 the frame, this will return before the user finishes doing that.
12567 The frame will not actually be visible at that time,
12568 but it will become visible later when the window manager
12569 finishes with it. */
12570
dfcf069d 12571void
f676886a
JB
12572x_make_frame_visible (f)
12573 struct frame *f;
dc6f92b8 12574{
990ba854 12575 Lisp_Object type;
1aa6072f 12576 int original_top, original_left;
31be9251
GM
12577 int retry_count = 2;
12578
12579 retry:
dc6f92b8 12580
dc6f92b8 12581 BLOCK_INPUT;
dc6f92b8 12582
990ba854
RS
12583 type = x_icon_type (f);
12584 if (!NILP (type))
12585 x_bitmap_icon (f, type);
bdcd49ba 12586
f676886a 12587 if (! FRAME_VISIBLE_P (f))
90e65f07 12588 {
1aa6072f
RS
12589 /* We test FRAME_GARBAGED_P here to make sure we don't
12590 call x_set_offset a second time
12591 if we get to x_make_frame_visible a second time
12592 before the window gets really visible. */
12593 if (! FRAME_ICONIFIED_P (f)
12594 && ! f->output_data.x->asked_for_visible)
12595 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
12596
12597 f->output_data.x->asked_for_visible = 1;
12598
90e65f07 12599 if (! EQ (Vx_no_window_manager, Qt))
f676886a 12600 x_wm_set_window_state (f, NormalState);
3afe33e7 12601#ifdef USE_X_TOOLKIT
d7a38a2e 12602 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 12603 XtMapWidget (f->output_data.x->widget);
3afe33e7 12604#else /* not USE_X_TOOLKIT */
7f9c7f94 12605 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
3afe33e7 12606#endif /* not USE_X_TOOLKIT */
0134a210
RS
12607#if 0 /* This seems to bring back scroll bars in the wrong places
12608 if the window configuration has changed. They seem
12609 to come back ok without this. */
ab648270 12610 if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
334208b7 12611 XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
0134a210 12612#endif
90e65f07 12613 }
dc6f92b8 12614
334208b7 12615 XFlush (FRAME_X_DISPLAY (f));
90e65f07 12616
0dacf791
RS
12617 /* Synchronize to ensure Emacs knows the frame is visible
12618 before we do anything else. We do this loop with input not blocked
12619 so that incoming events are handled. */
12620 {
12621 Lisp_Object frame;
12ce2351 12622 int count;
28c01ffe
RS
12623 /* This must be before UNBLOCK_INPUT
12624 since events that arrive in response to the actions above
12625 will set it when they are handled. */
12626 int previously_visible = f->output_data.x->has_been_visible;
1aa6072f
RS
12627
12628 original_left = f->output_data.x->left_pos;
12629 original_top = f->output_data.x->top_pos;
c0a04927
RS
12630
12631 /* This must come after we set COUNT. */
12632 UNBLOCK_INPUT;
12633
2745e6c4 12634 /* We unblock here so that arriving X events are processed. */
1aa6072f 12635
dcb07ae9
RS
12636 /* Now move the window back to where it was "supposed to be".
12637 But don't do it if the gravity is negative.
12638 When the gravity is negative, this uses a position
28c01ffe
RS
12639 that is 3 pixels too low. Perhaps that's really the border width.
12640
12641 Don't do this if the window has never been visible before,
12642 because the window manager may choose the position
12643 and we don't want to override it. */
1aa6072f 12644
4d3f5d9a 12645 if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
06c488fd 12646 && f->output_data.x->win_gravity == NorthWestGravity
28c01ffe 12647 && previously_visible)
1aa6072f 12648 {
2745e6c4
RS
12649 Drawable rootw;
12650 int x, y;
12651 unsigned int width, height, border, depth;
06a2c219 12652
1aa6072f 12653 BLOCK_INPUT;
9829ddba 12654
06a2c219
GM
12655 /* On some window managers (such as FVWM) moving an existing
12656 window, even to the same place, causes the window manager
12657 to introduce an offset. This can cause the window to move
12658 to an unexpected location. Check the geometry (a little
12659 slow here) and then verify that the window is in the right
12660 place. If the window is not in the right place, move it
12661 there, and take the potential window manager hit. */
2745e6c4
RS
12662 XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12663 &rootw, &x, &y, &width, &height, &border, &depth);
12664
12665 if (original_left != x || original_top != y)
12666 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
12667 original_left, original_top);
12668
1aa6072f
RS
12669 UNBLOCK_INPUT;
12670 }
9829ddba 12671
e0c1aef2 12672 XSETFRAME (frame, f);
c0a04927 12673
12ce2351
GM
12674 /* Wait until the frame is visible. Process X events until a
12675 MapNotify event has been seen, or until we think we won't get a
12676 MapNotify at all.. */
12677 for (count = input_signal_count + 10;
12678 input_signal_count < count && !FRAME_VISIBLE_P (f);)
2a6cf806 12679 {
12ce2351 12680 /* Force processing of queued events. */
334208b7 12681 x_sync (f);
12ce2351
GM
12682
12683 /* Machines that do polling rather than SIGIO have been
12684 observed to go into a busy-wait here. So we'll fake an
12685 alarm signal to let the handler know that there's something
12686 to be read. We used to raise a real alarm, but it seems
12687 that the handler isn't always enabled here. This is
12688 probably a bug. */
8b2f8d4e 12689 if (input_polling_used ())
3b2fa4e6 12690 {
12ce2351
GM
12691 /* It could be confusing if a real alarm arrives while
12692 processing the fake one. Turn it off and let the
12693 handler reset it. */
3e71d8f2 12694 extern void poll_for_input_1 P_ ((void));
bffcfca9
GM
12695 int old_poll_suppress_count = poll_suppress_count;
12696 poll_suppress_count = 1;
12697 poll_for_input_1 ();
12698 poll_suppress_count = old_poll_suppress_count;
3b2fa4e6 12699 }
12ce2351
GM
12700
12701 /* See if a MapNotify event has been processed. */
12702 FRAME_SAMPLE_VISIBILITY (f);
2a6cf806 12703 }
31be9251
GM
12704
12705 /* 2000-09-28: In
12706
12707 (let ((f (selected-frame)))
12708 (iconify-frame f)
12709 (raise-frame f))
12710
12711 the frame is not raised with various window managers on
12712 FreeBSD, Linux and Solaris. It turns out that, for some
12713 unknown reason, the call to XtMapWidget is completely ignored.
12714 Mapping the widget a second time works. */
12715
12716 if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
12717 goto retry;
0dacf791 12718 }
dc6f92b8
JB
12719}
12720
06a2c219 12721/* Change from mapped state to withdrawn state. */
dc6f92b8 12722
d047c4eb
KH
12723/* Make the frame visible (mapped and not iconified). */
12724
dfcf069d 12725void
f676886a
JB
12726x_make_frame_invisible (f)
12727 struct frame *f;
dc6f92b8 12728{
546e6d5b
RS
12729 Window window;
12730
12731#ifdef USE_X_TOOLKIT
12732 /* Use the frame's outermost window, not the one we normally draw on. */
7556890b 12733 window = XtWindow (f->output_data.x->widget);
546e6d5b
RS
12734#else /* not USE_X_TOOLKIT */
12735 window = FRAME_X_WINDOW (f);
12736#endif /* not USE_X_TOOLKIT */
dc6f92b8 12737
9319ae23 12738 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
12739 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
12740 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 12741
5627c40e 12742#if 0/* This might add unreliability; I don't trust it -- rms. */
9319ae23 12743 if (! f->async_visible && ! f->async_iconified)
dc6f92b8 12744 return;
5627c40e 12745#endif
dc6f92b8
JB
12746
12747 BLOCK_INPUT;
c118dd06 12748
af31d76f
RS
12749 /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
12750 that the current position of the window is user-specified, rather than
12751 program-specified, so that when the window is mapped again, it will be
12752 placed at the same location, without forcing the user to position it
12753 by hand again (they have already done that once for this window.) */
c32cdd9a 12754 x_wm_set_size_hint (f, (long) 0, 1);
af31d76f 12755
c118dd06
JB
12756#ifdef HAVE_X11R4
12757
334208b7
RS
12758 if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
12759 DefaultScreen (FRAME_X_DISPLAY (f))))
c118dd06
JB
12760 {
12761 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12762 error ("Can't notify window manager of window withdrawal");
c118dd06 12763 }
c118dd06 12764#else /* ! defined (HAVE_X11R4) */
16bd92ea 12765
c118dd06 12766 /* Tell the window manager what we're going to do. */
dc6f92b8
JB
12767 if (! EQ (Vx_no_window_manager, Qt))
12768 {
16bd92ea 12769 XEvent unmap;
dc6f92b8 12770
16bd92ea 12771 unmap.xunmap.type = UnmapNotify;
546e6d5b 12772 unmap.xunmap.window = window;
334208b7 12773 unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
16bd92ea 12774 unmap.xunmap.from_configure = False;
334208b7
RS
12775 if (! XSendEvent (FRAME_X_DISPLAY (f),
12776 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea 12777 False,
06a2c219 12778 SubstructureRedirectMaskSubstructureNotifyMask,
16bd92ea
JB
12779 &unmap))
12780 {
12781 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12782 error ("Can't notify window manager of withdrawal");
16bd92ea 12783 }
dc6f92b8
JB
12784 }
12785
16bd92ea 12786 /* Unmap the window ourselves. Cheeky! */
334208b7 12787 XUnmapWindow (FRAME_X_DISPLAY (f), window);
c118dd06 12788#endif /* ! defined (HAVE_X11R4) */
dc6f92b8 12789
5627c40e
RS
12790 /* We can't distinguish this from iconification
12791 just by the event that we get from the server.
12792 So we can't win using the usual strategy of letting
12793 FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
12794 and synchronize with the server to make sure we agree. */
12795 f->visible = 0;
12796 FRAME_ICONIFIED_P (f) = 0;
12797 f->async_visible = 0;
12798 f->async_iconified = 0;
12799
334208b7 12800 x_sync (f);
5627c40e 12801
dc6f92b8
JB
12802 UNBLOCK_INPUT;
12803}
12804
06a2c219 12805/* Change window state from mapped to iconified. */
dc6f92b8 12806
dfcf069d 12807void
f676886a
JB
12808x_iconify_frame (f)
12809 struct frame *f;
dc6f92b8 12810{
3afe33e7 12811 int result;
990ba854 12812 Lisp_Object type;
dc6f92b8 12813
9319ae23 12814 /* Don't keep the highlight on an invisible frame. */
0f941935
KH
12815 if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
12816 FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
9319ae23 12817
3a88c238 12818 if (f->async_iconified)
dc6f92b8
JB
12819 return;
12820
3afe33e7 12821 BLOCK_INPUT;
546e6d5b 12822
9af3143a
RS
12823 FRAME_SAMPLE_VISIBILITY (f);
12824
990ba854
RS
12825 type = x_icon_type (f);
12826 if (!NILP (type))
12827 x_bitmap_icon (f, type);
bdcd49ba
RS
12828
12829#ifdef USE_X_TOOLKIT
12830
546e6d5b
RS
12831 if (! FRAME_VISIBLE_P (f))
12832 {
12833 if (! EQ (Vx_no_window_manager, Qt))
12834 x_wm_set_window_state (f, IconicState);
12835 /* This was XtPopup, but that did nothing for an iconified frame. */
7556890b 12836 XtMapWidget (f->output_data.x->widget);
9cf30a30
RS
12837 /* The server won't give us any event to indicate
12838 that an invisible frame was changed to an icon,
12839 so we have to record it here. */
12840 f->iconified = 1;
1e6bc770 12841 f->visible = 1;
9cf30a30 12842 f->async_iconified = 1;
1e6bc770 12843 f->async_visible = 0;
546e6d5b
RS
12844 UNBLOCK_INPUT;
12845 return;
12846 }
12847
334208b7 12848 result = XIconifyWindow (FRAME_X_DISPLAY (f),
7556890b 12849 XtWindow (f->output_data.x->widget),
334208b7 12850 DefaultScreen (FRAME_X_DISPLAY (f)));
3afe33e7
RS
12851 UNBLOCK_INPUT;
12852
12853 if (!result)
546e6d5b 12854 error ("Can't notify window manager of iconification");
3afe33e7
RS
12855
12856 f->async_iconified = 1;
1e6bc770
RS
12857 f->async_visible = 0;
12858
8c002a25
KH
12859
12860 BLOCK_INPUT;
334208b7 12861 XFlush (FRAME_X_DISPLAY (f));
8c002a25 12862 UNBLOCK_INPUT;
3afe33e7
RS
12863#else /* not USE_X_TOOLKIT */
12864
fd13dbb2
RS
12865 /* Make sure the X server knows where the window should be positioned,
12866 in case the user deiconifies with the window manager. */
12867 if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
7556890b 12868 x_set_offset (f, f->output_data.x->left_pos, f->output_data.x->top_pos, 0);
fd13dbb2 12869
16bd92ea
JB
12870 /* Since we don't know which revision of X we're running, we'll use both
12871 the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
12872
12873 /* X11R4: send a ClientMessage to the window manager using the
12874 WM_CHANGE_STATE type. */
12875 {
12876 XEvent message;
58769bee 12877
c118dd06 12878 message.xclient.window = FRAME_X_WINDOW (f);
16bd92ea 12879 message.xclient.type = ClientMessage;
334208b7 12880 message.xclient.message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_wm_change_state;
16bd92ea
JB
12881 message.xclient.format = 32;
12882 message.xclient.data.l[0] = IconicState;
12883
334208b7
RS
12884 if (! XSendEvent (FRAME_X_DISPLAY (f),
12885 DefaultRootWindow (FRAME_X_DISPLAY (f)),
16bd92ea
JB
12886 False,
12887 SubstructureRedirectMask | SubstructureNotifyMask,
12888 &message))
dc6f92b8
JB
12889 {
12890 UNBLOCK_INPUT_RESIGNAL;
546e6d5b 12891 error ("Can't notify window manager of iconification");
dc6f92b8 12892 }
16bd92ea 12893 }
dc6f92b8 12894
58769bee 12895 /* X11R3: set the initial_state field of the window manager hints to
16bd92ea
JB
12896 IconicState. */
12897 x_wm_set_window_state (f, IconicState);
dc6f92b8 12898
a9c00105
RS
12899 if (!FRAME_VISIBLE_P (f))
12900 {
12901 /* If the frame was withdrawn, before, we must map it. */
7f9c7f94 12902 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
a9c00105
RS
12903 }
12904
3a88c238 12905 f->async_iconified = 1;
1e6bc770 12906 f->async_visible = 0;
dc6f92b8 12907
334208b7 12908 XFlush (FRAME_X_DISPLAY (f));
dc6f92b8 12909 UNBLOCK_INPUT;
8c002a25 12910#endif /* not USE_X_TOOLKIT */
dc6f92b8 12911}
19f71add 12912
d047c4eb 12913\f
19f71add 12914/* Free X resources of frame F. */
dc6f92b8 12915
dfcf069d 12916void
19f71add 12917x_free_frame_resources (f)
f676886a 12918 struct frame *f;
dc6f92b8 12919{
7f9c7f94
RS
12920 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
12921
dc6f92b8 12922 BLOCK_INPUT;
c0ff3fab 12923
6186a4a0
RS
12924 /* If a display connection is dead, don't try sending more
12925 commands to the X server. */
19f71add 12926 if (dpyinfo->display)
6186a4a0 12927 {
19f71add 12928 if (f->output_data.x->icon_desc)
6186a4a0 12929 XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
19f71add 12930
31f41daf 12931#ifdef HAVE_X_I18N
f5d11644
GM
12932 if (FRAME_XIC (f))
12933 free_frame_xic (f);
31f41daf 12934#endif
19f71add 12935
2662734b 12936 if (FRAME_X_WINDOW (f))
19f71add
GM
12937 XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
12938
3afe33e7 12939#ifdef USE_X_TOOLKIT
06a2c219 12940 if (f->output_data.x->widget)
30ca89f5
GM
12941 {
12942 XtDestroyWidget (f->output_data.x->widget);
12943 f->output_data.x->widget = NULL;
12944 }
6186a4a0 12945 free_frame_menubar (f);
3afe33e7
RS
12946#endif /* USE_X_TOOLKIT */
12947
3e71d8f2
GM
12948 unload_color (f, f->output_data.x->foreground_pixel);
12949 unload_color (f, f->output_data.x->background_pixel);
12950 unload_color (f, f->output_data.x->cursor_pixel);
12951 unload_color (f, f->output_data.x->cursor_foreground_pixel);
12952 unload_color (f, f->output_data.x->border_pixel);
12953 unload_color (f, f->output_data.x->mouse_pixel);
19f71add 12954
3e71d8f2
GM
12955 if (f->output_data.x->scroll_bar_background_pixel != -1)
12956 unload_color (f, f->output_data.x->scroll_bar_background_pixel);
12957 if (f->output_data.x->scroll_bar_foreground_pixel != -1)
12958 unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
12959 if (f->output_data.x->white_relief.allocated_p)
12960 unload_color (f, f->output_data.x->white_relief.pixel);
12961 if (f->output_data.x->black_relief.allocated_p)
12962 unload_color (f, f->output_data.x->black_relief.pixel);
4ca78676 12963
19f71add
GM
12964 if (FRAME_FACE_CACHE (f))
12965 free_frame_faces (f);
12966
4ca78676 12967 x_free_gcs (f);
6186a4a0
RS
12968 XFlush (FRAME_X_DISPLAY (f));
12969 }
dc6f92b8 12970
df89d8a4 12971 if (f->output_data.x->saved_menu_event)
06a2c219 12972 xfree (f->output_data.x->saved_menu_event);
0c49ce2f 12973
7556890b 12974 xfree (f->output_data.x);
19f71add
GM
12975 f->output_data.x = NULL;
12976
0f941935
KH
12977 if (f == dpyinfo->x_focus_frame)
12978 dpyinfo->x_focus_frame = 0;
12979 if (f == dpyinfo->x_focus_event_frame)
12980 dpyinfo->x_focus_event_frame = 0;
12981 if (f == dpyinfo->x_highlight_frame)
12982 dpyinfo->x_highlight_frame = 0;
c0ff3fab 12983
7f9c7f94 12984 if (f == dpyinfo->mouse_face_mouse_frame)
dc05a16b 12985 {
7f9c7f94
RS
12986 dpyinfo->mouse_face_beg_row
12987 = dpyinfo->mouse_face_beg_col = -1;
12988 dpyinfo->mouse_face_end_row
12989 = dpyinfo->mouse_face_end_col = -1;
12990 dpyinfo->mouse_face_window = Qnil;
21323706
RS
12991 dpyinfo->mouse_face_deferred_gc = 0;
12992 dpyinfo->mouse_face_mouse_frame = 0;
dc05a16b 12993 }
0134a210 12994
c0ff3fab 12995 UNBLOCK_INPUT;
dc6f92b8 12996}
19f71add
GM
12997
12998
12999/* Destroy the X window of frame F. */
13000
13001void
13002x_destroy_window (f)
13003 struct frame *f;
13004{
13005 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13006
13007 /* If a display connection is dead, don't try sending more
13008 commands to the X server. */
13009 if (dpyinfo->display != 0)
13010 x_free_frame_resources (f);
13011
13012 dpyinfo->reference_count--;
13013}
13014
dc6f92b8 13015\f
f451eb13
JB
13016/* Setting window manager hints. */
13017
af31d76f
RS
13018/* Set the normal size hints for the window manager, for frame F.
13019 FLAGS is the flags word to use--or 0 meaning preserve the flags
13020 that the window now has.
13021 If USER_POSITION is nonzero, we set the USPosition
13022 flag (this is useful when FLAGS is 0). */
6dba1858 13023
dfcf069d 13024void
af31d76f 13025x_wm_set_size_hint (f, flags, user_position)
f676886a 13026 struct frame *f;
af31d76f
RS
13027 long flags;
13028 int user_position;
dc6f92b8
JB
13029{
13030 XSizeHints size_hints;
3afe33e7
RS
13031
13032#ifdef USE_X_TOOLKIT
7e4f2521
FP
13033 Arg al[2];
13034 int ac = 0;
13035 Dimension widget_width, widget_height;
7556890b 13036 Window window = XtWindow (f->output_data.x->widget);
3afe33e7 13037#else /* not USE_X_TOOLKIT */
c118dd06 13038 Window window = FRAME_X_WINDOW (f);
3afe33e7 13039#endif /* not USE_X_TOOLKIT */
dc6f92b8 13040
b72a58fd
RS
13041 /* Setting PMaxSize caused various problems. */
13042 size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
dc6f92b8 13043
7556890b
RS
13044 size_hints.x = f->output_data.x->left_pos;
13045 size_hints.y = f->output_data.x->top_pos;
7553a6b7 13046
7e4f2521
FP
13047#ifdef USE_X_TOOLKIT
13048 XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
13049 XtSetArg (al[ac], XtNheight, &widget_height); ac++;
7556890b 13050 XtGetValues (f->output_data.x->widget, al, ac);
7e4f2521
FP
13051 size_hints.height = widget_height;
13052 size_hints.width = widget_width;
13053#else /* not USE_X_TOOLKIT */
f676886a
JB
13054 size_hints.height = PIXEL_HEIGHT (f);
13055 size_hints.width = PIXEL_WIDTH (f);
7e4f2521 13056#endif /* not USE_X_TOOLKIT */
7553a6b7 13057
7556890b
RS
13058 size_hints.width_inc = FONT_WIDTH (f->output_data.x->font);
13059 size_hints.height_inc = f->output_data.x->line_height;
334208b7
RS
13060 size_hints.max_width
13061 = FRAME_X_DISPLAY_INFO (f)->width - CHAR_TO_PIXEL_WIDTH (f, 0);
13062 size_hints.max_height
13063 = FRAME_X_DISPLAY_INFO (f)->height - CHAR_TO_PIXEL_HEIGHT (f, 0);
0134a210 13064
d067ea8b
KH
13065 /* Calculate the base and minimum sizes.
13066
13067 (When we use the X toolkit, we don't do it here.
13068 Instead we copy the values that the widgets are using, below.) */
13069#ifndef USE_X_TOOLKIT
b1c884c3 13070 {
b0342f17 13071 int base_width, base_height;
0134a210 13072 int min_rows = 0, min_cols = 0;
b0342f17 13073
f451eb13
JB
13074 base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
13075 base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
b0342f17 13076
0134a210 13077 check_frame_size (f, &min_rows, &min_cols);
b0342f17 13078
0134a210
RS
13079 /* The window manager uses the base width hints to calculate the
13080 current number of rows and columns in the frame while
13081 resizing; min_width and min_height aren't useful for this
13082 purpose, since they might not give the dimensions for a
13083 zero-row, zero-column frame.
58769bee 13084
0134a210
RS
13085 We use the base_width and base_height members if we have
13086 them; otherwise, we set the min_width and min_height members
13087 to the size for a zero x zero frame. */
b0342f17
JB
13088
13089#ifdef HAVE_X11R4
0134a210
RS
13090 size_hints.flags |= PBaseSize;
13091 size_hints.base_width = base_width;
13092 size_hints.base_height = base_height;
13093 size_hints.min_width = base_width + min_cols * size_hints.width_inc;
13094 size_hints.min_height = base_height + min_rows * size_hints.height_inc;
b0342f17 13095#else
0134a210
RS
13096 size_hints.min_width = base_width;
13097 size_hints.min_height = base_height;
b0342f17 13098#endif
b1c884c3 13099 }
dc6f92b8 13100
d067ea8b 13101 /* If we don't need the old flags, we don't need the old hint at all. */
af31d76f 13102 if (flags)
dc6f92b8 13103 {
d067ea8b
KH
13104 size_hints.flags |= flags;
13105 goto no_read;
13106 }
13107#endif /* not USE_X_TOOLKIT */
13108
13109 {
13110 XSizeHints hints; /* Sometimes I hate X Windows... */
13111 long supplied_return;
13112 int value;
af31d76f
RS
13113
13114#ifdef HAVE_X11R4
d067ea8b
KH
13115 value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
13116 &supplied_return);
af31d76f 13117#else
d067ea8b 13118 value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
af31d76f 13119#endif
58769bee 13120
d067ea8b
KH
13121#ifdef USE_X_TOOLKIT
13122 size_hints.base_height = hints.base_height;
13123 size_hints.base_width = hints.base_width;
13124 size_hints.min_height = hints.min_height;
13125 size_hints.min_width = hints.min_width;
13126#endif
13127
13128 if (flags)
13129 size_hints.flags |= flags;
13130 else
13131 {
13132 if (value == 0)
13133 hints.flags = 0;
13134 if (hints.flags & PSize)
13135 size_hints.flags |= PSize;
13136 if (hints.flags & PPosition)
13137 size_hints.flags |= PPosition;
13138 if (hints.flags & USPosition)
13139 size_hints.flags |= USPosition;
13140 if (hints.flags & USSize)
13141 size_hints.flags |= USSize;
13142 }
13143 }
13144
06a2c219 13145#ifndef USE_X_TOOLKIT
d067ea8b 13146 no_read:
06a2c219 13147#endif
0134a210 13148
af31d76f 13149#ifdef PWinGravity
7556890b 13150 size_hints.win_gravity = f->output_data.x->win_gravity;
af31d76f 13151 size_hints.flags |= PWinGravity;
dc05a16b 13152
af31d76f 13153 if (user_position)
6dba1858 13154 {
af31d76f
RS
13155 size_hints.flags &= ~ PPosition;
13156 size_hints.flags |= USPosition;
6dba1858 13157 }
2554751d 13158#endif /* PWinGravity */
6dba1858 13159
b0342f17 13160#ifdef HAVE_X11R4
334208b7 13161 XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13162#else
334208b7 13163 XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
b0342f17 13164#endif
dc6f92b8
JB
13165}
13166
13167/* Used for IconicState or NormalState */
06a2c219 13168
dfcf069d 13169void
f676886a
JB
13170x_wm_set_window_state (f, state)
13171 struct frame *f;
dc6f92b8
JB
13172 int state;
13173{
3afe33e7 13174#ifdef USE_X_TOOLKIT
546e6d5b
RS
13175 Arg al[1];
13176
13177 XtSetArg (al[0], XtNinitialState, state);
7556890b 13178 XtSetValues (f->output_data.x->widget, al, 1);
3afe33e7 13179#else /* not USE_X_TOOLKIT */
c118dd06 13180 Window window = FRAME_X_WINDOW (f);
dc6f92b8 13181
7556890b
RS
13182 f->output_data.x->wm_hints.flags |= StateHint;
13183 f->output_data.x->wm_hints.initial_state = state;
b1c884c3 13184
7556890b 13185 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
546e6d5b 13186#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13187}
13188
dfcf069d 13189void
7f2ae036 13190x_wm_set_icon_pixmap (f, pixmap_id)
f676886a 13191 struct frame *f;
7f2ae036 13192 int pixmap_id;
dc6f92b8 13193{
d2bd6bc4
RS
13194 Pixmap icon_pixmap;
13195
06a2c219 13196#ifndef USE_X_TOOLKIT
c118dd06 13197 Window window = FRAME_X_WINDOW (f);
75231bad 13198#endif
dc6f92b8 13199
7f2ae036 13200 if (pixmap_id > 0)
dbc4e1c1 13201 {
d2bd6bc4 13202 icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
7556890b 13203 f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
dbc4e1c1
JB
13204 }
13205 else
68568555
RS
13206 {
13207 /* It seems there is no way to turn off use of an icon pixmap.
13208 The following line does it, only if no icon has yet been created,
13209 for some window managers. But with mwm it crashes.
13210 Some people say it should clear the IconPixmapHint bit in this case,
13211 but that doesn't work, and the X consortium said it isn't the
13212 right thing at all. Since there is no way to win,
13213 best to explicitly give up. */
13214#if 0
13215 f->output_data.x->wm_hints.icon_pixmap = None;
13216#else
13217 return;
13218#endif
13219 }
b1c884c3 13220
d2bd6bc4
RS
13221#ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
13222
13223 {
13224 Arg al[1];
13225 XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
13226 XtSetValues (f->output_data.x->widget, al, 1);
13227 }
13228
13229#else /* not USE_X_TOOLKIT */
13230
7556890b
RS
13231 f->output_data.x->wm_hints.flags |= IconPixmapHint;
13232 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
d2bd6bc4
RS
13233
13234#endif /* not USE_X_TOOLKIT */
dc6f92b8
JB
13235}
13236
dfcf069d 13237void
f676886a
JB
13238x_wm_set_icon_position (f, icon_x, icon_y)
13239 struct frame *f;
dc6f92b8
JB
13240 int icon_x, icon_y;
13241{
75231bad 13242#ifdef USE_X_TOOLKIT
7556890b 13243 Window window = XtWindow (f->output_data.x->widget);
75231bad 13244#else
c118dd06 13245 Window window = FRAME_X_WINDOW (f);
75231bad 13246#endif
dc6f92b8 13247
7556890b
RS
13248 f->output_data.x->wm_hints.flags |= IconPositionHint;
13249 f->output_data.x->wm_hints.icon_x = icon_x;
13250 f->output_data.x->wm_hints.icon_y = icon_y;
b1c884c3 13251
7556890b 13252 XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
dc6f92b8
JB
13253}
13254
13255\f
06a2c219
GM
13256/***********************************************************************
13257 Fonts
13258 ***********************************************************************/
dc43ef94
KH
13259
13260/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
06a2c219 13261
dc43ef94
KH
13262struct font_info *
13263x_get_font_info (f, font_idx)
13264 FRAME_PTR f;
13265 int font_idx;
13266{
13267 return (FRAME_X_FONT_TABLE (f) + font_idx);
13268}
13269
13270
9c11f79e
GM
13271/* Return a list of names of available fonts matching PATTERN on frame F.
13272
13273 If SIZE is > 0, it is the size (maximum bounds width) of fonts
13274 to be listed.
13275
13276 SIZE < 0 means include scalable fonts.
13277
13278 Frame F null means we have not yet created any frame on X, and
13279 consult the first display in x_display_list. MAXNAMES sets a limit
13280 on how many fonts to match. */
dc43ef94
KH
13281
13282Lisp_Object
13283x_list_fonts (f, pattern, size, maxnames)
9c11f79e 13284 struct frame *f;
dc43ef94
KH
13285 Lisp_Object pattern;
13286 int size;
13287 int maxnames;
13288{
06a2c219
GM
13289 Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
13290 Lisp_Object tem, second_best;
9c11f79e
GM
13291 struct x_display_info *dpyinfo
13292 = f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
13293 Display *dpy = dpyinfo->display;
09c6077f 13294 int try_XLoadQueryFont = 0;
53ca4657 13295 int count;
9c11f79e
GM
13296 int allow_scalable_fonts_p = 0;
13297
13298 if (size < 0)
13299 {
13300 allow_scalable_fonts_p = 1;
13301 size = 0;
13302 }
dc43ef94 13303
6b0efe73 13304 patterns = Fassoc (pattern, Valternate_fontname_alist);
2da424f1
KH
13305 if (NILP (patterns))
13306 patterns = Fcons (pattern, Qnil);
81ba44e5 13307
09c6077f
KH
13308 if (maxnames == 1 && !size)
13309 /* We can return any single font matching PATTERN. */
13310 try_XLoadQueryFont = 1;
9a32686f 13311
8e713be6 13312 for (; CONSP (patterns); patterns = XCDR (patterns))
dc43ef94 13313 {
dc43ef94 13314 int num_fonts;
3e71d8f2 13315 char **names = NULL;
dc43ef94 13316
8e713be6 13317 pattern = XCAR (patterns);
536f4067
RS
13318 /* See if we cached the result for this particular query.
13319 The cache is an alist of the form:
9c11f79e
GM
13320 ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */
13321 tem = XCDR (dpyinfo->name_list_element);
13322 key = Fcons (Fcons (pattern, make_number (maxnames)),
13323 allow_scalable_fonts_p ? Qt : Qnil);
13324 list = Fassoc (key, tem);
13325 if (!NILP (list))
b5210ea7
KH
13326 {
13327 list = Fcdr_safe (list);
13328 /* We have a cashed list. Don't have to get the list again. */
13329 goto label_cached;
13330 }
13331
13332 /* At first, put PATTERN in the cache. */
09c6077f 13333
dc43ef94 13334 BLOCK_INPUT;
17d85edc
KH
13335 count = x_catch_errors (dpy);
13336
09c6077f
KH
13337 if (try_XLoadQueryFont)
13338 {
13339 XFontStruct *font;
13340 unsigned long value;
13341
13342 font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
17d85edc
KH
13343 if (x_had_errors_p (dpy))
13344 {
13345 /* This error is perhaps due to insufficient memory on X
13346 server. Let's just ignore it. */
13347 font = NULL;
13348 x_clear_errors (dpy);
13349 }
13350
09c6077f
KH
13351 if (font
13352 && XGetFontProperty (font, XA_FONT, &value))
13353 {
13354 char *name = (char *) XGetAtomName (dpy, (Atom) value);
13355 int len = strlen (name);
01c752b5 13356 char *tmp;
09c6077f 13357
6f6512e8
KH
13358 /* If DXPC (a Differential X Protocol Compressor)
13359 Ver.3.7 is running, XGetAtomName will return null
13360 string. We must avoid such a name. */
13361 if (len == 0)
13362 try_XLoadQueryFont = 0;
13363 else
13364 {
13365 num_fonts = 1;
13366 names = (char **) alloca (sizeof (char *));
13367 /* Some systems only allow alloca assigned to a
13368 simple var. */
13369 tmp = (char *) alloca (len + 1); names[0] = tmp;
13370 bcopy (name, names[0], len + 1);
13371 XFree (name);
13372 }
09c6077f
KH
13373 }
13374 else
13375 try_XLoadQueryFont = 0;
a083fd23
RS
13376
13377 if (font)
13378 XFreeFont (dpy, font);
09c6077f
KH
13379 }
13380
13381 if (!try_XLoadQueryFont)
17d85edc
KH
13382 {
13383 /* We try at least 10 fonts because XListFonts will return
13384 auto-scaled fonts at the head. */
13385 names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
13386 &num_fonts);
13387 if (x_had_errors_p (dpy))
13388 {
13389 /* This error is perhaps due to insufficient memory on X
13390 server. Let's just ignore it. */
13391 names = NULL;
13392 x_clear_errors (dpy);
13393 }
13394 }
13395
13396 x_uncatch_errors (dpy, count);
dc43ef94
KH
13397 UNBLOCK_INPUT;
13398
13399 if (names)
13400 {
13401 int i;
dc43ef94
KH
13402
13403 /* Make a list of all the fonts we got back.
13404 Store that in the font cache for the display. */
13405 for (i = 0; i < num_fonts; i++)
13406 {
06a2c219 13407 int width = 0;
dc43ef94 13408 char *p = names[i];
06a2c219
GM
13409 int average_width = -1, dashes = 0;
13410
dc43ef94 13411 /* Count the number of dashes in NAMES[I]. If there are
9c11f79e
GM
13412 14 dashes, and the field value following 12th dash
13413 (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
13414 is usually too ugly to be used for editing. Let's
13415 ignore it. */
dc43ef94
KH
13416 while (*p)
13417 if (*p++ == '-')
13418 {
13419 dashes++;
13420 if (dashes == 7) /* PIXEL_SIZE field */
13421 width = atoi (p);
13422 else if (dashes == 12) /* AVERAGE_WIDTH field */
13423 average_width = atoi (p);
13424 }
9c11f79e
GM
13425
13426 if (allow_scalable_fonts_p
13427 || dashes < 14 || average_width != 0)
dc43ef94
KH
13428 {
13429 tem = build_string (names[i]);
13430 if (NILP (Fassoc (tem, list)))
13431 {
13432 if (STRINGP (Vx_pixel_size_width_font_regexp)
f39db7ea
RS
13433 && ((fast_c_string_match_ignore_case
13434 (Vx_pixel_size_width_font_regexp, names[i]))
dc43ef94
KH
13435 >= 0))
13436 /* We can set the value of PIXEL_SIZE to the
b5210ea7 13437 width of this font. */
dc43ef94
KH
13438 list = Fcons (Fcons (tem, make_number (width)), list);
13439 else
13440 /* For the moment, width is not known. */
13441 list = Fcons (Fcons (tem, Qnil), list);
13442 }
13443 }
13444 }
e38f4136 13445
09c6077f 13446 if (!try_XLoadQueryFont)
e38f4136
GM
13447 {
13448 BLOCK_INPUT;
13449 XFreeFontNames (names);
13450 UNBLOCK_INPUT;
13451 }
dc43ef94
KH
13452 }
13453
b5210ea7 13454 /* Now store the result in the cache. */
9c11f79e
GM
13455 XCDR (dpyinfo->name_list_element)
13456 = Fcons (Fcons (key, list), XCDR (dpyinfo->name_list_element));
dc43ef94 13457
b5210ea7
KH
13458 label_cached:
13459 if (NILP (list)) continue; /* Try the remaining alternatives. */
dc43ef94 13460
b5210ea7
KH
13461 newlist = second_best = Qnil;
13462 /* Make a list of the fonts that have the right width. */
8e713be6 13463 for (; CONSP (list); list = XCDR (list))
b5210ea7 13464 {
536f4067
RS
13465 int found_size;
13466
8e713be6 13467 tem = XCAR (list);
dc43ef94 13468
8e713be6 13469 if (!CONSP (tem) || NILP (XCAR (tem)))
b5210ea7
KH
13470 continue;
13471 if (!size)
13472 {
8e713be6 13473 newlist = Fcons (XCAR (tem), newlist);
b5210ea7
KH
13474 continue;
13475 }
dc43ef94 13476
8e713be6 13477 if (!INTEGERP (XCDR (tem)))
dc43ef94 13478 {
b5210ea7 13479 /* Since we have not yet known the size of this font, we
9c11f79e 13480 must try slow function call XLoadQueryFont. */
dc43ef94
KH
13481 XFontStruct *thisinfo;
13482
13483 BLOCK_INPUT;
17d85edc 13484 count = x_catch_errors (dpy);
dc43ef94 13485 thisinfo = XLoadQueryFont (dpy,
8e713be6 13486 XSTRING (XCAR (tem))->data);
17d85edc
KH
13487 if (x_had_errors_p (dpy))
13488 {
13489 /* This error is perhaps due to insufficient memory on X
13490 server. Let's just ignore it. */
13491 thisinfo = NULL;
13492 x_clear_errors (dpy);
13493 }
13494 x_uncatch_errors (dpy, count);
dc43ef94
KH
13495 UNBLOCK_INPUT;
13496
13497 if (thisinfo)
13498 {
8e713be6 13499 XCDR (tem)
536f4067
RS
13500 = (thisinfo->min_bounds.width == 0
13501 ? make_number (0)
13502 : make_number (thisinfo->max_bounds.width));
e38f4136 13503 BLOCK_INPUT;
dc43ef94 13504 XFreeFont (dpy, thisinfo);
e38f4136 13505 UNBLOCK_INPUT;
dc43ef94
KH
13506 }
13507 else
b5210ea7 13508 /* For unknown reason, the previous call of XListFont had
06a2c219 13509 returned a font which can't be opened. Record the size
b5210ea7 13510 as 0 not to try to open it again. */
8e713be6 13511 XCDR (tem) = make_number (0);
dc43ef94 13512 }
536f4067 13513
8e713be6 13514 found_size = XINT (XCDR (tem));
536f4067 13515 if (found_size == size)
8e713be6 13516 newlist = Fcons (XCAR (tem), newlist);
536f4067 13517 else if (found_size > 0)
b5210ea7 13518 {
536f4067 13519 if (NILP (second_best))
b5210ea7 13520 second_best = tem;
536f4067
RS
13521 else if (found_size < size)
13522 {
8e713be6
KR
13523 if (XINT (XCDR (second_best)) > size
13524 || XINT (XCDR (second_best)) < found_size)
536f4067
RS
13525 second_best = tem;
13526 }
13527 else
13528 {
8e713be6
KR
13529 if (XINT (XCDR (second_best)) > size
13530 && XINT (XCDR (second_best)) > found_size)
536f4067
RS
13531 second_best = tem;
13532 }
b5210ea7
KH
13533 }
13534 }
13535 if (!NILP (newlist))
13536 break;
13537 else if (!NILP (second_best))
13538 {
8e713be6 13539 newlist = Fcons (XCAR (second_best), Qnil);
b5210ea7 13540 break;
dc43ef94 13541 }
dc43ef94
KH
13542 }
13543
13544 return newlist;
13545}
13546
06a2c219
GM
13547
13548#if GLYPH_DEBUG
13549
13550/* Check that FONT is valid on frame F. It is if it can be found in F's
13551 font table. */
13552
13553static void
13554x_check_font (f, font)
13555 struct frame *f;
13556 XFontStruct *font;
13557{
13558 int i;
13559 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13560
13561 xassert (font != NULL);
13562
13563 for (i = 0; i < dpyinfo->n_fonts; i++)
13564 if (dpyinfo->font_table[i].name
13565 && font == dpyinfo->font_table[i].font)
13566 break;
13567
13568 xassert (i < dpyinfo->n_fonts);
13569}
13570
13571#endif /* GLYPH_DEBUG != 0 */
13572
13573/* Set *W to the minimum width, *H to the minimum font height of FONT.
13574 Note: There are (broken) X fonts out there with invalid XFontStruct
13575 min_bounds contents. For example, handa@etl.go.jp reports that
13576 "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
13577 have font->min_bounds.width == 0. */
13578
13579static INLINE void
13580x_font_min_bounds (font, w, h)
13581 XFontStruct *font;
13582 int *w, *h;
13583{
13584 *h = FONT_HEIGHT (font);
13585 *w = font->min_bounds.width;
13586
13587 /* Try to handle the case where FONT->min_bounds has invalid
13588 contents. Since the only font known to have invalid min_bounds
13589 is fixed-width, use max_bounds if min_bounds seems to be invalid. */
13590 if (*w <= 0)
13591 *w = font->max_bounds.width;
13592}
13593
13594
13595/* Compute the smallest character width and smallest font height over
13596 all fonts available on frame F. Set the members smallest_char_width
13597 and smallest_font_height in F's x_display_info structure to
13598 the values computed. Value is non-zero if smallest_font_height or
13599 smallest_char_width become smaller than they were before. */
13600
13601static int
13602x_compute_min_glyph_bounds (f)
13603 struct frame *f;
13604{
13605 int i;
13606 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13607 XFontStruct *font;
13608 int old_width = dpyinfo->smallest_char_width;
13609 int old_height = dpyinfo->smallest_font_height;
13610
13611 dpyinfo->smallest_font_height = 100000;
13612 dpyinfo->smallest_char_width = 100000;
13613
13614 for (i = 0; i < dpyinfo->n_fonts; ++i)
13615 if (dpyinfo->font_table[i].name)
13616 {
13617 struct font_info *fontp = dpyinfo->font_table + i;
13618 int w, h;
13619
13620 font = (XFontStruct *) fontp->font;
13621 xassert (font != (XFontStruct *) ~0);
13622 x_font_min_bounds (font, &w, &h);
13623
13624 dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
13625 dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
13626 }
13627
13628 xassert (dpyinfo->smallest_char_width > 0
13629 && dpyinfo->smallest_font_height > 0);
13630
13631 return (dpyinfo->n_fonts == 1
13632 || dpyinfo->smallest_char_width < old_width
13633 || dpyinfo->smallest_font_height < old_height);
13634}
13635
13636
dc43ef94
KH
13637/* Load font named FONTNAME of the size SIZE for frame F, and return a
13638 pointer to the structure font_info while allocating it dynamically.
13639 If SIZE is 0, load any size of font.
13640 If loading is failed, return NULL. */
13641
13642struct font_info *
13643x_load_font (f, fontname, size)
13644 struct frame *f;
13645 register char *fontname;
13646 int size;
13647{
13648 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13649 Lisp_Object font_names;
d645aaa4 13650 int count;
dc43ef94
KH
13651
13652 /* Get a list of all the fonts that match this name. Once we
13653 have a list of matching fonts, we compare them against the fonts
13654 we already have by comparing names. */
09c6077f 13655 font_names = x_list_fonts (f, build_string (fontname), size, 1);
dc43ef94
KH
13656
13657 if (!NILP (font_names))
13658 {
13659 Lisp_Object tail;
13660 int i;
13661
13662 for (i = 0; i < dpyinfo->n_fonts; i++)
8e713be6 13663 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
06a2c219
GM
13664 if (dpyinfo->font_table[i].name
13665 && (!strcmp (dpyinfo->font_table[i].name,
8e713be6 13666 XSTRING (XCAR (tail))->data)
06a2c219 13667 || !strcmp (dpyinfo->font_table[i].full_name,
8e713be6 13668 XSTRING (XCAR (tail))->data)))
dc43ef94
KH
13669 return (dpyinfo->font_table + i);
13670 }
13671
13672 /* Load the font and add it to the table. */
13673 {
13674 char *full_name;
13675 XFontStruct *font;
13676 struct font_info *fontp;
13677 unsigned long value;
06a2c219 13678 int i;
dc43ef94 13679
2da424f1
KH
13680 /* If we have found fonts by x_list_font, load one of them. If
13681 not, we still try to load a font by the name given as FONTNAME
13682 because XListFonts (called in x_list_font) of some X server has
13683 a bug of not finding a font even if the font surely exists and
13684 is loadable by XLoadQueryFont. */
e1d6d5b9 13685 if (size > 0 && !NILP (font_names))
8e713be6 13686 fontname = (char *) XSTRING (XCAR (font_names))->data;
dc43ef94
KH
13687
13688 BLOCK_INPUT;
d645aaa4 13689 count = x_catch_errors (FRAME_X_DISPLAY (f));
dc43ef94 13690 font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
d645aaa4
KH
13691 if (x_had_errors_p (FRAME_X_DISPLAY (f)))
13692 {
13693 /* This error is perhaps due to insufficient memory on X
13694 server. Let's just ignore it. */
13695 font = NULL;
13696 x_clear_errors (FRAME_X_DISPLAY (f));
13697 }
13698 x_uncatch_errors (FRAME_X_DISPLAY (f), count);
dc43ef94 13699 UNBLOCK_INPUT;
b5210ea7 13700 if (!font)
dc43ef94
KH
13701 return NULL;
13702
06a2c219
GM
13703 /* Find a free slot in the font table. */
13704 for (i = 0; i < dpyinfo->n_fonts; ++i)
13705 if (dpyinfo->font_table[i].name == NULL)
13706 break;
13707
13708 /* If no free slot found, maybe enlarge the font table. */
13709 if (i == dpyinfo->n_fonts
13710 && dpyinfo->n_fonts == dpyinfo->font_table_size)
dc43ef94 13711 {
06a2c219
GM
13712 int sz;
13713 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
13714 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
dc43ef94 13715 dpyinfo->font_table
06a2c219 13716 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
dc43ef94
KH
13717 }
13718
06a2c219
GM
13719 fontp = dpyinfo->font_table + i;
13720 if (i == dpyinfo->n_fonts)
13721 ++dpyinfo->n_fonts;
dc43ef94
KH
13722
13723 /* Now fill in the slots of *FONTP. */
13724 BLOCK_INPUT;
13725 fontp->font = font;
06a2c219 13726 fontp->font_idx = i;
dc43ef94
KH
13727 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
13728 bcopy (fontname, fontp->name, strlen (fontname) + 1);
13729
13730 /* Try to get the full name of FONT. Put it in FULL_NAME. */
13731 full_name = 0;
13732 if (XGetFontProperty (font, XA_FONT, &value))
13733 {
13734 char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
13735 char *p = name;
13736 int dashes = 0;
13737
13738 /* Count the number of dashes in the "full name".
13739 If it is too few, this isn't really the font's full name,
13740 so don't use it.
13741 In X11R4, the fonts did not come with their canonical names
13742 stored in them. */
13743 while (*p)
13744 {
13745 if (*p == '-')
13746 dashes++;
13747 p++;
13748 }
13749
13750 if (dashes >= 13)
13751 {
13752 full_name = (char *) xmalloc (p - name + 1);
13753 bcopy (name, full_name, p - name + 1);
13754 }
13755
13756 XFree (name);
13757 }
13758
13759 if (full_name != 0)
13760 fontp->full_name = full_name;
13761 else
13762 fontp->full_name = fontp->name;
13763
13764 fontp->size = font->max_bounds.width;
d5749adb 13765 fontp->height = FONT_HEIGHT (font);
dc43ef94 13766
2da424f1
KH
13767 if (NILP (font_names))
13768 {
13769 /* We come here because of a bug of XListFonts mentioned at
13770 the head of this block. Let's store this information in
13771 the cache for x_list_fonts. */
13772 Lisp_Object lispy_name = build_string (fontname);
13773 Lisp_Object lispy_full_name = build_string (fontp->full_name);
9c11f79e
GM
13774 Lisp_Object key = Fcons (Fcons (lispy_name, make_number (256)),
13775 Qnil);
2da424f1 13776
8e713be6 13777 XCDR (dpyinfo->name_list_element)
9c11f79e 13778 = Fcons (Fcons (key,
2da424f1
KH
13779 Fcons (Fcons (lispy_full_name,
13780 make_number (fontp->size)),
13781 Qnil)),
8e713be6 13782 XCDR (dpyinfo->name_list_element));
2da424f1 13783 if (full_name)
9c11f79e
GM
13784 {
13785 key = Fcons (Fcons (lispy_full_name, make_number (256)),
13786 Qnil);
13787 XCDR (dpyinfo->name_list_element)
13788 = Fcons (Fcons (key,
13789 Fcons (Fcons (lispy_full_name,
13790 make_number (fontp->size)),
13791 Qnil)),
13792 XCDR (dpyinfo->name_list_element));
13793 }
2da424f1
KH
13794 }
13795
dc43ef94
KH
13796 /* The slot `encoding' specifies how to map a character
13797 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
ee569018
KH
13798 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
13799 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
8ff102bd 13800 2:0xA020..0xFF7F). For the moment, we don't know which charset
06a2c219 13801 uses this font. So, we set information in fontp->encoding[1]
8ff102bd
RS
13802 which is never used by any charset. If mapping can't be
13803 decided, set FONT_ENCODING_NOT_DECIDED. */
dc43ef94
KH
13804 fontp->encoding[1]
13805 = (font->max_byte1 == 0
13806 /* 1-byte font */
13807 ? (font->min_char_or_byte2 < 0x80
13808 ? (font->max_char_or_byte2 < 0x80
13809 ? 0 /* 0x20..0x7F */
8ff102bd 13810 : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
dc43ef94
KH
13811 : 1) /* 0xA0..0xFF */
13812 /* 2-byte font */
13813 : (font->min_byte1 < 0x80
13814 ? (font->max_byte1 < 0x80
13815 ? (font->min_char_or_byte2 < 0x80
13816 ? (font->max_char_or_byte2 < 0x80
13817 ? 0 /* 0x2020..0x7F7F */
8ff102bd 13818 : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
dc43ef94 13819 : 3) /* 0x20A0..0x7FFF */
8ff102bd 13820 : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
dc43ef94
KH
13821 : (font->min_char_or_byte2 < 0x80
13822 ? (font->max_char_or_byte2 < 0x80
13823 ? 2 /* 0xA020..0xFF7F */
8ff102bd 13824 : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
dc43ef94
KH
13825 : 1))); /* 0xA0A0..0xFFFF */
13826
13827 fontp->baseline_offset
13828 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
13829 ? (long) value : 0);
13830 fontp->relative_compose
13831 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
13832 ? (long) value : 0);
f78798df
KH
13833 fontp->default_ascent
13834 = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
13835 ? (long) value : 0);
dc43ef94 13836
06a2c219
GM
13837 /* Set global flag fonts_changed_p to non-zero if the font loaded
13838 has a character with a smaller width than any other character
13839 before, or if the font loaded has a smalle>r height than any
13840 other font loaded before. If this happens, it will make a
13841 glyph matrix reallocation necessary. */
13842 fonts_changed_p = x_compute_min_glyph_bounds (f);
dc43ef94 13843 UNBLOCK_INPUT;
dc43ef94
KH
13844 return fontp;
13845 }
13846}
13847
06a2c219
GM
13848
13849/* Return a pointer to struct font_info of a font named FONTNAME for
13850 frame F. If no such font is loaded, return NULL. */
13851
dc43ef94
KH
13852struct font_info *
13853x_query_font (f, fontname)
13854 struct frame *f;
13855 register char *fontname;
13856{
13857 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
13858 int i;
13859
13860 for (i = 0; i < dpyinfo->n_fonts; i++)
06a2c219
GM
13861 if (dpyinfo->font_table[i].name
13862 && (!strcmp (dpyinfo->font_table[i].name, fontname)
13863 || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
dc43ef94
KH
13864 return (dpyinfo->font_table + i);
13865 return NULL;
13866}
13867
06a2c219
GM
13868
13869/* Find a CCL program for a font specified by FONTP, and set the member
a6582676
KH
13870 `encoder' of the structure. */
13871
13872void
13873x_find_ccl_program (fontp)
13874 struct font_info *fontp;
13875{
a42f54e6 13876 Lisp_Object list, elt;
a6582676 13877
f9b5db02 13878 elt = Qnil;
8e713be6 13879 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
a6582676 13880 {
8e713be6 13881 elt = XCAR (list);
a6582676 13882 if (CONSP (elt)
8e713be6 13883 && STRINGP (XCAR (elt))
9f2feff6
KH
13884 && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
13885 >= 0)
13886 || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
13887 >= 0)))
a42f54e6
KH
13888 break;
13889 }
f9b5db02 13890
a42f54e6
KH
13891 if (! NILP (list))
13892 {
d27f8ca7
KH
13893 struct ccl_program *ccl
13894 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
a42f54e6 13895
8e713be6 13896 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
a42f54e6
KH
13897 xfree (ccl);
13898 else
13899 fontp->font_encoder = ccl;
a6582676
KH
13900 }
13901}
13902
06a2c219 13903
dc43ef94 13904\f
06a2c219
GM
13905/***********************************************************************
13906 Initialization
13907 ***********************************************************************/
f451eb13 13908
3afe33e7
RS
13909#ifdef USE_X_TOOLKIT
13910static XrmOptionDescRec emacs_options[] = {
13911 {"-geometry", ".geometry", XrmoptionSepArg, NULL},
13912 {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
13913
13914 {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
13915 XrmoptionSepArg, NULL},
13916 {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
13917
13918 {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13919 {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13920 {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
13921 {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
13922 {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
13923 {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
13924 {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
13925};
13926#endif /* USE_X_TOOLKIT */
13927
7a13e894
RS
13928static int x_initialized;
13929
29b38361
KH
13930#ifdef MULTI_KBOARD
13931/* Test whether two display-name strings agree up to the dot that separates
13932 the screen number from the server number. */
13933static int
13934same_x_server (name1, name2)
13935 char *name1, *name2;
13936{
13937 int seen_colon = 0;
cf591cc1
RS
13938 unsigned char *system_name = XSTRING (Vsystem_name)->data;
13939 int system_name_length = strlen (system_name);
13940 int length_until_period = 0;
13941
13942 while (system_name[length_until_period] != 0
13943 && system_name[length_until_period] != '.')
13944 length_until_period++;
13945
13946 /* Treat `unix' like an empty host name. */
13947 if (! strncmp (name1, "unix:", 5))
13948 name1 += 4;
13949 if (! strncmp (name2, "unix:", 5))
13950 name2 += 4;
13951 /* Treat this host's name like an empty host name. */
13952 if (! strncmp (name1, system_name, system_name_length)
13953 && name1[system_name_length] == ':')
13954 name1 += system_name_length;
13955 if (! strncmp (name2, system_name, system_name_length)
13956 && name2[system_name_length] == ':')
13957 name2 += system_name_length;
13958 /* Treat this host's domainless name like an empty host name. */
13959 if (! strncmp (name1, system_name, length_until_period)
13960 && name1[length_until_period] == ':')
13961 name1 += length_until_period;
13962 if (! strncmp (name2, system_name, length_until_period)
13963 && name2[length_until_period] == ':')
13964 name2 += length_until_period;
13965
29b38361
KH
13966 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
13967 {
13968 if (*name1 == ':')
13969 seen_colon++;
13970 if (seen_colon && *name1 == '.')
13971 return 1;
13972 }
13973 return (seen_colon
13974 && (*name1 == '.' || *name1 == '\0')
13975 && (*name2 == '.' || *name2 == '\0'));
13976}
13977#endif
13978
334208b7 13979struct x_display_info *
1f8255f2 13980x_term_init (display_name, xrm_option, resource_name)
334208b7 13981 Lisp_Object display_name;
1f8255f2
RS
13982 char *xrm_option;
13983 char *resource_name;
dc6f92b8 13984{
334208b7 13985 int connection;
7a13e894 13986 Display *dpy;
334208b7
RS
13987 struct x_display_info *dpyinfo;
13988 XrmDatabase xrdb;
13989
60439948
KH
13990 BLOCK_INPUT;
13991
7a13e894
RS
13992 if (!x_initialized)
13993 {
13994 x_initialize ();
13995 x_initialized = 1;
13996 }
dc6f92b8 13997
3afe33e7 13998#ifdef USE_X_TOOLKIT
2d7fc7e8
RS
13999 /* weiner@footloose.sps.mot.com reports that this causes
14000 errors with X11R5:
14001 X protocol error: BadAtom (invalid Atom parameter)
14002 on protocol request 18skiloaf.
14003 So let's not use it until R6. */
14004#ifdef HAVE_X11XTR6
bdcd49ba
RS
14005 XtSetLanguageProc (NULL, NULL, NULL);
14006#endif
14007
7f9c7f94
RS
14008 {
14009 int argc = 0;
14010 char *argv[3];
14011
14012 argv[0] = "";
14013 argc = 1;
14014 if (xrm_option)
14015 {
14016 argv[argc++] = "-xrm";
14017 argv[argc++] = xrm_option;
14018 }
14019 dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
14020 resource_name, EMACS_CLASS,
14021 emacs_options, XtNumber (emacs_options),
14022 &argc, argv);
39d8bb4d
KH
14023
14024#ifdef HAVE_X11XTR6
10537cb1 14025 /* I think this is to compensate for XtSetLanguageProc. */
71f8198a 14026 fixup_locale ();
39d8bb4d 14027#endif
7f9c7f94 14028 }
3afe33e7
RS
14029
14030#else /* not USE_X_TOOLKIT */
bdcd49ba
RS
14031#ifdef HAVE_X11R5
14032 XSetLocaleModifiers ("");
14033#endif
7a13e894 14034 dpy = XOpenDisplay (XSTRING (display_name)->data);
3afe33e7 14035#endif /* not USE_X_TOOLKIT */
334208b7 14036
7a13e894
RS
14037 /* Detect failure. */
14038 if (dpy == 0)
60439948
KH
14039 {
14040 UNBLOCK_INPUT;
14041 return 0;
14042 }
7a13e894
RS
14043
14044 /* We have definitely succeeded. Record the new connection. */
14045
14046 dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info));
f04e1297 14047 bzero (dpyinfo, sizeof *dpyinfo);
7a13e894 14048
29b38361
KH
14049#ifdef MULTI_KBOARD
14050 {
14051 struct x_display_info *share;
14052 Lisp_Object tail;
14053
14054 for (share = x_display_list, tail = x_display_name_list; share;
8e713be6
KR
14055 share = share->next, tail = XCDR (tail))
14056 if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
29b38361
KH
14057 XSTRING (display_name)->data))
14058 break;
14059 if (share)
14060 dpyinfo->kboard = share->kboard;
14061 else
14062 {
14063 dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
14064 init_kboard (dpyinfo->kboard);
59e755be
KH
14065 if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
14066 {
14067 char *vendor = ServerVendor (dpy);
9b6ed9f3 14068 UNBLOCK_INPUT;
59e755be
KH
14069 dpyinfo->kboard->Vsystem_key_alist
14070 = call1 (Qvendor_specific_keysyms,
14071 build_string (vendor ? vendor : ""));
9b6ed9f3 14072 BLOCK_INPUT;
59e755be
KH
14073 }
14074
29b38361
KH
14075 dpyinfo->kboard->next_kboard = all_kboards;
14076 all_kboards = dpyinfo->kboard;
0ad5446c
KH
14077 /* Don't let the initial kboard remain current longer than necessary.
14078 That would cause problems if a file loaded on startup tries to
06a2c219 14079 prompt in the mini-buffer. */
0ad5446c
KH
14080 if (current_kboard == initial_kboard)
14081 current_kboard = dpyinfo->kboard;
29b38361
KH
14082 }
14083 dpyinfo->kboard->reference_count++;
14084 }
b9737ad3
KH
14085#endif
14086
7a13e894
RS
14087 /* Put this display on the chain. */
14088 dpyinfo->next = x_display_list;
14089 x_display_list = dpyinfo;
14090
14091 /* Put it on x_display_name_list as well, to keep them parallel. */
14092 x_display_name_list = Fcons (Fcons (display_name, Qnil),
14093 x_display_name_list);
8e713be6 14094 dpyinfo->name_list_element = XCAR (x_display_name_list);
7a13e894
RS
14095
14096 dpyinfo->display = dpy;
dc6f92b8 14097
dc6f92b8 14098#if 0
7a13e894 14099 XSetAfterFunction (x_current_display, x_trace_wire);
c118dd06 14100#endif /* ! 0 */
7a13e894
RS
14101
14102 dpyinfo->x_id_name
fc932ac6
RS
14103 = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
14104 + STRING_BYTES (XSTRING (Vsystem_name))
7a13e894
RS
14105 + 2);
14106 sprintf (dpyinfo->x_id_name, "%s@%s",
14107 XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
28430d3c
JB
14108
14109 /* Figure out which modifier bits mean what. */
334208b7 14110 x_find_modifier_meanings (dpyinfo);
f451eb13 14111
ab648270 14112 /* Get the scroll bar cursor. */
7a13e894 14113 dpyinfo->vertical_scroll_bar_cursor
334208b7 14114 = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
f451eb13 14115
334208b7
RS
14116 xrdb = x_load_resources (dpyinfo->display, xrm_option,
14117 resource_name, EMACS_CLASS);
14118#ifdef HAVE_XRMSETDATABASE
14119 XrmSetDatabase (dpyinfo->display, xrdb);
14120#else
14121 dpyinfo->display->db = xrdb;
14122#endif
547d9db8 14123 /* Put the rdb where we can find it in a way that works on
7a13e894
RS
14124 all versions. */
14125 dpyinfo->xrdb = xrdb;
334208b7
RS
14126
14127 dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
14128 DefaultScreen (dpyinfo->display));
5ff67d81 14129 select_visual (dpyinfo);
43bd1b2b 14130 dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
334208b7
RS
14131 dpyinfo->height = HeightOfScreen (dpyinfo->screen);
14132 dpyinfo->width = WidthOfScreen (dpyinfo->screen);
14133 dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
14134 dpyinfo->grabbed = 0;
14135 dpyinfo->reference_count = 0;
14136 dpyinfo->icon_bitmap_id = -1;
06a2c219 14137 dpyinfo->font_table = NULL;
7a13e894
RS
14138 dpyinfo->n_fonts = 0;
14139 dpyinfo->font_table_size = 0;
14140 dpyinfo->bitmaps = 0;
14141 dpyinfo->bitmaps_size = 0;
14142 dpyinfo->bitmaps_last = 0;
14143 dpyinfo->scratch_cursor_gc = 0;
14144 dpyinfo->mouse_face_mouse_frame = 0;
14145 dpyinfo->mouse_face_deferred_gc = 0;
14146 dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
14147 dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
06a2c219 14148 dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
7a13e894 14149 dpyinfo->mouse_face_window = Qnil;
0a61c667 14150 dpyinfo->mouse_face_overlay = Qnil;
7a13e894
RS
14151 dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
14152 dpyinfo->mouse_face_defer = 0;
0f941935
KH
14153 dpyinfo->x_focus_frame = 0;
14154 dpyinfo->x_focus_event_frame = 0;
14155 dpyinfo->x_highlight_frame = 0;
06a2c219 14156 dpyinfo->image_cache = make_image_cache ();
334208b7 14157
43bd1b2b 14158 /* See if a private colormap is requested. */
5ff67d81
GM
14159 if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
14160 {
14161 if (dpyinfo->visual->class == PseudoColor)
14162 {
14163 Lisp_Object value;
14164 value = display_x_get_resource (dpyinfo,
14165 build_string ("privateColormap"),
14166 build_string ("PrivateColormap"),
14167 Qnil, Qnil);
14168 if (STRINGP (value)
14169 && (!strcmp (XSTRING (value)->data, "true")
14170 || !strcmp (XSTRING (value)->data, "on")))
14171 dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
14172 }
43bd1b2b 14173 }
5ff67d81
GM
14174 else
14175 dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
14176 dpyinfo->visual, AllocNone);
43bd1b2b 14177
06a2c219
GM
14178 {
14179 int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
14180 double pixels = DisplayHeight (dpyinfo->display, screen_number);
14181 double mm = DisplayHeightMM (dpyinfo->display, screen_number);
14182 dpyinfo->resy = pixels * 25.4 / mm;
14183 pixels = DisplayWidth (dpyinfo->display, screen_number);
14184 mm = DisplayWidthMM (dpyinfo->display, screen_number);
14185 dpyinfo->resx = pixels * 25.4 / mm;
14186 }
14187
334208b7
RS
14188 dpyinfo->Xatom_wm_protocols
14189 = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
14190 dpyinfo->Xatom_wm_take_focus
14191 = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
14192 dpyinfo->Xatom_wm_save_yourself
14193 = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
14194 dpyinfo->Xatom_wm_delete_window
14195 = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
14196 dpyinfo->Xatom_wm_change_state
14197 = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
14198 dpyinfo->Xatom_wm_configure_denied
14199 = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
14200 dpyinfo->Xatom_wm_window_moved
14201 = XInternAtom (dpyinfo->display, "WM_MOVED", False);
14202 dpyinfo->Xatom_editres
14203 = XInternAtom (dpyinfo->display, "Editres", False);
14204 dpyinfo->Xatom_CLIPBOARD
14205 = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
14206 dpyinfo->Xatom_TIMESTAMP
14207 = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
14208 dpyinfo->Xatom_TEXT
14209 = XInternAtom (dpyinfo->display, "TEXT", False);
dc43ef94
KH
14210 dpyinfo->Xatom_COMPOUND_TEXT
14211 = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
334208b7
RS
14212 dpyinfo->Xatom_DELETE
14213 = XInternAtom (dpyinfo->display, "DELETE", False);
14214 dpyinfo->Xatom_MULTIPLE
14215 = XInternAtom (dpyinfo->display, "MULTIPLE", False);
14216 dpyinfo->Xatom_INCR
14217 = XInternAtom (dpyinfo->display, "INCR", False);
14218 dpyinfo->Xatom_EMACS_TMP
14219 = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
14220 dpyinfo->Xatom_TARGETS
14221 = XInternAtom (dpyinfo->display, "TARGETS", False);
14222 dpyinfo->Xatom_NULL
14223 = XInternAtom (dpyinfo->display, "NULL", False);
14224 dpyinfo->Xatom_ATOM_PAIR
14225 = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
dc43ef94
KH
14226 /* For properties of font. */
14227 dpyinfo->Xatom_PIXEL_SIZE
14228 = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
14229 dpyinfo->Xatom_MULE_BASELINE_OFFSET
14230 = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
14231 dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
14232 = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
f78798df
KH
14233 dpyinfo->Xatom_MULE_DEFAULT_ASCENT
14234 = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
334208b7 14235
06a2c219
GM
14236 /* Ghostscript support. */
14237 dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
14238 dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
14239
14240 dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
14241 False);
14242
547d9db8
KH
14243 dpyinfo->cut_buffers_initialized = 0;
14244
334208b7
RS
14245 connection = ConnectionNumber (dpyinfo->display);
14246 dpyinfo->connection = connection;
14247
dc43ef94 14248 {
5d7cc324
RS
14249 char null_bits[1];
14250
14251 null_bits[0] = 0x00;
dc43ef94
KH
14252
14253 dpyinfo->null_pixel
14254 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14255 null_bits, 1, 1, (long) 0, (long) 0,
14256 1);
14257 }
14258
06a2c219
GM
14259 {
14260 extern int gray_bitmap_width, gray_bitmap_height;
10659c77 14261 extern char *gray_bitmap_bits;
06a2c219
GM
14262 dpyinfo->gray
14263 = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
14264 gray_bitmap_bits,
14265 gray_bitmap_width, gray_bitmap_height,
14266 (unsigned long) 1, (unsigned long) 0, 1);
14267 }
14268
f5d11644
GM
14269#ifdef HAVE_X_I18N
14270 xim_initialize (dpyinfo, resource_name);
14271#endif
14272
87485d6f
MW
14273#ifdef subprocesses
14274 /* This is only needed for distinguishing keyboard and process input. */
334208b7 14275 if (connection != 0)
7a13e894 14276 add_keyboard_wait_descriptor (connection);
87485d6f 14277#endif
6d4238f3 14278
041b69ac 14279#ifndef F_SETOWN_BUG
dc6f92b8 14280#ifdef F_SETOWN
dc6f92b8 14281#ifdef F_SETOWN_SOCK_NEG
61c3ce62 14282 /* stdin is a socket here */
334208b7 14283 fcntl (connection, F_SETOWN, -getpid ());
c118dd06 14284#else /* ! defined (F_SETOWN_SOCK_NEG) */
334208b7 14285 fcntl (connection, F_SETOWN, getpid ());
c118dd06
JB
14286#endif /* ! defined (F_SETOWN_SOCK_NEG) */
14287#endif /* ! defined (F_SETOWN) */
041b69ac 14288#endif /* F_SETOWN_BUG */
dc6f92b8
JB
14289
14290#ifdef SIGIO
eee20f6a
KH
14291 if (interrupt_input)
14292 init_sigio (connection);
c118dd06 14293#endif /* ! defined (SIGIO) */
dc6f92b8 14294
51b592fb 14295#ifdef USE_LUCID
f8c39f51 14296#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
51b592fb
RS
14297 /* Make sure that we have a valid font for dialog boxes
14298 so that Xt does not crash. */
14299 {
14300 Display *dpy = dpyinfo->display;
14301 XrmValue d, fr, to;
14302 Font font;
e99db5a1 14303 int count;
51b592fb
RS
14304
14305 d.addr = (XPointer)&dpy;
14306 d.size = sizeof (Display *);
14307 fr.addr = XtDefaultFont;
14308 fr.size = sizeof (XtDefaultFont);
14309 to.size = sizeof (Font *);
14310 to.addr = (XPointer)&font;
e99db5a1 14311 count = x_catch_errors (dpy);
51b592fb
RS
14312 if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
14313 abort ();
14314 if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
14315 XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
e99db5a1 14316 x_uncatch_errors (dpy, count);
51b592fb
RS
14317 }
14318#endif
f8c39f51 14319#endif
51b592fb 14320
34e23e5a
GM
14321 /* See if we should run in synchronous mode. This is useful
14322 for debugging X code. */
14323 {
14324 Lisp_Object value;
14325 value = display_x_get_resource (dpyinfo,
14326 build_string ("synchronous"),
14327 build_string ("Synchronous"),
14328 Qnil, Qnil);
14329 if (STRINGP (value)
14330 && (!strcmp (XSTRING (value)->data, "true")
14331 || !strcmp (XSTRING (value)->data, "on")))
14332 XSynchronize (dpyinfo->display, True);
14333 }
14334
60439948
KH
14335 UNBLOCK_INPUT;
14336
7a13e894
RS
14337 return dpyinfo;
14338}
14339\f
14340/* Get rid of display DPYINFO, assuming all frames are already gone,
14341 and without sending any more commands to the X server. */
dc6f92b8 14342
7a13e894
RS
14343void
14344x_delete_display (dpyinfo)
14345 struct x_display_info *dpyinfo;
14346{
14347 delete_keyboard_wait_descriptor (dpyinfo->connection);
14348
14349 /* Discard this display from x_display_name_list and x_display_list.
14350 We can't use Fdelq because that can quit. */
14351 if (! NILP (x_display_name_list)
8e713be6
KR
14352 && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
14353 x_display_name_list = XCDR (x_display_name_list);
7a13e894
RS
14354 else
14355 {
14356 Lisp_Object tail;
14357
14358 tail = x_display_name_list;
8e713be6 14359 while (CONSP (tail) && CONSP (XCDR (tail)))
7a13e894 14360 {
bffcfca9 14361 if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
7a13e894 14362 {
8e713be6 14363 XCDR (tail) = XCDR (XCDR (tail));
7a13e894
RS
14364 break;
14365 }
8e713be6 14366 tail = XCDR (tail);
7a13e894
RS
14367 }
14368 }
14369
9bda743f
GM
14370 if (next_noop_dpyinfo == dpyinfo)
14371 next_noop_dpyinfo = dpyinfo->next;
14372
7a13e894
RS
14373 if (x_display_list == dpyinfo)
14374 x_display_list = dpyinfo->next;
7f9c7f94
RS
14375 else
14376 {
14377 struct x_display_info *tail;
7a13e894 14378
7f9c7f94
RS
14379 for (tail = x_display_list; tail; tail = tail->next)
14380 if (tail->next == dpyinfo)
14381 tail->next = tail->next->next;
14382 }
7a13e894 14383
0d777288
RS
14384#ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
14385#ifndef AIX /* On AIX, XCloseDisplay calls this. */
7f9c7f94
RS
14386 XrmDestroyDatabase (dpyinfo->xrdb);
14387#endif
0d777288 14388#endif
29b38361
KH
14389#ifdef MULTI_KBOARD
14390 if (--dpyinfo->kboard->reference_count == 0)
39f79001 14391 delete_kboard (dpyinfo->kboard);
b9737ad3 14392#endif
f5d11644
GM
14393#ifdef HAVE_X_I18N
14394 if (dpyinfo->xim)
14395 xim_close_dpy (dpyinfo);
14396#endif
14397
b9737ad3
KH
14398 xfree (dpyinfo->font_table);
14399 xfree (dpyinfo->x_id_name);
f04e1297 14400 xfree (dpyinfo->color_cells);
b9737ad3 14401 xfree (dpyinfo);
7a13e894 14402}
f04e1297 14403
7a13e894
RS
14404\f
14405/* Set up use of X before we make the first connection. */
14406
06a2c219
GM
14407static struct redisplay_interface x_redisplay_interface =
14408{
14409 x_produce_glyphs,
14410 x_write_glyphs,
14411 x_insert_glyphs,
14412 x_clear_end_of_line,
14413 x_scroll_run,
14414 x_after_update_window_line,
14415 x_update_window_begin,
14416 x_update_window_end,
14417 XTcursor_to,
14418 x_flush,
71b8321e 14419 x_clear_mouse_face,
66ac4b0e
GM
14420 x_get_glyph_overhangs,
14421 x_fix_overlapping_area
06a2c219
GM
14422};
14423
dfcf069d 14424void
7a13e894
RS
14425x_initialize ()
14426{
06a2c219
GM
14427 rif = &x_redisplay_interface;
14428
14429 clear_frame_hook = x_clear_frame;
14430 ins_del_lines_hook = x_ins_del_lines;
14431 change_line_highlight_hook = x_change_line_highlight;
14432 delete_glyphs_hook = x_delete_glyphs;
dc6f92b8
JB
14433 ring_bell_hook = XTring_bell;
14434 reset_terminal_modes_hook = XTreset_terminal_modes;
14435 set_terminal_modes_hook = XTset_terminal_modes;
06a2c219
GM
14436 update_begin_hook = x_update_begin;
14437 update_end_hook = x_update_end;
dc6f92b8
JB
14438 set_terminal_window_hook = XTset_terminal_window;
14439 read_socket_hook = XTread_socket;
b8009dd1 14440 frame_up_to_date_hook = XTframe_up_to_date;
dc6f92b8 14441 reassert_line_highlight_hook = XTreassert_line_highlight;
90e65f07 14442 mouse_position_hook = XTmouse_position;
f451eb13 14443 frame_rehighlight_hook = XTframe_rehighlight;
dbc4e1c1 14444 frame_raise_lower_hook = XTframe_raise_lower;
ab648270
JB
14445 set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
14446 condemn_scroll_bars_hook = XTcondemn_scroll_bars;
14447 redeem_scroll_bar_hook = XTredeem_scroll_bar;
14448 judge_scroll_bars_hook = XTjudge_scroll_bars;
06a2c219 14449 estimate_mode_line_height_hook = x_estimate_mode_line_height;
58769bee 14450
f676886a 14451 scroll_region_ok = 1; /* we'll scroll partial frames */
9017309f 14452 char_ins_del_ok = 1;
dc6f92b8
JB
14453 line_ins_del_ok = 1; /* we'll just blt 'em */
14454 fast_clear_end_of_line = 1; /* X does this well */
58769bee 14455 memory_below_frame = 0; /* we don't remember what scrolls
dc6f92b8
JB
14456 off the bottom */
14457 baud_rate = 19200;
14458
7a13e894 14459 x_noop_count = 0;
9ea173e8 14460 last_tool_bar_item = -1;
06a2c219
GM
14461 any_help_event_p = 0;
14462
b30b24cb
RS
14463 /* Try to use interrupt input; if we can't, then start polling. */
14464 Fset_input_mode (Qt, Qnil, Qt, Qnil);
14465
7f9c7f94
RS
14466#ifdef USE_X_TOOLKIT
14467 XtToolkitInitialize ();
651f03b6 14468
7f9c7f94 14469 Xt_app_con = XtCreateApplicationContext ();
651f03b6
GM
14470
14471 /* Register a converter from strings to pixels, which uses
14472 Emacs' color allocation infrastructure. */
14473 XtAppSetTypeConverter (Xt_app_con,
14474 XtRString, XtRPixel, cvt_string_to_pixel,
14475 cvt_string_to_pixel_args,
14476 XtNumber (cvt_string_to_pixel_args),
14477 XtCacheByDisplay, cvt_pixel_dtor);
14478
665881ad 14479 XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
bffcfca9
GM
14480
14481 /* Install an asynchronous timer that processes Xt timeout events
14482 every 0.1s. This is necessary because some widget sets use
14483 timeouts internally, for example the LessTif menu bar, or the
14484 Xaw3d scroll bar. When Xt timouts aren't processed, these
14485 widgets don't behave normally. */
14486 {
14487 EMACS_TIME interval;
14488 EMACS_SET_SECS_USECS (interval, 0, 100000);
14489 start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
14490 }
db74249b 14491#endif
bffcfca9 14492
eccc05db 14493#ifdef USE_TOOLKIT_SCROLL_BARS
ec18280f
SM
14494 xaw3d_arrow_scroll = False;
14495 xaw3d_pick_top = True;
7f9c7f94
RS
14496#endif
14497
58769bee 14498 /* Note that there is no real way portable across R3/R4 to get the
c118dd06 14499 original error handler. */
e99db5a1 14500 XSetErrorHandler (x_error_handler);
334208b7 14501 XSetIOErrorHandler (x_io_error_quitter);
dc6f92b8 14502
06a2c219 14503 /* Disable Window Change signals; they are handled by X events. */
dc6f92b8
JB
14504#ifdef SIGWINCH
14505 signal (SIGWINCH, SIG_DFL);
c118dd06 14506#endif /* ! defined (SIGWINCH) */
dc6f92b8 14507
92e2441b 14508 signal (SIGPIPE, x_connection_signal);
dc6f92b8 14509}
55123275 14510
06a2c219 14511
55123275
JB
14512void
14513syms_of_xterm ()
14514{
e99db5a1
RS
14515 staticpro (&x_error_message_string);
14516 x_error_message_string = Qnil;
14517
7a13e894
RS
14518 staticpro (&x_display_name_list);
14519 x_display_name_list = Qnil;
334208b7 14520
ab648270 14521 staticpro (&last_mouse_scroll_bar);
e53cb100 14522 last_mouse_scroll_bar = Qnil;
59e755be
KH
14523
14524 staticpro (&Qvendor_specific_keysyms);
14525 Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
2237cac9
RS
14526
14527 staticpro (&last_mouse_press_frame);
14528 last_mouse_press_frame = Qnil;
06a2c219 14529
06a2c219 14530 help_echo = Qnil;
be010514
GM
14531 staticpro (&help_echo);
14532 help_echo_object = Qnil;
14533 staticpro (&help_echo_object);
7cea38bc
GM
14534 help_echo_window = Qnil;
14535 staticpro (&help_echo_window);
06a2c219 14536 previous_help_echo = Qnil;
be010514
GM
14537 staticpro (&previous_help_echo);
14538 help_echo_pos = -1;
06a2c219
GM
14539
14540 DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
14541 "*Non-nil means draw block cursor as wide as the glyph under it.\n\
14542For example, if a block cursor is over a tab, it will be drawn as\n\
14543wide as that tab on the display.");
14544 x_stretch_cursor_p = 0;
14545
a72d5ce5
GM
14546 DEFVAR_BOOL ("x-use-underline-position-properties",
14547 &x_use_underline_position_properties,
14548 "*Non-nil means make use of UNDERLINE_POSITION font properties.\n\
14549Nil means ignore them. If you encounter fonts with bogus\n\
14550UNDERLINE_POSITION font properties, for example 7x13 on XFree prior\n\
14551to 4.1, set this to nil.");
14552 x_use_underline_position_properties = 1;
14553
5bf04520
GM
14554 DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
14555 "What X toolkit scroll bars Emacs uses.\n\
14556A value of nil means Emacs doesn't use X toolkit scroll bars.\n\
14557Otherwise, value is a symbol describing the X toolkit.");
eccc05db 14558#ifdef USE_TOOLKIT_SCROLL_BARS
5bf04520
GM
14559#ifdef USE_MOTIF
14560 Vx_toolkit_scroll_bars = intern ("motif");
14561#elif defined HAVE_XAW3D
14562 Vx_toolkit_scroll_bars = intern ("xaw3d");
14563#else
14564 Vx_toolkit_scroll_bars = intern ("xaw");
14565#endif
06a2c219 14566#else
5bf04520 14567 Vx_toolkit_scroll_bars = Qnil;
06a2c219
GM
14568#endif
14569
06a2c219
GM
14570 staticpro (&last_mouse_motion_frame);
14571 last_mouse_motion_frame = Qnil;
55123275 14572}
6cf0ae86
RS
14573
14574#endif /* not HAVE_X_WINDOWS */